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;
25
int (*proj_lcc_to_lonlat_func)() = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26

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

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* 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
62

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
81

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

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

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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;
}

112

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

129
130
131
132
133
134
  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;
135

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

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

155
  gridptr->lcomplex      = false;
156
157
158
159
160
161
162
163
164
165
166
  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
167
168
169
  gridptr->vdimname[0]   = 0;
  gridptr->mapname[0]    = 0;
  gridptr->mapping[0]    = 0;
Thomas Jahns's avatar
Thomas Jahns committed
170
  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
171
172
  gridptr->name          = NULL;
  gridptr->vtable        = &cdiGridVtable;
173
  gridptr->atts.nalloc   = MAX_ATTRIBUTES;
174
  gridptr->atts.nelems   = 0;
175
  gridptr->uvRelativeToGrid      = 0;   // Some models deliver wind U,V relative to the grid-cell
176
177
178
179
180
181
182
183
184
185
  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
186
187
}

188

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

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

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

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

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

222
  return gridptr;
223
224
}

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
245

246
247
static
grid_t *grid_copy_base(grid_t *gridptrOrig)
Thomas Jahns's avatar
Thomas Jahns committed
248
249
250
251
252
{
  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
253
254
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
255

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

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
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;
}

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

284
285

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

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

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

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

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

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

333
334
335
336
337
            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");
          }
338
339
340
341
342
343
        break;
      }
    }
}


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

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

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

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

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

  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
    {
      if ( ysize > 2 )
Deike Kleberg's avatar
Deike Kleberg committed
393
394
395
396
397
398
	{
	  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 )
	      {
399
		double *restrict ytmp = NULL;
Deike Kleberg's avatar
Deike Kleberg committed
400
		int nstart, lfound = 0;
401
		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
Deike Kleberg's avatar
Deike Kleberg committed
402
403
404
		ny -= ny%2;
		if ( ny > ysize && ny < 4096 )
		  {
405
		    ytmp = (double *) Malloc((size_t)ny * sizeof (double));
Deike Kleberg's avatar
Deike Kleberg committed
406
		    calc_gaussgrid(ytmp, ny, yfirst, ylast);
407
408
409
410
411
412
                    {
                      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
413

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

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

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

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

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

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

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

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

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

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

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
498
499
#include "cdi.h"
   ...
500
501
#define  nlon  12
#define  nlat   6
Uwe Schulzweida's avatar
Uwe Schulzweida committed
502
   ...
503
504
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
505
506
int gridID;
   ...
507
508
509
gridID = gridCreate(GRID_LONLAT, nlon*nlat);
gridDefXsize(gridID, nlon);
gridDefYsize(gridID, nlat);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
510
511
512
513
gridDefXvals(gridID, lons);
gridDefYvals(gridID, lats);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
514
515
@EndFunction
*/
516
int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
517
{
518
  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
519

520
  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
521

522
  gridInit();
523

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

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

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

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

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

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

541
  int id = gridptr->self;
542

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

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

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

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

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

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


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

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

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


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

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

  switch (key)
    {
594
595
596
597
598
599
600
601
602
    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;
603
604
    case CDI_KEY_MAPPING:    keyptr = (void*)gridptr->mapname; break;
    case CDI_KEY_MAPNAME:    keyptr = (void*)gridptr->mapping; break;
605
606
    }

607
  return keyptr;
608
609
}

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

614
@Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
615
616
617
618
619
620
621
@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
622
The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
623
624

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

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

633
  grid_t *gridptr = grid_to_pointer(gridID);
634

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

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

  return 0;
}

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

652
@Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
653
654
655
656
657
658
659
660
661
662
@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
663
The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
664
665

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

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

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

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

  return 0;
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
687
688
689
690
691
692
/*
@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
693
694
    @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
695
696

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

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

/*
@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
712
713
    @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
714
715

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

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

/*
@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
731
732
    @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
733
734

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
744
745
746
747
748
749
/*
@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
750
751
    @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
752
753

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

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

/*
@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
769
770
    @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
771
772

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

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

/*
@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
788
789
    @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
790
791

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

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

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

Deike Kleberg's avatar
Deike Kleberg committed
805
@Prototype void gridInqXname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
806
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
807
808
    @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
809
                    returned string. The maximum possible length, in characters, of
810
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
811
812

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

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

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

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

Deike Kleberg's avatar
Deike Kleberg committed
829
@Prototype void gridInqXlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
830
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
831
832
    @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
833
                    returned string. The maximum possible length, in characters, of
834
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
835
836

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

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

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

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

Deike Kleberg's avatar
Deike Kleberg committed
853
@Prototype void gridInqXunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
854
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
855
856
    @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
857
                    returned string. The maximum possible length, in characters, of
858
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
859
860

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

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

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


void gridInqXstdname(int gridID, char *xstdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
876
877
878
879
880
881
  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
882
883
884
885
886
887
}

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

Deike Kleberg's avatar
Deike Kleberg committed
888
@Prototype void gridInqYname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
889
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
890
891
    @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
892
                    returned string. The maximum possible length, in characters, of
893
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
894
895

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

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

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

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

912
@Prototype void gridInqYlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
913
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
914
915
    @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
916
                    returned string. The maximum possible length, in characters, of
917
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
918
919

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

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

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

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

Deike Kleberg's avatar
Deike Kleberg committed
936
@Prototype void gridInqYunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
937
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
938
939
    @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
940
                    returned string. The maximum possible length, in characters, of
941
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
942
943

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

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

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

956

Uwe Schulzweida's avatar
Uwe Schulzweida committed
957
958
void gridInqYstdname(int gridID, char *ystdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
959
960
961
962
963
964
  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
965
966
}

967

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
981

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

988
989
990

int gridInqProjType(int gridID)
{