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

5
6
#ifdef HAVE_LIBNETCDF

7
//#define TEST_GROUPS 1
Uwe Schulzweida's avatar
Uwe Schulzweida committed
8

Uwe Schulzweida's avatar
Uwe Schulzweida committed
9
#include <ctype.h>
10
#include <limits.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
11

Uwe Schulzweida's avatar
Uwe Schulzweida committed
12
#include "dmemory.h"
13
#include "gaussgrid.h"
14
#include "cdi_int.h"
15
#include "cdi_uuid.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
16
17
18
19
#include "stream_cdf.h"
#include "cdf_int.h"
#include "varscan.h"
#include "vlist.h"
20
#include "cdf_util.h"
21
#include "cdf_lazy_grid.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
22
23
24
25
26
27
28


#define  X_AXIS  1
#define  Y_AXIS  2
#define  Z_AXIS  3
#define  T_AXIS  4

29
30
31
#define  POSITIVE_UP    1
#define  POSITIVE_DOWN  2

Uwe Schulzweida's avatar
Uwe Schulzweida committed
32
33
34
35
typedef struct {
  int     ncvarid;
  int     dimtype;
  size_t  len;
36
  char    name[CDI_MAX_NAME];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
37
}
38
ncdim_t;
39
40
41
#define  MAX_COORDVARS  4
#define  MAX_AUXVARS    4

Uwe Schulzweida's avatar
Uwe Schulzweida committed
42
typedef struct {
43
  int      ncid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
44
45
  int      isvar;
  bool     ignore;
46
47
  bool     isx;
  bool     isy;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
48
49
50
51
52
  bool     islon;
  bool     islat;
  bool     islev;
  bool     istime;
  bool     warn;
53
  bool     calendar;
54
  bool     climatology;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
55
  bool     lformulaterms;
56
  int      tsteptype;
57
  int      param;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
58
  int      code;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
59
  int      tabnum;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
60
61
62
63
64
65
66
67
68
69
70
71
  int      bounds;
  int      gridID;
  int      zaxisID;
  int      gridtype;
  int      zaxistype;
  int      xdim;
  int      ydim;
  int      zdim;
  int      xvarid;
  int      yvarid;
  int      zvarid;
  int      tvarid;
72
  int      psvarid;
73
  int      p0varid;
74
  int      ncoordvars;
75
76
77
  int      coordvarids[MAX_COORDVARS];
  int      nauxvars;
  int      auxvarids[MAX_AUXVARS];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
78
79
80
  int      cellarea;
  int      tableID;
  int      truncation;
81
  int      position;
82
83
  bool     defmissval;
  bool     deffillval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
84
85
86
  int      xtype;
  int      gmapid;
  int      positive;
87
  int      ndims;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
88
89
  int      dimids[8];
  int      dimtype[8];
90
91
92
  int      chunks[8];
  int      chunked;
  int      chunktype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
93
  int      natts;
94
  int      deflate;
95
96
  bool     lunsigned;
  bool     lvalidrange;
Thomas Jahns's avatar
Thomas Jahns committed
97
  int     *atts;
98
99
  size_t   vctsize;
  double  *vct;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
100
  double   missval;
101
  double   fillval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
102
103
  double   addoffset;
  double   scalefactor;
Deike Kleberg's avatar
Deike Kleberg committed
104
  double   validrange[2];
105
106
107
108
  char     name[CDI_MAX_NAME];
  char     longname[CDI_MAX_NAME];
  char     stdname[CDI_MAX_NAME];
  char     units[CDI_MAX_NAME];
109
  char     extra[CDI_MAX_NAME];
110
  ensinfo_t   *ensdata;    /* Ensemble information */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
111
}
112
113
ncvar_t;

114
115

