stream_cdf_i.c 142 KB
Newer Older
1
#ifdef HAVE_CONFIG_H
2
#include "config.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
3
4
#endif

5
6
#ifdef HAVE_LIBNETCDF

Uwe Schulzweida's avatar
Uwe Schulzweida committed
7
#include <ctype.h>
8
#include <limits.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
9

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


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

26
27
28
#define  POSITIVE_UP    1
#define  POSITIVE_DOWN  2

Uwe Schulzweida's avatar
Uwe Schulzweida committed
29
typedef struct {
30
  int     dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
31
32
33
  int     ncvarid;
  int     dimtype;
  size_t  len;
34
  char    name[CDI_MAX_NAME];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
35
}
36
ncdim_t;
37

38
39
40
#define  MAX_COORDVARS  4
#define  MAX_AUXVARS    4

Uwe Schulzweida's avatar
Uwe Schulzweida committed
41
typedef struct {
42
  int      ncid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
43
44
  int      isvar;
  bool     ignore;
45
46
  bool     isx;
  bool     isy;
47
  bool     isc;
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      param;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
57
  int      code;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
58
  int      tabnum;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
59
60
61
  int      bounds;
  int      gridID;
  int      zaxisID;
62
  int      timetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
63
64
65
66
67
68
69
  int      gridtype;
  int      zaxistype;
  int      xdim;
  int      ydim;
  int      zdim;
  int      xvarid;
  int      yvarid;
70
  int      rpvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
71
  int      zvarid;
72
  int      cvarids[MAX_COORDVARS];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
73
  int      tvarid;
74
  int      psvarid;
75
  int      p0varid;
76
  int      ncoordvars;
77
78
79
  int      coordvarids[MAX_COORDVARS];
  int      nauxvars;
  int      auxvarids[MAX_AUXVARS];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
80
81
82
  int      cellarea;
  int      tableID;
  int      truncation;
83
  int      position;
84
  int      numLPE;
85
86
  bool     defmissval;
  bool     deffillval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
87
88
89
  int      xtype;
  int      gmapid;
  int      positive;
90
  int      ndims;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
91
92
  int      dimids[8];
  int      dimtype[8];
93
  size_t   chunks[8];
94
95
  int      chunked;
  int      chunktype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
96
  int      natts;
97
  int      deflate;
98
99
  bool     lunsigned;
  bool     lvalidrange;
Thomas Jahns's avatar
Thomas Jahns committed
100
  int     *atts;
101
102
  size_t   vctsize;
  double  *vct;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
103
  double   missval;
104
  double   fillval;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
105
106
  double   addoffset;
  double   scalefactor;
Deike Kleberg's avatar
Deike Kleberg committed
107
  double   validrange[2];
108
109
110
111
  char     name[CDI_MAX_NAME];
  char     longname[CDI_MAX_NAME];
  char     stdname[CDI_MAX_NAME];
  char     units[CDI_MAX_NAME];
112
  char     extra[CDI_MAX_NAME];
113
114
115
  int      typeOfEnsembleForecast;
  int      numberOfForecastsInEnsemble;
  int      perturbationNumber;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
116
}
117
118
ncvar_t;

119
120

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
127
  if ( *ptu ) sscanf(ptu, "%d-%d-%d %d:%d:%d", &v1, &v2, &v3, &hour, &minute, &second);
128
129
130
131
132
133
134
135
136
137

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
138
139
140
static
int scanTimeUnit(const char *unitstr)
{
141
142
143
  const size_t len = strlen(unitstr);
  const int timeunit = get_timeunit(len, unitstr);
  if ( timeunit == -1 ) Message("Unsupported TIMEUNIT: %s!", unitstr);
144
  return timeunit;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
145
146
}

147
148
149
static
void setForecastTime(const char *timestr, taxis_t *taxis)
{
150
  const size_t len = strlen(timestr);
Thomas Jahns's avatar
Thomas Jahns committed
151
152
153
154
  if ( len != 0 )
    scanTimeString(timestr, &taxis->fdate, &taxis->ftime);
  else
    taxis->fdate = taxis->ftime = 0;
155
156
157
158
159
}

