grid.c 141 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
3
4
#if defined (HAVE_CONFIG_H)
#  include "config.h"
#endif

Thomas Jahns's avatar
Thomas Jahns committed
5
#include <assert.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6
#include <string.h>
7
#include <float.h>  /* FLT_EPSILON */
8
#include <limits.h> /* INT_MAX     */
9

Uwe Schulzweida's avatar
Uwe Schulzweida committed
10
11
#include "dmemory.h"
#include "cdi.h"
12
#include "cdi_cksum.h"
13
#include "cdi_int.h"
14
#include "cdi_uuid.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
15
#include "grid.h"
16
#include "gaussgrid.h"
17
#include "resource_handle.h"
18
#include "resource_unpack.h"
19
#include "namespace.h"
20
#include "serialize.h"
21
22
#include "vlist.h"

23
double grid_missval = -9999.;
24
int (*proj_lonlat_to_lcc_func)() = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
25

26
27
28
/* the value in the second pair of brackets must match the length of
 * the longest string (including terminating NUL) */
static const char Grids[][17] = {
29
30
31
32
33
34
35
36
37
  /*  0 */  "undefined",
  /*  1 */  "generic",
  /*  2 */  "gaussian",
  /*  3 */  "gaussian reduced",
  /*  4 */  "lonlat",
  /*  5 */  "spectral",
  /*  6 */  "fourier",
  /*  7 */  "gme",
  /*  8 */  "trajectory",
38
  /*  9 */  "unstructured",
39
40
  /* 10 */  "curvilinear",
  /* 11 */  "lcc",
41
  /* 12 */  "projection",
Uwe Schulzweida's avatar
Uwe Schulzweida committed
42
43
};

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/* must match table below */
enum xystdname_idx {
  grid_xystdname_grid_latlon,
  grid_xystdname_latlon,
  grid_xystdname_projection,
};
static const char xystdname_tab[][2][24] = {
  [grid_xystdname_grid_latlon] = { "grid_longitude",
                                   "grid_latitude" },
  [grid_xystdname_latlon] = { "longitude",
                              "latitude" },
  [grid_xystdname_projection] = { "projection_x_coordinate",
                                  "projection_y_coordinate" },

};


Uwe Schulzweida's avatar
Uwe Schulzweida committed
61

62
63
64
static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
static void   gridDestroyP    ( void * gridptr );
static void   gridPrintP      ( void * gridptr, FILE * fp );
65
static int    gridGetPackSize ( void * gridptr, void *context);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
66
static void   gridPack        ( void * gridptr, void * buff, int size, int *position, void *context);
Deike Kleberg's avatar
minimal    
Deike Kleberg committed
67
static int    gridTxCode      ( void );
Uwe Schulzweida's avatar
Uwe Schulzweida committed
68

69
static const resOps gridOps = {
70
71
72
73
74
75
  gridCompareP,
  gridDestroyP,
  gridPrintP,
  gridGetPackSize,
  gridPack,
  gridTxCode
76
};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
77

78
static int  GRID_Debug = 0;   /* If set to 1, debugging */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
79

Uwe Schulzweida's avatar
Uwe Schulzweida committed
80

81
grid_t *grid_to_pointer(int gridID)
82
83
84
{
  return (grid_t *)reshGetVal(gridID, &gridOps);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
85

86
#define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
87

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
static
bool cdiInqAttConvertedToFloat(int gridID, int atttype, const char *attname, int attlen, double *attflt)
{
  bool status = true;

  if ( atttype == CDI_DATATYPE_INT32 )
    {
      int attint[attlen];
      cdiInqAttInt(gridID, CDI_GLOBAL, attname, attlen, attint);
      for ( int i = 0; i < attlen; ++i ) attflt[i] = (double)attint[i];
    }
  else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
    {
      cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, attflt);
    }
  else
    {
      status = false;
    }

  return status;
}

111

