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

5
6
#ifdef HAVE_LIBNETCDF

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

9
#include <limits.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
10
11
12
#include <ctype.h>
#include <math.h>
#include <float.h>
13
14
15
16
17
18
19
20
21
22
#ifdef HAVE_MMAP
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#ifdef HAVE_LIBPTHREAD
#include <pthread.h>
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
23

24
#include <netcdf.h>
25

Uwe Schulzweida's avatar
Uwe Schulzweida committed
26
27
28
#include "dmemory.h"
#include "cdi.h"
#include "basetime.h"
29
#include "gaussgrid.h"
30
#include "cdi_int.h"
31
#include "cdi_uuid.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
32
#include "stream_cdf.h"
33
#include "cdf.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
34
35
36
#include "cdf_int.h"
#include "varscan.h"
#include "vlist.h"
37
#include "zaxis.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
38

39
40
//#define PROJECTION_TEST

Uwe Schulzweida's avatar
Uwe Schulzweida committed
41
42
43
44
45
46
47
48
#undef  UNDEFID
#define UNDEFID  CDI_UNDEFID

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

49
50
51
#define  POSITIVE_UP    1
#define  POSITIVE_DOWN  2

Uwe Schulzweida's avatar
Uwe Schulzweida committed
52
53
54
55
typedef struct {
  int     ncvarid;
  int     dimtype;
  size_t  len;
56
  char    name[CDI_MAX_NAME];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
57
}
58
ncdim_t;
59
60
61
#define  MAX_COORDVARS  4
#define  MAX_AUXVARS    4

Uwe Schulzweida's avatar
Uwe Schulzweida committed
62
typedef struct {
63
  int      ncid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
64
65
66
67
68
69
70
  int      isvar;
  bool     ignore;
  bool     islon;
  bool     islat;
  bool     islev;
  bool     istime;
  bool     warn;
71
  bool     climatology;
72
  int      tsteptype;
73
  int      param;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
74
  int      code;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
75
  int      tabnum;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
76
  int      bounds;
77
78
  int      lformula;
  int      lformulaterms;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
79
80
81
82
83
84
85
86
87
88
89
  int      gridID;
  int      zaxisID;
  int      gridtype;
  int      zaxistype;
  int      xdim;
  int      ydim;
  int      zdim;
  int      xvarid;
  int      yvarid;
  int      zvarid;
  int      tvarid;
90
  int      psvarid;
91
  int      p0varid;
92
  int      ncoordvars;
93
94
95
  int      coordvarids[MAX_COORDVARS];
  int      nauxvars;
  int      auxvarids[MAX_AUXVARS];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
96
97
98
99
  int      cellarea;
  int      calendar;
  int      tableID;
  int      truncation;
100
  int      position;
101
102
  bool     defmissval;
  bool     deffillval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
103
104
105
106
107
108
  int      xtype;
  int      ndims;
  int      gmapid;
  int      positive;
  int      dimids[8];
  int      dimtype[8];
109
110
111
  int      chunks[8];
  int      chunked;
  int      chunktype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
112
  int      natts;
113
  int      deflate;
114
115
  bool     lunsigned;
  bool     lvalidrange;
Thomas Jahns's avatar
Thomas Jahns committed
116
  int     *atts;
117
118
  size_t   vctsize;
  double  *vct;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
119
  double   missval;
120
  double   fillval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
121
122
  double   addoffset;
  double   scalefactor;
Deike Kleberg's avatar
Deike Kleberg committed
123
  double   validrange[2];
124
125
126
127
  char     name[CDI_MAX_NAME];
  char     longname[CDI_MAX_NAME];
  char     stdname[CDI_MAX_NAME];
  char     units[CDI_MAX_NAME];
128
  char     extra[CDI_MAX_NAME];
129
  ensinfo_t   *ensdata;    /* Ensemble information */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
130
}
131
132
133
134
135
136
ncvar_t;