static
116
void scanTimeString(const char *ptu, int *rdate, int *rtime)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
117
{
118
  int year = 1, month = 1, day = 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
119
  int hour = 0, minute = 0, second = 0;
120
  int v1 = 1, v2 = 1, v3 = 1;
121
122
123
124

  *rdate = 0;
  *rtime = 0;

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  if ( *ptu )
    {
      v1 = atoi(ptu);
      if ( v1 < 0 ) ptu++;
      while ( isdigit((int) *ptu) ) ptu++;
      if ( *ptu )
        {
          v2 = atoi(++ptu);
          while ( isdigit((int) *ptu) ) ptu++;
          if ( *ptu )
            {
              v3 = atoi(++ptu);
              while ( isdigit((int) *ptu) ) ptu++;
            }
        }
    }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

  if ( v3 > 999 && v1 < 32 )
    { year = v3; month = v2; day = v1; }
  else
    { year = v1; month = v2; day = v3; }

  while ( isspace((int) *ptu) ) ptu++;

  if ( *ptu )
    {
      while ( ! isdigit((int) *ptu) ) ptu++;

      hour = atoi(ptu);
      while ( isdigit((int) *ptu) ) ptu++;
      if ( *ptu == ':' )
        {
          ptu++;
          minute = atoi(ptu);
          while ( isdigit((int) *ptu) ) ptu++;
          if ( *ptu == ':' )
            {
              ptu++;
              second = atoi(ptu);
            }
        }
    }

  *rdate = cdiEncodeDate(year, month, day);
  *rtime = cdiEncodeTime(hour, minute, second);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
172
173
174
static
int scanTimeUnit(const char *unitstr)
{
175
  size_t len = strlen(unitstr);
176
  int timeunit = get_timeunit(len, unitstr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
178
179
  if ( timeunit == -1 )
    Message("Unsupported TIMEUNIT: %s!", unitstr);

180
  return timeunit;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
181
182
}

183
184
185
static
void setForecastTime(const char *timestr, taxis_t *taxis)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
186
187
188
  (*taxis).fdate = 0;
  (*taxis).ftime = 0;

189
  int len = (int) strlen(timestr);
190
191
192
193
194
195
196
197
198
199
200
201
  if ( len == 0 ) return;

  int fdate = 0, ftime = 0;
  scanTimeString(timestr, &fdate, &ftime);

  (*taxis).fdate = fdate;
  (*taxis).ftime = ftime;
}

static
int setBaseTime(const char *timeunits, taxis_t *taxis)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
202
203
204
  int timetype = TAXIS_ABSOLUTE;
  int rdate = -1, rtime = -1;

205
  size_t len = strlen(timeunits);
206
207
  char *tu = (char*) Malloc((len+1) * sizeof(char));
  memcpy(tu, timeunits, (len+1) * sizeof(char));
208
  char *ptu = tu;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
209

210
  for ( size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int) ptu[i]);
211

212
  int timeunit = get_timeunit(len, ptu);
