vlist.c 40.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 "vlist_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;
Thomas Jahns's avatar
Thomas Jahns committed
51
52
53
54
55
56
57
  diff = (a->nvars != b->nvars) | (a->ngrids != b->ngrids)
    | (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);
58
59
60
  size_t natts = a->atts.nelems;
  for (size_t attID = 0; attID < natts; ++attID)
    diff |= vlist_att_compare(a, CDI_GLOBAL, b, CDI_GLOBAL, (int)attID);
61
  return diff;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
62
63
}

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

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

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


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

93
94
static
void vlist_init_entry(vlist_t *vlistptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
95
{
96
  vlistptr->locked         = 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
111
112
  vlistptr->nsubtypes      = 0;
  for (int i=0; i<MAX_SUBTYPES_PS; i++)
    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
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
118
  vlist_t *vlistptr = (vlist_t*) xmalloc(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
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
127
128
129
  return (vlistptr);
}

130
131
static
void vlist_delete_entry(vlist_t *vlistptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
132
{
Thomas Jahns's avatar
Thomas Jahns committed
133
  int idx;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
134
135
136

  idx = vlistptr->self;

Thomas Jahns's avatar
Thomas Jahns committed
137
  reshRemove(idx, &vlistOps );
Uwe Schulzweida's avatar
Uwe Schulzweida committed
138
139
140
141

  free(vlistptr);

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

145
146
static
void vlist_initialize(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
147
148
149
150
151
{
  char *env;

  env = getenv("VLIST_DEBUG");
  if ( env ) VLIST_Debug = atoi(env);
152
153
154
#ifndef HAVE_LIBPTHREAD
  vlistIsInitialized = TRUE;
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
155
156
}

157
158
static
void vlist_copy(vlist_t *vlistptr2, vlist_t *vlistptr1)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
159
{
160
  int vlistID2 = vlistptr2->self;
161
  memcpy(vlistptr2, vlistptr1, sizeof(vlist_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
162
  vlistptr2->atts.nelems = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
163
164
165
  vlistptr2->self = vlistID2;
}

166
167
168
169
170
171
void vlist_lock(int vlistID)
{
  vlist_t *vlistptr = vlist_to_pointer(vlistID);

  if ( !vlistptr->locked )
    {
172
      vlistptr->locked += 1;
Thomas Jahns's avatar
Thomas Jahns committed
173
      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
174
175
176
177
178
179
180
181
182
183
    }
}


void vlist_unlock(int vlistID)
{
  vlist_t *vlistptr = vlist_to_pointer(vlistID);

  if ( vlistptr->locked )
    {
184
      vlistptr->locked -= 1;
Thomas Jahns's avatar
Thomas Jahns committed
185
      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
186
187
188
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
189
/*
190
@Function  vlistCreate
Uwe Schulzweida's avatar
Uwe Schulzweida committed
191
192
@Title     Create a variable list

193
@Prototype int vlistCreate(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
194

Uwe Schulzweida's avatar
Uwe Schulzweida committed
195
196
@Example
Here is an example using @func{vlistCreate} to create a variable list
197
and add a variable with @func{vlistDefVar.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
198
199
200
201
202
203
204

@Source
#include "cdi.h"
   ...
int vlistID, varID;
   ...
vlistID = vlistCreate();
205
varID = vlistDefVar(vlistID, gridID, zaxisID, TSTEP_INSTANT);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
206
207
208
209
210
211
   ...
streamDefVlist(streamID, vlistID);
   ...
vlistDestroy(vlistID);
   ...
@EndSource
Uwe Schulzweida's avatar
Uwe Schulzweida committed
212
213
@EndFunction
*/
214
int vlistCreate(void)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
215
{
216
217
  cdiInitialize();

218
  VLIST_INIT();
Uwe Schulzweida's avatar
Uwe Schulzweida committed
219

220
  vlist_t *vlistptr = vlist_new_entry(CDI_UNDEFID);
221
  if ( CDI_Debug ) Message("create vlistID = %d", vlistptr->self);
222
  return (vlistptr->self);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
223
224
}

225
226
static void
vlist_delete(vlist_t *vlistptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
227
{
228
  int vlistID = vlistptr->self;
229
  if ( CDI_Debug ) Message("call to vlist_delete, vlistID = %d", vlistID);
230

Deike Kleberg's avatar
Deike Kleberg committed
231
  vlistDelAtts(vlistID, CDI_GLOBAL);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
232

233
  int nvars = vlistptr->nvars;
234
  var_t *vars = vlistptr->vars;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
235

236
  for ( int varID = 0; varID < nvars; varID++ )
Deike Kleberg's avatar
Deike Kleberg committed
237
    {
238
239
240
241
242
243
      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);
244

245
      if ( vlistptr->vars[varID].opt_grib_kvpair )
246
247
248
249
250
251
252
        {
          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);
          }
          free(vlistptr->vars[varID].opt_grib_kvpair);
        }
253
254
255
      vlistptr->vars[varID].opt_grib_nentries    = 0;
      vlistptr->vars[varID].opt_grib_kvpair_size = 0;
      vlistptr->vars[varID].opt_grib_kvpair      = NULL;
256

Deike Kleberg's avatar
Deike Kleberg committed
257
      vlistDelAtts(vlistID, varID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
258
    }
259

260
  if ( vars ) free(vars);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
261

Deike Kleberg's avatar
Deike Kleberg committed
262
  vlist_delete_entry(vlistptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
263
264
}

265
266
267
268
269
270
271

/*
@Function  vlistDestroy
@Title     Destroy a variable list

@Prototype void vlistDestroy(int vlistID)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
272
    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
273
274
275
276
277

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

280
  if ( vlistptr->locked != 0 )
281
282
283
    Warning("Destroying of a locked object (vlistID=%d) failed!", vlistID);
  else
    vlist_delete(vlistptr);
284
285
}

286
287
288
289
290
291
292
293
294
295
296
297
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 )
    {
      var2->ensdata = (ensinfo_t *)xmalloc(sizeof(ensinfo_t));
      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
  vlistCopyVarAtts(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
355
356
357

      size_t n = (size_t)vlistptr2->varsAllocated;
      vars2 = xrealloc(vars2, n*sizeof(var_t));
      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
	  vlistCopyVarAtts(vlistID1, varID, vlistID2, varID);
365

366
          if ( vars1[varID].levinfo )
367
            {
368
369
370
              n = (size_t)zaxisInqSize(vars1[varID].zaxisID);
              vars2[varID].levinfo = xmalloc(n*sizeof(levinfo_t));
              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
398
399
400
401
402
403
404
  vlistCopy(vlistIDnew, vlistID);
  return (vlistIDnew);
}


void vlistClearFlag(int vlistID)
{
  int varID, levID;
405
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
406
407
408
409

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

419
static
Thomas Jahns's avatar
Thomas Jahns committed
420
421
int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *levels,
                         const double *lbounds, const double *ubounds, int vctsize, const double *vct)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
422
423
424
{
  int zaxisID = CDI_UNDEFID;
  int zaxisglobdefined = 0;
425
  int has_bounds = FALSE;
426
427
428
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
  int zaxisdefined = 0;
  int nzaxis = vlistptr->nzaxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
429

430
431
  if ( lbounds && ubounds ) has_bounds = TRUE;

432
  for ( int index = 0; index < nzaxis; ++index )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
433
434
435
    {
      zaxisID = vlistptr->zaxisIDs[index];

436
      if ( zaxisCompare(zaxisID, zaxistype, nlevels, has_bounds, levels, NULL, NULL, 0) == 0 )
Thomas Jahns's avatar
Thomas Jahns committed
437
438
439
440
        {
          zaxisdefined = 1;
          break;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
441
442
443
444
    }

  if ( ! zaxisdefined )
    {
445
      unsigned nzaxis = cdiZaxisCount();
446
447
      if ( nzaxis > 0 )
        {
448
          int *zaxisIndexList = (int *)xmalloc((size_t)nzaxis * sizeof (int));
Thomas Jahns's avatar
Thomas Jahns committed
449
          reshLock();
450
451
          cdiZaxisGetIndexList(nzaxis, zaxisIndexList);
          for (unsigned index = 0; index < nzaxis; ++index)
452
453
454
455
456
457
458
459
            {
              zaxisID = zaxisIndexList[index];
              if ( zaxisCompare(zaxisID, zaxistype, nlevels, has_bounds, levels, NULL, NULL, 0) == 0 )
                {
                  zaxisglobdefined = 1;
                  break;
                }
            }
Thomas Jahns's avatar
Thomas Jahns committed
460
          reshUnlock();
461
          free(zaxisIndexList);
462
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
463
464
465
466
467
    }

  if ( ! zaxisdefined )
    {
      if ( ! zaxisglobdefined )
468
469
470
	{
	  zaxisID = zaxisCreate(zaxistype, nlevels);
	  zaxisDefLevels(zaxisID, levels);
471
	  if ( has_bounds )
472
	    {
473
474
	      zaxisDefLbounds(zaxisID, lbounds);
	      zaxisDefUbounds(zaxisID, ubounds);
475
476
477
478
479
480
481
482
483
484
	    }

	  if ( zaxistype == ZAXIS_HYBRID )
	    {
	      if ( vctsize > 0 )
		zaxisDefVct(zaxisID, vctsize, vct);
	      else
		Warning("VCT missing");
	    }
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499

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

  return (zaxisID);
}

/*
@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
500
501
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
502
503

@Description
504
The function @func{vlistCopyFlag} copies all entries with a flag from vlistID1 to vlistID2.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
505
506
507
508
509

@EndFunction
*/
void vlistCopyFlag(int vlistID2, int vlistID1)
{
510
511
512
513
514
  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
515
  vlist_copy(vlistptr2, vlistptr1);
Thomas Jahns's avatar
Thomas Jahns committed
516

517
  vlistCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
518

Uwe Schulzweida's avatar
Uwe Schulzweida committed
519
520
521
  if ( vlistptr1->vars )
    {
      int nvars = vlistptr1->nvars;
522
523
      int nvars2 = 0;
      int varID2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
524
525
526
527

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

528
      for ( int varID = 0; varID < nvars; varID++ )
529
        nvars2 += (vars1[varID].flag != 0);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
530
531

      vlistptr2->nvars = nvars2;
532
      vlistptr2->varsAllocated = nvars2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
533
      if ( nvars2 > 0 )
534
        vars2 = (var_t *)xmalloc((size_t)nvars2*sizeof(var_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
535
      else
536
537
538
        vars2 = NULL;

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

      varID2 = 0;
541
      for ( int varID = 0; varID < nvars; varID++ )
542
	if ( vars1[varID].flag )
543
544
	  {
	    vlistptr2->vars[varID2].flag = FALSE;
545
546
547
	    int zaxisID   = vlistptr1->vars[varID].zaxisID;
	    int gridID    = vlistptr1->vars[varID].gridID;
	    int subtypeID = vlistptr1->vars[varID].subtypeID;
548

549
	    memcpy(&vars2[varID2], &vars1[varID], sizeof(var_t));
550

551
552
	    vars1[varID].fvarID = varID2;
	    vars2[varID2].fvarID = varID;
553

554
	    vars2[varID2].mvarID = varID2;
555

556
            var_copy_entries(&vars2[varID2], &vars1[varID]);
557

558
559
560
	    vlistptr2->vars[varID2].atts.nelems = 0;
	    vlistCopyVarAtts(vlistID1, varID, vlistID2, varID2);

561
	    int nlevs  = zaxisInqSize(vars1[varID].zaxisID);
562
	    int nlevs2 = 0;
563
            if ( vars1[varID].levinfo )
564
              for ( int levID = 0; levID < nlevs; levID++ )
565
                nlevs2 += (vars1[varID].levinfo[levID].flag != 0);
566

567
	    vars2[varID2].levinfo = (levinfo_t *)xmalloc((size_t)nlevs2 * sizeof(levinfo_t));
568
569
570
571

	    if ( nlevs != nlevs2 )
	      {
		int nvct = 0;
572
		double *lbounds = NULL, *ubounds = NULL;
573
		const double *vct = NULL;
574
                char ctemp[CDI_MAX_NAME];
575

576
		zaxisID = vars1[varID].zaxisID;
577
		double *levels = (double *)xmalloc((size_t)nlevs2 * sizeof (double));
578
                int levID2 = 0;
579
                if ( !vars1[varID].levinfo )
580
                  cdiVlistCreateVarLevInfo(vlistptr1, varID);
581
                for ( int levID = 0; levID < nlevs; ++levID )
582
                  if ( vars1[varID].levinfo[levID].flag )
583
                    {
584
585
                      vars1[varID].levinfo[levID].flevelID = levID2;
                      vars1[varID].levinfo[levID].mlevelID = levID2;
586
587
588
                      levels[levID2++] = zaxisInqLevel(zaxisID, levID);
                    }
		int zaxisType = zaxisInqType(zaxisID);
589
590
591
592
593
594

		if ( zaxisType == ZAXIS_HYBRID )
		  {
		    nvct = zaxisInqVctSize(zaxisID);
		    vct  = zaxisInqVctPtr(zaxisID);
		  }
595
596
597

                if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
                  {
598
                    lbounds = (double *)xmalloc(2 * (size_t)nlevs2 * sizeof (double));
599
600
                    ubounds = lbounds + nlevs2;

601
                    double *lbounds1 = (double *)xmalloc(2 * (size_t)nlevs * sizeof (double)),
602
                      *ubounds1 = lbounds1 + nlevs;
603
604
605
606

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

607
608
                    int levID2 = 0;
                    for ( int levID = 0; levID < nlevs; ++levID )
609
                      if ( vars1[varID].levinfo[levID].flag )
610
611
612
613
614
615
616
617
618
                        {
                          lbounds[levID2] = lbounds1[levID];
                          ubounds[levID2] = ubounds1[levID];
                          levID2++;
                        }

                    free(lbounds1);
                  }

619
		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct);
620
		free(levels);
621
                free(lbounds);
622

623
624
625
626
627
628
                zaxisInqName(zaxisID, ctemp);
                zaxisDefName(zaxisID2, ctemp);
                zaxisInqLongname(zaxisID, ctemp);
                zaxisDefLongname(zaxisID2, ctemp);
                zaxisInqUnits(zaxisID, ctemp);
                zaxisDefUnits(zaxisID2, ctemp);
629
630

		zaxisID = zaxisID2;
631
		vars2[varID2].zaxisID = zaxisID2;
632
633
	      }

634
	    for ( int levID = 0; levID < nlevs2; levID++ )
635
	      {
636
637
		vars2[varID2].levinfo[levID].flag  = FALSE;
		vars2[varID2].levinfo[levID].index = -1;
638
639
	      }

640
641
	    int levID2 = 0;
	    for ( int levID = 0; levID < nlevs; levID++ )
642
	      if ( vars1[varID].levinfo[levID].flag )
643
		{
644
645
		  vars2[varID2].levinfo[levID2].flevelID = levID;
		  vars2[varID2].levinfo[levID2].mlevelID = levID;
646
647
648
		  levID2++;
		}

649
            vlistAdd2GridIDs(vlistptr2, gridID);
650
            vlistAdd2ZaxisIDs(vlistptr2, zaxisID);
651
            vlistAdd2SubtypeIDs(vlistptr2, subtypeID);
652
653
654

	    varID2++;
	  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
655
656
657
658
659
660
661
662
663
    }
}

/*
@Function  vlistCat
@Title     Concatenate two variable lists

@Prototype void vlistCat(int vlistID2, int vlistID1)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
664
665
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
666
667
668
669
670
671
672
673

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

@EndFunction
*/
void vlistCat(int vlistID2, int vlistID1)
{
674
675
676
677
  vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
  vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
  var_t *vars1 = vlistptr1->vars;
  var_t *vars2 = vlistptr2->vars;
678
679
680
  int nvars1 = vlistptr1->nvars;
  int nvars2 = vlistptr2->nvars;
  int nvars = nvars1 + nvars2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
681
682
  vlistptr2->nvars = nvars;

683
684
685
  if ( nvars > vlistptr2->varsAllocated )
    {
      vlistptr2->varsAllocated = nvars;
686
687
      vars2 = xrealloc(vars2, (size_t)nvars*sizeof(var_t));
      vlistptr2->vars = vars2;
688
    }
689
  memcpy(vars2+nvars2, vars1, (size_t)nvars1 * sizeof(var_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
690

691
  for ( int varID = 0; varID < nvars1; varID++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
692
    {
693
      int varID2 = varID + nvars2;
694
695
      vars1[varID].fvarID = varID2;
      vars2[varID2].fvarID = varID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
696

697
698
      vars1[varID].mvarID = varID2;
      vars2[varID2].mvarID = varID;
699

700
      if ( vars1[varID].param < 0 )
701
702
	{
	  int pnum, pcat, pdis;
703
	  cdiDecodeParam(vars1[varID].param, &pnum, &pcat, &pdis);
704
	  pnum = -(varID2+1);
705
	  vars2[varID2].param = cdiEncodeParam(pnum, pcat, pdis);
706
	}
707

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

710
711
      int nlevs = zaxisInqSize(vars1[varID].zaxisID);
      if ( vars1[varID].levinfo )
712
        {
713
714
715
          vars2[varID2].levinfo = (levinfo_t *)xmalloc((size_t)nlevs * sizeof(levinfo_t));
          memcpy(vars2[varID2].levinfo, vars1[varID].levinfo,
                 (size_t)nlevs * sizeof(levinfo_t));
716
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
717

718
      vars2[varID2].atts.nelems = 0;
719
720
      vlistCopyVarAtts(vlistID1, varID, vlistID2, varID2);

721
722
      vlistAdd2GridIDs(vlistptr2, vars1[varID].gridID);
      vlistAdd2ZaxisIDs(vlistptr2, vars1[varID].zaxisID);
723
      vlistAdd2SubtypeIDs(vlistptr2, vlistptr1->vars[varID].subtypeID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
724
725
726
727
728
729
730
731
732
    }
}

/*
@Function  vlistMerge
@Title     Merge two variable lists

@Prototype void vlistMerge(int vlistID2, int vlistID1)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
733
734
    @Item  vlistID2  Target variable list ID.
    @Item  vlistID1  Source variable list ID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
736

@Description
Uwe Schulzweida's avatar
Uwe Schulzweida committed
737
Merge the variable list vlistID1 to the variable list vlistID2.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
738
739
740
741
742

@EndFunction
*/
void vlistMerge(int vlistID2, int vlistID1)
{
743
  int varID = 0;
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
  int nvars1 = vlistptr1->nvars;
  int nvars2 = vlistptr2->nvars;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
750
751
752
753

  if ( nvars1 == nvars2 )
    {
      for ( varID = 0; varID < nvars2; varID++ )
754
	{
755
756
757
758
759
          int ngp1 = gridInqSize(vars1[varID].gridID);
          int ngp2 = gridInqSize(vars2[varID].gridID);
          if ( ngp1 != ngp2 ) break;

	  if ( vars1[varID].name && vars2[varID].name )
760
	    {
761
	      if ( strcmp(vars1[varID].name, vars2[varID].name) != 0 ) break;
762
763
764
	    }
	  else
	    {
765
	      if ( vars1[varID].param != vars2[varID].param ) break;
766
767
	    }
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
768
769
770
771
772
    }

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

777
778
          vars1[varID].mvarID = varID;
          vars2[varID].mvarID = varID;
779

780
781
          int nlevs1 = zaxisInqSize(vars1[varID].zaxisID);
          int nlevs2 = zaxisInqSize(vars2[varID].zaxisID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
782

783
          int nlevs = nlevs1 + nlevs2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
784

Thomas Jahns's avatar
Thomas Jahns committed
785
786
787
          /*
          fprintf(stderr, "var %d %d %d %d %d\n", varID, nlevs1, nlevs2, nlevs, sizeof(levinfo_t));
          */
788
          if ( vars1[varID].levinfo )
789
            {
790
              vars2[varID].levinfo = (levinfo_t*)xrealloc(vars2[varID].levinfo,
791
                                     (size_t)nlevs * sizeof(levinfo_t));
792

793
794
              memcpy(vars2[varID].levinfo+nlevs2, vars1[varID].levinfo,
                     (size_t)nlevs1 * sizeof(levinfo_t));
795
796
797
            }
          else
            cdiVlistCreateVarLevInfo(vlistptr1, varID);
798

799
	  for ( int levID = 0; levID < nlevs1; levID++ )
800
            vars1[varID].levinfo[levID].mlevelID = nlevs2 + levID;
801
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
802

803
      int *lvar = (int *)xcalloc((size_t)nvars2, sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
804
805

      for ( varID = 0; varID < nvars2; varID++ )
Thomas Jahns's avatar
Thomas Jahns committed
806
807
808
        {
          if ( lvar[varID] == TRUE ) continue;

809
810
          int zaxisID1 = vars1[varID].zaxisID;
          int zaxisID2 = vars2[varID].zaxisID;
Thomas Jahns's avatar
Thomas Jahns committed
811
          /*
812
813
          nlevs1 = zaxisInqSize(vars1[varID].zaxisID);
          nlevs2 = zaxisInqSize(vars2[varID].zaxisID);
Thomas Jahns's avatar
Thomas Jahns committed
814
          */
815
816
          int nlevs1 = zaxisInqSize(zaxisID1);
          int nlevs2 = zaxisInqSize(zaxisID2);
Thomas Jahns's avatar
Thomas Jahns committed
817
818
819
          /*
          fprintf(stderr, "zaxis %d %d %d %d\n", zaxisID1, zaxisID2, nlevs1, nlevs2);
          */
820
          int nlevs = nlevs1 + nlevs2;
Thomas Jahns's avatar
Thomas Jahns committed
821

822
          int zaxisID = zaxisDuplicate(zaxisID2);
Thomas Jahns's avatar
Thomas Jahns committed
823
824
825

          zaxisResize(zaxisID, nlevs);

826
          double *levels = (double *)xmalloc((size_t)nlevs1 * sizeof(double));
Thomas Jahns's avatar
Thomas Jahns committed
827
828
829
830

          zaxisInqLevels(zaxisID1, levels);
          /*
          for ( levID = 0; levID < nlevs1; levID++ )
831
            fprintf(stderr, "%d %d %d %d %d %g\n", varID, levID, nlevs1, nlevs2, vars2[varID].nlevs, levels[levID]);
Thomas Jahns's avatar
Thomas Jahns committed
832
          */
833
          for ( int levID = 0; levID < nlevs1; levID++ )
Thomas Jahns's avatar
Thomas Jahns committed
834
835
836
837
            zaxisDefLevel(zaxisID, nlevs2+levID, levels[levID]);

          free(levels);

838
          for ( int index = 0; index < vlistptr2->nzaxis; index++ )
Thomas Jahns's avatar
Thomas Jahns committed
839
840
841
            if ( vlistptr2->zaxisIDs[index] == zaxisID2 )
              vlistptr2->zaxisIDs[index] = zaxisID;

842
          for ( int varID2 = 0; varID2 < nvars2; varID2++ )
843
            if ( lvar[varID2] == FALSE && vars2[varID2].zaxisID == zaxisID2 )
Thomas Jahns's avatar
Thomas Jahns committed
844
              {
845
                vars2[varID2].zaxisID = zaxisID;
Thomas Jahns's avatar
Thomas Jahns committed
846
847
848
                lvar[varID2] = TRUE;
              }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863

      free(lvar);
    }
  else
    {
      vlistCat(vlistID2, vlistID1);
    }
}

/*
@Function  vlistNvars
@Title     Number of variables in a variable list

@Prototype int vlistNvars(int vlistID)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
864
    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
865
866

@Description
867
The function @func{vlistNvars} returns the number of variables in the variable list vlistID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
868
869

@Result
870
@func{vlistNvars} returns the number of variables in a variable list.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
871
872
873
874
875

@EndFunction
*/
int vlistNvars(int vlistID)
{
876
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
877
878
879
  return (vlistptr->nvars);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
880

Uwe Schulzweida's avatar
Uwe Schulzweida committed
881
882
int vlistNrecs(int vlistID)
{
883
884
  int nrecs = 0;
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
885

886
  for ( int varID = 0; varID < vlistptr->nvars; varID++ )
887
    nrecs +=  zaxisInqSize(vlistptr->vars[varID].zaxisID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
888
889
890
891
892

  return (nrecs);
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
893
894
int vlistNumber(int vlistID)
{
895
896
  int number, number2, datatype;
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
897

898
899
900
901
902
903
  datatype = vlistptr->vars[0].datatype;
  if (  datatype== DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
    number = CDI_COMP;
  else
    number = CDI_REAL;

904
  for ( int varID = 1; varID < vlistptr->nvars; varID++ )
905
906
907
    {
      datatype = vlistptr->vars[varID].datatype;
      if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
Thomas Jahns's avatar
Thomas Jahns committed
908
        number2 = CDI_COMP;
909
      else
Thomas Jahns's avatar
Thomas Jahns committed
910
        number2 = CDI_REAL;
911
912

      if ( number2 != number )
Thomas Jahns's avatar
Thomas Jahns committed
913
914
915
916
        {
          number = CDI_BOTH;
          break;
        }
917
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
918
919
920
921

  return (number);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
922
923
924
925
926
927
/*
@Function  vlistNgrids
@Title     Number of grids in a variable list

@Prototype int vlistNgrids(int vlistID)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
928
    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
929
930

@Description
931
The function @func{vlistNgrids} returns the number of grids in the variable list vlistID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
932
933

@Result
934
@func{vlistNgrids} returns the number of grids in a variable list.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
935
936
937
938
939

@EndFunction
*/
int vlistNgrids(int vlistID)
{
940
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
941
942
943
944
945
946
947
948
949
950

  return (vlistptr->ngrids);
}

/*
@Function  vlistNzaxis
@Title     Number of zaxis in a variable list

@Prototype int vlistNzaxis(int vlistID)
@Parameter
Uwe Schulzweida's avatar
Uwe Schulzweida committed
951
    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
952
953

@Description
954
The function @func{vlistNzaxis} returns the number of zaxis in the variable list vlistID.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
955
956

@Result
957
@func{vlistNzaxis} returns the number of zaxis in a variable list.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
958
959
960
961
962

@EndFunction
*/
int vlistNzaxis(int vlistID)
{
963
  vlist_t *vlistptr = vlist_to_pointer(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
964