static
void strtolower(char *str)
{
  if ( str )
137
    for (size_t i = 0; str[i]; ++i)
138
      str[i] = (char)tolower((int)str[i]);
139
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
140

141
static
142
int get_timeunit(size_t len, const char *ptu)
143
144
{
  int timeunit = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
145

146
147
148
149
150
151
152
153
154
155
  if ( len > 2 )
    {
      if      ( memcmp(ptu, "sec",    3) == 0 )          timeunit = TUNIT_SECOND;
      else if ( memcmp(ptu, "minute", 6) == 0 )          timeunit = TUNIT_MINUTE;
      else if ( memcmp(ptu, "hour",   4) == 0 )          timeunit = TUNIT_HOUR;
      else if ( memcmp(ptu, "day",    3) == 0 )          timeunit = TUNIT_DAY;
      else if ( memcmp(ptu, "month",  5) == 0 )          timeunit = TUNIT_MONTH;
      else if ( memcmp(ptu, "calendar_month", 14) == 0 ) timeunit = TUNIT_MONTH;
      else if ( memcmp(ptu, "year",   4) == 0 )          timeunit = TUNIT_YEAR;
    }
156
157
158
159
  else if ( len == 1 )
    {
      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
    }
160

161
  return timeunit;
162
163
164
}

static
165
bool isTimeUnits(const char *timeunits)
166
{
Thomas Jahns's avatar
Thomas Jahns committed
167
168
169
170
171
  bool status = strncmp(timeunits, "sec",    3) == 0
    || strncmp(timeunits, "minute", 6) == 0
    || strncmp(timeunits, "hour",   4) == 0
    || strncmp(timeunits, "day",    3) == 0
    || strncmp(timeunits, "month",  5) == 0;
172
  return status;
173
174
175
}

static
176
bool isTimeAxisUnits(const char *timeunits)
177
{
178
  bool status = false;
179

180
  size_t len = strlen(timeunits);
Thomas Jahns's avatar
Thomas Jahns committed
181
  char *tu = (char *) Malloc((len+1)*sizeof(char));
182
  memcpy(tu, timeunits, (len+1) * sizeof(char));
Thomas Jahns's avatar
Thomas Jahns committed
183
  char *ptu = tu;
184

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

Thomas Jahns's avatar
Thomas Jahns committed
187
  int timeunit = get_timeunit(len, ptu);
188
189
190
191
192
  if ( timeunit != -1 )
    {

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
193
194
        {
          while ( isspace(*ptu) ) ptu++;
Deike Kleberg's avatar
Deike Kleberg committed
195

Thomas Jahns's avatar
Thomas Jahns committed
196
197
          int timetype = memcmp(ptu, "as", 2) == 0 ? TAXIS_ABSOLUTE :
            memcmp(ptu, "since", 5) == 0 ? TAXIS_RELATIVE : -1;
198

Thomas Jahns's avatar
Thomas Jahns committed
199
          status = timetype != -1;
200
        }
201
202
    }

203
  Free(tu);
204

205
  return status;
206
207
208
}

static
209
void scanTimeString(const char *ptu, int *rdate, int *rtime)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
210
{
211
  int year = 1, month = 1, day = 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
212
  int hour = 0, minute = 0, second = 0;
213
  int v1 = 1, v2 = 1, v3 = 1;
214
215
216
217

  *rdate = 0;
  *rtime = 0;

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  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++;
            }
        }
    }
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264

  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