213
  if ( timeunit == -1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
214
    {
215
      Message("Unsupported TIMEUNIT: %s!", timeunits);
216
      return 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
217
218
219
220
221
    }

  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
  if ( *ptu )
    {
222
      while ( isspace(*ptu) ) ptu++;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
223

224
      if ( str_is_equal(ptu, "as") )
225
        timetype = TAXIS_ABSOLUTE;
226
      else if ( str_is_equal(ptu, "since") )
227
        timetype = TAXIS_RELATIVE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
228
229
230

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
231
232
233
234
235
        {
          while ( isspace(*ptu) ) ptu++;

          if ( timetype == TAXIS_ABSOLUTE )
            {
236
              if ( !str_is_equal(ptu, "%y%m%d.%f") && timeunit == TUNIT_DAY )
237
238
239
240
                {
                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
                  timeunit = -1;
                }
241
              else if ( !str_is_equal(ptu, "%y%m.%f") && timeunit == TUNIT_MONTH )
242
243
244
245
246
247
248
249
                {
                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
                  timeunit = -1;
                }
            }
          else if ( timetype == TAXIS_RELATIVE )
            {
              scanTimeString(ptu, &rdate, &rtime);
250

251
252
              (*taxis).rdate = rdate;
              (*taxis).rtime = rtime;
253

254
255
256
              if ( CDI_Debug )
                Message("rdate = %d  rtime = %d", rdate, rtime);
            }
257
        }
258
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
259

260
261
  (*taxis).type = timetype;
  (*taxis).unit = timeunit;
Deike Kleberg's avatar
Deike Kleberg committed
262

263
  Free(tu);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
264

265
266
  if ( CDI_Debug )
    Message("timetype = %d  unit = %d", timetype, timeunit);
Deike Kleberg's avatar
Deike Kleberg committed
267

268
269
  return 0;
}
270

271
272
273
274
275
static
void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
{
  nc_type atttype;
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
276

277
  *attint = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
278

279
280
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Deike Kleberg's avatar
Deike Kleberg committed
281

282
283
284
285
  if ( atttype != NC_CHAR )
    {
      int *pintatt = (int)nc_attlen > attlen
        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
286

287
      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
288

289
290
291
292
      if ( (int)nc_attlen > attlen )
        {
          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
          Free(pintatt);
293
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
294
295
296
    }
}

297
static
298
void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
299
{
300
301
  nc_type atttype;
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
302

303
  *attdouble = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
304

305
306
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
307

308
  if ( atttype != NC_CHAR )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
309
    {
310
      double *pdoubleatt = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
311

312
313
314
315
      if ( (int)nc_attlen > attlen )
        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
      else
        pdoubleatt = attdouble;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
316

317
318
319
320
321
322
323
324
325
      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);

      if ( (int)nc_attlen > attlen )
        {
          memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
          Free(pdoubleatt);
        }
    }
}
326

327
static
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
bool cdfCheckAttText(int fileID, int ncvarid, const char *attname)
{
  bool status = false;
  nc_type atttype;

  int status_nc = nc_inq_atttype(fileID, ncvarid, attname, &atttype);

  if ( status_nc == NC_NOERR
       && (atttype == NC_CHAR
#if  defined  (HAVE_NETCDF4)
           || atttype == NC_STRING
#endif
           ) )
    {
      status = true;
    }

  return status;
}

static
349
void cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, char *atttext)
350
{
351
352
353
354
355
  nc_type atttype;
  size_t nc_attlen;

  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
356

357
  if ( atttype == NC_CHAR )
358
    {
359
360
361
362
      char attbuf[65636];
      if ( nc_attlen < sizeof(attbuf) )
        {
          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
363

364
          if ( nc_attlen > (attlen-1) ) nc_attlen = (attlen-1);
365

366
367
368
369
          attbuf[nc_attlen++] = 0;
          memcpy(atttext, attbuf, nc_attlen);
        }
      else
370
        {
371
          atttext[0] = 0;
372
        }
373
    }
374
375
#if  defined  (HAVE_NETCDF4)
  else if ( atttype == NC_STRING )
376
    {
377
      if ( nc_attlen == 1 )
378
        {
379
380
          char *attbuf = NULL;
          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
381

382
          size_t ssize = strlen(attbuf) + 1;
383

384
          if ( ssize > attlen ) ssize = attlen;
385
386
387
388
389
390
391
          memcpy(atttext, attbuf, ssize);
          atttext[ssize - 1] = 0;
          Free(attbuf);
        }
      else
        {
          atttext[0] = 0;
392
        }
393
    }
394
395
#endif
}
396

397
398
399
400
static
bool xtypeIsText(nc_type xtype)
{
  bool isText = false;
401

402
403
404
405
  if      ( xtype == NC_CHAR ) isText = true;
#if  defined  (HAVE_NETCDF4)
  else if ( xtype == NC_STRING ) isText = true;
#endif
406

407
408
  return isText;
}
409

410
411
412
413
static
bool xtypeIsFloat(nc_type xtype)
{
  bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
414

415
  return isFloat;
416
417
}

418
419
420
421
422
423
424
425
426
427
428
429
430
static
bool xtypeIsInt(nc_type xtype)
{
  bool isInt = xtype == NC_SHORT || xtype == NC_INT
            || xtype == NC_BYTE
#if  defined  (HAVE_NETCDF4)
            || xtype == NC_USHORT || xtype == NC_UINT
            || xtype == NC_UBYTE
#endif
             ;

  return isInt;
}
431

