grid.c 146 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
  /* 13 */  "characterXY",
Uwe Schulzweida's avatar
Uwe Schulzweida committed
44
45
};

46
47
48
49
50
/* must match table below */
enum xystdname_idx {
  grid_xystdname_grid_latlon,
  grid_xystdname_latlon,
  grid_xystdname_projection,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
51
  grid_xystdname_char,
52
53
54
55
56
57
58
59
};
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
60
61
  [grid_xystdname_char] = { "region",
                            "region" },
62
63
64
};


Uwe Schulzweida's avatar
Uwe Schulzweida committed
65

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
84

85
grid_t *grid_to_pointer(int gridID)
86
87
88
{
  return (grid_t *)reshGetVal(gridID, &gridOps);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
89

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

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

115

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

136
137
138
139
140
141
  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;
142

143
144
145
146
  gridptr->gme.nd        = 0;
  gridptr->gme.ni        = 0;
  gridptr->gme.ni2       = 0;
  gridptr->gme.ni3       = 0;
147

148
149
150
151
152
153
154
  gridptr->trunc         = 0;
  gridptr->nvertex       = 0;
  gridptr->number        = 0;
  gridptr->position      = 0;
  gridptr->reference     = NULL;
  gridptr->prec          = 0;
  gridptr->size          = 0;
155
156
  gridptr->x.size        = 0;
  gridptr->y.size        = 0;
157
  gridptr->np            = 0;
158
159
  gridptr->x.flag        = 0;
  gridptr->y.flag        = 0;
160
  gridptr->isCyclic      = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
161

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

195

196
197
static
void grid_free_components(grid_t *gridptr)
Deike Kleberg's avatar
Deike Kleberg committed
198
{
199
  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
200
                     gridptr->x.vals, gridptr->y.vals,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
                     gridptr->x.cvals, gridptr->y.cvals,
202
203
204
205
                     gridptr->x.bounds, gridptr->y.bounds,
                     gridptr->rowlon, gridptr->area,
                     gridptr->reference, gridptr->name};

206
  for ( size_t i = 0; i < sizeof(p2free)/sizeof(p2free[0]); ++i )
207
    if ( p2free[i] ) Free(p2free[i]);
208
}
Deike Kleberg's avatar
Deike Kleberg committed
209

210
211
212
void grid_free(grid_t *gridptr)
{
  grid_free_components(gridptr);
Deike Kleberg's avatar
Deike Kleberg committed
213
214
215
  grid_init(gridptr);
}

216
217
static
grid_t *gridNewEntry(cdiResH resH)
218
{
219
  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
220
  grid_init(gridptr);
221

222
  if ( resH == CDI_UNDEFID )
223
224
225
226
227
228
    gridptr->self = reshPut(gridptr, &gridOps);
  else
    {
      gridptr->self = resH;
      reshReplace(resH, gridptr, &gridOps);
    }
229

230
  return gridptr;
231
232
}

233
static
234
void gridInit(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
235
{
236
  static bool gridInitialized = false;
237
  if ( gridInitialized ) return;
238
  gridInitialized = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
239

Uwe Schulzweida's avatar
Uwe Schulzweida committed
240
  const char *env = getenv("GRID_DEBUG");
241
  if ( env ) GRID_Debug = atoi(env);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
242
243
}

244
245
static
void grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
246
{
Thomas Jahns's avatar
Thomas Jahns committed
247
248
  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
  gridptrDup->self = CDI_UNDEFID;
249
  if ( gridptrOrig->reference )
Thomas Jahns's avatar
Thomas Jahns committed
250
251
252
    gridptrDup->reference = strdupx(gridptrOrig->reference);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
253

254
255
static
grid_t *grid_copy_base(grid_t *gridptrOrig)
Thomas Jahns's avatar
Thomas Jahns committed
256
257
258
259
260
{
  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
261
262
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
263

264
unsigned cdiGridCount(void)
Thomas Jahns's avatar
Thomas Jahns committed
265
{
266
  return reshCountType(&gridOps);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
267
268
}

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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;
}

285
286
static inline
void gridSetName(char *gridstrname, const char *name)
287
{
288
289
  strncpy(gridstrname, name, CDI_MAX_NAME);
  gridstrname[CDI_MAX_NAME - 1] = 0;
290
291
}

292
293

void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
294
295
296
297
{
  gridptr->type = gridtype;
  gridptr->size = size;

298
299
300
  if      ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;

301
302
303
304
305
306
  switch (gridtype)
    {
    case GRID_LONLAT:
    case GRID_GAUSSIAN:
    case GRID_GAUSSIAN_REDUCED:
    case GRID_TRAJECTORY:
307
308
309
    case GRID_CURVILINEAR:
    case GRID_UNSTRUCTURED:
    case GRID_GME:
310
311
312
      {
        if ( gridtype == GRID_TRAJECTORY )
          {
313
314
            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "tlon");
            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "tlat");
315
316
317
          }
        else
          {
318
319
            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "lon");
            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "lat");
320
          }
321

322
323
        gridSetName(gridptr->x.longname, "longitude");
        gridSetName(gridptr->y.longname, "latitude");
324

325
326
        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
327
328
        gridSetName(gridptr->x.units, "degrees_east");
        gridSetName(gridptr->y.units, "degrees_north");
329

330
331
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
332
333
334
335
336
337
338
    case GRID_CHARXY:
      {
        if ( gridptr->x.cvals )
          gridptr->x.stdname = xystdname_tab[grid_xystdname_char][0];
        if ( gridptr->y.cvals )
          gridptr->y.stdname = xystdname_tab[grid_xystdname_char][0];
      }
339
    case GRID_GENERIC:
340
    case GRID_PROJECTION:
341
      {
342
343
        if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "x");
        if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "y");