265
266
267
static
int scanTimeUnit(const char *unitstr)
{
268
  size_t len = strlen(unitstr);
269
  int timeunit = get_timeunit(len, unitstr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
270
271
272
  if ( timeunit == -1 )
    Message("Unsupported TIMEUNIT: %s!", unitstr);

273
  return timeunit;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
274
275
}

276
277
278
static
void setForecastTime(const char *timestr, taxis_t *taxis)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
279
280
281
  (*taxis).fdate = 0;
  (*taxis).ftime = 0;

282
  int len = (int) strlen(timestr);
283
284
285
286
287
288
289
290
291
292
293
294
  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
295
296
297
  int timetype = TAXIS_ABSOLUTE;
  int rdate = -1, rtime = -1;

298
  size_t len = strlen(timeunits);
299
  char *tu = (char *) Malloc((len+1) * sizeof (char));
300
  memcpy(tu, timeunits, (len+1) * sizeof (char));
301
  char *ptu = tu;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
302

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

305
  int timeunit = get_timeunit(len, ptu);
306
  if ( timeunit == -1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
307
    {
308
      Message("Unsupported TIMEUNIT: %s!", timeunits);
309
      return 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
310
311
312
313
314
    }

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

317
      if ( memcmp(ptu, "as", 2) == 0 )
318
        timetype = TAXIS_ABSOLUTE;
319
      else if ( memcmp(ptu, "since", 5) == 0 )
320
        timetype = TAXIS_RELATIVE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
321
322
323

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
324
325
326
327
328
329
330
331
332
333
334
        {
          while ( isspace(*ptu) ) ptu++;

          if ( timetype == TAXIS_ABSOLUTE )
            {
              if ( memcmp(ptu, "%y%m%d.%f", 9) != 0 && timeunit == TUNIT_DAY )
                {
                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
                  timeunit = -1;
                }
              else if ( memcmp(ptu, "%y%m.%f", 7) != 0 && timeunit == TUNIT_MONTH )
335
336
337
338
339
340
341
342
                {
                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
                  timeunit = -1;
                }
            }
          else if ( timetype == TAXIS_RELATIVE )
            {
              scanTimeString(ptu, &rdate, &rtime);
343

344
345
              (*taxis).rdate = rdate;
              (*taxis).rtime = rtime;
346

347
348
349
              if ( CDI_Debug )
                Message("rdate = %d  rtime = %d", rdate, rtime);
            }
350
        }
351
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
352

353
354
  (*taxis).type = timetype;
  (*taxis).unit = timeunit;
Deike Kleberg's avatar
Deike Kleberg committed
355

356
  Free(tu);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
357

358
359
  if ( CDI_Debug )
    Message("timetype = %d  unit = %d", timetype, timeunit);
Deike Kleberg's avatar
Deike Kleberg committed
360

361
362
  return 0;
}
363

364
365
366
367
368
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
369

370
  *attint = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
371

372
373
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Deike Kleberg's avatar
Deike Kleberg committed
374

375
376
377
378
  if ( atttype != NC_CHAR )
    {
      int *pintatt = (int)nc_attlen > attlen
        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
379

380
      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
381

382
383
384
385
      if ( (int)nc_attlen > attlen )
        {
          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
          Free(pintatt);
386
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
387
388
389
    }
}

390
static
391
void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
392
{
393
394
  nc_type atttype;
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
395

396
  *attdouble = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
397

398
399
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
400

401
  if ( atttype != NC_CHAR )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
402
    {
403
      double *pdoubleatt = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
404

405
406
407
408
      if ( (int)nc_attlen > attlen )
        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
      else
        pdoubleatt = attdouble;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
409

410
411
412
413
414
415
416
417
418
      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);

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

420
static
421
void cdfGetAttText(int fileID, int ncvarid,const char *attname, int attlen, char *atttext)
422
{
423
424
425
426
427
  nc_type atttype;
  size_t nc_attlen;

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

429
  if ( atttype == NC_CHAR )
430
    {
431
432
433
434
      char attbuf[65636];
      if ( nc_attlen < sizeof(attbuf) )
        {
          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
435

436
          if ( (int) nc_attlen > (attlen-1) ) nc_attlen = (size_t)(attlen-1);
437

438
439
440
441
          attbuf[nc_attlen++] = 0;
          memcpy(atttext, attbuf, nc_attlen);
        }
      else
442
        {
443
          atttext[0] = 0;
444
        }
445
    }
446
447
#if  defined  (HAVE_NETCDF4)
  else if ( atttype == NC_STRING )
448
    {
449
      if ( nc_attlen == 1 )
450
        {
451
452
          char *attbuf = NULL;
          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
453

454
          size_t ssize = strlen(attbuf) + 1;
455

456
457
458
459
460
461
462
463
          if ( ssize > (size_t)attlen ) ssize = (size_t)attlen;
          memcpy(atttext, attbuf, ssize);
          atttext[ssize - 1] = 0;
          Free(attbuf);
        }
      else
        {
          atttext[0] = 0;
464
        }
465
    }
466
467
#endif
}
468

469
470
471
472
static
bool xtypeIsText(nc_type xtype)
{
  bool isText = false;
473

474
475
476
477
  if      ( xtype == NC_CHAR ) isText = true;
#if  defined  (HAVE_NETCDF4)
  else if ( xtype == NC_STRING ) isText = true;
#endif
478

479
480
  return isText;
}
481

482
483
484
485
static
bool xtypeIsFloat(nc_type xtype)
{
  bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
486

487
  return isFloat;
488
489
}

490
491
492
493
494
495
496
497
498
499
500
501
502
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;
}
503

504
static
505
int cdfInqDatatype(int xtype, bool lunsigned)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
506
{
507
  int datatype = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
508

509
510
511
#if  defined  (HAVE_NETCDF4)
  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
512

513
514
515
516
517
518
519
520
521
522
523
524
525
526
  if      ( xtype == NC_BYTE   )  datatype = DATATYPE_INT8;
  /* else if ( xtype == NC_CHAR   )  datatype = DATATYPE_UINT8; */
  else if ( xtype == NC_SHORT  )  datatype = DATATYPE_INT16;
  else if ( xtype == NC_INT    )  datatype = DATATYPE_INT32;
  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
#if  defined  (HAVE_NETCDF4)
  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
  else if ( xtype == NC_LONG   )  datatype = DATATYPE_INT32;
  else if ( xtype == NC_USHORT )  datatype = DATATYPE_UINT16;
  else if ( xtype == NC_UINT   )  datatype = DATATYPE_UINT32;
  else if ( xtype == NC_INT64  )  datatype = DATATYPE_FLT64;
  else if ( xtype == NC_UINT64 )  datatype = DATATYPE_FLT64;
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
527

528
529
  return datatype;
}
530
531


532
533
534
535
/* not used
int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
{
  int tsID, recID;
536

537
538
539
  recID = streamptr->tsteps[0].curRecID++;
  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
540

541
  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
542
    {
543
      streamptr->tsteps[0].curRecID = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
544
    }
545

546
547
548
549
550
551
552
553
554
555
  *varID   = streamptr->tsteps[0].records[recID].varID;
  *levelID = streamptr->tsteps[0].records[recID].levelID;

  streamptr->record->varID   = *varID;
  streamptr->record->levelID = *levelID;

  if ( CDI_Debug )
    Message("recID = %d  varID = %d  levelID = %d", recID, *varID, *levelID);

  return (recID+1);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
556
}
557
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
558

559
static
560
void scale_add(size_t size, double *data, double addoffset, double scalefactor)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
561
{
562
563
  int laddoffset;
  int lscalefactor;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
564

565
566
  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
567

568
569
570
571
572
573
574
575
576
  if ( laddoffset || lscalefactor )
    {
      for (size_t i = 0; i < size; ++i )
        {
          if ( lscalefactor ) data[i] *= scalefactor;
          if ( laddoffset )   data[i] += addoffset;
        }
    }
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
577

578
579
static
void cdfCreateRecords(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
580
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
581
  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
582

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

585
586
  int vlistID  = streamptr->vlistID;

587
588
589
590
591
592
593
594
  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
595
596
  if ( tsID == 0 )
    {
597
      int nvrecs = nrecs; /* use all records at first timestep */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
598

Uwe Schulzweida's avatar
Uwe Schulzweida committed
599
      streamptr->nrecs += nrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
600

601
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
602
603
604
605
      destTstep->nrecs      = nrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
      destTstep->curRecID   = UNDEFID;
606
      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
607
      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
608

609
      record_t *records = destTstep->records;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
610

611
      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
612
        {
613
614
615
          int zaxisID = vlistInqVarZaxis(vlistID, varID);
          int nlev    = zaxisInqSize(zaxisID);
          for ( int levelID = 0; levelID < nlev; levelID++ )
616
617
            {
              recordInitEntry(&records[recID]);
618
619
              records[recID].varID   = (short)varID;
              records[recID].levelID = (short)levelID;
620
621
622
              recID++;
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
623
624
625
    }
  else if ( tsID == 1 )
    {
626
627
      int nvrecs = 0;
      for ( int varID = 0; varID < nvars; varID++ )
628
        {
629
          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
630
            {
631
              int zaxisID = vlistInqVarZaxis(vlistID, varID);
632
633
634
              nvrecs += zaxisInqSize(zaxisID);
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
635

Uwe Schulzweida's avatar
Uwe Schulzweida committed
636
      streamptr->nrecs += nvrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
637

638
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
639
640
641
642
      destTstep->nrecs      = nvrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
      destTstep->curRecID   = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
643

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

646
      if ( nvrecs )
647
        {
648
          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
649
          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
650
            {
651
              int varID = destTstep->records[recID].varID;
652
              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
653
                {
654
                  destTstep->recIDs[vrecID++] = recID;
655
656
657
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
658
659
660
    }
  else
    {
661
      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
662

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
665
      streamptr->nrecs += nvrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
666

667
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
668
669
670
671
      destTstep->nrecs      = nvrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
      destTstep->curRecID   = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
672

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

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

677
      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
678
679
680
    }
}

681

682
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
683
684
int cdfTimeDimID(int fileID, int ndims, int nvars)
{
685
686
  char dimname[80];
  for ( int dimid = 0; dimid < ndims; ++dimid )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
687
    {
688
      dimname[0] = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
689
      cdf_inq_dimname(fileID, dimid, dimname);
690
691
      size_t len = strlen(dimname);
      if ( len >= 4 && memcmp(dimname, "time", 4) == 0 ) return dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
692
693
    }

694
  for ( int varid = 0; varid < nvars; ++varid )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
695
    {
696
      nc_type xtype;
697
      int nvdims, nvatts, dimids[9];
698
      cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
699
      if ( nvdims == 1 )
700
        {
701
702
          char sbuf[CDI_MAX_NAME];
          for ( int iatt = 0; iatt < nvatts; ++iatt )
703
            {
704
              sbuf[0] = 0;
705
706
              cdf_inq_attname(fileID, varid, iatt, sbuf);
              if ( strncmp(sbuf, "units", 5) == 0 )
707
                {
708
709
                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
                  strtolower(sbuf);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
710

711
                  if ( isTimeUnits(sbuf) ) return dimids[0];
712
713
714
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
715
716
    }

717
  return UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
718
719
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
720
static
721
void init_ncdims(long ndims, ncdim_t *ncdims)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
722
{
723
  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
724
725
726
727
728
729
730
731
732
    {
      ncdims[ncdimid].ncvarid      = UNDEFID;
      ncdims[ncdimid].dimtype      = UNDEFID;
      ncdims[ncdimid].len          = 0;
      ncdims[ncdimid].name[0]      = 0;
    }
}

static
733
void init_ncvars(long nvars, ncvar_t *ncvars)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
734
{
735
  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
Deike Kleberg's avatar
Deike Kleberg committed
736
    {
737
      ncvars[ncvarid].ncid            = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
738
      ncvars[ncvarid].isvar           = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
739
740
741
742
743
744
      ncvars[ncvarid].ignore          = false;
      ncvars[ncvarid].islon           = false;
      ncvars[ncvarid].islat           = false;
      ncvars[ncvarid].islev           = false;
      ncvars[ncvarid].istime          = false;
      ncvars[ncvarid].warn            = false;
745
      ncvars[ncvarid].climatology     = false;
746
      ncvars[ncvarid].tsteptype       = TSTEP_CONSTANT;
747
      ncvars[ncvarid].param           = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
      ncvars[ncvarid].code            = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
749
      ncvars[ncvarid].tabnum          = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
750
751
      ncvars[ncvarid].calendar        = FALSE;
      ncvars[ncvarid].bounds          = UNDEFID;
752
753
      ncvars[ncvarid].lformula        = FALSE;
      ncvars[ncvarid].lformulaterms   = FALSE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
755
756
757
758
759
760
761
762
763
764
      ncvars[ncvarid].gridID          = UNDEFID;
      ncvars[ncvarid].zaxisID         = UNDEFID;
      ncvars[ncvarid].gridtype        = UNDEFID;
      ncvars[ncvarid].zaxistype       = UNDEFID;
      ncvars[ncvarid].xdim            = UNDEFID;
      ncvars[ncvarid].ydim            = UNDEFID;
      ncvars[ncvarid].zdim            = UNDEFID;
      ncvars[ncvarid].xvarid          = UNDEFID;
      ncvars[ncvarid].yvarid          = UNDEFID;
      ncvars[ncvarid].zvarid          = UNDEFID;
      ncvars[ncvarid].tvarid          = UNDEFID;
765
      ncvars[ncvarid].psvarid         = UNDEFID;
766
      ncvars[ncvarid].p0varid         = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
767
      ncvars[ncvarid].ncoordvars      = 0;
768
769
770
771
772
      for ( int i = 0; i < MAX_COORDVARS; ++i )
        ncvars[ncvarid].coordvarids[i]  = UNDEFID;
      ncvars[ncvarid].nauxvars      = 0;
      for ( int i = 0; i < MAX_AUXVARS; ++i )
        ncvars[ncvarid].auxvarids[i]  = UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
773
774
775
776
777
      ncvars[ncvarid].cellarea        = UNDEFID;
      ncvars[ncvarid].tableID         = UNDEFID;
      ncvars[ncvarid].xtype           = 0;
      ncvars[ncvarid].ndims           = 0;
      ncvars[ncvarid].gmapid          = UNDEFID;
778
779
      ncvars[ncvarid].vctsize         = 0;
      ncvars[ncvarid].vct             = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
780
      ncvars[ncvarid].truncation      = 0;
781
      ncvars[ncvarid].position        = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
782
      ncvars[ncvarid].positive        = 0;
783
784
      ncvars[ncvarid].chunked         = 0;
      ncvars[ncvarid].chunktype       = UNDEFID;
785
786
      ncvars[ncvarid].defmissval      = false;
      ncvars[ncvarid].deffillval      = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
787
      ncvars[ncvarid].missval         = 0;
788
      ncvars[ncvarid].fillval         = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
789
790
791
792
793
794
      ncvars[ncvarid].addoffset       = 0;
      ncvars[ncvarid].scalefactor     = 1;
      ncvars[ncvarid].name[0]         = 0;
      ncvars[ncvarid].longname[0]     = 0;
      ncvars[ncvarid].stdname[0]      = 0;
      ncvars[ncvarid].units[0]        = 0;
795
      ncvars[ncvarid].extra[0]        = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
796
797
798
      ncvars[ncvarid].natts           = 0;
      ncvars[ncvarid].atts            = NULL;
      ncvars[ncvarid].deflate         = 0;
799
800
      ncvars[ncvarid].lunsigned       = false;
      ncvars[ncvarid].lvalidrange     = false;
Deike Kleberg's avatar
Deike Kleberg committed
801
802
      ncvars[ncvarid].validrange[0]   = VALIDMISS;
      ncvars[ncvarid].validrange[1]   = VALIDMISS;
803
      ncvars[ncvarid].ensdata         = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
804
805
806
    }
}

807
static
Thomas Jahns's avatar
Thomas Jahns committed
808
void cdfSetVar(ncvar_t *ncvars, int ncvarid, short isvar)
809
810
811
{
  if ( ncvars[ncvarid].isvar != UNDEFID &&
       ncvars[ncvarid].isvar != isvar   &&
Uwe Schulzweida's avatar
Uwe Schulzweida committed
812
       ncvars[ncvarid].warn  == false )
813
814
815
816
    {
      if ( ! ncvars[ncvarid].ignore )
        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
817
      ncvars[ncvarid].warn = true;
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
      isvar = FALSE;
    }

  ncvars[ncvarid].isvar = isvar;
}

static
void cdfSetDim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
{
  if ( ncvars[ncvarid].dimtype[dimid] != UNDEFID &&
       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;
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
837
static
838
bool isLonAxis(const char *units, const char *stdname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
839
{
840
  bool status = false;
841
  char lc_units[16];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
842

843
844
845
  memcpy(lc_units, units, 15);
  lc_units[15] = 0;
  strtolower(lc_units);
846

847
848
  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
        (memcmp(stdname, "grid_longitude", 14) == 0 || memcmp(stdname, "longitude", 9) == 0)) )
849
    {
850
      status = true;
851
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
852

853
  if ( status == false &&
854
855
       memcmp(stdname, "grid_latitude", 13) && memcmp(stdname, "latitude", 8) &&
       memcmp(lc_units, "degree", 6) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
856
    {
857
858
859
      int ioff = 6;
      if ( lc_units[ioff] == 's' ) ioff++;
      if ( lc_units[ioff] == '_' ) ioff++;
860
      if ( lc_units[ioff] == 'e' ) status = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
861
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
862

863
  return status;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
864
865
866
}

static
867
bool isLatAxis(const char *units, const char *stdname)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
868
{
869
  bool status = false;
870
  char lc_units[16];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
871

872
873
874
  memcpy(lc_units, units, 15);
  lc_units[15] = 0;
  strtolower(lc_units);
875

876
877
  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
        (memcmp(stdname, "grid_latitude", 13) == 0 || memcmp(stdname, "latitude", 8) == 0)) )
878
    {
879
      status = true;
880
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
881

882
  if ( status == false &&
883
884
       memcmp(stdname, "grid_longitude", 14) && memcmp(stdname, "longitude", 9) &&
       memcmp(lc_units, "degree", 6) == 0 )
885
    {
886
887
888
      int ioff = 6;
      if ( lc_units[ioff] == 's' ) ioff++;
      if ( lc_units[ioff] == '_' ) ioff++;
889
      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = true;
890
891
    }

892
  return status;
893
894
895
}

static
896
bool isDBLAxis(/*const char *units,*/ const char *longname)
897
{
898
  bool status = false;
899
900
901
902
903

  if ( strcmp(longname, "depth below land")         == 0 ||
       strcmp(longname, "depth_below_land")         == 0 ||
       strcmp(longname, "levels below the surface") == 0 )
    {
904
905
906
907
908
      /*
      if ( strcmp(ncvars[ncvarid].units, "cm") == 0 ||
           strcmp(ncvars[ncvarid].units, "dm") == 0 ||
           strcmp(ncvars[ncvarid].units, "m")  == 0 )
      */
909
        status = true;
910
911
    }

912
  return status;
913
914
}

915
static
916
bool unitsIsHeight(const char *units)
917
{
Uwe Schulzweida's avatar