432
static
433
int cdfInqDatatype(int xtype, bool lunsigned)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
434
{
435
  int datatype = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
436

437
438
439
#if  defined  (HAVE_NETCDF4)
  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
440

441
442
443
444
445
446
  if      ( xtype == NC_BYTE   )  datatype = CDI_DATATYPE_INT8;
  /* else if ( xtype == NC_CHAR   )  datatype = CDI_DATATYPE_UINT8; */
  else if ( xtype == NC_SHORT  )  datatype = CDI_DATATYPE_INT16;
  else if ( xtype == NC_INT    )  datatype = CDI_DATATYPE_INT32;
  else if ( xtype == NC_FLOAT  )  datatype = CDI_DATATYPE_FLT32;
  else if ( xtype == NC_DOUBLE )  datatype = CDI_DATATYPE_FLT64;
447
#if  defined  (HAVE_NETCDF4)
448
449
450
451
452
453
  else if ( xtype == NC_UBYTE  )  datatype = CDI_DATATYPE_UINT8;
  else if ( xtype == NC_LONG   )  datatype = CDI_DATATYPE_INT32;
  else if ( xtype == NC_USHORT )  datatype = CDI_DATATYPE_UINT16;
  else if ( xtype == NC_UINT   )  datatype = CDI_DATATYPE_UINT32;
  else if ( xtype == NC_INT64  )  datatype = CDI_DATATYPE_FLT64;
  else if ( xtype == NC_UINT64 )  datatype = CDI_DATATYPE_FLT64;
454
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
455

456
457
  return datatype;
}
458
459


