stream_cdf.c 233 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 cdfDefGlobalAtts(stream_t *streamptr);
void cdfDefLocalAtts(stream_t *streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
37
38
39
40
41
42
43


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

44
45
46
#define  POSITIVE_UP    1
#define  POSITIVE_DOWN  2

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

55
56
57
#define  MAX_COORDVARS  4
#define  MAX_AUXVARS    4

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

125
#ifdef HAVE_LIBNETCDF
126
127
128
129
130
131
132
133
134
135
136
137
static
void strtolower(char *str)
{
  int i, len;

  if ( str )
    {
      len = (int) strlen(str);
      for ( i = 0; i < len; i++ )
        str[i] = tolower((int) str[i]);
    }
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
138

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

144
145
146
147
148
149
150
151
152
153
  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;
    }
154
155
156
157
  else if ( len == 1 )
    {
      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
    }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

  return (timeunit);
}

static
int isTimeUnits(const char *timeunits)
{
  int len, i;
  char *ptu, *tu;
  int timetype = -1;
  int timeunit;
  int status = FALSE;

  len = (int) strlen(timeunits);
  tu = (char *) malloc((len+1)*sizeof(char));
  memcpy(tu, timeunits, (len+1)*sizeof(char));
  ptu = tu;

  for ( i = 0; i < len; i++ ) ptu[i] = tolower((int) ptu[i]);

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

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
184
185
        {
          while ( isspace(*ptu) ) ptu++;
Deike Kleberg's avatar
Deike Kleberg committed
186

187
188
189
190
          if ( memcmp(ptu, "as", 2) == 0 )
            timetype = TAXIS_ABSOLUTE;
          else if ( memcmp(ptu, "since", 5) == 0 )
            timetype = TAXIS_RELATIVE;
191

192
193
          if ( timetype != -1 ) status = TRUE;
        }
194
195
196
197
198
199
200
201
    }

  free(tu);

  return (status);
}

static
202
void scanTimeString(const char *ptu, int *rdate, int *rtime)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
203
204
205
{
  int year, month, day;
  int hour = 0, minute = 0, second = 0;
206
207
208
209
210
211
212
213
214
215
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
259
260
261
262
263
264
265
266
  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);
}

