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

5
//#define TEST_GROUPS 1
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6

Uwe Schulzweida's avatar
Uwe Schulzweida committed
7
8
9
10
11
12
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <float.h>

13
14
15
16
17
#if  defined  (HAVE_LIBNETCDF)
#  include <netcdf.h>
#endif


Uwe Schulzweida's avatar
Uwe Schulzweida committed
18
19
20
21
#include "dmemory.h"

#include "cdi.h"
#include "basetime.h"
22
#include "gaussgrid.h"
23
#include "cdi_int.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
24
25
26
27
28
#include "stream_cdf.h"
#include "cdf_int.h"
#include "varscan.h"
#include "vlist.h"

29
30
//#define PROJECTION_TEST

Uwe Schulzweida's avatar
Uwe Schulzweida committed
31
32
33
34
#undef  UNDEFID
#define UNDEFID  CDI_UNDEFID


35
36
void    vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);

37
38
void cdfDefGlobalAtts(stream_t *streamptr);
void cdfDefLocalAtts(stream_t *streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
39
40
41
42
43
44
45


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

46
47
48
#define  POSITIVE_UP    1
#define  POSITIVE_DOWN  2

Uwe Schulzweida's avatar
Uwe Schulzweida committed
49
50
51
52
typedef struct {
  int     ncvarid;
  int     dimtype;
  size_t  len;
53
  char    name[CDI_MAX_NAME];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
54
}
55
ncdim_t;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
56

57
58
59
#define  MAX_COORDVARS  4
#define  MAX_AUXVARS    4

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

127
#ifdef HAVE_LIBNETCDF
128
129
130
131
static
void strtolower(char *str)
{
  if ( str )
132
    for (size_t i = 0; str[i]; ++i)
133
      str[i] = (char)tolower((int)str[i]);
134
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
135

136
static
137
int get_timeunit(size_t len, const char *ptu)
138
139
{
  int timeunit = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
140

141
142
143
144
145
146
147
148
149
150
  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;
    }
151
152
153
154
  else if ( len == 1 )
    {
      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
    }
155
156
157
158
159
160

  return (timeunit);
}

static
int isTimeUnits(const char *timeunits)
161
162
163
164
165
166
167
168
169
170
171
172
173
174
{
  int status = 0;

  if ( 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 ) status = 1;

  return (status);
}

static
int isTimeAxisUnits(const char *timeunits)
175
176
177
178
179
180
{
  char *ptu, *tu;
  int timetype = -1;
  int timeunit;
  int status = FALSE;

181
182
183
  size_t len = strlen(timeunits);
  tu = xmalloc((len+1)*sizeof(char));
  memcpy(tu, timeunits, (len+1) * sizeof(char));
184
185
  ptu = tu;

186
  for (size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int)ptu[i]);
187
188
189
190
191
192
193

  timeunit = get_timeunit(len, ptu);
  if ( timeunit != -1 )
    {

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

197
198
199
200
          if ( memcmp(ptu, "as", 2) == 0 )
            timetype = TAXIS_ABSOLUTE;
          else if ( memcmp(ptu, "since", 5) == 0 )
            timetype = TAXIS_RELATIVE;
201

202
203
          if ( timetype != -1 ) status = TRUE;
        }
204
205
206
207
208
209
210
211
    }

  free(tu);

  return (status);
}

