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

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
183
184
185
186
187
188
189
190
191
  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
192
193
}

194

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

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

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

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

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

229
  return gridptr;
230
231
}

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
252

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
262

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

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

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

291

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

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

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

321
322
323
324
325
        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");
326

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

537
  xassert(size);
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

543
  const 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