grid.c 132 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
3
4
#if defined (HAVE_CONFIG_H)
#  include "config.h"
#endif

Thomas Jahns's avatar
Thomas Jahns committed
5
#include <assert.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6
#include <string.h>
7
#include <float.h>  /* FLT_EPSILON */
8
#include <limits.h> /* INT_MAX     */
9

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
23

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

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* must match table below */
enum xystdname_idx {
  grid_xystdname_grid_latlon,
  grid_xystdname_latlon,
  grid_xystdname_projection,
};
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
61
62
static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
static void   gridDestroyP    ( void * gridptr );
static void   gridPrintP      ( void * gridptr, FILE * fp );
63
static int    gridGetPackSize ( void * gridptr, void *context);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
64
static void   gridPack        ( void * gridptr, void * buff, int size, int *position, void *context);
Deike Kleberg's avatar
minimal    
Deike Kleberg committed
65
static int    gridTxCode      ( void );
Uwe Schulzweida's avatar
Uwe Schulzweida committed
66

67
static const resOps gridOps = {
68
69
70
71
72
73
  gridCompareP,
  gridDestroyP,
  gridPrintP,
  gridGetPackSize,
  gridPack,
  gridTxCode
74
};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
75

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
78

79
grid_t *grid_to_pointer(int gridID)
80
81
82
{
  return (grid_t *)reshGetVal(gridID, &gridOps);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
83

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

86

Deike Kleberg's avatar
Deike Kleberg committed
87
void grid_init(grid_t *gridptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
88
{
89
90
91
  gridptr->self          = CDI_UNDEFID;
  gridptr->type          = CDI_UNDEFID;
  gridptr->proj          = CDI_UNDEFID;
92
  gridptr->projtype      = CDI_UNDEFID;
93
94
  gridptr->mask          = NULL;
  gridptr->mask_gme      = NULL;
95
96
97
98
  gridptr->x.vals        = NULL;
  gridptr->y.vals        = NULL;
  gridptr->x.bounds      = NULL;
  gridptr->y.bounds      = NULL;
99
  gridptr->area          = NULL;
100
101
  gridptr->rowlon        = NULL;
  gridptr->nrowlon       = 0;
102

103
104
105
106
107
108
  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;
109

110
111
112
113
114
115
116
117
118
119
  gridptr->lcc.originLon = 0.0;
  gridptr->lcc.originLat = 0.0;
  gridptr->lcc.lonParY   = 0.0;
  gridptr->lcc.lat1      = 0.0;
  gridptr->lcc.lat2      = 0.0;
  gridptr->lcc.xinc      = 0.0;
  gridptr->lcc.yinc      = 0.0;
  gridptr->lcc.projflag  = 0;
  gridptr->lcc.scanflag  = 0;
  gridptr->lcc.defined   = FALSE;
120

121
122
123
124
  gridptr->gme.nd        = 0;
  gridptr->gme.ni        = 0;
  gridptr->gme.ni2       = 0;
  gridptr->gme.ni3       = 0;
125

126
127
128
129
130
131
132
  gridptr->trunc         = 0;
  gridptr->nvertex       = 0;
  gridptr->number        = 0;
  gridptr->position      = 0;
  gridptr->reference     = NULL;
  gridptr->prec          = 0;
  gridptr->size          = 0;
133
134
  gridptr->x.size        = 0;
  gridptr->y.size        = 0;
135
  gridptr->np            = 0;
136
137
  gridptr->x.flag        = 0;
  gridptr->y.flag        = 0;
138
  gridptr->isCyclic      = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
139

140
  gridptr->lcomplex      = false;
141
142
143
144
145
146
147
148
149
150
151
  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
152
153
154
  gridptr->vdimname[0]   = 0;
  gridptr->mapname[0]    = 0;
  gridptr->mapping[0]    = 0;
Thomas Jahns's avatar
Thomas Jahns committed
155
  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
156
157
  gridptr->name          = NULL;
  gridptr->vtable        = &cdiGridVtable;
158
  gridptr->atts.nalloc   = MAX_ATTRIBUTES;
159
  gridptr->atts.nelems   = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
160
161
}

162

163
164
static
void grid_free_components(grid_t *gridptr)
Deike Kleberg's avatar
Deike Kleberg committed
165
{
166
  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
167
168
169
170
171
                     gridptr->x.vals, gridptr->y.vals,
                     gridptr->x.bounds, gridptr->y.bounds,
                     gridptr->rowlon, gridptr->area,
                     gridptr->reference, gridptr->name};

172
  for ( size_t i = 0; i < sizeof(p2free)/sizeof(p2free[0]); ++i )
173
    if ( p2free[i] ) Free(p2free[i]);
174
}
Deike Kleberg's avatar
Deike Kleberg committed
175

176
177
178
void grid_free(grid_t *gridptr)
{
  grid_free_components(gridptr);
Deike Kleberg's avatar
Deike Kleberg committed
179
180
181
  grid_init(gridptr);
}

182
183
static
grid_t *gridNewEntry(cdiResH resH)
184
{
185
  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
186
  grid_init(gridptr);
187

188
  if ( resH == CDI_UNDEFID )
189
190
191
192
193
194
    gridptr->self = reshPut(gridptr, &gridOps);
  else
    {
      gridptr->self = resH;
      reshReplace(resH, gridptr, &gridOps);
    }
195

196
  return gridptr;
197
198
}

199
static
200
void gridInit(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
{
202
  static bool gridInitialized = false;
203
  if ( gridInitialized ) return;
204
  gridInitialized = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
205

Uwe Schulzweida's avatar
Uwe Schulzweida committed
206
  const char *env = getenv("GRID_DEBUG");
207
  if ( env ) GRID_Debug = atoi(env);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
208
209
}

210
211
static
void grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
212
{
Thomas Jahns's avatar
Thomas Jahns committed
213
214
  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
  gridptrDup->self = CDI_UNDEFID;
215
  if ( gridptrOrig->reference )
Thomas Jahns's avatar
Thomas Jahns committed
216
217
218
    gridptrDup->reference = strdupx(gridptrOrig->reference);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
219

220
221
static
grid_t *grid_copy_base(grid_t *gridptrOrig)
Thomas Jahns's avatar
Thomas Jahns committed
222
223
224
225
226
{
  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
227
228
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
229

230
unsigned cdiGridCount(void)
Thomas Jahns's avatar
Thomas Jahns committed
231
{
232
  return reshCountType(&gridOps);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
233
234
}

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
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;
}

251
252
static inline
void gridSetName(char *gridstrname, const char *name)
253
{
254
255
  strncpy(gridstrname, name, CDI_MAX_NAME);
  gridstrname[CDI_MAX_NAME - 1] = 0;
256
257
}

258
259

void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
260
261
262
263
{
  gridptr->type = gridtype;
  gridptr->size = size;

264
265
266
  if      ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;

267
268
269
270
271
272
  switch (gridtype)
    {
    case GRID_LONLAT:
    case GRID_GAUSSIAN:
    case GRID_GAUSSIAN_REDUCED:
    case GRID_TRAJECTORY:
273
274
275
    case GRID_CURVILINEAR:
    case GRID_UNSTRUCTURED:
    case GRID_GME:
276
277
278
      {
        if ( gridtype == GRID_TRAJECTORY )
          {
279
280
            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "tlon");
            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "tlat");
281
282
283
          }
        else
          {
284
285
            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "lon");
            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "lat");
286
          }
287

288
289
        gridSetName(gridptr->x.longname, "longitude");
        gridSetName(gridptr->y.longname, "latitude");
290

291
292
        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
293
294
        gridSetName(gridptr->x.units, "degrees_east");
        gridSetName(gridptr->y.units, "degrees_north");
295

296
297
298
        break;
      }
    case GRID_GENERIC:
299
    case GRID_PROJECTION:
300
      {
301
302
        if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "x");
        if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "y");