460
void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
461
{
462
463
  bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
  bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
464

465
466
  if ( laddoffset || lscalefactor )
    {
467
      for ( size_t i = 0; i < size; ++i )
468
469
470
471
472
473
        {
          if ( lscalefactor ) data[i] *= scalefactor;
          if ( laddoffset )   data[i] += addoffset;
        }
    }
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
474

475
476
static
void cdfCreateRecords(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
477
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
478
  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
479

Uwe Schulzweida's avatar
Uwe Schulzweida committed
480
  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
481

482
483
  int vlistID  = streamptr->vlistID;

484
485
486
487
488
489
490
491
  tsteps_t* sourceTstep = streamptr->tsteps;
  tsteps_t* destTstep = sourceTstep + tsID;

  int nvars = vlistNvars(vlistID);
  int nrecs = vlistNrecs(vlistID);

  if ( nrecs <= 0 ) return;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
492
493
  if ( tsID == 0 )
    {
494
      int nvrecs = nrecs; /* use all records at first timestep */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
495

Uwe Schulzweida's avatar
Uwe Schulzweida committed
496
      streamptr->nrecs += nrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
497

498
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
499
500
501
      destTstep->nrecs      = nrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
502
      destTstep->curRecID   = CDI_UNDEFID;
503
      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
504
      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
505

506
      record_t *records = destTstep->records;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
507

508
      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
509
        {
510
511
512
          int zaxisID = vlistInqVarZaxis(vlistID, varID);
          int nlev    = zaxisInqSize(zaxisID);
          for ( int levelID = 0; levelID < nlev; levelID++ )
513
514
            {
              recordInitEntry(&records[recID]);
515
516
              records[recID].varID   = (short)varID;
              records[recID].levelID = (short)levelID;
517
518
519
              recID++;
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
520
521
522
    }
  else if ( tsID == 1 )
    {
523
524
      int nvrecs = 0;
      for ( int varID = 0; varID < nvars; varID++ )
525
        {
526
          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
527
            {
528
              int zaxisID = vlistInqVarZaxis(vlistID, varID);
529
530
531
              nvrecs += zaxisInqSize(zaxisID);
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
532

Uwe Schulzweida's avatar
Uwe Schulzweida committed
533
      streamptr->nrecs += nvrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
534

535
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
536
537
538
      destTstep->nrecs      = nvrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
539
      destTstep->curRecID   = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
540

541
      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
542

543
      if ( nvrecs )
544
        {
545
          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
546
          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
547
            {
548
              int varID = destTstep->records[recID].varID;
549
              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
550
                {
551
                  destTstep->recIDs[vrecID++] = recID;
552
553
554
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
555
556
557
    }
  else
    {
558
      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
559

560
      int nvrecs = streamptr->tsteps[1].nrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
561

Uwe Schulzweida's avatar
Uwe Schulzweida committed
562
      streamptr->nrecs += nvrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
563

564
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
565
566
567
      destTstep->nrecs      = nvrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
568
      destTstep->curRecID   = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
569

570
      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
571

572
      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
573

574
      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
575
576
577
    }
}

578
static
579
int cdf_time_dimid(int fileID, int ndims, int nvars)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
580
{
581
582
  char dimname[80];
  for ( int dimid = 0; dimid < ndims; ++dimid )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
583
    {
584
      dimname[0] = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
585
      cdf_inq_dimname(fileID, dimid, dimname);
586
      if ( str_is_equal(dimname, "time") || str_is_equal(dimname, "Time") ) return dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
587
588
    }

589
  for ( int varid = 0; varid < nvars; ++varid )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
590
    {
591
      nc_type xtype;
592
      int nvdims, nvatts, dimids[9];
593
      cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
594
      if ( nvdims == 1 )
595
        {
596
597
          char sbuf[CDI_MAX_NAME];
          for ( int iatt = 0; iatt < nvatts; ++iatt )
598
            {
599
              sbuf[0] = 0;
600
601
              cdf_inq_attname(fileID, varid, iatt, sbuf);
              if ( strncmp(sbuf, "units", 5) == 0 )
602
                {
603
                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
604
                  str_tolower(sbuf);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
605

606
                  if ( is_time_units(sbuf) ) return dimids[0];
607
608
609
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
610
611
    }

612
  return CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
613
614
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
615
static
616
void init_ncdims(long ndims, ncdim_t *ncdims)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
617
{
618
  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
619
    {
620
621
      ncdims[ncdimid].ncvarid      = CDI_UNDEFID;
      ncdims[ncdimid].dimtype      = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
622
623
624
625
626
627
      ncdims[ncdimid].len          = 0;
      ncdims[ncdimid].name[0]      = 0;
    }
}

static
628
void init_ncvars(long nvars, ncvar_t *ncvars)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
629
{
630
  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
Deike Kleberg's avatar
Deike Kleberg committed
631
    {
632
633
      ncvars[ncvarid].ncid            = CDI_UNDEFID;
      ncvars[ncvarid].isvar           = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
634
      ncvars[ncvarid].ignore          = false;
635
636
      ncvars[ncvarid].isx             = false;
      ncvars[ncvarid].isy             = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
637
638
639
640
641
      ncvars[ncvarid].islon           = false;
      ncvars[ncvarid].islat           = false;
      ncvars[ncvarid].islev           = false;
      ncvars[ncvarid].istime          = false;
      ncvars[ncvarid].warn            = false;
642
      ncvars[ncvarid].calendar        = false;
643
      ncvars[ncvarid].climatology     = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
644
      ncvars[ncvarid].lformulaterms   = false;
645
      ncvars[ncvarid].tsteptype       = TSTEP_CONSTANT;
646
647
      ncvars[ncvarid].param           = CDI_UNDEFID;
      ncvars[ncvarid].code            = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
648
      ncvars[ncvarid].tabnum          = 0;
649
650
651
652
653
654
655
656
657
658
659
660
661
662
      ncvars[ncvarid].bounds          = CDI_UNDEFID;
      ncvars[ncvarid].gridID          = CDI_UNDEFID;
      ncvars[ncvarid].zaxisID         = CDI_UNDEFID;
      ncvars[ncvarid].gridtype        = CDI_UNDEFID;
      ncvars[ncvarid].zaxistype       = CDI_UNDEFID;
      ncvars[ncvarid].xdim            = CDI_UNDEFID;
      ncvars[ncvarid].ydim            = CDI_UNDEFID;
      ncvars[ncvarid].zdim            = CDI_UNDEFID;
      ncvars[ncvarid].xvarid          = CDI_UNDEFID;
      ncvars[ncvarid].yvarid          = CDI_UNDEFID;
      ncvars[ncvarid].zvarid          = CDI_UNDEFID;
      ncvars[ncvarid].tvarid          = CDI_UNDEFID;
      ncvars[ncvarid].psvarid         = CDI_UNDEFID;
      ncvars[ncvarid].p0varid         = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
663
      ncvars[ncvarid].ncoordvars      = 0;
664
      for ( int i = 0; i < MAX_COORDVARS; ++i )
665
        ncvars[ncvarid].coordvarids[i]  = CDI_UNDEFID;
666
667
      ncvars[ncvarid].nauxvars      = 0;
      for ( int i = 0; i < MAX_AUXVARS; ++i )
668
669
670
        ncvars[ncvarid].auxvarids[i]  = CDI_UNDEFID;
      ncvars[ncvarid].cellarea        = CDI_UNDEFID;
      ncvars[ncvarid].tableID         = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
671
672
      ncvars[ncvarid].xtype           = 0;
      ncvars[ncvarid].ndims           = 0;
673
      ncvars[ncvarid].gmapid          = CDI_UNDEFID;
674
675
      ncvars[ncvarid].vctsize         = 0;
      ncvars[ncvarid].vct             = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
676
      ncvars[ncvarid].truncation      = 0;
677
      ncvars[ncvarid].position        = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
678
      ncvars[ncvarid].positive        = 0;
679
      ncvars[ncvarid].chunked         = 0;
680
      ncvars[ncvarid].chunktype       = CDI_UNDEFID;
681
682
      ncvars[ncvarid].defmissval      = false;
      ncvars[ncvarid].deffillval      = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
683
      ncvars[ncvarid].missval         = 0;
684
      ncvars[ncvarid].fillval         = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
685
686
687
688
689
      ncvars[ncvarid].addoffset       = 0;
      ncvars[ncvarid].scalefactor     = 1;
      ncvars[ncvarid].natts           = 0;
      ncvars[ncvarid].atts            = NULL;
      ncvars[ncvarid].deflate         = 0;
690
691
      ncvars[ncvarid].lunsigned       = false;
      ncvars[ncvarid].lvalidrange     = false;
Deike Kleberg's avatar
Deike Kleberg committed
692
693
      ncvars[ncvarid].validrange[0]   = VALIDMISS;
      ncvars[ncvarid].validrange[1]   = VALIDMISS;
694
      ncvars[ncvarid].ensdata         = NULL;
695
696
697
698
699
      memset(ncvars[ncvarid].name, 0, CDI_MAX_NAME);
      memset(ncvars[ncvarid].longname, 0, CDI_MAX_NAME);
      memset(ncvars[ncvarid].stdname, 0, CDI_MAX_NAME);
      memset(ncvars[ncvarid].units, 0, CDI_MAX_NAME);
      memset(ncvars[ncvarid].extra, 0, CDI_MAX_NAME);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
700
701
702
    }
}

703
static
704
void cdf_set_var(ncvar_t *ncvars, int ncvarid, short isvar)
705
{
706
  if ( ncvars[ncvarid].isvar != CDI_UNDEFID &&
707
       ncvars[ncvarid].isvar != isvar   &&
Uwe Schulzweida's avatar
Uwe Schulzweida committed
708
       ncvars[ncvarid].warn  == false )
709
710
711
712
    {
      if ( ! ncvars[ncvarid].ignore )
        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
713
      ncvars[ncvarid].warn = true;
714
715
716
717
718
719
720
      isvar = FALSE;
    }

  ncvars[ncvarid].isvar = isvar;
}

static
721
void cdf_set_dim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
722
{
723
  if ( ncvars[ncvarid].dimtype[dimid] != CDI_UNDEFID &&
724
725
726
727
728
729
730
731
732
733
       ncvars[ncvarid].dimtype[dimid] != dimtype )
    {
      Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
              ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
    }

  ncvars[ncvarid].dimtype[dimid] = dimtype;
}

static
734
void scan_hybrid_formulaterms(int ncid, int ncfvarid, int *avarid, int *bvarid, int *psvarid, int *p0varid)
735
{
736
  *avarid  = -1;
737
738
  *bvarid  = -1;
  *psvarid = -1;
739
  *p0varid = -1;
740

741
  char attstring[1024];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
742
743
  cdfGetAttText(ncid, ncfvarid, "formula_terms", sizeof(attstring), attstring);
  char *pstring = attstring;
744

745
  bool lstop = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
746
  for ( int i = 0; i < 4; i++ )
747
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
749
750
751
752
753
754
755
756
757
758
759
760
761
      while ( isspace((int) *pstring) ) pstring++;
      if ( *pstring == 0 ) break;
      char *tagname = pstring;
      while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
      if ( *pstring == 0 ) lstop = true;
      *pstring++ = 0;

      while ( isspace((int) *pstring) ) pstring++;
      if ( *pstring == 0 ) break;
      char *varname = pstring;
      while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
      if ( *pstring == 0 ) lstop = true;
      *pstring++ = 0;

762
      int dimvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
763
764
      int status_nc = nc_inq_varid(ncid, varname, &dimvarid);
      if ( status_nc == NC_NOERR )
765
        {
766
767
          if      ( strcmp(tagname, "ap:") == 0 ) *avarid  = dimvarid;
          else if ( strcmp(tagname, "a:")  == 0 ) *avarid  = dimvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
768
769
770
          else if ( strcmp(tagname, "b:")  == 0 ) *bvarid  = dimvarid;
          else if ( strcmp(tagname, "ps:") == 0 ) *psvarid = dimvarid;
          else if ( strcmp(tagname, "p0:") == 0 ) *p0varid = dimvarid;
771
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
772
773
774
775
776
777
      else if ( strcmp(tagname, "ps:") != 0 )
        {
          Warning("%s - %s", nc_strerror(status_nc), varname);
        }

      if ( lstop ) break;
778
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
779
780
}

781
static
782
bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
783
{
784
  bool status = false;
785
786
787
788
  ncvar_t *ncvar = &ncvars[ncvarid];

  if ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
    {
789
790
      cdiConvention = CDI_CONVENTION_CF;

791
      status = true;
792
      ncvar->zaxistype = ZAXIS_HYBRID;
793
      //int ndims = ncvar->ndims;
794
      int dimid = ncvar->dimids[0];
Thomas Jahns's avatar
Thomas Jahns committed
795
      size_t dimlen = ncdims[dimid].len;
796
      int avarid1 = -1, bvarid1 = -1, psvarid1 = -1, p0varid1 = -1;
797
      int ncfvarid = ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
798
      if ( ncvars[ncfvarid].lformulaterms )
799
800
        scan_hybrid_formulaterms(ncid, ncfvarid, &avarid1, &bvarid1, &psvarid1, &p0varid1);
      // printf("avarid1, bvarid1, psvarid1, p0varid1 %d %d %d %d\n", avarid1, bvarid1, psvarid1, p0varid1);
801
      if ( avarid1  != -1 ) ncvars[avarid1].isvar = FALSE;
802
803
      if ( bvarid1  != -1 ) ncvars[bvarid1].isvar = FALSE;
      if ( psvarid1 != -1 ) ncvar->psvarid = psvarid1;
804
      if ( p0varid1 != -1 ) ncvar->p0varid = p0varid1;
805

806
      if ( ncvar->bounds != CDI_UNDEFID && ncvars[ncvar->bounds].lformulaterms )
807
808
        {
          ncfvarid = ncvar->bounds;
809
          int avarid2 = -1, bvarid2 = -1, psvarid2 = -1, p0varid2 = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
810
          if ( ncvars[ncfvarid].lformulaterms )
811
812
            scan_hybrid_formulaterms(ncid, ncfvarid, &avarid2, &bvarid2, &psvarid2, &p0varid2);
          // printf("avarid2, bvarid2, psvarid2, p0varid2 %d %d %d %d\n", avarid2, bvarid2, psvarid2, p0varid2);
813
          if ( avarid2 != -1 && bvarid2 != -1 )
814
            {
815
              ncvars[avarid2].isvar = FALSE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
816
              ncvars[bvarid2].isvar = FALSE;
817

818
819
820
821
822
823
              int ndims2 = ncvars[avarid2].ndims;
              int dimid2 = ncvars[avarid2].dimids[0];
              size_t dimlen2 = ncdims[dimid2].len;

              if ( (ndims2 == 2 && dimid == ncvars[avarid2].dimids[0] ) ||
                   (ndims2 == 1 && dimlen == dimlen2-1 ) )
824
                {
825
                  double px = 1;
826
                  if ( p0varid1 != -1 && p0varid1 == p0varid2 )
827
828
                    cdf_get_var_double(ncid, p0varid2, &px);

829
                  double abuf[dimlen*2], bbuf[dimlen*2];
830
                  cdf_get_var_double(ncid, avarid2, abuf);
831
                  cdf_get_var_double(ncid, bvarid2, bbuf);
832

Thomas Jahns's avatar
Thomas Jahns committed
833
                  size_t vctsize = (dimlen+1)*2;
834
835
836
837
838
839
840
841
842
843
844
845
                  double *vct = (double *) Malloc(vctsize*sizeof(double));
                  if ( ndims2 == 2 )
                    {
                      for ( size_t i = 0; i < dimlen; ++i )
                        {
                          vct[i] = abuf[i*2];
                          vct[i+dimlen+1] = bbuf[i*2];
                        }
                      vct[dimlen]     = abuf[dimlen*2-1];
                      vct[dimlen*2+1] = bbuf[dimlen*2-1];
                    }
                  else
846
                    {
847
848
849
850
851
                       for ( size_t i = 0; i < dimlen2; ++i )
                        {
                          vct[i] = abuf[i];
                          vct[i+dimlen+1] = bbuf[i];
                        }
852
853
                    }

854
                  if ( p0varid1 != -1 && IS_NOT_EQUAL(px, 1) )
855
856
                    for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;

857
858
859
860
861
862
863
864
865
866
                  ncvar->vct = vct;
                  ncvar->vctsize = vctsize;
                }
            }
        }
    }

  return status;
}

867
868
869
870
871
872
873
874
875
876
877
878
879
880
static
void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID)
{
  nc_type atttype;
  size_t attlen;
  char attname[CDI_MAX_NAME];

  cdf_inq_attname(ncid, ncvarid, attnum, attname);
  cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
  cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
  if ( xtypeIsInt(atttype) )
    {
      int attint[attlen];
      cdfGetAttInt(ncid, ncvarid, attname, (int)attlen, attint);
881
882
      int datatype = (atttype == NC_SHORT)  ? CDI_DATATYPE_INT16 :
                     (atttype == NC_BYTE)   ? CDI_DATATYPE_INT8 :
883
#if  defined  (HAVE_NETCDF4)
884
885
886
                     (atttype == NC_UBYTE)  ? CDI_DATATYPE_UINT8 :
                     (atttype == NC_USHORT) ? CDI_DATATYPE_UINT16 :
                     (atttype == NC_UINT)   ? CDI_DATATYPE_UINT32 :
887
#endif
888
                     CDI_DATATYPE_INT32;
889
      cdiDefAttInt(cdiID, varID, attname, datatype, (int)attlen, attint);
890
891
892
893
894
    }
  else if ( xtypeIsFloat(atttype) )
    {
      double attflt[attlen];
      cdfGetAttDouble(ncid, ncvarid, attname, (int)attlen, attflt);
895
      int datatype = (atttype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
896
      cdiDefAttFlt(cdiID, varID, attname, datatype, (int)attlen, attflt);
897
898
899
    }
  else if ( xtypeIsText(atttype) )
    {
900
901
      char attstring[8192];
      cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
902
      cdiDefAttTxt(cdiID, varID, attname, (int)attlen, attstring);
903
904
905
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
906
static