344
345
346
        if ( gridtype == GRID_PROJECTION )
          {
            gridSetName(gridptr->mapname, "Projection");
347

348
349
350
351
352
            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");
          }
353
354
355
356
357
358
        break;
      }
    }
}


359
// used also in CDO
360
void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
361
{
362
  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
363
364
    {
      if ( xfirst >= xlast )
Thomas Jahns's avatar
Thomas Jahns committed
365
366
367
368
        {
          while ( xfirst >= xlast ) xlast += 360;
          xinc = (xlast-xfirst)/(xsize);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
369
      else
Thomas Jahns's avatar
Thomas Jahns committed
370
371
372
        {
          xinc = (xlast-xfirst)/(xsize-1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
373
374
    }

375
  for ( int i = 0; i < xsize; ++i )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
376
377
378
    xvals[i] = xfirst + i*xinc;
}

379
static
380
void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
381
{
382
  double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
383
  gaussaw(yvals, yw, (size_t)ysize);
384
  Free(yw);
385
  for (int i = 0; i < ysize; i++ )
386
387
388
389
    yvals[i] = asin(yvals[i])/M_PI*180.0;

  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
    {
390
391
      int yhsize = ysize/2;
      for (int i = 0; i < yhsize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
392
        {
393
          double ytmp = yvals[i];
Thomas Jahns's avatar
Thomas Jahns committed
394
395
396
          yvals[i] = yvals[ysize-i-1];
          yvals[ysize-i-1] = ytmp;
        }
397
398
399
    }
}

400
// used also in CDO
Thomas Jahns's avatar
Thomas Jahns committed
401
void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
402
{
403
  const double deleps = 0.002;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
404
405
406
407

  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
    {
      if ( ysize > 2 )
Deike Kleberg's avatar
Deike Kleberg committed
408
409
410
411
412
413
	{
	  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 )
	      {
414
		double *restrict ytmp = NULL;
Deike Kleberg's avatar
Deike Kleberg committed
415
		int nstart, lfound = 0;
416
		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
Deike Kleberg's avatar
Deike Kleberg committed
417
418
419
		ny -= ny%2;
		if ( ny > ysize && ny < 4096 )
		  {
420
		    ytmp = (double *) Malloc((size_t)ny * sizeof (double));
Deike Kleberg's avatar
Deike Kleberg committed
421
		    calc_gaussgrid(ytmp, ny, yfirst, ylast);
422
423
424
425
426
427
                    {
                      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
428

429
430
		    lfound = (nstart+ysize-1) < ny
                      && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
431
432
433
434
                    if ( lfound )
                      {
                        for (int i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
                      }
Deike Kleberg's avatar
Deike Kleberg committed
435
436
		  }

437
		if ( !lfound )
Deike Kleberg's avatar
Deike Kleberg committed
438
		  {
439
		    Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
440
		    for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
Deike Kleberg's avatar
Deike Kleberg committed
441
442
443
444
		    yvals[0] = yfirst;
		    yvals[ysize-1] = ylast;
		  }

445
		if ( ytmp ) Free(ytmp);
Deike Kleberg's avatar
Deike Kleberg committed
446
447
	      }
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
448
      else
Thomas Jahns's avatar
Thomas Jahns committed
449
450
451
452
        {
          yvals[0] = yfirst;
          yvals[ysize-1] = ylast;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
453
454
455
456
    }
  /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
  else
    {
457
      if ( (! (fabs(yinc) > 0)) && ysize > 1 )
Thomas Jahns's avatar
Thomas Jahns committed
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
        {
          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
479
480
481

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

482
      for (int i = 0; i < ysize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
483
        yvals[i] = yfirst + i*yinc;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
484
485
486
    }
  /*
    else
487
    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
488
489
490
491
  */
}

/*
492
@Function  gridCreate
493
@Title     Create a horizontal Grid
Uwe Schulzweida's avatar
Uwe Schulzweida committed
494

495
@Prototype int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
496
497
@Parameter
    @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
498
                     The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
499
                     @func{GRID_LONLAT}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL},
500
                     @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
501
502
503
    @Item  size      Number of gridpoints.

@Description
504
The function @func{gridCreate} creates a horizontal Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
505
506

@Result
507
@func{gridCreate} returns an identifier to the Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
508
509

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

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
513
514
#include "cdi.h"
   ...
515
516
#define  nlon  12
#define  nlat   6
Uwe Schulzweida's avatar
Uwe Schulzweida committed
517
   ...
518
519
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
520
521
int gridID;
   ...
522
523
524
gridID = gridCreate(GRID_LONLAT, nlon*nlat);
gridDefXsize(gridID, nlon);
gridDefYsize(gridID, nlat);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
525
526
527
528
gridDefXvals(gridID, lons);
gridDefYvals(gridID, lats);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
529
530
@EndFunction
*/
531
int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
532
{
533
  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
534

535
  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
536

537
  gridInit();
538

Uwe Schulzweida's avatar
Uwe Schulzweida committed
539
  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
540
  if ( ! gridptr ) Error("No memory");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
541

Uwe Schulzweida's avatar
Uwe Schulzweida committed
542
  int gridID = gridptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
543

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

546
  cdiGridTypeInit(gridptr, gridtype, size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
547

Uwe Schulzweida's avatar
Uwe Schulzweida committed
548
  return gridID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
549
550
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
551
552
static
void gridDestroyKernel( grid_t * gridptr )
553
{
Deike Kleberg's avatar
Deike Kleberg committed
554
  xassert ( gridptr );
555

556
  int id = gridptr->self;
557

558
  grid_free_components(gridptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
559
  Free( gridptr );
560

561
  reshRemove ( id, &gridOps );
562
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
563

564
565
566
567
568
569
/*
@Function  gridDestroy
@Title     Destroy a horizontal Grid

@Prototype void gridDestroy(int gridID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
570
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
571
572
573
574
575

@EndFunction
*/
void gridDestroy(int gridID)
{
576
  grid_t *gridptr = grid_to_pointer(gridID);
577
  gridptr->vtable->destroy(gridptr);
578
579
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
580
581
static
void gridDestroyP(void * gridptr)
582
{
583
  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
584
585
586
}


587
const char *gridNamePtr(int gridtype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
588
{
589
  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
590

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
593
  return name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
594
595
596
597
598
599
600
601
}


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

602
static
603
void *grid_key_to_ptr(grid_t *gridptr, int key)
604
{
605
  void *keyptr = NULL;
606
607
608

  switch (key)
    {
609
610
611
612
613
614
615
616
617
    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;
618
619
    case CDI_KEY_MAPPING:    keyptr = (void*)gridptr->mapname; break;
    case CDI_KEY_MAPNAME:    keyptr = (void*)gridptr->mapping; break;
620
621
    }

622
  return keyptr;
623
624
}

625
/*
626
@Function  cdiGridDefKeyStr
627
628
@Title     Define a CDI grid string value from a key

629
@Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
630
631
632
633
634
635
636
@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
637
The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
638
639

@Result
640
@func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
641
642
643

@EndFunction
*/
644
int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
645
{
646
  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
647

648
  grid_t *gridptr = grid_to_pointer(gridID);
649

650
651
  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL )
652
653
654
655
656
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

657
  gridSetString(keyptr, mesg, (size_t)size);
658
659
660
661
662
663
  gridMark4Update(gridID);

  return 0;
}

/*
664
@Function  cdiGridInqKeyStr
665
666
@Title     Get a CDI grid string value from a key

667
@Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
668
669
670
671
672
673
674
675
676
677
@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
678
The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
679
680

@Result
681
@func{cdiGridInqKeyStr} returns 0 if OK and integer value on error.
682
683
684

@EndFunction
*/
685
int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
686
{
687
  if ( size < 1 || mesg == NULL ) return -1;
688

689
  grid_t *gridptr = grid_to_pointer(gridID);
690
691
  const char *keyptr = (const char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL)
692
693
694
695
696
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

697
  gridGetString(mesg, keyptr, (size_t)size);
698
699
700
701

  return 0;
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
702
703
704
705
706
707
/*
@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
708
709
    @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
710
711

@Description
712
The function @func{gridDefXname} defines the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
713
714
715

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
716
void gridDefXname(int gridID, const char *xname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
717
{
718
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
719
720
721
722
723
724
725
726
}

/*
@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
727
728
    @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
729
730

@Description
731
The function @func{gridDefXlongname} defines the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
732
733
734

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
void gridDefXlongname(int gridID, const char *xlongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
736
{
737
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
738
739
740
741
742
743
744
745
}

/*
@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
746
747
    @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
748
749

@Description
750
The function @func{gridDefXunits} defines the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
752
753

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
void gridDefXunits(int gridID, const char *xunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
755
{
756
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
757
758
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
759
760
761
762
763
764
/*
@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
765
766
    @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
767
768

@Description
769
The function @func{gridDefYname} defines the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
771
772

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
773
void gridDefYname(int gridID, const char *yname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
774
{
775
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776
777
778
779
780
781
782
783
}

/*
@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
784
785
    @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
786
787

@Description
788
The function @func{gridDefYlongname} defines the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
789
790
791

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
792
void gridDefYlongname(int gridID, const char *ylongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
793
{
794
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
795
796
797
798
799
800
801
802
}

/*
@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
803
804
    @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
805
806

@Description
807
The function @func{gridDefYunits} defines the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
808
809
810

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
811
void gridDefYunits(int gridID, const char *yunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
812
{
813
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
814
815
816
817
818
819
}

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

Deike Kleberg's avatar
Deike Kleberg committed
820
@Prototype void gridInqXname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
821
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
822
823
    @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
824
                    returned string. The maximum possible length, in characters, of
825
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
826
827

@Description
828
The function @func{gridInqXname} returns the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
829
830

@Result
831
@func{gridInqXname} returns the name of the X-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
832
833
834
835
836

@EndFunction
*/
void gridInqXname(int gridID, char *xname)
{
837
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
838
839
840
841
842
843
}

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

Deike Kleberg's avatar
Deike Kleberg committed
844
@Prototype void gridInqXlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
845
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
846
847
    @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
848
                    returned string. The maximum possible length, in characters, of
849
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
850
851

@Description
852
The function @func{gridInqXlongname} returns the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
853
854

@Result
855
@func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
856
857
858
859
860

@EndFunction
*/
void gridInqXlongname(int gridID, char *xlongname)
{
861
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
862
863
864
865
866
867
}

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

Deike Kleberg's avatar
Deike Kleberg committed
868
@Prototype void gridInqXunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
869
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
870
871
    @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
872
                    returned string. The maximum possible length, in characters, of
873
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
874
875

@Description
876
The function @func{gridInqXunits} returns the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
877
878

@Result
879
@func{gridInqXunits} returns the units of the X-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
880
881
882
883
884

@EndFunction
*/
void gridInqXunits(int gridID, char *xunits)
{
885
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
886
887
888
889
890
}


void gridInqXstdname(int gridID, char *xstdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
891
892
893
894
895
896
  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
897
898
899
900
901
902
}

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

Deike Kleberg's avatar
Deike Kleberg committed
903
@Prototype void gridInqYname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
904
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
905
906
    @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
907
                    returned string. The maximum possible length, in characters, of
908
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
909
910

@Description
911
The function @func{gridInqYname} returns the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
912
913

@Result
914
@func{gridInqYname} returns the name of the Y-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
915
916
917
918
919

@EndFunction
*/
void gridInqYname(int gridID, char *yname)
{
920
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
921
922
923
924
925
926
}

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

927
@Prototype void gridInqYlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
928
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
929
930
    @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
931
                    returned string. The maximum possible length, in characters, of
932
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
933
934

@Description
935
The function @func{gridInqYlongname} returns the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
936
937

@Result
938
@func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
939
940
941
942
943

@EndFunction
*/
void gridInqYlongname(int gridID, char *ylongname)
{
944
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
945
946
947
948
949
950
}

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

Deike Kleberg's avatar
Deike Kleberg committed
951
@Prototype void gridInqYunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
952
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
953
954
    @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
955
                    returned string. The maximum possible length, in characters, of
956
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
957
958

@Description
959
The function @func{gridInqYunits} returns the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
960
961

@Result
962
@func{gridInqYunits} returns the units of the Y-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
963
964
965
966
967

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

971

Uwe Schulzweida's avatar
Uwe Schulzweida committed
972
973
void gridInqYstdname(int gridID, char *ystdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
974
975
976
977
978
979
  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
980
981
}

982

983
void gridDefProj(int gridID, int projID)