grid.c 147 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

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

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

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

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


Uwe Schulzweida's avatar
Uwe Schulzweida committed
63

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
82

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

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

90
91
92
93
94
95
96
static
bool cdiInqAttConvertedToFloat(int gridID, int atttype, const char *attname, int attlen, double *attflt)
{
  bool status = true;

  if ( atttype == CDI_DATATYPE_INT32 )
    {
97
98
      int attint;
      int *pattint = attlen > 1 ? (int*) malloc(attlen*sizeof(int)) : &attint;
99
100
      cdiInqAttInt(gridID, CDI_GLOBAL, attname, attlen, pattint);
      for ( int i = 0; i < attlen; ++i ) attflt[i] = (double)pattint[i];
101
      if (attlen > 1) free(pattint);
102
103
104
105
106
107
108
109
110
111
112
113
114
    }
  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
  gridptr->trunc         = 0;
  gridptr->nvertex       = 0;
  gridptr->number        = 0;
  gridptr->position      = 0;
  gridptr->reference     = NULL;
153
  gridptr->datatype      = CDI_DATATYPE_FLT64;
154
  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, size_t 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] ) gridSetName(gridptr->x.name, "tlon");
            if ( !gridptr->y.name[0] ) gridSetName(gridptr->y.name, "tlat");
315
316
317
          }
        else
          {
318
319
            if ( !gridptr->x.name[0] ) gridSetName(gridptr->x.name, "lon");
            if ( !gridptr->y.name[0] ) gridSetName(gridptr->y.name, "lat");
320
          }
321

322
323
324
325
326
        if ( !gridptr->x.longname[0] ) gridSetName(gridptr->x.longname, "longitude");
        if ( !gridptr->y.longname[0] ) gridSetName(gridptr->y.longname, "latitude");

        if ( !gridptr->x.units[0] ) gridSetName(gridptr->x.units, "degrees_east");
        if ( !gridptr->y.units[0] ) gridSetName(gridptr->y.units, "degrees_north");
327

328
329
        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
330

331
332
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
333
334
    case GRID_CHARXY:
      {
335
336
337
338
339
        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];

        break;
     }
340
    case GRID_GENERIC:
341
    case GRID_PROJECTION:
342
      {
343
344
        if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "x");
        if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "y");
345
346
347
        if ( gridtype == GRID_PROJECTION )
          {
            gridSetName(gridptr->mapname, "Projection");
348

349
350
            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
351
352
353

            if ( !gridptr->x.units[0] ) gridSetName(gridptr->x.units, "m");
            if ( !gridptr->y.units[0] ) gridSetName(gridptr->y.units, "m");
354
          }
355
356
357
358
359
360
        break;
      }
    }
}


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

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

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

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

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

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

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

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

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

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

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

/*
495
@Function  gridCreate
496
@Title     Create a horizontal Grid
Uwe Schulzweida's avatar
Uwe Schulzweida committed
497

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

@Description
507
The function @func{gridCreate} creates a horizontal Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
508
509

@Result
510
@func{gridCreate} returns an identifier to the Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
511
512

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

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

538
  gridInit();
539

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

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

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

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

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

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

557
  int id = gridptr->self;
558

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

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

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

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

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

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


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

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

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


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

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

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

623
  return keyptr;
624
625
}

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

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

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

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

649
  grid_t *gridptr = grid_to_pointer(gridID);
650

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

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

  return 0;
}

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

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

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

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

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

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

  return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

972

Uwe Schulzweida's avatar
Uwe Schulzweida committed
973
974
void gridInqYstdname(int gridID, char *ystdname)
{