grid.c 155 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 "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
int (*proj_lonlat_to_lcc_func)() = NULL;
22
int (*proj_lcc_to_lonlat_func)() = NULL;
23
24
int (*proj_lonlat_to_stere_func)() = NULL;
int (*proj_stere_to_lonlat_func)() = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
25

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

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


Uwe Schulzweida's avatar
Uwe Schulzweida committed
64

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
83

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

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

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

  if ( atttype == CDI_DATATYPE_INT32 )
    {
98
99
      int attint;
      int *pattint = attlen > 1 ? (int*) malloc(attlen*sizeof(int)) : &attint;
100
101
      cdiInqAttInt(gridID, CDI_GLOBAL, attname, attlen, pattint);
      for ( int i = 0; i < attlen; ++i ) attflt[i] = (double)pattint[i];
102
      if (attlen > 1) free(pattint);
103
104
105
106
107
108
109
110
111
112
113
114
115
    }
  else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
    {
      cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, attflt);
    }
  else
    {
      status = false;
    }

  return status;
}

116

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

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

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

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

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

196

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

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

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

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

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

231
  return gridptr;
232
233
}

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
254

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
264

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

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

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

293

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

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

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

323
324
325
326
327
        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");
328

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

539
  gridInit();
540

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

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

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

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

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

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

558
  int id = gridptr->self;
559

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

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

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

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

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

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


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

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

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


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

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

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

624
  return keyptr;
625
626
}

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

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

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

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

650
  grid_t *gridptr = grid_to_pointer(gridID);
651

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

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

  return 0;
}

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

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

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

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

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

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

  return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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