static
212
void scanTimeString(const char *ptu, int *rdate, int *rtime)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
213
214
215
{
  int year, month, day;
  int hour = 0, minute = 0, second = 0;
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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
  int v1, v2, v3;

  *rdate = 0;
  *rtime = 0;

  v1 = atoi(ptu);
  if ( v1 < 0 ) ptu++;
  while ( isdigit((int) *ptu) ) ptu++;
  v2 = atoi(++ptu);
  while ( isdigit((int) *ptu) ) ptu++;
  v3 = atoi(++ptu);
  while ( isdigit((int) *ptu) ) ptu++;

  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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
static
int scanTimeUnit(const char *unitstr)
{
  int timeunit = -1;
  int len;

  len = (int) strlen(unitstr);
  timeunit = get_timeunit(len, unitstr);
  if ( timeunit == -1 )
    Message("Unsupported TIMEUNIT: %s!", unitstr);

  return (timeunit);
}

273
274
275
static
void setForecastTime(const char *timestr, taxis_t *taxis)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
276
277
278
279
280
281
  int len;

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

  len = (int) strlen(timestr);
282
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)
{
  char *ptu, *tu;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
295
296
  int timetype = TAXIS_ABSOLUTE;
  int rdate = -1, rtime = -1;
297
  int timeunit;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
298

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

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

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

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

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

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
        {
          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 )
                {
                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
                  timeunit = -1;
                }
            }
          else if ( timetype == TAXIS_RELATIVE )
            {
343
              scanTimeString(ptu, &rdate, &rtime);
344
345
346
347
348

              (*taxis).rdate = rdate;
              (*taxis).rtime = rtime;

              if ( CDI_Debug )
Deike Kleberg's avatar
Deike Kleberg committed
349
                Message("rdate = %d  rtime = %d", rdate, rtime);
350
351
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
352
353
354
355
356
    }

  (*taxis).type = timetype;
  (*taxis).unit = timeunit;

357
358
  free(tu);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
359
  if ( CDI_Debug )
360
    Message("timetype = %d  unit = %d", timetype, timeunit);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
361
362
363
364

  return (0);
}