static
void setForecastTime(const char *timestr, taxis_t *taxis)
{
  int len = (int) strlen(timestr);
  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)
{
  int len, i;
  char *ptu, *tu;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
267
268
  int timetype = TAXIS_ABSOLUTE;
  int rdate = -1, rtime = -1;
269
  int timeunit;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
270

Uwe Schulzweida's avatar
Uwe Schulzweida committed
271
  len = (int) strlen(timeunits);
272
273
274
  tu = (char *) malloc((len+1)*sizeof(char));
  memcpy(tu, timeunits, (len+1)*sizeof(char));
  ptu = tu;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
275

276
277
  for ( i = 0; i < len; i++ ) ptu[i] = tolower((int) ptu[i]);

278
279
  timeunit = get_timeunit(len, ptu);
  if ( timeunit == -1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
280
    {
281
      Message("Unsupported TIMEUNIT: %s!", timeunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
282
283
284
285
286
287
      return (1);
    }

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

290
      if ( memcmp(ptu, "as", 2) == 0 )
291
        timetype = TAXIS_ABSOLUTE;
292
      else if ( memcmp(ptu, "since", 5) == 0 )
293
        timetype = TAXIS_RELATIVE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
294
295
296

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
        {
          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 )
            {
315
              scanTimeString(ptu, &rdate, &rtime);
316
317
318
319
320

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

              if ( CDI_Debug )
Deike Kleberg's avatar
Deike Kleberg committed
321
                Message("rdate = %d  rtime = %d", rdate, rtime);
322
323
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
324
325
326
327
328
    }

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

329
330
  free(tu);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
331
  if ( CDI_Debug )
332
    Message("timetype = %d  unit = %d", timetype, timeunit);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
333
334
335
336

  return (0);
}

337
338
static
void cdfGetAttInt(int fileID, int ncvarid, char *attname, int attlen, int *attint)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
339
{
340
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
341
342
  int *pintatt;

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

345
346
  if ( (int)nc_attlen > attlen )
    pintatt = (int *) malloc(nc_attlen*sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
347
  else
348
    pintatt = attint;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
349
350
351

  cdf_get_att_int(fileID, ncvarid, attname, pintatt);

352
353
354
355
356
  if ( (int)nc_attlen > attlen )
    {
      memcpy(attint, pintatt, attlen*sizeof(int));
      free(pintatt);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
357
358
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
359
360
static
void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
361
{
362
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
363
364
  double *pdoubleatt;

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

367
368
  if ( (int)nc_attlen > attlen )
    pdoubleatt = (double *) malloc(nc_attlen*sizeof(double));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
369
  else
370
    pdoubleatt = attdouble;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
371
372
373

  cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);

374
375
376
377
378
  if ( (int)nc_attlen > attlen )
    {
      memcpy(attdouble, pdoubleatt, attlen*sizeof(double));
      free(pdoubleatt);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
379
380
}

381
382
static
void cdfGetAttText(int fileID, int ncvarid, char *attname, int attlen, char *atttext)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
383
{
384
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
385
386
  char attbuf[65636];

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

389
  if ( nc_attlen < sizeof(attbuf) )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
390
391
392
    {
      cdf_get_att_text(fileID, ncvarid, attname, attbuf);

393
      attbuf[nc_attlen++] = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
394

395
396
      if ( (int) nc_attlen > attlen ) nc_attlen = attlen;
      memcpy(atttext, attbuf, nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
397
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
398
399
400
401
  else
    {
      atttext[0] = 0;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
402
403
}

404
405
406
407
408
409
410
411
static
int xtypeIsFloat(int xtype)
{
  int isFloat = FALSE;
  if ( xtype == NC_FLOAT || xtype == NC_DOUBLE ) isFloat = TRUE;
  return isFloat;
}

412
static
Deike Kleberg's avatar
Deike Kleberg committed
413
int cdfInqDatatype(int xtype, int lunsigned)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
414
{
415
  int datatype = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
416

417
#if  defined  (HAVE_NETCDF4)
Deike Kleberg's avatar
Deike Kleberg committed
418
  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
419
#endif
Deike Kleberg's avatar
Deike Kleberg committed
420

Uwe Schulzweida's avatar
Uwe Schulzweida committed
421
422
423
424
  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;
425
  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
426
  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
Deike Kleberg's avatar
Deike Kleberg committed
427
#if  defined  (HAVE_NETCDF4)
428
  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
429
430
431
432
433
434
  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
435
436
437
438

  return (datatype);
}

439
static
440
int cdfDefDatatype(int datatype, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
441
442
443
{
  int xtype;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
444
  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
445
446
447
448
449
450
451
    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
452
#if  defined  (HAVE_NETCDF4)
453
454
455
456
      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
457
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
458
459
460
461
462
463
464
465
466
467
468
      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;
469
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
470
471
472
473
474
      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
475

Uwe Schulzweida's avatar
Uwe Schulzweida committed
476
477
478
  return (xtype);
}

479
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
480
481
482
void defineAttributes(int vlistID, int varID, int fileID, int ncvarID)
{
  int natts, iatt;
483
  int atttype, attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
484
  size_t len;
485
  char attname[1024];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
486
487
488
489
490

  vlistInqNatts(vlistID, varID, &natts);

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

493
494
      if ( attlen == 0 ) continue;

495
      if ( atttype == DATATYPE_TXT )
496
        {
Deike Kleberg's avatar
Deike Kleberg committed
497
498
499
          char *atttxt;
          atttxt = (char *) malloc(attlen*sizeof(char));
          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
500
501
          len = attlen;
          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
Deike Kleberg's avatar
Deike Kleberg committed
502
          free(atttxt);
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
        }
      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
        {
          int *attint;
          attint = (int *) malloc(attlen*sizeof(int));
          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
          len = attlen;
          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 )
        {
          double *attflt;
          attflt = (double *) malloc(attlen*sizeof(double));
          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
          len = attlen;
          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
528
529
530
531
    }
}
#endif

532
int cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
533
534
{
  double *data;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
535
  int datasize;
Thomas Jahns's avatar
Thomas Jahns committed
536
  int tsID1, recID1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
537
538
539
  int ivarID, gridID;
  int nmiss;
  int ierr = 0;
540
  int memtype = MEMTYPE_DOUBLE;
Thomas Jahns's avatar
Thomas Jahns committed
541
  int vlistID1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
542

Uwe Schulzweida's avatar
Uwe Schulzweida committed
543
  vlistID1 = streamptr1->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
544

Uwe Schulzweida's avatar
Uwe Schulzweida committed
545
  tsID1 = streamptr1->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546

Uwe Schulzweida's avatar
Uwe Schulzweida committed
547
  recID1 = streamptr1->tsteps[tsID1].curRecID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
548

Uwe Schulzweida's avatar
Uwe Schulzweida committed
549
550
551
  ivarID = streamptr1->tsteps[tsID1].records[recID1].varID;

  gridID = vlistInqVarGrid(vlistID1, ivarID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
552

Deike Kleberg's avatar
Deike Kleberg committed
553
  datasize = gridInqSize(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
554
555
556
557
558
  /* bug fix for constant netCDF fields */
  if ( datasize < 1048576 ) datasize = 1048576;

  data = (double *) malloc(datasize*sizeof(double));

559
560
  cdfReadRecord(streamptr1, data, &nmiss);
  cdf_write_record(streamptr2, memtype, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
561
562
563
564
565

  free(data);

  return (ierr);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
566

Uwe Schulzweida's avatar
Uwe Schulzweida committed
567
/* not used
568
int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
569
570
571
{
  int tsID, recID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
572
573
574
  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
575

576
  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
577
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
578
      streamptr->tsteps[0].curRecID = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
579
580
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
581
582
  *varID   = streamptr->tsteps[0].records[recID].varID;
  *levelID = streamptr->tsteps[0].records[recID].levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
583

Uwe Schulzweida's avatar
Uwe Schulzweida committed
584
585
  streamptr->record->varID   = *varID;
  streamptr->record->levelID = *levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
586
587

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
590
591
592
  return (recID+1);
}
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
593

Uwe Schulzweida's avatar
Uwe Schulzweida committed
594

595
596
597
int cdfDefRecord(stream_t *streamptr)
{
  int ierr = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
598

Uwe Schulzweida's avatar
Uwe Schulzweida committed
599
600
  if ( streamptr->fileID < 0 ) ierr = 1;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
601
602
603
  return (ierr);
}

604
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
605
static
606
void cdfWriteGridTraj(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
607
608
609
610
611
612
{
  int tsID, fileID;
  int lonID, latID, gridindex;
  size_t index;
  double xlon, xlat;
  int vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
613

614
615
  vlistID = streamptr->vlistID;
  fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
616
617

  gridindex = vlistGridIndex(vlistID, gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
618
619
  lonID = streamptr->xdimID[gridindex];
  latID = streamptr->ydimID[gridindex];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
620
621
622

  xlon = gridInqXval(gridID, 0);
  xlat = gridInqYval(gridID, 0);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
623
  tsID = streamptr->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
624
625
626
627
628
629
  index = tsID;

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

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
630
static
631
void cdfReadGridTraj(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
632
633
634
635
636
637
{
  int tsID, fileID;
  int lonID, latID, gridindex;
  size_t index;
  double xlon, xlat;
  int vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
638

639
640
  vlistID = streamptr->vlistID;
  fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
641
642

  gridindex = vlistGridIndex(vlistID, gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
643
644
  lonID = streamptr->xdimID[gridindex];
  latID = streamptr->ydimID[gridindex];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
645

Uwe Schulzweida's avatar
Uwe Schulzweida committed
646
  tsID = streamptr->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
647
648
649
650
651
652
653
654
  index = tsID;

  cdf_get_var1_double(fileID, lonID, &index, &xlon);
  cdf_get_var1_double(fileID, latID, &index, &xlat);

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

657
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
658
static
659
660
void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
{
Deike Kleberg's avatar
Deike Kleberg committed
661
#if  defined  (HAVE_NETCDF4)
662
663
664
665
666
667
668
669
670
  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)))
    {
671
      Error("nc_def_var_deflate failed, status = %d", retval);
672
673
674
675
676
677
678
    }
#else
  static int lwarn = TRUE;

  if ( lwarn )
    {
      lwarn = FALSE;
679
      Warning("Deflate compression failed, netCDF4 not available!");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
680
681
682
683
684
    }
#endif
}
#endif

Uwe Schulzweida's avatar
Uwe Schulzweida committed
685
#if  defined(HAVE_LIBNETCDF) && defined(NC_SZIP_NN_OPTION_MASK)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
686
687
688
689
690
static
void cdfDefVarSzip(int ncid, int ncvarid)
{
  int retval;
  /* Set options_mask and bits_per_pixel. */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
691
  int options_mask = NC_SZIP_NN_OPTION_MASK;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
692
693
694
695
696
  int bits_per_pixel = 16;

  if ((retval = nc_def_var_szip(ncid, ncvarid, options_mask, bits_per_pixel)))
    {
      if ( retval == NC_EINVAL )
697
698
699
700
701
702
703
        {
          static int lwarn = TRUE;

          if ( lwarn )
            {
              lwarn = FALSE;
              Warning("netCDF4/Szip compression not compiled in!");
Deike Kleberg's avatar
Deike Kleberg committed
704
            }
705
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
706
      else
707
        Error("nc_def_var_szip failed, status = %d", retval);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
708
    }
709
710
711
}
#endif

712
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
713
static
714
void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
715
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
716
  if ( streamptr->vars[varID].defmiss == FALSE )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
717
718
719
720
721
722
723
    {
      int fileID;
      int ncvarid;
      double missval;
      int vlistID;
      int xtype;

724
725
      vlistID = streamptr->vlistID;
      fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
726
      ncvarid = streamptr->vars[varID].ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
727
      missval = vlistInqVarMissval(vlistID, varID);
728

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

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

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

735
736
      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
737

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
740
      streamptr->vars[varID].defmiss = TRUE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
741
742
    }
}
743
#endif
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
744

745
void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
746
747
748
749
750
{
#if  defined  (HAVE_LIBNETCDF)
  int varID;
  int levelID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
752
  varID   = streamptr->record->varID;
  levelID = streamptr->record->levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
753

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

756
  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
757
758
759
#endif
}

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
760

761
int cdfReadRecord(stream_t *streamptr, double *data, int *nmiss)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
762
763
764
765
{
  int ierr = 0;
  int levelID, varID, tsID, recID, vrecID;

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
768
769
770
771
772
  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
773

774
  cdfReadVarSliceDP(streamptr, varID, levelID, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
775
776
777
778

  return (ierr);
}

779
#if  defined  (HAVE_LIBNETCDF)
780
static
781
void cdfDefTimeValue(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
782
783
784
785
786
{
  int fileID;
  double timevalue;
  int ncvarid;
  size_t index;
787
  taxis_t *taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
788

789
  fileID = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
790
791

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
796
  if ( streamptr->ncmode == 1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
797
798
    {
      cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
799
      streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
800
801
802
803
    }

  index = tsID;

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
807
  ncvarid = streamptr->basetime.ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
808
809
810
811
812
813
  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
814
      ncvarid = streamptr->basetime.ncvarboundsid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
815

Uwe Schulzweida's avatar
Uwe Schulzweida committed
816
      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
817
818
819
      start[0] = tsID; count[0] = 1; start[1] = 0; count[1] = 1;
      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
820
      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_ub, &streamptr->tsteps[0].taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
821
822
823
824
825
826
827
828
      start[0] = tsID; count[0] = 1; start[1] = 1; count[1] = 1;
      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
    }
  /*
printf("fileID = %d %d %d %f\n", fileID, time_varid, index, timevalue);
  */
}

829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
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
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);

      if ( timeunit == TUNIT_QUARTER ) timeunit = TUNIT_MINUTE;
      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);
    }
}
#endif

907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
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);

924
#if  defined  (HAVE_LIBNETCDF)
925
  if ( len ) cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
926
#endif
927
928
}

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
929
static
930
void cdfDefTime(stream_t* streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
931
932
933
934
{
#if  defined  (HAVE_LIBNETCDF)
  int fileID;
  int time_varid;
935
936
937
  int time_dimid;
  int time_bndsid = -1;
  char unitstr[CDI_MAX_NAME];
938
939
  char tmpstr[CDI_MAX_NAME];
  char default_name[] = "time";
940
  char* taxis_name = default_name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
941
  size_t len;
942
  taxis_t* taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
943

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

946
  fileID = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
947

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

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

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

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

956
957
  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
  streamptr->basetime.ncdimid = time_dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
958

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

961
  streamptr->basetime.ncvarid = time_varid;
Deike Kleberg's avatar
Deike Kleberg committed
962
963
964
965

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

966
967
968
  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
969
970
  if ( taxis->has_bounds )
    {
971
972
      time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
      streamptr->basetime.ncvarboundsid = time_bndsid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
973
974
    }

975
  cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
976
977
978

  len = strlen(unitstr);
  if ( len )
979
980
    {
      cdf_put_att_text(fileID, time_varid, "units", len, unitstr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
981

982
983
984
      if ( taxis->has_bounds )
        cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
985
986
987

  if ( taxis->calendar != -1 )
    {
988
      cdfDefCalendar(fileID, time_varid, taxis->calendar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
989

990
991
      if ( taxis->has_bounds )
        cdfDefCalendar(fileID, time_bndsid, taxis->calendar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
992
993
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
994
  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
995
996
997
998
#endif
}


999
void cdfDefTimestep(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1000
{
For faster browsing, not all history is shown. View entire blame