static
int setBaseTime(const char *timeunits, taxis_t *taxis)
{
160
  int taxistype = TAXIS_ABSOLUTE;
161
162
  int64_t rdate = -1;
  int rtime = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
163

164
  size_t len = strlen(timeunits);
165
166
  while ( isspace(*timeunits) && len ) { timeunits++; len--; }

Thomas Jahns's avatar
Thomas Jahns committed
167
  char *restrict tu = (char *)Malloc((len+1) * sizeof(char));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
168

Thomas Jahns's avatar
Thomas Jahns committed
169
170
  for ( size_t i = 0; i < len; i++ ) tu[i] = (char)tolower((int)timeunits[i]);
  tu[len] = 0;
171

Thomas Jahns's avatar
Thomas Jahns committed
172
  int timeunit = get_timeunit(len, tu);
173
  if ( timeunit == -1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
174
    {
175
      Message("Unsupported TIMEUNIT: %s!", timeunits);
176
      return 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
178
    }

Thomas Jahns's avatar
Thomas Jahns committed
179
  size_t pos = 0;
180
  while ( pos < len && !isspace(tu[pos]) ) ++pos;
Thomas Jahns's avatar
Thomas Jahns committed
181
  if ( tu[pos] )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
182
    {
Thomas Jahns's avatar
Thomas Jahns committed
183
      while ( isspace(tu[pos]) ) ++pos;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
184

185
      if ( strStartsWith(tu+pos, "since") )
186
        taxistype = TAXIS_RELATIVE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
187

188
      while ( pos < len && !isspace(tu[pos]) ) ++pos;
Thomas Jahns's avatar
Thomas Jahns committed
189
      if ( tu[pos] )
190
        {
Thomas Jahns's avatar
Thomas Jahns committed
191
          while ( isspace(tu[pos]) ) ++pos;
192

193
          if ( taxistype == TAXIS_ABSOLUTE )
194
            {
195
              if ( timeunit == TUNIT_DAY )
196
                {
197
                  if ( !strStartsWith(tu+pos, "%y%m%d.%f") )
198
199
200
201
                    {
                      Message("Unsupported format %s for TIMEUNIT day!", tu+pos);
                      timeunit = -1;
                    }
202
                }
203
              else if ( timeunit == TUNIT_MONTH )
204
                {
205
                  if ( !strStartsWith(tu+pos, "%y%m.%f") )
206
207
208
209
                    {
                      Message("Unsupported format %s for TIMEUNIT month!", tu+pos);
                      timeunit = -1;
                    }
210
211
                }
            }
212
          else if ( taxistype == TAXIS_RELATIVE )
213
            {
Thomas Jahns's avatar
Thomas Jahns committed
214
              scanTimeString(tu+pos, &rdate, &rtime);
215

216
217
              taxis->rdate = rdate;
              taxis->rtime = rtime;
218

219
              if ( CDI_Debug )
220
                Message("rdate = %lld  rtime = %d", rdate, rtime);
221
            }
222
        }
223
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
224

225
  taxis->type = taxistype;
226
  taxis->unit = timeunit;
Deike Kleberg's avatar
Deike Kleberg committed
227

228
  Free(tu);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
229

230
  if ( CDI_Debug )
231
    Message("taxistype = %d  unit = %d", taxistype, timeunit);
Deike Kleberg's avatar
Deike Kleberg committed
232

233
234
  return 0;
}
235

236
static
237
bool xtypeIsText(int xtype)
238
{
239
  const bool isText = (xtype == NC_CHAR)
240
#ifdef HAVE_NETCDF4
Uwe Schulzweida's avatar
Uwe Schulzweida committed
241
    || (xtype == NC_STRING)
242
243
244
245
246
247
248
249
#endif
    ;
  return isText;
}

static
bool xtypeIsFloat(nc_type xtype)
{
250
  const bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
251
252
253
254
255
256
  return isFloat;
}

static
bool xtypeIsInt(nc_type xtype)
{
257
  const bool isInt = xtype == NC_SHORT || xtype == NC_INT
258
            || xtype == NC_BYTE
259
#ifdef HAVE_NETCDF4
260
261
262
263
264
265
266
267
268
269
270
271
272
            || xtype == NC_USHORT || xtype == NC_UINT
            || xtype == NC_UBYTE
#endif
             ;

  return isInt;
}

static
int cdfInqDatatype(int xtype, bool lunsigned)
{
  int datatype = -1;

273
#ifdef HAVE_NETCDF4
274
275
276
277
  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
#endif

  if      ( xtype == NC_BYTE   )  datatype = CDI_DATATYPE_INT8;
278
  else if ( xtype == NC_CHAR   )  datatype = CDI_DATATYPE_UINT8;
279
280
281
282
  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;
283
#ifdef HAVE_NETCDF4
284
285
286
287
288
289
290
  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;
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
291

292
293
294
295
296
297
  return datatype;
}

static
void cdfGetAttInt(int fileID, int ncvarid, const char *attname, size_t attlen, int *attint)
{
298
  *attint = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
299

300
301
  nc_type atttype;
  size_t nc_attlen;
302
303
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Deike Kleberg's avatar
Deike Kleberg committed
304

305
  if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) )
306
    {
307
      const bool lalloc = nc_attlen > attlen;
308
      int *pintatt = lalloc ? (int *)(Malloc(nc_attlen*sizeof(int))) : attint;
309
      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
310
      if ( lalloc )
311
        {
312
          memcpy(attint, pintatt, attlen*sizeof(int));
313
          Free(pintatt);
314
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
315
316
317
    }
}

318
static
319
void cdfGetAttDouble(int fileID, int ncvarid, char *attname, size_t attlen, double *attdouble)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
320
{
321
  *attdouble = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
322

323
324
  nc_type atttype;
  size_t nc_attlen;
325
326
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
327

328
  if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
329
    {
330
      const bool lalloc = nc_attlen > attlen;
331
      double *pdoubleatt = lalloc ? (double*)Malloc(nc_attlen*sizeof(double)) : attdouble;
332
      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
333
      if ( lalloc )
334
        {
335
          memcpy(attdouble, pdoubleatt, attlen*sizeof(double));
336
337
338
339
          Free(pdoubleatt);
        }
    }
}
340

341
static
342
343
344
345
346
bool cdfCheckAttText(int fileID, int ncvarid, const char *attname)
{
  bool status = false;
  nc_type atttype;

347
348
  const int status_nc = nc_inq_atttype(fileID, ncvarid, attname, &atttype);
  if ( status_nc == NC_NOERR && (atttype == NC_CHAR
349
#ifdef HAVE_NETCDF4
350
351
352
353
354
355
356
357
358
359
360
           || atttype == NC_STRING
#endif
           ) )
    {
      status = true;
    }

  return status;
}

static
361
void cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, char *atttext)
362
{
363
364
  atttext[0] = 0;

365
366
367
368
  nc_type atttype;
  size_t nc_attlen;
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
369

370
  if ( atttype == NC_CHAR )
371
    {
372
373
374
375
      char attbuf[65636];
      if ( nc_attlen < sizeof(attbuf) )
        {
          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
376

377
          if ( nc_attlen > (attlen-1) ) nc_attlen = (attlen-1);
378

379
380
381
          attbuf[nc_attlen++] = 0;
          memcpy(atttext, attbuf, nc_attlen);
        }
382
    }
383
#ifdef HAVE_NETCDF4
384
  else if ( atttype == NC_STRING )
385
    {
386
      if ( nc_attlen == 1 )
387
        {
388
389
          char *attbuf = NULL;
          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
390

391
          size_t ssize = strlen(attbuf) + 1;
392
          if ( ssize > attlen ) ssize = attlen;
393
394
395
396
          memcpy(atttext, attbuf, ssize);
          atttext[ssize - 1] = 0;
          Free(attbuf);
        }
397
    }
398
399
#endif
}
400