Deike Kleberg's avatar
Deike Kleberg committed
112
void grid_init(grid_t *gridptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
113
{
114
115
116
  gridptr->self          = CDI_UNDEFID;
  gridptr->type          = CDI_UNDEFID;
  gridptr->proj          = CDI_UNDEFID;
117
  gridptr->projtype      = CDI_UNDEFID;
118
119
  gridptr->mask          = NULL;
  gridptr->mask_gme      = NULL;
120
121
122
123
  gridptr->x.vals        = NULL;
  gridptr->y.vals        = NULL;
  gridptr->x.bounds      = NULL;
  gridptr->y.bounds      = NULL;
124
  gridptr->area          = NULL;
125
126
  gridptr->rowlon        = NULL;
  gridptr->nrowlon       = 0;
127

128
129
130
131
132
133
  gridptr->x.first       = 0.0;
  gridptr->x.last        = 0.0;
  gridptr->x.inc         = 0.0;
  gridptr->y.first       = 0.0;
  gridptr->y.last        = 0.0;
  gridptr->y.inc         = 0.0;
134

135
136
137
138
  gridptr->gme.nd        = 0;
  gridptr->gme.ni        = 0;
  gridptr->gme.ni2       = 0;
  gridptr->gme.ni3       = 0;
139

140
141
142
143
144
145
146
  gridptr->trunc         = 0;
  gridptr->nvertex       = 0;
  gridptr->number        = 0;
  gridptr->position      = 0;
  gridptr->reference     = NULL;
  gridptr->prec          = 0;
  gridptr->size          = 0;
147
148
  gridptr->x.size        = 0;
  gridptr->y.size        = 0;
149
  gridptr->np            = 0;
150
151
  gridptr->x.flag        = 0;
  gridptr->y.flag        = 0;
152
  gridptr->isCyclic      = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
153

154
  gridptr->lcomplex      = false;
155
156
157
158
159
160
161
162
163
164
165
  gridptr->hasdims       = true;
  gridptr->x.dimname[0]  = 0;
  gridptr->y.dimname[0]  = 0;
  gridptr->x.name[0]     = 0;
  gridptr->y.name[0]     = 0;
  gridptr->x.longname[0] = 0;
  gridptr->y.longname[0] = 0;
  gridptr->x.units[0]    = 0;
  gridptr->y.units[0]    = 0;
  gridptr->x.stdname     = NULL;
  gridptr->y.stdname     = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
166
167
168
  gridptr->vdimname[0]   = 0;
  gridptr->mapname[0]    = 0;
  gridptr->mapping[0]    = 0;
Thomas Jahns's avatar
Thomas Jahns committed
169
  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
170
171
  gridptr->name          = NULL;
  gridptr->vtable        = &cdiGridVtable;
172
  gridptr->atts.nalloc   = MAX_ATTRIBUTES;
173
  gridptr->atts.nelems   = 0;
174
  gridptr->uvRelativeToGrid      = 0;   // Some models deliver wind U,V relative to the grid-cell
175
176
177
178
179
180
181
182
183
184
  gridptr->iScansNegatively      = 0;
  gridptr->jScansPositively      = 1;
  gridptr->jPointsAreConsecutive = 0;
  gridptr->scanningMode          = 128*gridptr->iScansNegatively + 64*gridptr->jScansPositively + 32*gridptr->jPointsAreConsecutive;
  /* scanningMode  = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
               64  = 128 * 0                + 64 *        1         + 32 * 0
               00  = 128 * 0                + 64 *        0         + 32 * 0
               96  = 128 * 0                + 64 *        1         + 32 * 1
     Default / implicit scanning mode is 64:
                        i and j scan positively, i points are consecutive (row-major)        */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
185
186
}

187

188
189
static
void grid_free_components(grid_t *gridptr)
Deike Kleberg's avatar
Deike Kleberg committed
190
{
191
  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
192
193
194
195
196
                     gridptr->x.vals, gridptr->y.vals,
                     gridptr->x.bounds, gridptr->y.bounds,
                     gridptr->rowlon, gridptr->area,
                     gridptr->reference, gridptr->name};

197
  for ( size_t i = 0; i < sizeof(p2free)/sizeof(p2free[0]); ++i )
198
    if ( p2free[i] ) Free(p2free[i]);
199
}
Deike Kleberg's avatar
Deike Kleberg committed
200

