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

Thomas Jahns's avatar
Thomas Jahns committed
5
#include <assert.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6
#include <string.h>
7

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

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

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

44
45
46
47
48
/* must match table below */
enum xystdname_idx {
  grid_xystdname_grid_latlon,
  grid_xystdname_latlon,
  grid_xystdname_projection,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
49
  grid_xystdname_char,
50
51
52
53
54
55
56
57
};
static const char xystdname_tab[][2][24] = {
  [grid_xystdname_grid_latlon] = { "grid_longitude",
                                   "grid_latitude" },
  [grid_xystdname_latlon] = { "longitude",
                              "latitude" },
  [grid_xystdname_projection] = { "projection_x_coordinate",
                                  "projection_y_coordinate" },
Uwe Schulzweida's avatar
Uwe Schulzweida committed
58
59
  [grid_xystdname_char] = { "region",
                            "region" },
60
61
62
};


Uwe Schulzweida's avatar
Uwe Schulzweida committed
63

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
82

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

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

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

  if ( atttype == CDI_DATATYPE_INT32 )
    {
97
      int attint[64];
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
      cdiInqAttInt(gridID, CDI_GLOBAL, attname, attlen, attint);
      for ( int i = 0; i < attlen; ++i ) attflt[i] = (double)attint[i];
    }
  else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
    {
      cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, attflt);
    }
  else
    {
      status = false;
    }

  return status;
}

113

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

134
135
136
137
138
139
  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;
140

141
142
143
144
  gridptr->gme.nd        = 0;
  gridptr->gme.ni        = 0;
  gridptr->gme.ni2       = 0;
  gridptr->gme.ni3       = 0;
145

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

160
  gridptr->lcomplex      = false;
161
162
163
164
165
166
167
168
169
170
171
  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
172
173
174
  gridptr->vdimname[0]   = 0;
  gridptr->mapname[0]    = 0;
  gridptr->mapping[0]    = 0;
Thomas Jahns's avatar
Thomas Jahns committed
175
  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
176
177
  gridptr->name          = NULL;
  gridptr->vtable        = &cdiGridVtable;
178
  gridptr->atts.nalloc   = MAX_ATTRIBUTES;
179
  gridptr->atts.nelems   = 0;
180
  gridptr->uvRelativeToGrid      = 0;   // Some models deliver wind U,V relative to the grid-cell
181
182
183
184
185
186
187
188
189
190
  gridptr->iScansNegatively      = 0;
  gridptr->jScansPositively      = 1;
  gridptr->jPointsAreConsecutive = 0;
  gridptr->scanningMode          = 128*gridptr->iScansNegatively + 64*gridptr->jScansPositively + 32*gridptr->jPointsAreConsecutive;
  /* scanningMode  = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
               64  = 128 * 0                + 64 *        1         + 32 * 0
               00  = 128 * 0                + 64 *        0         + 32 * 0
               96  = 128 * 0                + 64 *        1         + 32 * 1
     Default / implicit scanning mode is 64:
                        i and j scan positively, i points are consecutive (row-major)        */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
191
192
}

193

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

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

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

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

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

228
  return gridptr;
229
230
}

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
251

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
261

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

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

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

290

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

536
  gridInit();
537

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
541
  int gridID = gridptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
542

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

545
  cdiGridTypeInit(gridptr, gridtype, size);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546

Uwe Schulzweida's avatar
Uwe Schulzweida committed
547
  return gridID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
548
549
}

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

555
  int id = gridptr->self;
556

557
  grid_free_components(gridptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
558
  Free( gridptr );
559

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

563
564
565
566
567
568
/*
@Function  gridDestroy
@Title     Destroy a horizontal Grid

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

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

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


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

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

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


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

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

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

621
  return keyptr;
622
623
}

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

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

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

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

647
  grid_t *gridptr = grid_to_pointer(gridID);
648

649
650
  char *keyptr = (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
  gridSetString(keyptr, mesg, (size_t)size);
657
658
659
660
661
662
  gridMark4Update(gridID);

  return 0;
}

/*
663
@Function  cdiGridInqKeyStr
664
665
@Title     Get a CDI grid string value from a key

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

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

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

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

696
  gridGetString(mesg, keyptr, (size_t)size);
697
698
699
700

  return 0;
}

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

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

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

/*
@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
726
727
    @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
728
729

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

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

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

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

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

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

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

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

/*
@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
783
784
    @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
785
786

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

970

Uwe Schulzweida's avatar
Uwe Schulzweida committed
971
972
void gridInqYstdname(int gridID, char *ystdname)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
973
974
975
976
977
978
  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
979
980
}