303
304
305
        if ( gridtype == GRID_PROJECTION )
          {
            gridSetName(gridptr->mapname, "Projection");
306

307
308
309
310
311
            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
            gridSetName(gridptr->x.units, "m");
            gridSetName(gridptr->y.units, "m");
          }
312
313
314
315
316
317
        break;
      }
    }
}


318
// used also in CDO
319
void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
320
{
321
  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
322
323
    {
      if ( xfirst >= xlast )
Thomas Jahns's avatar
Thomas Jahns committed
324
325
326
327
        {
          while ( xfirst >= xlast ) xlast += 360;
          xinc = (xlast-xfirst)/(xsize);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
328
      else
Thomas Jahns's avatar
Thomas Jahns committed
329
330
331
        {
          xinc = (xlast-xfirst)/(xsize-1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
332
333
    }

334
  for ( int i = 0; i < xsize; ++i )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
335
336
337
    xvals[i] = xfirst + i*xinc;
}

338
static
339
void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
340
{
341
  double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
342
  gaussaw(yvals, yw, (size_t)ysize);
343
  Free(yw);
344
  for (int i = 0; i < ysize; i++ )
345
346
347
348
    yvals[i] = asin(yvals[i])/M_PI*180.0;

  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
    {
349
350
      int yhsize = ysize/2;
      for (int i = 0; i < yhsize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
351
        {
352
          double ytmp = yvals[i];
Thomas Jahns's avatar
Thomas Jahns committed
353
354
355
          yvals[i] = yvals[ysize-i-1];
          yvals[ysize-i-1] = ytmp;
        }
356
357
358
    }
}

359
// used also in CDO
Thomas Jahns's avatar
Thomas Jahns committed
360
void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
361
{
362
  const double deleps = 0.002;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
363
364
365
366

  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
    {
      if ( ysize > 2 )
Deike Kleberg's avatar
Deike Kleberg committed
367
368
369
370
371
372
	{
	  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 )
	      {
373
		double *restrict ytmp = NULL;
Deike Kleberg's avatar
Deike Kleberg committed
374
		int nstart, lfound = 0;
375
		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
Deike Kleberg's avatar
Deike Kleberg committed
376
377
378
		ny -= ny%2;
		if ( ny > ysize && ny < 4096 )
		  {
379
		    ytmp = (double *) Malloc((size_t)ny * sizeof (double));
Deike Kleberg's avatar
Deike Kleberg committed
380
		    calc_gaussgrid(ytmp, ny, yfirst, ylast);
381
382
383
384
385
386
                    {
                      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
387

388
389
		    lfound = (nstart+ysize-1) < ny
                      && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
390
391
392
393
                    if ( lfound )
                      {
                        for (int i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
                      }
Deike Kleberg's avatar
Deike Kleberg committed
394
395
		  }

396
		if ( !lfound )
Deike Kleberg's avatar
Deike Kleberg committed
397
		  {
398
		    Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
399
		    for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
Deike Kleberg's avatar
Deike Kleberg committed
400
401
402
403
		    yvals[0] = yfirst;
		    yvals[ysize-1] = ylast;
		  }

404
		if ( ytmp ) Free(ytmp);
Deike Kleberg's avatar
Deike Kleberg committed
405
406
	      }
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
407
      else
Thomas Jahns's avatar
Thomas Jahns committed
408
409
410
411
        {
          yvals[0] = yfirst;
          yvals[ysize-1] = ylast;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
412
413
414
415
    }
  /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
  else
    {
416
      if ( (! (fabs(yinc) > 0)) && ysize > 1 )
Thomas Jahns's avatar
Thomas Jahns committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
        {
          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
438
439
440

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

441
      for (int i = 0; i < ysize; i++ )
Thomas Jahns's avatar
Thomas Jahns committed
442
        yvals[i] = yfirst + i*yinc;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
443
444
445
    }
  /*
    else
446
    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
447
448
449
450
  */
}

/*
451
@Function  gridCreate
452
@Title     Create a horizontal Grid
Uwe Schulzweida's avatar
Uwe Schulzweida committed
453

454
@Prototype int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
455
456
@Parameter
    @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
457
                     The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
Uwe Schulzweida's avatar
Uwe Schulzweida committed
458
                     @func{GRID_LONLAT}, @func{GRID_LCC}, @func{GRID_SPECTRAL},
459
                     @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
460
461
462
    @Item  size      Number of gridpoints.

@Description
463
The function @func{gridCreate} creates a horizontal Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
464
465

@Result
466
@func{gridCreate} returns an identifier to the Grid.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
467
468

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

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
472
473
#include "cdi.h"
   ...
474
475
#define  nlon  12
#define  nlat   6
Uwe Schulzweida's avatar
Uwe Schulzweida committed
476
   ...
477
478
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
479
480
int gridID;
   ...
481
482
483
gridID = gridCreate(GRID_LONLAT, nlon*nlat);
gridDefXsize(gridID, nlon);
gridDefYsize(gridID, nlat);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
484
485
486
487
gridDefXvals(gridID, lons);
gridDefYvals(gridID, lats);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
488
489
@EndFunction
*/
490
int gridCreate(int gridtype, int size)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
491
{
492
  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
493

494
  if ( size < 0 || size > INT_MAX ) Error("Grid size (%d) out of bounds (0 - %d)!", size, INT_MAX);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
495

496
  gridInit();
497

Uwe Schulzweida's avatar
Uwe Schulzweida committed
498
  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
499
  if ( ! gridptr ) Error("No memory");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
500

Uwe Schulzweida's avatar
Uwe Schulzweida committed
501
  int gridID = gridptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
502

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

505
  cdiGridTypeInit(gridptr, gridtype, size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
506

Uwe Schulzweida's avatar
Uwe Schulzweida committed
507
  return gridID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
508
509
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
510
511
static
void gridDestroyKernel( grid_t * gridptr )
512
{
Deike Kleberg's avatar
Deike Kleberg committed
513
  xassert ( gridptr );
514

515
  int id = gridptr->self;
516

517
  grid_free_components(gridptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
518
  Free( gridptr );
519

520
  reshRemove ( id, &gridOps );
521
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
522

523
524
525
526
527
528
/*
@Function  gridDestroy
@Title     Destroy a horizontal Grid

@Prototype void gridDestroy(int gridID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
529
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
530
531
532
533
534

@EndFunction
*/
void gridDestroy(int gridID)
{
535
  grid_t *gridptr = grid_to_pointer(gridID);
536
  gridptr->vtable->destroy(gridptr);
537
538
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
539
540
static
void gridDestroyP(void * gridptr)
541
{
542
  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
543
544
545
}


546
const char *gridNamePtr(int gridtype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
547
{
548
  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
549

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
552
  return name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
553
554
555
556
557
558
559
560
}


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

561
static
562
void *grid_key_to_ptr(grid_t *gridptr, int key)
563
{
564
  void *keyptr = NULL;
565
566
567

  switch (key)
    {
568
569
570
571
572
573
574
575
576
    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;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
577
    case CDI_KEY_MAPNAME:    keyptr = (void*)gridptr->mapname; break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
578
    case CDI_KEY_MAPPING:    keyptr = (void*)gridptr->mapping; break;
579
580
    }

581
  return keyptr;
582
583
}

584
/*
585
@Function  cdiGridDefKeyStr
586
587
@Title     Define a CDI grid string value from a key

588
@Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
589
590
591
592
593
594
595
@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
596
The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
597
598

@Result
599
@func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
600
601
602

@EndFunction
*/
603
int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
604
{
605
  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
606

607
  grid_t *gridptr = grid_to_pointer(gridID);
608

609
610
  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
  if ( keyptr == NULL )
611
612
613
614
615
    {
      Warning("CDI grid string key %d not supported!", key);
      return -1;
    }

616
  gridSetString(keyptr, mesg, (size_t)size);
617
618
619
620
621
622
  gridMark4Update(gridID);

  return 0;
}

/*
623
@Function  cdiGridInqKeyStr
624
625
@Title     Get a CDI grid string value from a key

626
@Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
627
628
629
630
631
632
633
634
635
636
@Parameter
    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
    @Item  key      The key to be searched.
    @Item  size     The allocated length of the string on input.
    @Item  mesg     The address of a string where the data will be 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
637
The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
638
639

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

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

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

656
  gridGetString(mesg, keyptr, (size_t)size);
657
658
659
660

  return 0;
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
661
662
663
664
665
666
/*
@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
667
668
    @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
669
670

@Description
671
The function @func{gridDefXname} defines the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
672
673
674

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
675
void gridDefXname(int gridID, const char *xname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
676
{
677
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
678
679
680
681
682
683
684
685
}

/*
@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
686
687
    @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
688
689

@Description
690
The function @func{gridDefXlongname} defines the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
691
692
693

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
694
void gridDefXlongname(int gridID, const char *xlongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
695
{
696
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
697
698
699
700
701
702
703
704
}

/*
@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
705
706
    @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
707
708

@Description
709
The function @func{gridDefXunits} defines the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
710
711
712

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
713
void gridDefXunits(int gridID, const char *xunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
714
{
715
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
716
717
}

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

@Description
728
The function @func{gridDefYname} defines the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
729
730
731

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
732
void gridDefYname(int gridID, const char *yname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
733
{
734
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
736
737
738
739
740
741
742
}

/*
@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
743
744
    @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
745
746

@Description
747
The function @func{gridDefYlongname} defines the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
749
750

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
void gridDefYlongname(int gridID, const char *ylongname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
752
{
753
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
755
756
757
758
759
760
761
}

/*
@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
762
763
    @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
764
765

@Description
766
The function @func{gridDefYunits} defines the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
767
768
769

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
void gridDefYunits(int gridID, const char *yunits)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
771
{
772
  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
773
774
775
776
777
778
}

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

Deike Kleberg's avatar
Deike Kleberg committed
779
@Prototype void gridInqXname(int gridID, char *name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
780
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
781
782
    @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
783
                    returned string. The maximum possible length, in characters, of
784
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
785
786

@Description
787
The function @func{gridInqXname} returns the name of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
788
789

@Result
790
@func{gridInqXname} returns the name of the X-axis to the parameter name.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
791
792
793
794
795

@EndFunction
*/
void gridInqXname(int gridID, char *xname)
{
796
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
797
798
799
800
801
802
}

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

Deike Kleberg's avatar
Deike Kleberg committed
803
@Prototype void gridInqXlongname(int gridID, char *longname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
804
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
805
806
    @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
807
                    returned string. The maximum possible length, in characters, of
808
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
809
810

@Description
811
The function @func{gridInqXlongname} returns the longname of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
812
813

@Result
814
@func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
815
816
817
818
819

@EndFunction
*/
void gridInqXlongname(int gridID, char *xlongname)
{
820
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
821
822
823
824
825
826
}

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

Deike Kleberg's avatar
Deike Kleberg committed
827
@Prototype void gridInqXunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
828
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
829
830
    @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
831
                    returned string. The maximum possible length, in characters, of
832
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
833
834

@Description
835
The function @func{gridInqXunits} returns the units of a X-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
836
837

@Result
838
@func{gridInqXunits} returns the units of the X-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
839
840
841
842
843

@EndFunction
*/
void gridInqXunits(int gridID, char *xunits)
{
844
  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
845
846
847
848
849
}


void gridInqXstdname(int gridID, char *xstdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
850
851
852
853
854
855
  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
856
857
858
859
860
861
}

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

Deike Kleberg's avatar
Deike Kleberg committed
862
@Prototype void gridInqYname(int gridID, char *name)
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  name     Name of the Y-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{gridInqYname} returns the name of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
871
872

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

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

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

886
@Prototype void gridInqYlongname(int gridID, char *longname)
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  longname Longname of the Y-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{gridInqYlongname} returns the longname of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
895
896

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

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

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

Deike Kleberg's avatar
Deike Kleberg committed
910
@Prototype void gridInqYunits(int gridID, char *units)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
911
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
912
913
    @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
914
                    returned string. The maximum possible length, in characters, of
915
                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
916
917

@Description
918
The function @func{gridInqYunits} returns the units of a Y-axis.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
919
920

@Result
921
@func{gridInqYunits} returns the units of the Y-axis to the parameter units.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
922
923
924
925
926

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

930

Uwe Schulzweida's avatar
Uwe Schulzweida committed
931
932
void gridInqYstdname(int gridID, char *ystdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
933
934
935
936
937
938
  if ( ystdname )
    {
      ystdname[0] = 0;
      grid_t *gridptr = grid_to_pointer(gridID);
      if ( gridptr->y.stdname ) strcpy(ystdname, gridptr->y.stdname);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
939
940
}

941

942
void gridDefProj(int gridID, int projID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
943
{
944
  grid_t *gridptr = grid_to_pointer(gridID);
945
  gridptr->proj = projID;
946
947
948

  if ( gridptr->type == GRID_CURVILINEAR )
    {
949
      grid_t *projptr = grid_to_pointer(projID);
950
951
952
      if ( projptr->x.name[0] ) strcpy(gridptr->x.dimname, projptr->x.name);
      if ( projptr->y.name[0] ) strcpy(gridptr->y.dimname, projptr->y.name);
    }
953
954
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
955

956
957
int gridInqProj(int gridID)
{
958
  grid_t *gridptr = grid_to_pointer(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
959
960
961
  return gridptr->proj;
}

962
963
964

int gridInqProjType(int gridID)
{
965
  grid_t *gridptr = grid_to_pointer(gridID);
966
967
968
969
970
971
972
973
974

  int projtype = gridptr->projtype;

  if ( projtype == -1 )
    {
      char mapping[CDI_MAX_NAME]; mapping[0] = 0;
      cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, mapping);
      if ( mapping[0] )
        {
975
976
977
978
979
          if      ( strcmp(mapping, "rotated_latitude_longitude") == 0 )   projtype = CDI_PROJ_RLL;
          else if ( strcmp(mapping, "lambert_azimuthal_equal_area") == 0 ) projtype = CDI_PROJ_LAEA;
          else if ( strcmp(mapping, "lambert_conformal_conic") == 0 )      projtype = CDI_PROJ_LCC;
          else if ( strcmp(mapping, "sinusoidal") == 0 )                   projtype = CDI_PROJ_SINU;

980
981
982
983
984
985
986
          gridptr->projtype = projtype;
        }
    }

  return projtype;
}

987
988
989