201
202
203
void grid_free(grid_t *gridptr)
{
  grid_free_components(gridptr);
Deike Kleberg's avatar
Deike Kleberg committed
204
205
206
  grid_init(gridptr);
}

207
208
static
grid_t *gridNewEntry(cdiResH resH)
209
{
210
  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
211
  grid_init(gridptr);
212

213
  if ( resH == CDI_UNDEFID )
214
215
216
217
218
219
    gridptr->self = reshPut(gridptr, &gridOps);
  else
    {
      gridptr->self = resH;
      reshReplace(resH, gridptr, &gridOps);
    }
220

221
  return gridptr;
222
223
}

224
static
225
void gridInit(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
226
{
227
  static bool gridInitialized = false;
228
  if ( gridInitialized ) return;
229
  gridInitialized = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
230

Uwe Schulzweida's avatar
Uwe Schulzweida committed
231
  const char *env = getenv("GRID_DEBUG");
232
  if ( env ) GRID_Debug = atoi(env);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
233
234
}

235
236
static
void grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
237
{
Thomas Jahns's avatar
Thomas Jahns committed
238
239
  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
  gridptrDup->self = CDI_UNDEFID;
240
  if ( gridptrOrig->reference )
Thomas Jahns's avatar
Thomas Jahns committed
241
242
243
    gridptrDup->reference = strdupx(gridptrOrig->reference);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
244

245
246
static
grid_t *grid_copy_base(grid_t *gridptrOrig)
Thomas Jahns's avatar
Thomas Jahns committed
247
248
249
250
251
{
  grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
  gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
  gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
  return gridptrDup;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
252
253
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
254

255
unsigned cdiGridCount(void)
Thomas Jahns's avatar
Thomas Jahns committed
256
{
257
  return reshCountType(&gridOps);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
258
259
}

260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
static inline
void gridSetString(char *gridstrname, const char *name, size_t len)
{
  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
  strncpy(gridstrname, name, len);
  gridstrname[len - 1] = 0;
}

static inline
void gridGetString(char *name, const char *gridstrname, size_t len)
{
  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
  strncpy(name, gridstrname, len);
  name[len - 1] = 0;
}

276
277
static inline
void gridSetName(char *gridstrname, const char *name)
278
{
279
280
  strncpy(gridstrname, name, CDI_MAX_NAME);
  gridstrname[CDI_MAX_NAME - 1] = 0;
281
282
}

283
284

void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
285
286
287
288
{
  gridptr->type = gridtype;
  gridptr->size = size;

289
290
291
  if      ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;

292
293
294
295
296
297
  switch (gridtype)
    {
    case GRID_LONLAT:
    case GRID_GAUSSIAN:
    case GRID_GAUSSIAN_REDUCED:
    case GRID_TRAJECTORY:
298
299
300
    case GRID_CURVILINEAR:
    case GRID_UNSTRUCTURED:
    case GRID_GME:
301
302
303
      {
        if ( gridtype == GRID_TRAJECTORY )
          {
304
305
            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "tlon");
            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "tlat");
306
307
308
          }
        else
          {
309
310
            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "lon");
            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "lat");
311
          }
312

313
314
        gridSetName(gridptr->x.longname, "longitude");
        gridSetName(gridptr->y.longname, "latitude");
315

316
317
        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
318
319
        gridSetName(gridptr->x.units, "degrees_east");
        gridSetName(gridptr->y.units, "degrees_north");
320

321
322
323
        break;
      }
    case GRID_GENERIC:
324
    case GRID_PROJECTION:
325
      {
326
327
        if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "x");
        if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "y");
