grid.c 150 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
#ifdef HAVE_CONFIG_H
2
#include "config.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
3
4
#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 "resource_handle.h"
15
#include "resource_unpack.h"
16
#include "namespace.h"
17
#include "serialize.h"
18
19
#include "vlist.h"

20
int (*proj_lonlat_to_lcc_func)() = NULL;
21
int (*proj_lcc_to_lonlat_func)() = NULL;
22
23
int (*proj_lonlat_to_stere_func)() = NULL;
int (*proj_stere_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
116
117
static
void grid_axis_init(struct gridaxis_t *axisptr)
{
118
119
120
121
122
123
124
  axisptr->size           = 0;
  axisptr->vals           = NULL;
  axisptr->bounds         = NULL;
  axisptr->flag           = 0;
  axisptr->first          = 0.0;
  axisptr->last           = 0.0;
  axisptr->inc            = 0.0;
125
#ifndef USE_MPI
126
127
  axisptr->clength        = 0;
  axisptr->cvals          = NULL;
128
#endif
129
130
131
132
133
134
135
  axisptr->dimname[0]     = 0;
  axisptr->name[0]        = 0;
  axisptr->longname[0]    = 0;
  axisptr->units[0]       = 0;
  axisptr->stdname        = NULL;
  axisptr->keys.nalloc    = MAX_KEYS;
  axisptr->keys.nelems    = 0;
136
}
137

Deike Kleberg's avatar
Deike Kleberg committed
138
void grid_init(grid_t *gridptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
139
{
140
141
142
  gridptr->self          = CDI_UNDEFID;
  gridptr->type          = CDI_UNDEFID;
  gridptr->proj          = CDI_UNDEFID;
143
  gridptr->projtype      = CDI_UNDEFID;
144
145
  gridptr->mask          = NULL;
  gridptr->mask_gme      = NULL;
146
147
148
149
150
  gridptr->size          = 0;

  grid_axis_init(&gridptr->x);
  grid_axis_init(&gridptr->y);

151
  gridptr->area          = NULL;
152
  gridptr->reducedPoints        = NULL;
153
  gridptr->reducedPointsSize       = 0;
154

155
156
157
158
  gridptr->gme.nd        = 0;
  gridptr->gme.ni        = 0;
  gridptr->gme.ni2       = 0;
  gridptr->gme.ni3       = 0;
159

160
161
162
163
164
  gridptr->trunc         = 0;
  gridptr->nvertex       = 0;
  gridptr->number        = 0;
  gridptr->position      = 0;
  gridptr->reference     = NULL;
165
  gridptr->datatype      = CDI_DATATYPE_FLT64;
166
167
  gridptr->np            = 0;
  gridptr->isCyclic      = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
168

169
  gridptr->lcomplex      = false;
170
  gridptr->hasdims       = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
171
172
173
  gridptr->vdimname[0]   = 0;
  gridptr->mapname[0]    = 0;
  gridptr->mapping[0]    = 0;
Thomas Jahns's avatar
Thomas Jahns committed
174
  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
175
176
177
178
179
180
  gridptr->name           = NULL;
  gridptr->vtable         = &cdiGridVtable;
  gridptr->keys.nalloc    = MAX_KEYS;
  gridptr->keys.nelems    = 0;
  gridptr->atts.nalloc    = MAX_ATTRIBUTES;
  gridptr->atts.nelems    = 0;
181
182
183
184
185
186
187
188
189
190
  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
191
192
}

193

194
195
static
void grid_free_components(grid_t *gridptr)
Deike Kleberg's avatar
Deike Kleberg committed
196
{
197
  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
198
                     gridptr->x.vals, gridptr->y.vals,
199
#ifndef USE_MPI
Uwe Schulzweida's avatar
Uwe Schulzweida committed
200
                     gridptr->x.cvals, gridptr->y.cvals,
201
#endif
202
                     gridptr->x.bounds, gridptr->y.bounds,
203
                     gridptr->reducedPoints, gridptr->area,
204
205
                     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
static inline
void gridSetString(char *gridstrname, const char *name, size_t len)
{
  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
273
  strncpy(gridstrname, name, len - 1);
274
275
276
277
278
279
280
281
282
283
284
  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
  if      ( gridtype == GRID_LONLAT   ) gridptr->nvertex = 2;
  else if ( gridtype == GRID_GAUSSIAN ) gridptr->nvertex = 2;
300
  else if ( gridtype == GRID_GAUSSIAN_REDUCED ) gridptr->nvertex = 2;
301
  else if ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
302
303
  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;

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

325
326
327
328
329
        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");
330

331
332
        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
333

334
335
        break;
      }
336
#ifndef USE_MPI
Uwe Schulzweida's avatar
Uwe Schulzweida committed
337
338
    case GRID_CHARXY:
      {
339
340
341
342
        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;
343
344
      }
#endif
345
    case GRID_GENERIC:
346
    case GRID_PROJECTION:
347
      {
348
349
        if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "x");
        if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "y");
350
351
352
        if ( gridtype == GRID_PROJECTION )
          {
            gridSetName(gridptr->mapname, "Projection");
353

354
355
            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
356
357
358

            if ( !gridptr->x.units[0] ) gridSetName(gridptr->x.units, "m");
            if ( !gridptr->y.units[0] ) gridSetName(gridptr->y.units, "m");
359
          }
360
361
362
363
364
365
        break;
      }
    }
}


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