401

402
void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
403
{
404
405
  const bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
  const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
406

407
  if ( laddoffset && lscalefactor )
408
    {
409
      for (size_t i = 0; i < size; ++i) data[i] = data[i] * scalefactor + addoffset;
410
411
412
    }
  else if (lscalefactor)
    {
413
      for (size_t i = 0; i < size; ++i) data[i] *= scalefactor;
414
415
416
    }
  else if (laddoffset)
    {
417
      for (size_t i = 0; i < size; ++i) data[i] += addoffset;
418
419
    }
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
420

421
422
static
void cdfCreateRecords(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
423
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
424
  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
425

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

428
429
  int vlistID  = streamptr->vlistID;

430
431
432
  tsteps_t* sourceTstep = streamptr->tsteps;
  tsteps_t* destTstep = sourceTstep + tsID;

433
434
  const int nvars = vlistNvars(vlistID);
  const int nrecs = vlistNrecs(vlistID);
435
436
  if ( nrecs <= 0 ) return;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
437
438
  if ( tsID == 0 )
    {
439
      const int nvrecs = nrecs; /* use all records at first timestep */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
440

Uwe Schulzweida's avatar
Uwe Schulzweida committed
441
      streamptr->nrecs += nrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
442

443
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
444
445
446
      destTstep->nrecs      = nrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
447
      destTstep->curRecID   = CDI_UNDEFID;
448
      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
449
      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
450

451
      record_t *records = destTstep->records;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
452

453
      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
454
        {
455
456
          const int zaxisID = vlistInqVarZaxis(vlistID, varID);
          const int nlev    = zaxisInqSize(zaxisID);
457
          for ( int levelID = 0; levelID < nlev; levelID++ )
458
459
            {
              recordInitEntry(&records[recID]);
460
461
              records[recID].varID   = (short)varID;
              records[recID].levelID = (short)levelID;
462
463
464
              recID++;
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
465
466
467
    }
  else if ( tsID == 1 )
    {
468
469
      int nvrecs = 0;
      for ( int varID = 0; varID < nvars; varID++ )
470
        {
471
          if ( vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT )
472
            {
473
              int zaxisID = vlistInqVarZaxis(vlistID, varID);
474
475
476
              nvrecs += zaxisInqSize(zaxisID);
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
477

Uwe Schulzweida's avatar
Uwe Schulzweida committed
478
      streamptr->nrecs += nvrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
479

480
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
481
482
483
      destTstep->nrecs      = nvrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
484
      destTstep->curRecID   = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
485

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

488
      if ( nvrecs )
489
        {
490
          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
491
          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
492
            {
493
              int varID = destTstep->records[recID].varID;
494
              if ( vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT )
495
                {
496
                  destTstep->recIDs[vrecID++] = recID;
497
498
499
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
500
501
502
    }
  else
    {
503
      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
504

505
      const int nvrecs = streamptr->tsteps[1].nrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
506

Uwe Schulzweida's avatar
Uwe Schulzweida committed
507
      streamptr->nrecs += nvrecs;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
508

509
      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
510
511
512
      destTstep->nrecs      = nvrecs;
      destTstep->nallrecs   = nrecs;
      destTstep->recordSize = nrecs;
513
      destTstep->curRecID   = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
514

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

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

519
      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
520
521
522
    }
}

523
static
524
int cdf_time_dimid(int fileID, int ndims, int nvars, ncdim_t *ncdims)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
525
{
526
527
  char dimname[CDI_MAX_NAME];

528
  for ( int dimid = 0; dimid < ndims; ++dimid )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
529
    {
530
      dimname[0] = 0;
531
      cdf_inq_dimname(fileID, ncdims[dimid].dimid, dimname);
532
      if ( strIsEqual(dimname, "time") || strIsEqual(dimname, "Time") ) return dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
533
534
    }

535
  for ( int varid = 0; varid < nvars; ++varid )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
536
    {
537
      nc_type xtype;
538
      int nvdims, nvatts, dimids[9];
539
      cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
540
541
542
543
544
545
546
547
      for ( int i = 0; i < nvdims; ++i )
        for ( int dimid = 0; dimid < ndims; ++dimid )
          if ( ncdims[dimid].dimid == dimids[i] )
            {
              dimids[i] = dimid;
              break;
            }

548
      if ( nvdims == 1 )
549
        {
550
551
          char sbuf[CDI_MAX_NAME];
          for ( int iatt = 0; iatt < nvatts; ++iatt )
552
            {
553
              sbuf[0] = 0;
554
555
              cdf_inq_attname(fileID, varid, iatt, sbuf);
              if ( strncmp(sbuf, "units", 5) == 0 )
556
                {
557
                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
558
                  strToLower(sbuf);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
559

560
                  if ( is_time_units(sbuf) ) return dimids[0];
561
562
563
                }
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
564
565
    }

566
  return CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
567
568
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
569
static
570
void init_ncdims(long ndims, ncdim_t *ncdims)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
571
{
572
  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
573
    {
574
      ncdims[ncdimid].dimid        = CDI_UNDEFID;
575
576
      ncdims[ncdimid].ncvarid      = CDI_UNDEFID;
      ncdims[ncdimid].dimtype      = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
577
578
579
580
581
582
      ncdims[ncdimid].len          = 0;
      ncdims[ncdimid].name[0]      = 0;
    }
}

static
583
void init_ncvars(long nvars, ncvar_t *ncvars)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
584
{
585
  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
Deike Kleberg's avatar
Deike Kleberg committed
586
    {
587
588
      ncvars[ncvarid].ncid            = CDI_UNDEFID;
      ncvars[ncvarid].isvar           = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
589
      ncvars[ncvarid].ignore          = false;
590
591
      ncvars[ncvarid].isx             = false;
      ncvars[ncvarid].isy             = false;
592
      ncvars[ncvarid].isc             = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
593
594
595
596
597
      ncvars[ncvarid].islon           = false;
      ncvars[ncvarid].islat           = false;
      ncvars[ncvarid].islev           = false;
      ncvars[ncvarid].istime          = false;
      ncvars[ncvarid].warn            = false;
598
      ncvars[ncvarid].calendar        = false;
599
      ncvars[ncvarid].climatology     = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
600
      ncvars[ncvarid].lformulaterms   = false;
601
      ncvars[ncvarid].timetype        = TIME_CONSTANT;
602
603
      ncvars[ncvarid].param           = CDI_UNDEFID;
      ncvars[ncvarid].code            = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
604
      ncvars[ncvarid].tabnum          = 0;
605
606
607
608
609
610
611
612
613
614
      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;
615
      ncvars[ncvarid].rpvarid         = CDI_UNDEFID;
616
617
618
619
      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
620
      ncvars[ncvarid].ncoordvars      = 0;
621
      for ( int i = 0; i < MAX_COORDVARS; ++i )
622
623
624
625
        {
          ncvars[ncvarid].coordvarids[i]  = CDI_UNDEFID;
          ncvars[ncvarid].cvarids[i]      = CDI_UNDEFID;
        }
626
627
      ncvars[ncvarid].nauxvars      = 0;
      for ( int i = 0; i < MAX_AUXVARS; ++i )
628
629
630
        ncvars[ncvarid].auxvarids[i]  = CDI_UNDEFID;
      ncvars[ncvarid].cellarea        = CDI_UNDEFID;
      ncvars[ncvarid].tableID         = CDI_UNDEFID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
631
632
      ncvars[ncvarid].xtype           = 0;
      ncvars[ncvarid].ndims           = 0;
633
      ncvars[ncvarid].gmapid          = CDI_UNDEFID;
634
635
      ncvars[ncvarid].vctsize         = 0;
      ncvars[ncvarid].vct             = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
636
      ncvars[ncvarid].truncation      = 0;
637
      ncvars[ncvarid].position        = 0;
638
      ncvars[ncvarid].numLPE          = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
639
      ncvars[ncvarid].positive        = 0;
640
      ncvars[ncvarid].chunked         = 0;
641
      ncvars[ncvarid].chunktype       = CDI_UNDEFID;
642
643
      ncvars[ncvarid].defmissval      = false;
      ncvars[ncvarid].deffillval      = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
644
      ncvars[ncvarid].missval         = 0;
645
      ncvars[ncvarid].fillval         = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
646
647
648
649
650
      ncvars[ncvarid].addoffset       = 0;
      ncvars[ncvarid].scalefactor     = 1;
      ncvars[ncvarid].natts           = 0;
      ncvars[ncvarid].atts            = NULL;
      ncvars[ncvarid].deflate         = 0;
651
652
      ncvars[ncvarid].lunsigned       = false;
      ncvars[ncvarid].lvalidrange     = false;
Deike Kleberg's avatar
Deike Kleberg committed
653
654
      ncvars[ncvarid].validrange[0]   = VALIDMISS;
      ncvars[ncvarid].validrange[1]   = VALIDMISS;
655
656
657
      ncvars[ncvarid].typeOfEnsembleForecast      = -1;
      ncvars[ncvarid].numberOfForecastsInEnsemble = -1;
      ncvars[ncvarid].perturbationNumber          = -1;
658
659
660
661
662
      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
663
664
665
    }
}

666
static
667
void cdf_set_var(ncvar_t *ncvars, int ncvarid, short isvar)
668
{
669
  if ( ncvars[ncvarid].isvar != CDI_UNDEFID &&
670
       ncvars[ncvarid].isvar != isvar   &&
Uwe Schulzweida's avatar
Uwe Schulzweida committed
671
       ncvars[ncvarid].warn  == false )
672
673
674
675
    {
      if ( ! ncvars[ncvarid].ignore )
        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
676
      ncvars[ncvarid].warn = true;
677
678
679
680
681
682
683
      isvar = FALSE;
    }

  ncvars[ncvarid].isvar = isvar;
}

static
684
void cdf_set_dim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
685
{
686
  if ( ncvars[ncvarid].dimtype[dimid] != CDI_UNDEFID &&
687
688
689
690
691
692
693
694
695
696
       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
697
void scan_hybrid_formulaterms(int ncid, int ncfvarid, int *avarid, int *bvarid, int *psvarid, int *p0varid)
698
{
699
  *avarid  = -1;
700
701
  *bvarid  = -1;
  *psvarid = -1;
702
  *p0varid = -1;
703

704
  char attstring[1024];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
705
706
  cdfGetAttText(ncid, ncfvarid, "formula_terms", sizeof(attstring), attstring);
  char *pstring = attstring;
707

708
  bool lstop = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
709
  for ( int i = 0; i < 4; i++ )
710
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
711
712
713
714
715
716
717
718
719
720
721
722
723
724
      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;

725
      int dimvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
726
727
      int status_nc = nc_inq_varid(ncid, varname, &dimvarid);
      if ( status_nc == NC_NOERR )
728
        {
729
730
731
732
733
          if      ( strIsEqual(tagname, "ap:") ) *avarid  = dimvarid;
          else if ( strIsEqual(tagname, "a:")  ) *avarid  = dimvarid;
          else if ( strIsEqual(tagname, "b:")  ) *bvarid  = dimvarid;
          else if ( strIsEqual(tagname, "ps:") ) *psvarid = dimvarid;
          else if ( strIsEqual(tagname, "p0:") ) *p0varid = dimvarid;
734
        }
735
      else if ( !strIsEqual(tagname, "ps:") )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
736
737
738
739
740
        {
          Warning("%s - %s", nc_strerror(status_nc), varname);
        }

      if ( lstop ) break;
741
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
742
743
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
static
void readVCT(int ncid, int ndims2, size_t dimlen, size_t dimlen2, int avarid2, int bvarid2, double *vct)
{
  double *abuf = (double*) Malloc(dimlen*2*sizeof(double));
  double *bbuf = (double*) Malloc(dimlen*2*sizeof(double));
  cdf_get_var_double(ncid, avarid2, abuf);
  cdf_get_var_double(ncid, bvarid2, bbuf);

  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
    {
      for ( size_t i = 0; i < dimlen2; ++i )
        {
          vct[i] = abuf[i];
          vct[i+dimlen+1] = bbuf[i];
        }
    }

  Free(abuf);
  Free(bbuf);
}

775
static
776
bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
777
{
778
  bool status = false;
779
780
  ncvar_t *ncvar = &ncvars[ncvarid];

781
  if ( strIsEqual(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") )
782
    {
783
      CDI_convention = CDI_CONVENTION_CF;
784

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

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

812
813
814
              const int ndims2 = ncvars[avarid2].ndims;
              const int dimid2 = ncvars[avarid2].dimids[0];
              const size_t dimlen2 = ncdims[dimid2].len;
815
816
817

              if ( (ndims2 == 2 && dimid == ncvars[avarid2].dimids[0] ) ||
                   (ndims2 == 1 && dimlen ==