328
329
330
        if ( gridtype == GRID_PROJECTION )
          {
            gridSetName(gridptr->mapname, "Projection");
331

332
333
334
335
336
            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
            gridSetName(gridptr->x.units, "m");
            gridSetName(gridptr->y.units, "m");
          }
337
338
339
340
341
342
        break;
      }
    }
}


343
// used also in CDO
344
void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
345
{
346
  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
347
348
    {
      if ( xfirst >= xlast )
Thomas Jahns's avatar
Thomas Jahns committed
349
350
351
352
        {
          while ( xfirst >= xlast ) xlast += 360;
          xinc = (xlast-xfirst)/(xsize);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
353
      else
Thomas Jahns's avatar
Thomas Jahns committed
354
355
356
        {
          xinc = (xlast-xfirst)/(xsize-1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
357
358
    }

359
  for ( int i = 0; i < xsize; ++i )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
360
361
362
    xvals[i] = xfirst + i*xinc;
}

363
static
364
void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
365
{
366
  double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
367
  gaussaw(yvals, yw, (size_t)ysize);
368
  Free(yw);
369
  for (int i = 0; i < ysize; i++ )
370
371
372
373
    yvals[i] = asin(yvals[i])/M_PI*180.0;

  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
    {
374
375
      int yhsize = ysize/2;
      for (int i = 0; i < yhsize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
376
        {
377
          double ytmp = yvals[i];
Thomas Jahns's avatar
Thomas Jahns committed
378
379
380
          yvals[i] = yvals[ysize-i-1];
          yvals[ysize-i-1] = ytmp;
        }
381
382
383
    }
}

384
// used also in CDO
Thomas Jahns's avatar
Thomas Jahns committed
385
void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
386
{
387
  const double deleps = 0.002;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
388
389
390
391

  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
    {
      if ( ysize > 2 )
Deike Kleberg's avatar
Deike Kleberg committed
392
393
394
395
396
397
	{
	  calc_gaussgrid(yvals, ysize, yfirst, ylast);

	  if ( ! (IS_EQUAL(yfirst, 0) && IS_EQUAL(ylast, 0)) )
	    if ( fabs(yvals[0] - yfirst) > deleps || fabs(yvals[ysize-1] - ylast) > deleps )
	      {
398
		double *restrict ytmp = NULL;
Deike Kleberg's avatar
Deike Kleberg committed
399
		int nstart, lfound = 0;
400
		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
Deike Kleberg's avatar
Deike Kleberg committed
401
402
403
		ny -= ny%2;
		if ( ny > ysize && ny < 4096 )
		  {
404
		    ytmp = (double *) Malloc((size_t)ny * sizeof (double));
Deike Kleberg's avatar
Deike Kleberg committed
405
		    calc_gaussgrid(ytmp, ny, yfirst, ylast);
406
407
408
409
410
411
                    {
                      int i;
                      for ( i = 0; i < (ny-ysize); i++ )
                        if ( fabs(ytmp[i] - yfirst) < deleps ) break;
                      nstart = i;
                    }
Deike Kleberg's avatar
Deike Kleberg committed
412

413
414
		    lfound = (nstart+ysize-1) < ny
                      && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
415
416
417
418
                    if ( lfound )
                      {
                        for (int i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
                      }
Deike Kleberg's avatar
Deike Kleberg committed
419
420
		  }

421
		if ( !lfound )
Deike Kleberg's avatar
Deike Kleberg committed
422
		  {
423
		    Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
424
		    for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
Deike Kleberg's avatar
Deike Kleberg committed
425
426
427
428
		    yvals[0] = yfirst;
		    yvals[ysize-1] = ylast;
		  }

429
		if ( ytmp ) Free(ytmp);
Deike Kleberg's avatar
Deike Kleberg committed
430
431
	      }
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
432
      else
Thomas Jahns's avatar
Thomas Jahns committed
433
434
435
436
        {
          yvals[0] = yfirst;
          yvals[ysize-1] = ylast;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
437
438
439
440
    }
  /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
  else
    {
441
      if ( (! (fabs(yinc) > 0)) && ysize > 1 )
Thomas Jahns's avatar
Thomas Jahns committed
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
        {
          if ( IS_EQUAL(yfirst, ylast) && IS_NOT_EQUAL(yfirst, 0) ) ylast *= -1;

          if ( yfirst > ylast )
            yinc = (yfirst-ylast)/(ysize-1);
          else if ( yfirst < ylast )
            yinc = (ylast-yfirst)/(ysize-1);
          else
            {
              if ( ysize%2 != 0 )
                {
                  yinc = 180.0/(ysize-1);
                  yfirst = -90;
                }
              else
                {
                  yinc = 180.0/ysize;
                  yfirst = -90 + yinc/2;
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
463
464
465

      if ( yfirst > ylast && yinc > 0 ) yinc = -yinc;

466
      for (int i = 0; i < ysize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
467
        yvals[i] = yfirst + i*yinc;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
468
469
470
    }
  /*
    else
471
    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
472
473
474
475
  */
}

/*
476
@Function  gridCreate
477
@Title     Create a horizontal Grid
Uwe Schulzweida's avatar
Uwe Schulzweida committed
478

479
@Prototype int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
480
481
@Parameter
    @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
482
                     The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
483
                     @func{GRID_LONLAT}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL},
484
                     @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
485
486
487
    @Item  size      Number of gridpoints.

@Description
488
The function @func{gridCreate} creates a horizontal Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
489
490

@Result
491
@func{gridCreate} returns an identifier to the Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
492
493

@Example
494
Here is an example using @func{gridCreate} to create a regular lon/lat Grid:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
495
496

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
497
498
#include "cdi.h"
   ...
499
500
#define  nlon  12
#define  nlat   6
Uwe Schulzweida's avatar
Uwe Schulzweida committed
501
   ...
502
503
double lons[nlon] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
double lats[nlat] = {-75, -45, -15, 15, 45, 75};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
504
505
int gridID;
   ...
506
507
508
gridID = gridCreate(GRID_LONLAT, nlon*nlat);
gridDefXsize(gridID, nlon);
gridDefYsize(gridID, nlat);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
509
510
511
512
gridDefXvals(gridID, lons);
gridDefYvals(gridID, lats);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
513
514
@EndFunction
*/
515
int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
516
{
517
  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
518

519
  if ( size < 0 || size > INT_MAX ) Error("Grid size (%d) out of bounds (0 - %d)!", size, INT_MAX);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
520

521
  gridInit();
522

Uwe Schulzweida's avatar
Uwe Schulzweida committed
523
  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
524
  if ( ! gridptr ) Error("No memory");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
525

Uwe Schulzweida's avatar
Uwe Schulzweida committed
526
  int gridID = gridptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
527

528
  if ( CDI_Debug ) Message("gridID: %d", gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
529

530
  cdiGridTypeInit(gridptr, gridtype, size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
531

Uwe Schulzweida's avatar
Uwe Schulzweida committed
532
  return gridID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
533
534
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
535
536
static
void gridDestroyKernel( grid_t * gridptr )
537
{
Deike Kleberg's avatar
Deike Kleberg committed
538
  xassert ( gridptr );
539

540
  int id = gridptr->self;
541

542
  grid_free_components(gridptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
543
  Free( gridptr );
544

545
  reshRemove ( id, &gridOps );
546
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
547

548
549
550
551
552
553
/*
@Function  gridDestroy
@Title     Destroy a horizontal Grid

@Prototype void gridDestroy(int gridID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
554
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
555
556
557
558
559

@EndFunction
*/
void gridDestroy(int gridID)
{
560
  grid_t *gridptr = grid_to_pointer(gridID);
561
  gridptr->vtable->destroy(gridptr);
562
563
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
564
565
static
void gridDestroyP(void * gridptr)
566
{
567
  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
568
569
570
}


571
const char *gridNamePtr(int gridtype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
572
{
573
  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
574

Uwe Schulzweida's avatar
Uwe Schulzweida committed
575
  const char *name = (gridtype >= 0 && gridtype < size) ? Grids[gridtype] : Grids[GRID_GENERIC];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
576

Uwe Schulzweida's avatar
Uwe Schulzweida committed
577
  return name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
578
579
580
581
582
583
584
585
}


void gridName(int gridtype, char *gridname)
{
  strcpy(gridname, gridNamePtr(gridtype));
}

586
static
587
void *grid_key_to_ptr(grid_t *gridptr, int key)
588
{
589
  void *keyptr = NULL;
590
591
592

  switch (key)
    {
593
594
595
596
597
598
599
600
601
    case CDI_KEY_XNAME:      keyptr = (void*)gridptr->x.name; break;
    case CDI_KEY_XLONGNAME:  keyptr = (void*)gridptr->x.longname; break;
    case CDI_KEY_XUNITS:     keyptr = (void*)gridptr->x.units; break;
    case CDI_KEY_YNAME:      keyptr = (void*)gridptr->y.name; break;
    case CDI_KEY_YLONGNAME:  keyptr = (void*)gridptr->y.longname; break;
    case CDI_KEY_YUNITS:     keyptr = (void*)gridptr->y.units; break;
    case CDI_KEY_XDIMNAME:   keyptr = (void*)gridptr->x.dimname; break;
    case CDI_KEY_YDIMNAME:   keyptr = (void*)gridptr->y.dimname; break;
    case CDI_KEY_VDIMNAME:   keyptr = (void*)gridptr->vdimname; break;
602
603
    case CDI_KEY_MAPPING:    keyptr = (void*)gridptr->mapname; break;
    case CDI_KEY_MAPNAME:    keyptr = (void*)gridptr->mapping; break;
604
605
    }

606
  return keyptr;
607
608
}

609
/*
610
@Function  cdiGridDefKeyStr
611
612
@Title     Define a CDI grid string value from a key

613
@Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
614
615
616
617
618
619
620
@Parameter
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  key      The key to be searched
    @Item  size     The allocated length of the string on input
    @Item  mesg     The address of a string where the data will be read

@Description
621
The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
622
623

@Result
624
@func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
625
626
627

@EndFunction
*/
628
int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
629
{
630
  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
631

632
  grid_t *gridptr = grid_to_pointer(gridID);
633

634
635
  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL )
636
637
638
639
640
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

641
  gridSetString(keyptr, mesg, (size_t)size);
642
643
644
645
646
647
  gridMark4Update(gridID);

  return 0;
}

/*
648
@Function  cdiGridInqKeyStr
649
650
@Title     Get a CDI grid string value from a key

651
@Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
652
653
654
655
656
657
658
659
660
661
@Parameter
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  key      The key to be searched.
    @Item  size     The allocated length of the string on input.
    @Item  mesg     The address of a string where the data will be retrieved.
                    The caller must allocate space for the returned string.
                    The maximum possible length, in characters, of the string
                    is given by the predefined constant @func{CDI_MAX_NAME}.

@Description
662
The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
663
664

@Result
665
@func{cdiGridInqKeyStr} returns 0 if OK and integer value on error.
666
667
668

@EndFunction
*/
669
int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
670
{
671
  if ( size < 1 || mesg == NULL ) return -1;
672

673
  grid_t *gridptr = grid_to_pointer(gridID);
674
675
  const char *keyptr = (const char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL)
676
677
678
679
680
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

681
  gridGetString(mesg, keyptr, (size_t)size);
682
683
684
685

  return 0;
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
686
687
688
689
690
691
/*
@Function  gridDefXname
@Title     Define the name of a X-axis

@Prototype void gridDefXname(int gridID, const char *name)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
692
693
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  name     Name of the X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
694
695

@Description
696
The function @func{gridDefXname} defines the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
697
698
699

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
700
void gridDefXname(int gridID, const char *xname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
701
{
702
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
703
704
705
706
707
708
709
710
}

/*
@Function  gridDefXlongname
@Title     Define the longname of a X-axis

@Prototype void gridDefXlongname(int gridID, const char *longname)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
711
712
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  longname Longname of the X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
713
714

@Description
715
The function @func{gridDefXlongname} defines the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
716
717
718

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
719
void gridDefXlongname(int gridID, const char *xlongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
720
{
721
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
722
723
724
725
726
727
728
729
}

/*
@Function  gridDefXunits
@Title     Define the units of a X-axis

@Prototype void gridDefXunits(int gridID, const char *units)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
730
731
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  units    Units of the X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
732
733

@Description
734
The function @func{gridDefXunits} defines the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
736
737

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
738
void gridDefXunits(int gridID, const char *xunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
739
{
740
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
741
742
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
743
744
745
746
747
748
/*
@Function  gridDefYname
@Title     Define the name of a Y-axis

@Prototype void gridDefYname(int gridID, const char *name)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
749
750
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  name     Name of the Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
752

@Description
753
The function @func{gridDefYname} defines the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
755
756

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
757
void gridDefYname(int gridID, const char *yname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
758
{
759
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
760
761
762
763
764
765
766
767
}

/*
@Function  gridDefYlongname
@Title     Define the longname of a Y-axis

@Prototype void gridDefYlongname(int gridID, const char *longname)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
768
769
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  longname Longname of the Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
771

@Description
772
The function @func{gridDefYlongname} defines the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
773
774
775

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776
void gridDefYlongname(int gridID, const char *ylongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
777
{
778
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
779
780
781
782
783
784
785
786
}

/*
@Function  gridDefYunits
@Title     Define the units of a Y-axis

@Prototype void gridDefYunits(int gridID, const char *units)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
787
788
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  units    Units of the Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
789
790

@Description
791
The function @func{gridDefYunits} defines the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
792
793
794

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
795
void gridDefYunits(int gridID, const char *yunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
796
{
797
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
798
799
800
801
802
803
}

/*
@Function  gridInqXname
@Title     Get the name of a X-axis

Deike Kleberg's avatar
Deike Kleberg committed
804
@Prototype void gridInqXname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
805
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
806
807
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
    @Item  name     Name of the X-axis. The caller must allocate space for the
Deike Kleberg's avatar
Deike Kleberg committed
808
                    returned string. The maximum possible length, in characters, of
809
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
810
811

@Description
812
The function @func{gridInqXname} returns the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
813
814

@Result
815
@func{gridInqXname} returns the name of the X-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
816
817
818
819
820

@EndFunction
*/
void gridInqXname(int gridID, char *xname)
{
821
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
822
823
824
825
826
827
}

/*
@Function  gridInqXlongname
@Title     Get the longname of a X-axis

Deike Kleberg's avatar
Deike Kleberg committed
828
@Prototype void gridInqXlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
829
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
830
831
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
    @Item  longname Longname of the X-axis. The caller must allocate space for the
Deike Kleberg's avatar
Deike Kleberg committed
832
                    returned string. The maximum possible length, in characters, of
833
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
834
835

@Description
836
The function @func{gridInqXlongname} returns the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
837
838

@Result
839
@func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
840
841
842
843
844

@EndFunction
*/
void gridInqXlongname(int gridID, char *xlongname)
{
845
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
846
847
848
849
850
851
}

/*
@Function  gridInqXunits
@Title     Get the units of a X-axis

Deike Kleberg's avatar
Deike Kleberg committed
852
@Prototype void gridInqXunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
853
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
854
855
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
    @Item  units    Units of the X-axis. The caller must allocate space for the
Deike Kleberg's avatar
Deike Kleberg committed
856
                    returned string. The maximum possible length, in characters, of
857
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
858
859

@Description
860
The function @func{gridInqXunits} returns the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
861
862

@Result
863
@func{gridInqXunits} returns the units of the X-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
864
865
866
867
868

@EndFunction
*/
void gridInqXunits(int gridID, char *xunits)
{
869
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
870
871
872
873
874
}


void gridInqXstdname(int gridID, char *xstdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
875
876
877
878
879
880
  if ( xstdname )
    {
      xstdname[0] = 0;
      grid_t *gridptr = grid_to_pointer(gridID);
      if ( gridptr->x.stdname ) strcpy(xstdname, gridptr->x.stdname);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
881
882
883
884
885
886
}

/*
@Function  gridInqYname
@Title     Get the name of a Y-axis

Deike Kleberg's avatar
Deike Kleberg committed
887
@Prototype void gridInqYname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
888
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
889
890
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
    @Item  name     Name of the Y-axis. The caller must allocate space for the
Deike Kleberg's avatar
Deike Kleberg committed
891
                    returned string. The maximum possible length, in characters, of
892
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
893
894

@Description
895
The function @func{gridInqYname} returns the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
896
897

@Result
898
@func{gridInqYname} returns the name of the Y-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
899
900
901
902
903

@EndFunction
*/
void gridInqYname(int gridID, char *yname)
{
904
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
905
906
907
908
909
910
}

/*
@Function  gridInqYlongname
@Title     Get the longname of a Y-axis

911
@Prototype void gridInqYlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
912
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
913
914
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
    @Item  longname Longname of the Y-axis. The caller must allocate space for the
Deike Kleberg's avatar
Deike Kleberg committed
915
                    returned string. The maximum possible length, in characters, of
916
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
917
918

@Description
919
The function @func{gridInqYlongname} returns the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
920
921

@Result
922
@func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
923
924
925
926
927

@EndFunction
*/
void gridInqYlongname(int gridID, char *ylongname)
{
928
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
929
930
931
932
933
934
}

/*
@Function  gridInqYunits
@Title     Get the units of a Y-axis

Deike Kleberg's avatar
Deike Kleberg committed
935
@Prototype void gridInqYunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
936
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
937
938
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
    @Item  units    Units of the Y-axis. The caller must allocate space for the
Deike Kleberg's avatar
Deike Kleberg committed
939
                    returned string. The maximum possible length, in characters, of
940
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
941
942

@Description
943
The function @func{gridInqYunits} returns the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
944
945

@Result
946
@func{gridInqYunits} returns the units of the Y-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
947
948
949
950
951

@EndFunction
*/
void gridInqYunits(int gridID, char *yunits)
{
952
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
953
954
}

955

Uwe Schulzweida's avatar
Uwe Schulzweida committed
956
957
void gridInqYstdname(int gridID, char *ystdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
958
959
960
961
962
963
  if ( ystdname )
    {
      ystdname[0] = 0;
      grid_t *gridptr = grid_to_pointer(gridID);
      if ( gridptr->y.stdname ) strcpy(ystdname, gridptr->y.stdname);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
964
965
}

966

967
void gridDefProj(int gridID, int projID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
968
{
969
  grid_t *gridptr = grid_to_pointer(gridID);
970
  gridptr->proj = projID;
971
972
973

  if ( gridptr->type == GRID_CURVILINEAR )
    {
974
      grid_t *projptr = grid_to_pointer(projID);
975
976
977
      if ( projptr->x.name[0] ) strcpy(gridptr->x.dimname, projptr->x.name);
      if ( projptr->y.name[0] ) strcpy(gridptr->y.dimname, projptr->y.name);
    }
978
979
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
980

981
982
int gridInqProj(int gridID)
{
983
  grid_t *gridptr = grid_to_pointer(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
984
985
986
  return gridptr->proj;
}

987
988
989

int gridInqProjType(int gridID)
{
990
  grid_t *gridptr = grid_to_pointer(gridID);