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

#include "dmemory.h"
#include "cdi.h"
7
#include "cdi_int.h"
8
#include "error.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
9
#include "vlist.h"
10
#include "zaxis.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
11
#include "varscan.h"
12
#include "namespace.h"
13
#include "resource_handle.h"
Thomas Jahns's avatar
Thomas Jahns committed
14
#include "vlist_var.h"
15
#include "cdi_att.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
16

17
18
19
#include "resource_unpack.h"
#include "serialize.h"

20
21
22
23
24
25
#if  defined  (HAVE_LIBGRIB_API)
/* list of additional GRIB2 keywords which are read by the open process */
int    cdiNAdditionalGRIBKeys = 0;
char*  cdiAdditionalGRIBKeys[MAX_OPT_GRIB_ENTRIES];
#endif

26
static int VLIST_Debug = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
28
29
30
31
32

static void vlist_initialize(void);

#if  defined  (HAVE_LIBPTHREAD)
#  include <pthread.h>

33
static pthread_once_t  _vlist_init_thread = PTHREAD_ONCE_INIT;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
34

35
#  define VLIST_INIT()        \
36
  pthread_once(&_vlist_init_thread, vlist_initialize)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
37
38
39

#else

40
static int vlistIsInitialized = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
41

42
#  define VLIST_INIT()               \
43
  if ( !vlistIsInitialized ) vlist_initialize()
44
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
45
46


47
48
static int
vlist_compare(vlist_t *a, vlist_t *b)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
49
{
50
  int diff = (a->nvars != b->nvars) | (a->ngrids != b->ngrids)
Thomas Jahns's avatar
Thomas Jahns committed
51
52
53
54
55
56
    | (a->nzaxis != b->nzaxis) | (a->instID != b->instID)
    | (a->modelID != b->modelID) | (a->tableID != b->tableID)
    | (a->ntsteps != b->ntsteps) | (a->atts.nelems != b->atts.nelems);
  int nvars = a->nvars;
  for (int varID = 0; varID < nvars; ++varID)
    diff |= vlistVarCompare(a, varID, b, varID);
57
58
  size_t natts = a->atts.nelems;
  for (size_t attID = 0; attID < natts; ++attID)
59
    diff |= cdi_att_compare(a, CDI_GLOBAL, b, CDI_GLOBAL, (int)attID);
60
  return diff;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
61
62
}

63
static void
64
vlistPrintKernel(vlist_t *vlistptr, FILE * fp );
65
66
67
static void
vlist_delete(vlist_t *vlistptr);

68
static int  vlistGetSizeP ( void * vlistptr, void *context);
69
static void vlistPackP    ( void * vlistptr, void * buff, int size,
70
                            int *position, void *context);
71
static int  vlistTxCode   ( void );
72

73
74
75
#if !defined(__cplusplus)
const
#endif
Thomas Jahns's avatar
Thomas Jahns committed
76
resOps vlistOps = {
77
  (valCompareFunc)vlist_compare,
78
  (valDestroyFunc)vlist_delete,
79
80
  (valPrintFunc)vlistPrintKernel,
  vlistGetSizeP,
81
82
  vlistPackP,
  vlistTxCode
83
};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
84
85