365
366
static
void cdfGetAttInt(int fileID, int ncvarid, char *attname, int attlen, int *attint)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
367
{
368
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
369
370
  int *pintatt;

371
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
372

373
  if ( (int)nc_attlen > attlen )
374
    pintatt = (int *) malloc(nc_attlen * sizeof (int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
375
  else
376
    pintatt = attint;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
377
378
379

  cdf_get_att_int(fileID, ncvarid, attname, pintatt);

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
387
388
static
void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
389
{
390
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
391
392
  double *pdoubleatt;

393
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
394

395
  if ( (int)nc_attlen > attlen )
396
    pdoubleatt = (double *) malloc(nc_attlen * sizeof (double));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
397
  else
398
    pdoubleatt = attdouble;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
399
400
401

  cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);

402
403
  if ( (int)nc_attlen > attlen )
    {
404
      memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
405
406
      free(pdoubleatt);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
407
408
}

409
410
static
void cdfGetAttText(int fileID, int ncvarid, char *attname, int attlen, char *atttext)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
411
{
412
  nc_type atttype;
413
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
414

415
  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
416
  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
417

418
  if ( atttype == NC_CHAR )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
419
    {
420
421
422
423
      char attbuf[65636];
      if ( nc_attlen < sizeof(attbuf) )
        {
          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
424

425
          attbuf[nc_attlen++] = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
426

427
          if ( (int) nc_attlen > attlen ) nc_attlen = (size_t)attlen;
428
429
430
431
432
433
          memcpy(atttext, attbuf, nc_attlen);
        }
      else
        {
          atttext[0] = 0;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
434
    }
435
436
#if  defined  (HAVE_NETCDF4)
  else if ( atttype == NC_STRING )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
437
    {
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
      if ( nc_attlen == 1 )
        {
          char *attbuf = NULL;
          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);

          int slen = (int) strlen(attbuf);
          slen++;

          if ( slen > attlen ) slen = attlen;
          memcpy(atttext, attbuf, slen);

          free(attbuf);
        }
      else
        {
          atttext[0] = 0;
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
455
    }
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#endif
}

static
int xtypeIsText(int xtype)
{
  int isText = FALSE;

  if ( xtype == NC_CHAR )
    isText = TRUE;
#if  defined  (HAVE_NETCDF4)
  else if ( xtype == NC_STRING )
    isText = TRUE;
#endif

  return (isText);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
472
473
}

474
475
476
477
static
int xtypeIsFloat(int xtype)
{
  int isFloat = FALSE;
478

479
  if ( xtype == NC_FLOAT || xtype == NC_DOUBLE ) isFloat = TRUE;
480

481
482
483
  return isFloat;
}

484
static
Deike Kleberg's avatar
Deike Kleberg committed
485
int cdfInqDatatype(int xtype, int lunsigned)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
486
{
487
  int datatype = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
488

489
#if  defined  (HAVE_NETCDF4)
Deike Kleberg's avatar
Deike Kleberg committed
490
  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
491
#endif
Deike Kleberg's avatar
Deike Kleberg committed
492

Uwe Schulzweida's avatar
Uwe Schulzweida committed
493
494
495
496
  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;
497
  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
498
  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
Deike Kleberg's avatar
Deike Kleberg committed
499
#if  defined  (HAVE_NETCDF4)
500
  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
501
502
503
504
505
506
  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
507
508
509
510

  return (datatype);
}

511
static
512
int cdfDefDatatype(int datatype, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
513
514
515
{
  int xtype;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
516
  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
517
518
519
520
521
522
523
    Error("CDI/netCDF library does not support complex numbers!");

  if ( filetype == FILETYPE_NC4 )
    {
      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
Deike Kleberg's avatar
Deike Kleberg committed
524
#if  defined  (HAVE_NETCDF4)
525
526
527
528
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_UBYTE;
      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_USHORT;
      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_UINT;
#else
529
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
530
531
532
533
534
535
536
537
538
539
540
      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
#endif
      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
      else                                    xtype = NC_FLOAT;
    }
  else
    {
      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
541
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
542
543
544
545
546
      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
      else                                    xtype = NC_FLOAT;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
547

Uwe Schulzweida's avatar
Uwe Schulzweida committed
548
549
550
  return (xtype);
}

551
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
552
553
554
void defineAttributes(int vlistID, int varID, int fileID, int ncvarID)
{
  int natts, iatt;
555
  int atttype, attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
556
  size_t len;
557
  char attname[1024];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
558
559
560
561
562

  vlistInqNatts(vlistID, varID, &natts);

  for ( iatt = 0; iatt < natts; iatt++ )
    {
563
      vlistInqAtt(vlistID, varID, iatt, attname, &atttype, &attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
564

565
566
      if ( attlen == 0 ) continue;

567
      if ( atttype == DATATYPE_TXT )
568
        {
569
          char *atttxt = (char *)xmalloc((size_t)attlen*sizeof(char));
Deike Kleberg's avatar
Deike Kleberg committed
570
          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
571
          len = (size_t)attlen;
572
          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
Deike Kleberg's avatar
Deike Kleberg committed
573
          free(atttxt);
574
575
576
        }
      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
        {
577
          int *attint = (int *)xmalloc((size_t)attlen*sizeof(int));
578
          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
579
          len = (size_t)attlen;
580
581
582
583
584
585
586
587
          if ( atttype == DATATYPE_INT16 )
            cdf_put_att_int(fileID, ncvarID, attname, NC_SHORT, len, attint);
          else
            cdf_put_att_int(fileID, ncvarID, attname, NC_INT, len, attint);
          free(attint);
        }
      else if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
        {
588
          double *attflt = (double *)xmalloc((size_t)attlen*sizeof(double));
589
          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
590
          len = (size_t)attlen;
591
592
593
594
595
596
          if ( atttype == DATATYPE_FLT32 )
            cdf_put_att_double(fileID, ncvarID, attname, NC_FLOAT, len, attflt);
          else
            cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
          free(attflt);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
597
598
599
600
    }
}
#endif

601
void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
602
{
603
  int memtype = MEMTYPE_DOUBLE;
604
  int vlistID1 = streamptr1->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
605

606
  int tsID1 = streamptr1->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
607

608
  int recID1 = streamptr1->tsteps[tsID1].curRecID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
609

610
  int ivarID = streamptr1->tsteps[tsID1].records[recID1].varID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
611

612
  int gridID = vlistInqVarGrid(vlistID1, ivarID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
613

614
  int datasize = gridInqSize(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
615
616
617
  /* bug fix for constant netCDF fields */
  if ( datasize < 1048576 ) datasize = 1048576;

618
  double *data = xmalloc((size_t)datasize * sizeof (double));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
619

620
  int nmiss;
621
622
  cdfReadRecord(streamptr1, data, &nmiss);
  cdf_write_record(streamptr2, memtype, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
623
624
625

  free(data);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
626

Uwe Schulzweida's avatar
Uwe Schulzweida committed
627
/* not used
628
int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
629
630
631
{
  int tsID, recID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
632
633
634
  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
635

636
  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
637
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
638
      streamptr->tsteps[0].curRecID = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
639
640
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
641
642
  *varID   = streamptr->tsteps[0].records[recID].varID;
  *levelID = streamptr->tsteps[0].records[recID].levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
643

Uwe Schulzweida's avatar
Uwe Schulzweida committed
644
645
  streamptr->record->varID   = *varID;
  streamptr->record->levelID = *levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
646
647

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
650
651
652
  return (recID+1);
}
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
653

Uwe Schulzweida's avatar
Uwe Schulzweida committed
654

655
void cdfDefRecord(stream_t *streamptr)
656
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
657
658
}

659
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
660
static
661
void cdfWriteGridTraj(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
662
{
663
664
  int vlistID = streamptr->vlistID;
  int fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
665

666
667
668
  int gridindex = vlistGridIndex(vlistID, gridID);
  int lonID = streamptr->xdimID[gridindex],
    latID = streamptr->ydimID[gridindex];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
669

670
671
672
673
  double xlon = gridInqXval(gridID, 0),
    xlat = gridInqYval(gridID, 0);
  int tsID = streamptr->curTsID;
  size_t index = (size_t)tsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
674
675
676
677
678

  cdf_put_var1_double(fileID, lonID, &index, &xlon);
  cdf_put_var1_double(fileID, latID, &index, &xlat);
}

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
679
static
680
void cdfReadGridTraj(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
681
{
682
683
  int vlistID = streamptr->vlistID;
  int fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
684

685
686
687
  int gridindex = vlistGridIndex(vlistID, gridID);
  int lonID = streamptr->xdimID[gridindex];
  int latID = streamptr->ydimID[gridindex];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
688

689
690
  int tsID = streamptr->curTsID;
  size_t index = (size_t)tsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
691

692
  double xlon, xlat;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
693
694
695
696
697
698
  cdf_get_var1_double(fileID, lonID, &index, &xlon);
  cdf_get_var1_double(fileID, latID, &index, &xlat);

  gridDefXvals(gridID, &xlon);
  gridDefYvals(gridID, &xlat);
}
699
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
700

701
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
702
static
703
704
void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
{
Deike Kleberg's avatar
Deike Kleberg committed
705
#if  defined  (HAVE_NETCDF4)
706
707
708
709
710
711
712
713
714
  int retval;
  /* Set chunking, shuffle, and deflate. */
  int shuffle = 1;
  int deflate = 1;

  if ( deflate_level < 1 || deflate_level > 9 ) deflate_level = 1;

  if ((retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)))
    {
715
      Error("nc_def_var_deflate failed, status = %d", retval);
716
717
718
719
720
721
722
    }
#else
  static int lwarn = TRUE;

  if ( lwarn )
    {
      lwarn = FALSE;
723
      Warning("Deflate compression failed, netCDF4 not available!");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
724
725
726
727
728
    }
#endif
}
#endif

Uwe Schulzweida's avatar
Uwe Schulzweida committed
729
#if  defined(HAVE_LIBNETCDF) && defined(NC_SZIP_NN_OPTION_MASK)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
730
731
732
733
734
static
void cdfDefVarSzip(int ncid, int ncvarid)
{
  int retval;
  /* Set options_mask and bits_per_pixel. */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
  int options_mask = NC_SZIP_NN_OPTION_MASK;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
736
737
738
739
740
  int bits_per_pixel = 16;

  if ((retval = nc_def_var_szip(ncid, ncvarid, options_mask, bits_per_pixel)))
    {
      if ( retval == NC_EINVAL )
741
742
743
744
745
746
747
        {
          static int lwarn = TRUE;

          if ( lwarn )
            {
              lwarn = FALSE;
              Warning("netCDF4/Szip compression not compiled in!");
Deike Kleberg's avatar
Deike Kleberg committed
748
            }
749
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
750
      else
751
        Error("nc_def_var_szip failed, status = %d", retval);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
752
    }
753
754
755
}
#endif

756
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
757
static
758
void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
759
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
760
  if ( streamptr->vars[varID].defmiss == FALSE )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
761
762
763
764
765
766
767
    {
      int fileID;
      int ncvarid;
      double missval;
      int vlistID;
      int xtype;

768
769
      vlistID = streamptr->vlistID;
      fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
      ncvarid = streamptr->vars[varID].ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
771
      missval = vlistInqVarMissval(vlistID, varID);
772

773
      if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
774

775
      xtype = cdfDefDatatype(dtype, streamptr->filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776

777
      if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
778

779
780
      cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
      cdf_put_att_double(fileID, ncvarid, "missing_value", (nc_type) xtype, 1, &missval);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
781

782
      if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
783

Uwe Schulzweida's avatar
Uwe Schulzweida committed
784
      streamptr->vars[varID].defmiss = TRUE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
785
786
    }
}
787
#endif
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
788

789
void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
790
791
792
793
794
{
#if  defined  (HAVE_LIBNETCDF)
  int varID;
  int levelID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
795
796
  varID   = streamptr->record->varID;
  levelID = streamptr->record->levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
797

798
  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
799

800
  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
801
802
803
#endif
}

804
void cdfReadRecord(stream_t *streamptr, double *data, int *nmiss)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
805
806
807
{
  int levelID, varID, tsID, recID, vrecID;

808
  if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
809

Uwe Schulzweida's avatar
Uwe Schulzweida committed
810
811
812
813
814
  tsID    = streamptr->curTsID;
  vrecID  = streamptr->tsteps[tsID].curRecID;
  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
  varID   = streamptr->tsteps[tsID].records[recID].varID;
  levelID = streamptr->tsteps[tsID].records[recID].levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
815

816
  cdfReadVarSliceDP(streamptr, varID, levelID, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
817
818
}

819
#if  defined  (HAVE_LIBNETCDF)
820
static
821
void cdfDefTimeValue(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
822
823
824
{
  int fileID;
  int ncvarid;
825
  taxis_t *taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
826

827
  fileID = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
828
829

  if ( CDI_Debug )
830
    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
831

Uwe Schulzweida's avatar
Uwe Schulzweida committed
832
  taxis = &streamptr->tsteps[tsID].taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
833

Uwe Schulzweida's avatar
Uwe Schulzweida committed
834
  if ( streamptr->ncmode == 1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
835
836
    {
      cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
837
      streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
838
839
    }

840
  size_t index = (size_t)tsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
841

842
  double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
843
  if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
844

Uwe Schulzweida's avatar
Uwe Schulzweida committed
845
  ncvarid = streamptr->basetime.ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
846
847
848
849
850
851
  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);

  if ( taxis->has_bounds )
    {
      size_t start[2], count[2];

Uwe Schulzweida's avatar
Uwe Schulzweida committed
852
      ncvarid = streamptr->basetime.ncvarboundsid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
853

Uwe Schulzweida's avatar
Uwe Schulzweida committed
854
      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
855
      start[0] = (size_t)tsID; count[0] = 1; start[1] = 0; count[1] = 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
856
857
      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
858
      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_ub, &streamptr->tsteps[0].taxis);
859
      start[0] = (size_t)tsID; count[0] = 1; start[1] = 1; count[1] = 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
860
861
      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
    }
862
863
864
865
866
867
868
869

  ncvarid = streamptr->basetime.leadtimeid;
  if ( taxis->type == TAXIS_FORECAST && ncvarid != UNDEFID )
    {
      timevalue = taxis->fc_period;
      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
870
871
872
873
874
  /*
printf("fileID = %d %d %d %f\n", fileID, time_varid, index, timevalue);
  */
}

875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
static
int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, char* taxis_name, taxis_t* taxis)
{
  int time_bndsid = -1;
  int dims[2];
  char tmpstr[CDI_MAX_NAME];

  dims[0] = nctimedimid;

  /* fprintf(stderr, "time has bounds\n"); */

  if ( nc_inq_dimid(fileID, "nb2", &dims[1]) != NC_NOERR )
    cdf_def_dim(fileID, "nb2", 2, &dims[1]);

  if ( taxis->climatology )
    {
      strcpy(tmpstr, "climatology");
      strcat(tmpstr, "_bnds");
      cdf_def_var(fileID, tmpstr, NC_DOUBLE, 2, dims, &time_bndsid);

      cdf_put_att_text(fileID, nctimevarid, "climatology", strlen(tmpstr), tmpstr);
    }
  else
    {
      strcpy(tmpstr, taxis_name);
      strcat(tmpstr, "_bnds");
      cdf_def_var(fileID, tmpstr, NC_DOUBLE, 2, dims, &time_bndsid);

      cdf_put_att_text(fileID, nctimevarid, "bounds", strlen(tmpstr), tmpstr);
    }

  return (time_bndsid);
}

static
void cdfDefTimeUnits(char *unitstr, taxis_t* taxis0, taxis_t* taxis)
{
  unitstr[0] = 0;

  if ( taxis0->type == TAXIS_ABSOLUTE )
    {
      if ( taxis0->unit == TUNIT_YEAR )
        sprintf(unitstr, "year as %s", "%Y.%f");
      else if ( taxis0->unit == TUNIT_MONTH )
        sprintf(unitstr, "month as %s", "%Y%m.%f");
      else
        sprintf(unitstr, "day as %s", "%Y%m%d.%f");
    }
  else
    {
      int year, month, day, hour, minute, second;
      int rdate, rtime;
      int timeunit;

      timeunit = taxis->unit;
      if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
      rdate    = taxis->rdate;
      rtime    = taxis->rtime;
      if ( rdate == -1 )
        {
          rdate  = taxis->vdate;
          rtime  = taxis->vtime;
        }

      cdiDecodeDate(rdate, &year, &month, &day);
      cdiDecodeTime(rtime, &hour, &minute, &second);

942
943
      if ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
      if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
944
945
946
947
948
949
950
951
      if ( timeunit == TUNIT_3HOURS  ||
	   timeunit == TUNIT_6HOURS  ||
	   timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;

      sprintf(unitstr, "%s since %d-%02d-%02d %02d:%02d:%02d",
              tunitNamePtr(timeunit), year, month, day, hour, minute, second);
    }
}
952
953
954
955
956
957
958
959

static
void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
{
  unitstr[0] = 0;

  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;

960
961
  if ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
  if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
962
963
964
965
966
967
  if ( timeunit == TUNIT_3HOURS  ||
       timeunit == TUNIT_6HOURS  ||
       timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;

  sprintf(unitstr, "%s", tunitNamePtr(timeunit));
}
968
969
#endif

970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
static
void cdfDefCalendar(int fileID, int ncvarid, int calendar)
{
  size_t len;
  char calstr[80];

  calstr[0] = 0;

  if      ( calendar == CALENDAR_STANDARD )  strcpy(calstr, "standard");
  else if ( calendar == CALENDAR_PROLEPTIC ) strcpy(calstr, "proleptic_gregorian");
  else if ( calendar == CALENDAR_NONE )      strcpy(calstr, "none");
  else if ( calendar == CALENDAR_360DAYS )   strcpy(calstr, "360_day");
  else if ( calendar == CALENDAR_365DAYS )   strcpy(calstr, "365_day");
  else if ( calendar == CALENDAR_366DAYS )   strcpy(calstr, "366_day");

  len = strlen(calstr);

987
#if  defined  (HAVE_LIBNETCDF)
988
  if ( len ) cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
989
#endif
990
991
}

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
992
static
993
void cdfDefTime(stream_t* streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
994
995
996
997
{
#if  defined  (HAVE_LIBNETCDF)
  int fileID;
  int time_varid;
998
999
1000
  int time_dimid;
  int time_bndsid = -1;
  char unitstr[CDI_MAX_NAME];
1001
1002
  char tmpstr[CDI_MAX_NAME];
  char default_name[] = "time";
1003
  char* taxis_name = default_name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1004
  size_t len;
1005
  taxis_t* taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1006

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1007
  if ( streamptr->basetime.ncvarid != UNDEFID ) return;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1008

1009
  fileID = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1010

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1011
  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1012

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1013
  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1014

1015
  taxis = &streamptr->tsteps[0].taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1016

1017
  if ( taxis->name && taxis->name[0] ) taxis_name = taxis->name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1018

1019
1020
  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
  streamptr->basetime.ncdimid = time_dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1021

1022
  cdf_def_var(fileID, taxis_name, NC_DOUBLE, 1, &time_dimid, &time_varid);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1023

1024
  streamptr->basetime.ncvarid = time_varid;
Deike Kleberg's avatar
Deike Kleberg committed
1025
1026
1027
1028

  strcpy(tmpstr, "time");
  cdf_put_att_text(fileID, time_varid, "standard_name", strlen(tmpstr), tmpstr);

1029
1030
1031
  if ( taxis->longname && taxis->longname[0] )
    cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1032
1033
  if ( taxis->has_bounds )
    {
1034
1035
      time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
      streamptr->basetime.ncvarboundsid = time_bndsid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1036
1037
    }

1038
  cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1039
1040
1041

  len = strlen(unitstr);
  if ( len )
1042
1043
    {
      cdf_put_att_text(fileID, time_varid, "units", len, unitstr);
1044
      /*
1045
1046
      if ( taxis->has_bounds )
        cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr);
1047
      */
1048
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1049
1050
1051

  if ( taxis->calendar != -1 )
    {
1052
      cdfDefCalendar(fileID, time_varid, taxis->calendar);
1053
      /*
1054
1055
      if ( taxis->has_bounds )
        cdfDefCalendar(fileID, time_bndsid, taxis->calendar);
1056
      */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1057
1058
    }

1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  if ( taxis->type == TAXIS_FORECAST )
    {
      int leadtimeid;

      cdf_def_var(fileID, "leadtime", NC_DOUBLE, 1, &time_dimid, &leadtimeid);

      streamptr->basetime.leadtimeid = leadtimeid;

      strcpy(tmpstr, "forecast_period");
      cdf_put_att_text(fileID, leadtimeid, "standard_name", strlen(tmpstr), tmpstr);

      strcpy(tmpstr, "Time elapsed since the start of the forecast");
      cdf_put_att_text(fileID, leadtimeid, "long_name", strlen(tmpstr), tmpstr);

      cdfDefForecastTimeUnits(unitstr, taxis->fc_unit);

      len = strlen(unitstr);
      if ( len ) cdf_put_att_text(fileID, leadtimeid, "units", len, unitstr);
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1079
  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1080
1081
1082
1083
#endif
}


1084
void cdfDefTimestep(stream_t *streamptr, int