382
  for ( int i = 0; i < xsize; ++i )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
383
384
385
    xvals[i] = xfirst + i*xinc;
}

386
static
387
void calc_gaussgrid(double *restrict yvals, size_t ysize, double yfirst, double ylast)
388
{
389
  double *restrict yw = (double *) Malloc(ysize * sizeof(double));
390
  gaussianLatitudes(yvals, yw, ysize);
391
  Free(yw);
392
  for (size_t i = 0; i < ysize; i++ )
393
394
395
396
    yvals[i] = asin(yvals[i])/M_PI*180.0;

  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
    {
397
      const size_t yhsize = ysize/2;
398
      for (size_t i = 0; i < yhsize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
399
        {
400
          const double ytmp = yvals[i];
Thomas Jahns's avatar
Thomas Jahns committed
401
402
403
          yvals[i] = yvals[ysize-i-1];
          yvals[ysize-i-1] = ytmp;
        }
404
405
406
    }
}

407
408
static
void gridGenYvalsGaussian(int ysize, double yfirst, double ylast, double *restrict yvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
409
{
410
  const double deleps = 0.002;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
411

412
413
414
415
416
417
418
419
420
421
  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 )
      {
        bool lfound = false;
        int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
        ny -= ny%2;
        if ( ny > ysize && ny < 4096 )
          {
422
            double *ytmp = (double *) Malloc((size_t)ny * sizeof (double));
423
            calc_gaussgrid(ytmp, ny, yfirst, ylast);
424
425
426
427
428

            int i;
            for ( i = 0; i < (ny-ysize); i++ )
              if ( fabs(ytmp[i] - yfirst) < deleps ) break;
            int nstart = i;
429
430
431
432

            lfound = (nstart+ysize-1) < ny && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
            if ( lfound )
              {
433
                for (i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
434
              }
435
436

            if ( ytmp ) Free(ytmp);
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
          }

        if ( !lfound )
          {
            Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
            for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
            yvals[0] = yfirst;
            yvals[ysize-1] = ylast;
          }
      }
}

static
void gridGenYvalsRegular(int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
{
  if (fabs(yinc) <= 0 && ysize > 1)
    {
      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;
            }
        }
    }

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

  for (int i = 0; i < ysize; i++ )
    yvals[i] = yfirst + i*yinc;
}

// used also in CDO
void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
484
485
486
  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
    {
      if ( ysize > 2 )
Deike Kleberg's avatar
Deike Kleberg committed
487
	{
488
          gridGenYvalsGaussian(ysize, yfirst, ylast, yvals);
Deike Kleberg's avatar
Deike Kleberg committed
489
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
490
      else
Thomas Jahns's avatar
Thomas Jahns committed
491
492
493
494
        {
          yvals[0] = yfirst;
          yvals[ysize-1] = ylast;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
495
496
497
498
    }
  /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
  else
    {
499
      gridGenYvalsRegular(ysize, yfirst, ylast, yinc, yvals);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
500
    }
501
   /*
Uwe Schulzweida's avatar
Uwe Schulzweida committed
502
    else
503
    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
504
505
506
507
  */
}

/*
508
@Function  gridCreate
509
@Title     Create a horizontal Grid
Uwe Schulzweida's avatar
Uwe Schulzweida committed
510

511
@Prototype int gridCreate(int gridtype, size_t size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
512
513
@Parameter
    @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
514
                     The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
515
                     @func{GRID_LONLAT}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL},
516
                     @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
517
518
519
    @Item  size      Number of gridpoints.

@Description
520
The function @func{gridCreate} creates a horizontal Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
521
522

@Result
523
@func{gridCreate} returns an identifier to the Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
524
525

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

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
529
530
#include "cdi.h"
   ...
531
532
#define  nlon  12
#define  nlat   6
Uwe Schulzweida's avatar
Uwe Schulzweida committed
533
   ...
534
535
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
536
537
int gridID;
   ...
538
539
540
gridID = gridCreate(GRID_LONLAT, nlon*nlat);
gridDefXsize(gridID, nlon);
gridDefYsize(gridID, nlat);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
541
542
543
544
gridDefXvals(gridID, lons);
gridDefYvals(gridID, lats);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
545
546
@EndFunction
*/
547
int gridCreate(int gridtype, size_t size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
548
{
549
  if ( CDI_Debug ) Message("gridtype=%s  size=%zu", gridNamePtr(gridtype), size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
550

551
  xassert(size);
552
  gridInit();
553

Uwe Schulzweida's avatar
Uwe Schulzweida committed
554
  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
555
  if ( ! gridptr ) Error("No memory");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
556

557
  const int gridID = gridptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
558

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

561
  cdiGridTypeInit(gridptr, gridtype, size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
562

Uwe Schulzweida's avatar
Uwe Schulzweida committed
563
  return gridID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
564
565
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
566
567
static
void gridDestroyKernel( grid_t * gridptr )
568
{
Deike Kleberg's avatar
Deike Kleberg committed
569
  xassert ( gridptr );
570

571
  const int id = gridptr->self;
572

573
  grid_free_components(gridptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
574
  Free( gridptr );
575

576
  reshRemove( id, &gridOps );
577
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
578

579
580
581
582
583
584
/*
@Function  gridDestroy
@Title     Destroy a horizontal Grid

@Prototype void gridDestroy(int gridID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
585
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
586
587
588
589
590

@EndFunction
*/
void gridDestroy(int gridID)
{
591
592
593
  //cdiDeleteKeys(gridID, CDI_GLOBAL);
  //cdiDeleteAtts(gridID, CDI_GLOBAL);

594
  grid_t *gridptr = grid_to_pointer(gridID);
595
  gridptr->vtable->destroy(gridptr);
596
597
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
598
599
static
void gridDestroyP(void * gridptr)
600
{
601
  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
602
603
604
}


605
const char *gridNamePtr(int gridtype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
606
{
607
  const int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
608

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
611
  return name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
612
613
614
615
616
617
618
619
}


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

620
static
621
void *grid_key_to_ptr(grid_t *gridptr, int key)
622
{
623
  void *keyptr = NULL;
624
625
626

  switch (key)
    {
627
628
629
630
631
632
633
634
635
    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;
636
637
    case CDI_KEY_GRIDMAP_VARNAME:    keyptr = (void*)gridptr->mapname; break;
    case CDI_KEY_GRIDMAP_NAME:    keyptr = (void*)gridptr->mapping; break;
638
639
    }

640
  return keyptr;
641
642
}

643
/*
644
@Function  cdiGridDefKeyStr
645
646
@Title     Define a CDI grid string value from a key

647
@Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
648
649
650
651
652
653
654
@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
655
The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
656
657

@Result
658
@func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
659
660
661

@EndFunction
*/
662
int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
663
{
664
  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
665

666
  grid_t *gridptr = grid_to_pointer(gridID);
667

668
669
  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL )
670
671
672
673
674
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

675
  gridSetString(keyptr, mesg, (size_t)size);
676
677
678
679
680
681
  gridMark4Update(gridID);

  return 0;
}

/*
682
@Function  cdiGridInqKeyStr
683
684
@Title     Get a CDI grid string value from a key

685
@Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
686
687
688
689
690
691
692
693
694
695
@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
696
The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
697
698

@Result
699
@func{cdiGridInqKeyStr} returns 0 if OK and integer value on error.
700
701
702

@EndFunction
*/
703
int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
704
{
705
  if ( size < 1 || mesg == NULL ) return -1;
706

707
  grid_t *gridptr = grid_to_pointer(gridID);
708
709
  const char *keyptr = (const char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL)
710
711
712
713
714
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

715
  gridGetString(mesg, keyptr, (size_t)size);
716
717
718
719

  return 0;
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
720
721
722
723
724
725
/*
@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
726
727
    @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
728
729

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

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

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

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

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
753
void gridDefXlongname(int gridID, const char *xlongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
{
755
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
756
757
758
759
760
761
762
763
}

/*
@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
764
765
    @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
766
767

@Description
768
The function @func{gridDefXunits} defines the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
769
770
771

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
772
void gridDefXunits(int gridID, const char *xunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
773
{
774
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
775
776
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
777
778
779
780
781
782
/*
@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
783
784
    @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
785
786

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

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

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

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

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

/*
@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
821
822
    @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
823
824

@Description
825
The function @func{gridDefYunits} defines the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
826
827
828

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
829
void gridDefYunits(int gridID, const char *yunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
830
{
831
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
832
833
834
835
836
837
}

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

Deike Kleberg's avatar
Deike Kleberg committed
838
@Prototype void gridInqXname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
839
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
840
841
    @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
842
                    returned string. The maximum possible length, in characters, of
843
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
844
845

@Description
846
The function @func{gridInqXname} returns the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
847
848

@Result
849
@func{gridInqXname} returns the name of the X-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
850
851
852
853
854

@EndFunction
*/
void gridInqXname(int gridID, char *xname)
{
855
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
856
857
858
859
860
861
}

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

Deike Kleberg's avatar
Deike Kleberg committed
862
@Prototype void gridInqXlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
863
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
864
865
    @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
866
                    returned string. The maximum possible length, in characters, of
867
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
868
869

@Description
870
The function @func{gridInqXlongname} returns the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
871
872

@Result
873
@func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
874
875
876
877
878

@EndFunction
*/
void gridInqXlongname(int gridID, char *xlongname)
{
879
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
880
881
882
883
884
885
}

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

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

@Description
894
The function @func{gridInqXunits} returns the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
895
896

@Result
897
@func{gridInqXunits} returns the units of the X-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
898
899
900
901
902

@EndFunction
*/
void gridInqXunits(int gridID, char *xunits)
{
903
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
904
905
906
907
908
}


void gridInqXstdname(int gridID, char *xstdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
909
910
911
912
913
914
  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
915
916
917
918
919
920
}

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

Deike Kleberg's avatar
Deike Kleberg committed
921
@Prototype void gridInqYname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
922
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
923
924
    @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
925
                    returned string. The maximum possible length, in characters, of
926
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
927
928

@Description
929
The function @func{gridInqYname} returns the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
930
931

@Result
932
@func{gridInqYname} returns the name of the Y-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
933
934
935
936
937

@EndFunction
*/
void gridInqYname(int gridID, char *yname)
{
938
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
939
940
941
942
943
944
}

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

945
@Prototype void gridInqYlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
946
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
947
948
    @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
949
                    returned string. The maximum possible length, in characters, of
950
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
951
952

@Description
953
The function @func{gridInqYlongname} returns the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
954
955

@Result
956
@func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
957
958
959
960
961

@EndFunction
*/
void gridInqYlongname(int gridID, char *ylongname)
{
962
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
963
964
965
966
967
968
}

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

Deike Kleberg's avatar
Deike Kleberg committed
969
@Prototype void gridInqYunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
970
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
971
972
    @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
973
                    returned string. The maximum possible length, in characters, of
974
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
975
976

@Description
977
The function @func{gridInqYunits} returns the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
978
979

@Result
980
@func{gridInqYunits} returns the units of the Y-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
981
982
983
984
985

@EndFunction
*/
void gridInqYunits(int gridID, char *yunits)
{