86
vlist_t *vlist_to_pointer(int vlistID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
87
{
88
  VLIST_INIT();
89
  return (vlist_t*) reshGetVal(vlistID, &vlistOps);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
90
91
}

92
93
static
void vlist_init_entry(vlist_t *vlistptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
94
{
95
96
  vlistptr->immutable      = 0;
  vlistptr->internal       = 0;
97
  vlistptr->self           = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
98
99
100
101
  vlistptr->nvars          = 0;
  vlistptr->vars           = NULL;
  vlistptr->ngrids         = 0;
  vlistptr->nzaxis         = 0;
102
  vlistptr->taxisID        = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
103
104
105
106
107
  vlistptr->instID         = cdiDefaultInstID;
  vlistptr->modelID        = cdiDefaultModelID;
  vlistptr->tableID        = cdiDefaultTableID;
  vlistptr->varsAllocated  = 0;
  vlistptr->ntsteps        = CDI_UNDEFID;
108
  vlistptr->atts.nalloc    = MAX_ATTRIBUTES;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
109
  vlistptr->atts.nelems    = 0;
110
  vlistptr->nsubtypes      = 0;
111
  for ( int i = 0; i < MAX_SUBTYPES_PS; i++ )
112
    vlistptr->subtypeIDs[i] = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
113
114
}

115
static
116
vlist_t *vlist_new_entry(cdiResH resH)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
117
{
118
  vlist_t *vlistptr = (vlist_t*) Malloc(sizeof(vlist_t));
119
  vlist_init_entry(vlistptr);
120
  if (resH == CDI_UNDEFID)
Thomas Jahns's avatar
Thomas Jahns committed
121
    vlistptr->self = reshPut(vlistptr, &vlistOps);
122
123
124
  else
    {
      vlistptr->self = resH;
Thomas Jahns's avatar
Thomas Jahns committed
125
      reshReplace(resH, vlistptr, &vlistOps);
126
    }
127
  return vlistptr;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
128
129
}

130
131
static
void vlist_delete_entry(vlist_t *vlistptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
132
{
133
  int idx = vlistptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
134

Thomas Jahns's avatar
Thomas Jahns committed
135
  reshRemove(idx, &vlistOps );
Uwe Schulzweida's avatar
Uwe Schulzweida committed
136

137
  Free(vlistptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
138
139

  if ( VLIST_Debug )
140
    Message("Removed idx %d from vlist list", idx);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
141
142
}

143
144
static
void vlist_initialize(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
145
{
146
  char *env = getenv("VLIST_DEBUG");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
147
  if ( env ) VLIST_Debug = atoi(env);
148
149
150
#ifndef HAVE_LIBPTHREAD
  vlistIsInitialized = TRUE;
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
151
152
}

153
154
static
void vlist_copy(vlist_t *vlistptr2, vlist_t *vlistptr1)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
155
{
156
  int vlistID2 = vlistptr2->self;
157
  int vlist2internal = vlistptr2->internal;
158
  memcpy(vlistptr2, vlistptr1, sizeof(vlist_t));
159
160
  vlistptr2->internal = vlist2internal;    //the question who's responsible to destroy the vlist is tied to its containing memory region, so we retain this flag
  vlistptr2->immutable = 0;    //this is a copy, so it's mutable, independent of whether the original is mutable or not
Uwe Schulzweida's avatar
Uwe Schulzweida committed
161
  vlistptr2->atts.nelems = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
162
163
164
  vlistptr2->self = vlistID2;
}

165
void cdiVlistMakeInternal(int vlistID)
166
{
167
  vlist_to_pointer(vlistID)->internal = 1;
168
169
}

170
void cdiVlistMakeImmutable(int vlistID)
171
{
172
  vlist_to_pointer(vlistID)->immutable = 1;
173
174
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
175
/*
176
@Function  vlistCreate
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
178
@Title     Create a variable list

179
@Prototype int vlistCreate(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
180

Uwe Schulzweida's avatar
Uwe Schulzweida committed
181
182
@Example
Here is an example using @func{vlistCreate} to create a variable list
Uwe Schulzweida's avatar
Uwe Schulzweida committed
183
and add a variable with @func{vlistDefVar}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
184
185
186
187
188
189
190

@Source
#include "cdi.h"
   ...
int vlistID, varID;
   ...
vlistID = vlistCreate();
191
varID = vlistDefVar(vlistID, gridID, zaxisID, TSTEP_INSTANT);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
192
193
194
195
196
197
   ...
streamDefVlist(streamID, vlistID);
   ...
vlistDestroy(vlistID);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
198
199
@EndFunction
*/
200
int vlistCreate(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
{
202
203
  cdiInitialize();

204
  VLIST_INIT();
Uwe Schulzweida's avatar
Uwe Schulzweida committed
205

206
  vlist_t *vlistptr = vlist_new_entry(CDI_UNDEFID);
207
  if ( CDI_Debug ) Message("create vlistID = %d", vlistptr->self);
208
  return vlistptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
209
210
}

211
212
static void
vlist_delete(vlist_t *vlistptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
213
{
214
  int vlistID = vlistptr->self;
215
  if ( CDI_Debug ) Message("call to vlist_delete, vlistID = %d", vlistID);
216

217
  cdiDelAtts(vlistID, CDI_GLOBAL);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
218

219
  int nvars = vlistptr->nvars;
220
  var_t *vars = vlistptr->vars;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
221

222
  for ( int varID = 0; varID < nvars; varID++ )
Deike Kleberg's avatar
Deike Kleberg committed
223
    {
224
225
226
227
228
229
      if ( vars[varID].levinfo )  Free(vars[varID].levinfo);
      if ( vars[varID].name )     Free(vars[varID].name);
      if ( vars[varID].longname ) Free(vars[varID].longname);
      if ( vars[varID].stdname )  Free(vars[varID].stdname);
      if ( vars[varID].units )    Free(vars[varID].units);
      if ( vars[varID].ensdata )  Free(vars[varID].ensdata);
230

231
      if ( vlistptr->vars[varID].opt_grib_kvpair )
232
        {
233
234
235
236
237
          for ( int i = 0; i<vlistptr->vars[varID].opt_grib_nentries; i++ )
            {
              if ( vlistptr->vars[varID].opt_grib_kvpair[i].keyword )
                Free(vlistptr->vars[varID].opt_grib_kvpair[i].keyword);
            }
238
          Free(vlistptr->vars[varID].opt_grib_kvpair);
239
        }
240
241
242
      vlistptr->vars[varID].opt_grib_nentries    = 0;
      vlistptr->vars[varID].opt_grib_kvpair_size = 0;
      vlistptr->vars[varID].opt_grib_kvpair      = NULL;
243

244
      cdiDelAtts(vlistID, varID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
245
    }
246

247
  if ( vars ) Free(vars);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
248

Deike Kleberg's avatar
Deike Kleberg committed
249
  vlist_delete_entry(vlistptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
250
251
}

252
253
254
255
256
257
258

/*
@Function  vlistDestroy
@Title     Destroy a variable list

@Prototype void vlistDestroy(int vlistID)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
259
    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
260
261
262
263
264

@EndFunction
*/
void vlistDestroy(int vlistID)
{
265
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
266

267
268
  if ( vlistptr->internal )
    Warning("Attempt to destroy an internal vlist object by the user (vlistID=%d).", vlistID);
269
270
  else
    vlist_delete(vlistptr);
271
272
}

273
274
275
276
277
278
279
280
281
282
283
284
285
// destroy an internal vlist object
void cdiVlistDestroy_(int vlistID)
{
  vlist_t *vlistptr = vlist_to_pointer(vlistID);

  if(!vlistptr->internal)
    Warning("Destroying a vlist object that is owned by the user.\n"
            "This is most likely because of a missing vlistDestroy() in the application code.\n"
            "If that's not the case, and you are absolutely certain about it, please report the bug.");

  vlist_delete(vlistptr);
}

286
287
288
289
290
291
292
293
294
static
void var_copy_entries(var_t *var2, var_t *var1)
{
  if ( var1->name )     var2->name     = strdupx(var1->name);
  if ( var1->longname ) var2->longname = strdupx(var1->longname);
  if ( var1->stdname )  var2->stdname  = strdupx(var1->stdname);
  if ( var1->units )    var2->units    = strdupx(var1->units);
  if ( var1->ensdata )
    {
295
      var2->ensdata = (ensinfo_t *) Malloc(sizeof(ensinfo_t));
296
297
      memcpy(var2->ensdata, var1->ensdata, sizeof(ensinfo_t));
    }
298
299
300
301
302

  var2->opt_grib_kvpair_size = 0;
  var2->opt_grib_kvpair      = NULL;
  var2->opt_grib_nentries    = 0;

303
  resize_opt_grib_entries(var2, var1->opt_grib_nentries);
304
  var2->opt_grib_nentries = var1->opt_grib_nentries;
305
306
307
  if ((var2->opt_grib_nentries > 0) && CDI_Debug )
    Message("copy %d optional GRIB keywords", var2->opt_grib_nentries);

308
  for (int i=0; i<var1->opt_grib_nentries; i++) {
309
310
311
312
313
314
315
316
317
318
    if ( CDI_Debug )  Message("copy entry \"%s\" ...", var1->opt_grib_kvpair[i].keyword);
    var2->opt_grib_kvpair[i].keyword = NULL;
    if ( var1->opt_grib_kvpair[i].keyword != NULL ) {
      var2->opt_grib_kvpair[i]         = var1->opt_grib_kvpair[i];
      var2->opt_grib_kvpair[i].keyword = strdupx(var1->opt_grib_kvpair[i].keyword);
      var2->opt_grib_kvpair[i].update  = TRUE;
      if ( CDI_Debug )  Message("done.");
    }
    else {
      if ( CDI_Debug )  Message("not done.");
319
    }
320
  }
321
322
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
323
324
325
326
327
328
/*
@Function  vlistCopy
@Title     Copy a variable list

@Prototype void vlistCopy(int vlistID2, int vlistID1)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
329
330
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
331
332

@Description
333
The function @func{vlistCopy} copies all entries from vlistID1 to vlistID2.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
334
335
336
337
338

@EndFunction
*/
void vlistCopy(int vlistID2, int vlistID1)
{
339
340
  vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
  vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
341
  if ( CDI_Debug ) Message("call to vlistCopy, vlistIDs %d -> %d", vlistID1, vlistID2);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
342

343
344
  var_t *vars1 = vlistptr1->vars;
  var_t *vars2 = vlistptr2->vars;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
345
346
  vlist_copy(vlistptr2, vlistptr1);

347
  cdiCopyAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
348

349
  if ( vars1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
350
351
    {
      int nvars = vlistptr1->nvars;
352
      //vlistptr2->varsAllocated = nvars;
353
354

      size_t n = (size_t)vlistptr2->varsAllocated;
355
      vars2 = (var_t *) Realloc(vars2, n*sizeof(var_t));
356
357
      memcpy(vars2, vars1, n*sizeof(var_t));
      vlistptr2->vars = vars2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
358

359
      for ( int varID = 0; varID < nvars; varID++ )
Thomas Jahns's avatar
Thomas Jahns committed
360
        {
361
          var_copy_entries(&vars2[varID], &vars1[varID]);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
362

363
          vlistptr2->vars[varID].atts.nelems = 0;
364
	  cdiCopyAtts(vlistID1, varID, vlistID2, varID);
365

366
          if ( vars1[varID].levinfo )
367
            {
368
              n = (size_t)zaxisInqSize(vars1[varID].zaxisID);
369
              vars2[varID].levinfo = (levinfo_t *) Malloc(n*sizeof(levinfo_t));
370
              memcpy(vars2[varID].levinfo, vars1[varID].levinfo, n*sizeof(levinfo_t));
371
            }
372
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
373
374
375
376
377
378
379
380
381
    }
}

/*
@Function  vlistDuplicate
@Title     Duplicate a variable list

@Prototype int vlistDuplicate(int vlistID)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
382
    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
383
384

@Description
385
The function @func{vlistDuplicate} duplicates the variable list from vlistID1.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
386
387

@Result
388
@func{vlistDuplicate} returns an identifier to the duplicated variable list.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
389
390
391
392
393

@EndFunction
*/
int vlistDuplicate(int vlistID)
{
394
395
  if ( CDI_Debug ) Message("call to vlistDuplicate");

396
  int vlistIDnew = vlistCreate();
Uwe Schulzweida's avatar
Uwe Schulzweida committed
397
  vlistCopy(vlistIDnew, vlistID);
398
  return vlistIDnew;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
399
400
401
402
403
}


void vlistClearFlag(int vlistID)
{
404
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
405

406
  for ( int varID = 0; varID < vlistptr->nvars; varID++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
407
408
    {
      vlistptr->vars[varID].flag = FALSE;
409
      if ( vlistptr->vars[varID].levinfo )
410
411
        {
          int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
412
          for ( int levID = 0; levID < nlevs; levID++ )
413
            vlistptr->vars[varID].levinfo[levID].flag = FALSE;
414
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
415
416
417
    }
}

Thomas Jahns's avatar
Thomas Jahns committed
418
419
420
421
422
423

struct vgzSearchState
{
  int resIDValue;
  int zaxistype;
  int nlevels;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
424
  bool lbounds;
Thomas Jahns's avatar
Thomas Jahns committed
425
426
427
428
429
430
431
432
433
434
  const double *levels;
};

static enum cdiApplyRet
vgzZAxisSearch(int id, void *res, void *data)
{
  struct vgzSearchState *state = (struct vgzSearchState *)data;
  (void)res;
  if (zaxisCompare(id, state->zaxistype, state->nlevels, state->lbounds,
                   state->levels, NULL, NULL, 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
435
      == false)
Thomas Jahns's avatar
Thomas Jahns committed
436
437
438
439
440
441
442
443
    {
      state->resIDValue = id;
      return CDI_APPLY_STOP;
    }
  else
    return CDI_APPLY_GO_ON;
}

444
static
Thomas Jahns's avatar
Thomas Jahns committed
445
int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *levels,
446
447
                         const double *lbounds, const double *ubounds, int vctsize, const double *vct,
                         const char **cvals, size_t clen)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
448
449
{
  int zaxisID = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
450
451
452
  bool zaxisdefined = false;
  bool zaxisglobdefined = false;
  bool has_bounds = false;
453
454
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
  int nzaxis = vlistptr->nzaxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
455

Uwe Schulzweida's avatar
Uwe Schulzweida committed
456
  if ( lbounds && ubounds ) has_bounds = true;
457

458
  for ( int index = 0; index < nzaxis; ++index )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
459
460
461
    {
      zaxisID = vlistptr->zaxisIDs[index];

Uwe Schulzweida's avatar
Uwe Schulzweida committed
462
      if ( zaxisCompare(zaxisID, zaxistype, nlevels, has_bounds, levels, NULL, NULL, 0) == false )
Thomas Jahns's avatar
Thomas Jahns committed
463
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
464
          zaxisdefined = true;
Thomas Jahns's avatar
Thomas Jahns committed
465
466
          break;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
467
468
469
470
    }

  if ( ! zaxisdefined )
    {
Thomas Jahns's avatar
Thomas Jahns committed
471
472
473
474
475
476
477
478
479
480
      struct vgzSearchState query;
      query.zaxistype = zaxistype;
      query.nlevels = nlevels;
      query.levels = levels;
      query.lbounds = has_bounds;

      if ((zaxisglobdefined
           = (cdiResHFilterApply(getZaxisOps(), vgzZAxisSearch, &query)
              == CDI_APPLY_STOP)))
        zaxisID = query.resIDValue;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
481
482
483
484
485
    }

  if ( ! zaxisdefined )
    {
      if ( ! zaxisglobdefined )
486
487
488
	{
	  zaxisID = zaxisCreate(zaxistype, nlevels);
	  zaxisDefLevels(zaxisID, levels);
489
490
491
492

          if ( zaxistype == ZAXIS_CHAR )
            zaxisDefCvals(zaxisID, cvals, clen);

493
	  if ( has_bounds )
494
	    {
495
496
	      zaxisDefLbounds(zaxisID, lbounds);
	      zaxisDefUbounds(zaxisID, ubounds);
497
498
	    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
499
500
	  if ( zaxistype == ZAXIS_HYBRID && vctsize > 0 )
            zaxisDefVct(zaxisID, vctsize, vct);
501
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
502
503
504
505
506
507

      nzaxis = vlistptr->nzaxis;
      vlistptr->zaxisIDs[nzaxis] = zaxisID;
      vlistptr->nzaxis++;
    }

508
  return zaxisID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
509
510
511
512
513
514
515
516
}

/*
@Function  vlistCopyFlag
@Title     Copy some entries of a variable list

@Prototype void vlistCopyFlag(int vlistID2, int vlistID1)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
517
518
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
519
520

@Description
521
The function @func{vlistCopyFlag} copies all entries with a flag from vlistID1 to vlistID2.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
522
523
524
525
526

@EndFunction
*/
void vlistCopyFlag(int vlistID2, int vlistID1)
{
527
528
529
530
531
  vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
  vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
  var_t *vars1 = vlistptr1->vars;
  var_t *vars2 = vlistptr2->vars;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
532
  vlist_copy(vlistptr2, vlistptr1);
Thomas Jahns's avatar
Thomas Jahns committed
533

534
  cdiCopyAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
535

Uwe Schulzweida's avatar
Uwe Schulzweida committed
536
537
538
  if ( vlistptr1->vars )
    {
      int nvars = vlistptr1->nvars;
539
      int nvars2 = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
540
541
542
543

      vlistptr2->ngrids = 0;
      vlistptr2->nzaxis = 0;

544
      for ( int varID = 0; varID < nvars; varID++ )
545
        nvars2 += (vars1[varID].flag != 0);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546
547

      vlistptr2->nvars = nvars2;
548
      vlistptr2->varsAllocated = nvars2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
549
      if ( nvars2 > 0 )
550
        vars2 = (var_t *) Malloc((size_t)nvars2*sizeof(var_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
551
      else
552
553
554
        vars2 = NULL;

      vlistptr2->vars = vars2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
555

556
      int varID2 = 0;
557
      for ( int varID = 0; varID < nvars; varID++ )
558
	if ( vars1[varID].flag )
559
560
	  {
	    vlistptr2->vars[varID2].flag = FALSE;
561
562
563
	    int zaxisID   = vlistptr1->vars[varID].zaxisID;
	    int gridID    = vlistptr1->vars[varID].gridID;
	    int subtypeID = vlistptr1->vars[varID].subtypeID;
564

565
	    memcpy(&vars2[varID2], &vars1[varID], sizeof(var_t));
566

567
568
	    vars1[varID].fvarID = varID2;
	    vars2[varID2].fvarID = varID;
569

570
	    vars2[varID2].mvarID = varID2;
571

572
            var_copy_entries(&vars2[varID2], &vars1[varID]);
573

574
	    vlistptr2->vars[varID2].atts.nelems = 0;
575
	    cdiCopyAtts(vlistID1, varID, vlistID2, varID2);
576

577
	    int nlevs  = zaxisInqSize(vars1[varID].zaxisID);
578
	    int nlevs2 = 0;
579
            if ( vars1[varID].levinfo )
580
              for ( int levID = 0; levID < nlevs; levID++ )
581
                nlevs2 += (vars1[varID].levinfo[levID].flag != 0);
582

583
	    vars2[varID2].levinfo = (levinfo_t *) Malloc((size_t)nlevs2 * sizeof(levinfo_t));
584
585
586
587

	    if ( nlevs != nlevs2 )
	      {
		int nvct = 0;
588
                double *levels = NULL;
589
590
                char **cvals1 = NULL, **cvals2 = NULL;
                size_t clen2 = 0;
591
		double *lbounds = NULL, *ubounds = NULL;
592
		const double *vct = NULL;
593
                char ctemp[CDI_MAX_NAME];
594

595
596
                if ( !vars1[varID].levinfo ) cdiVlistCreateVarLevInfo(vlistptr1, varID);

597
		zaxisID = vars1[varID].zaxisID;
598
599
600
601
602
603
604
605
606
607
                int zaxisType = zaxisInqType(zaxisID);

                int levID2 = 0;
                for ( int levID = 0; levID < nlevs; ++levID )
                  if ( vars1[varID].levinfo[levID].flag )
                    {
                      vars1[varID].levinfo[levID].flevelID = levID2;
                      vars1[varID].levinfo[levID].mlevelID = levID2;
                    }

608

609
610
611
612
613
614
615
                if ( zaxisInqLevels(zaxisID, NULL) )
                  {
                    levels = (double *) Malloc((size_t)nlevs2 * sizeof (double));

                    levID2 = 0;
                    for ( int levID = 0; levID < nlevs; ++levID )
                      if ( vars1[varID].levinfo[levID].flag )
616
                        levels[levID2++] = zaxisInqLevel(zaxisID, levID);
617
618
619
620
621
622
623
                  }

                if ( zaxisType == ZAXIS_HYBRID )
                  {
                    nvct = zaxisInqVctSize(zaxisID);
                    vct  = zaxisInqVctPtr(zaxisID);
                  }
624

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
                if ( zaxisType == ZAXIS_CHAR )
                  {
                    cvals1 = zaxisInqCLevelsPtr(zaxisID);
                    for ( int levID = 0; levID < nlevs; ++levID )
                      if ( vars1[varID].levinfo[levID].flag )
                          {
                            size_t testlen = (size_t) strlen(cvals1[levID]);
                            while ( cvals1[levID][testlen-1] == ' ' )
                              testlen--;
                            if ( clen2 < testlen )
                              clen2 = testlen;
                          }
                    cvals2 = (char **) Malloc((size_t)nlevs2 * sizeof (char *));
                    levID2 = 0;

                    for ( int levID = 0; levID < nlevs; ++levID )
                      if ( vars1[varID].levinfo[levID].flag )
                        {
                          cvals2[levID2] = Malloc((size_t)(clen2+1) * sizeof (char));
                          strcpy(cvals2[levID2], cvals1[levID]);
                          cvals2[levID2][clen2] = 0;
                          levID2++;
                        }
                  }

650
651
                if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
                  {
652
                    lbounds = (double *) Malloc(2 * (size_t)nlevs2 * sizeof (double));
653
654
                    ubounds = lbounds + nlevs2;

655
                    double *lbounds1 = (double *) Malloc(2 * (size_t)nlevs * sizeof (double)),
Uwe Schulzweida's avatar
Uwe Schulzweida committed
656
                           *ubounds1 = lbounds1 + nlevs;
657
658
659
660

                    zaxisInqLbounds(zaxisID, lbounds1);
                    zaxisInqUbounds(zaxisID, ubounds1);

661
                    levID2 = 0;
662
                    for ( int levID = 0; levID < nlevs; ++levID )
663
                      if ( vars1[varID].levinfo[levID].flag )
664
665
666
667
668
669
                        {
                          lbounds[levID2] = lbounds1[levID];
                          ubounds[levID2] = ubounds1[levID];
                          levID2++;
                        }

670
                    Free(lbounds1);
671
672
                  }

673
		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct, (const char **)cvals2, clen2);
674
675
		if ( levels )  Free(levels);
                if ( lbounds ) Free(lbounds);
676
677
678
679
680
681
                if ( cvals2 )
                  {
                    for ( int levID = 0; levID < nlevs2; ++levID )
                      Free(cvals2[levID]);
                    Free(cvals2);
                  }
682

683
684
685
686
687
688
                zaxisInqName(zaxisID, ctemp);
                zaxisDefName(zaxisID2, ctemp);
                zaxisInqLongname(zaxisID, ctemp);
                zaxisDefLongname(zaxisID2, ctemp);
                zaxisInqUnits(zaxisID, ctemp);
                zaxisDefUnits(zaxisID2, ctemp);
689
690
691
692
693
694
695
696
             
                if ( zaxisType == ZAXIS_CHAR )
                  {
                    char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
                    cdiZaxisInqKeyStr(zaxisID, CDI_KEY_DIMNAME, CDI_MAX_NAME, dimname);
                    if ( dimname[0] == 0 ) { memcpy(dimname, "area_type", 10); dimname[10] = 0; }
                    cdiZaxisDefKeyStr(zaxisID2, CDI_KEY_DIMNAME, CDI_MAX_NAME, dimname);
                  }
697

Uwe Schulzweida's avatar
Uwe Schulzweida committed
698
699
                if ( zaxisType == ZAXIS_GENERIC ) zaxisDefLtype(zaxisID2, zaxisInqLtype(zaxisID));

700
		zaxisID = zaxisID2;
701
		vars2[varID2].zaxisID = zaxisID2;
702
703
	      }

704
	    for ( int levID = 0; levID < nlevs2; levID++ )
705
	      {
706
707
		vars2[varID2].levinfo[levID].flag  = FALSE;
		vars2[varID2].levinfo[levID].index = -1;
708
709
	      }

710
711
	    int levID2 = 0;
	    for ( int levID = 0; levID < nlevs; levID++ )
712
	      if ( vars1[varID].levinfo[levID].flag )
713
		{
714
715
		  vars2[varID2].levinfo[levID2].flevelID = levID;
		  vars2[varID2].levinfo[levID2].mlevelID = levID;
716
717
718
		  levID2++;
		}

719
            vlistAdd2GridIDs(vlistptr2, gridID);
720
            vlistAdd2ZaxisIDs(vlistptr2, zaxisID);
721
            vlistAdd2SubtypeIDs(vlistptr2, subtypeID);
722
723
724

	    varID2++;
	  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
726
727
728
729
730
731
732
733
    }
}

/*
@Function  vlistCat
@Title     Concatenate two variable lists

@Prototype void vlistCat(int vlistID2, int vlistID1)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
734
735
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
736
737
738
739
740
741
742
743

@Description
Concatenate the variable list vlistID1 at the end of vlistID2.

@EndFunction
*/
void vlistCat(int vlistID2, int vlistID1)
{
744
745
746
747
  vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
  vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
  var_t *vars1 = vlistptr1->vars;
  var_t *vars2 = vlistptr2->vars;
748
749
750
  int nvars1 = vlistptr1->nvars;
  int nvars2 = vlistptr2->nvars;
  int nvars = nvars1 + nvars2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
752
  vlistptr2->nvars = nvars;

753
754
755
  if ( nvars > vlistptr2->varsAllocated )
    {
      vlistptr2->varsAllocated = nvars;
756
      vars2 = (var_t *) Realloc(vars2, (size_t)nvars*sizeof(var_t));
757
      vlistptr2->vars = vars2;
758
    }
759
  memcpy(vars2+nvars2, vars1, (size_t)nvars1 * sizeof(var_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
760

761
  for ( int varID = 0; varID < nvars1; varID++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
762
    {
763
      int varID2 = varID + nvars2;
764
765
      vars1[varID].fvarID = varID2;
      vars2[varID2].fvarID = varID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
766

767
768
      vars1[varID].mvarID = varID2;
      vars2[varID2].mvarID = varID;
769

770
      if ( vars1[varID].param < 0 )
771
772
	{
	  int pnum, pcat, pdis;
773
	  cdiDecodeParam(vars1[varID].param, &pnum, &pcat, &pdis);
774
	  pnum = -(varID2+1);
775
	  vars2[varID2].param = cdiEncodeParam(pnum, pcat, pdis);
776
	}
777

778
      var_copy_entries(&vars2[varID2], &vars1[varID]);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
779

780
      if ( vars1[varID].levinfo )
781
        {
Thomas Jahns's avatar
Thomas Jahns committed
782
783
          size_t nlevs = (size_t)zaxisInqSize(vars1[varID].zaxisID);
          vars2[varID2].levinfo = (levinfo_t *) Malloc(nlevs * sizeof(levinfo_t));
784
          memcpy(vars2[varID2].levinfo, vars1[varID].levinfo,
Thomas Jahns's avatar
Thomas Jahns committed
785
                 nlevs * sizeof(levinfo_t));
786
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
787

788
      vars2[varID2].atts.nelems = 0;
789
      cdiCopyAtts(vlistID1, varID, vlistID2, varID2);
790

791
792
      vlistAdd2GridIDs(vlistptr2, vars1[varID].gridID);
      vlistAdd2ZaxisIDs(vlistptr2, vars1[varID].zaxisID);
793
      vlistAdd2SubtypeIDs(vlistptr2, vars1[varID].subtypeID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
794
795
796
797
798
799
800
801
802
    }
}

/*
@Function  vlistMerge
@Title     Merge two variable lists

@Prototype void vlistMerge(int vlistID2, int vlistID1)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
803
804
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
805
806

@Description
Uwe Schulzweida's avatar
Uwe Schulzweida committed
807
Merge the variable list vlistID1 to the variable list vlistID2.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
808
809
810
811
812

@EndFunction
*/
void vlistMerge(int vlistID2, int vlistID1)
{
813
  int varID = 0;
814
815
816
817
  vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
  vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
  var_t *vars1 = vlistptr1->vars;
  var_t *vars2 = vlistptr2->vars;
818
819
  int nvars1 = vlistptr1->nvars;
  int nvars2 = vlistptr2->nvars;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
820
821
822
823

  if ( nvars1 == nvars2 )
    {
      for ( varID = 0; varID < nvars2; varID++ )
824
	{
825
826
827
828
829
          int ngp1 = gridInqSize(vars1[varID].gridID);
          int ngp2 = gridInqSize(vars2[varID].gridID);
          if ( ngp1 != ngp2 ) break;

	  if ( vars1[varID].name && vars2[varID].name )
830
	    {
831
	      if ( strcmp(vars1[varID].name, vars2[varID].name) != 0 ) break;
832
833
834
	    }
	  else
	    {
835
	      if ( vars1[varID].param != vars2[varID].param ) break;
836
837
	    }
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
838
839
840
841
842
    }

  if ( varID == nvars2 ) /* same variables in vlistID1 and vlistID2 */
    {
      for ( varID = 0; varID < nvars2; varID++ )
Thomas Jahns's avatar
Thomas Jahns committed
843
        {
844
845
          vars1[varID].fvarID = varID;
          vars2[varID].fvarID = varID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
846

847
848
          vars1[varID].mvarID = varID;
          vars2[varID].mvarID = varID;
849

850
851
          int nlevs1 = zaxisInqSize(vars1[varID].zaxisID);
          int nlevs2 = zaxisInqSize(vars2[varID].zaxisID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
852

853
          int nlevs = nlevs1 + nlevs2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
854

Thomas Jahns's avatar
Thomas Jahns committed
855
856
857
          /*
          fprintf(stderr, "var %d %d %d %d %d\n", varID, nlevs1, nlevs2, nlevs, sizeof(levinfo_t));
          */
858
          if ( vars1[varID].levinfo )
859
            {
860
              vars2[varID].levinfo = (levinfo_t*) Realloc(vars2[varID].levinfo,
861
                                     (size_t)nlevs * sizeof(levinfo_t));
862

863
864
              memcpy(vars2[varID].levinfo+nlevs2, vars1[varID].levinfo,
                     (size_t)nlevs1 * sizeof(levinfo_t));
865
866
867
            }
          else
            cdiVlistCreateVarLevInfo(vlistptr1, varID);
868

869
	  for ( int levID = 0; levID < nlevs1; levID++ )
870
            vars1[varID].levinfo[levID].mlevelID = nlevs2 + levID;
871
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
872

873
      bool *lvar = (bool *) Calloc((size_t)nvars2, sizeof(bool));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
874
875

      for ( varID = 0; varID < nvars2; varID++ )
Thomas Jahns's avatar
Thomas Jahns committed
876
        {
877
          if ( lvar[varID] == true ) continue;
Thomas Jahns's avatar
Thomas Jahns committed
878

879
880
          int zaxisID1 = vars1[varID].zaxisID;
          int zaxisID2 = vars2[varID].zaxisID;
Thomas Jahns's avatar
Thomas Jahns committed
881
          /*
882
883
          nlevs1 = zaxisInqSize(vars1[varID].zaxisID);
          nlevs2 = zaxisInqSize(vars2[varID].zaxisID);
Thomas Jahns's avatar
Thomas Jahns committed
884
          */
885
886
          int nlevs1 = zaxisInqSize(zaxisID1);
          int nlevs2 = zaxisInqSize(zaxisID2);
Thomas Jahns's avatar
Thomas Jahns committed
887
888
889
          /*
          fprintf(stderr, "zaxis %d %d %d %d\n", zaxisID1, zaxisID2, nlevs1, nlevs2);
          */
890
          int nlevs = nlevs1 + nlevs2;
Thomas Jahns's avatar
Thomas Jahns committed
891

892
          int zaxisID = zaxisDuplicate(zaxisID2);
893
          zaxisResize(zaxisID, nlevs);
Thomas Jahns's avatar
Thomas Jahns committed
894

895
896
897
          if ( zaxisInqLevels(zaxisID1, NULL) )
            {
              double *levels = (double *) Malloc((size_t)nlevs1 * sizeof(double));
Thomas Jahns's avatar
Thomas Jahns committed
898

899
900
901
902
903
904
905
              zaxisInqLevels(zaxisID1, levels);
              /*
                for ( levID = 0; levID < nlevs1; levID++ )
                fprintf(stderr, "%d %d %d %d %d %g\n", varID, levID, nlevs1, nlevs2, vars2[varID].nlevs, levels[levID]);
              */
              for ( int levID = 0; levID < nlevs1; levID++ )
                zaxisDefLevel(zaxisID, nlevs2+levID, levels[levID]);
Thomas Jahns's avatar
Thomas Jahns committed
906

907
908
              Free(levels);
            }
Thomas Jahns's avatar
Thomas Jahns committed
909

910
          for ( int index = 0; index < vlistptr2->nzaxis; index++ )
Thomas Jahns's avatar
Thomas Jahns committed
911
912
913
            if ( vlistptr2->zaxisIDs[index] == zaxisID2 )
              vlistptr2->zaxisIDs[index] = zaxisID;

914
          for ( int varID2 = 0; varID2 < nvars2; varID2++ )
915
            if ( lvar[varID2] == false && vars2[varID2].zaxisID == zaxisID2 )
Thomas Jahns's avatar
Thomas Jahns committed
916