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
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
140
int get_timeunit(int len, const char *ptu)
141
142
{
  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
  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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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);
}

263
264
265
static
void setForecastTime(const char *timestr, taxis_t *taxis)
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
266
267
268
269
270
271
  int len;

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

  len = (int) strlen(timestr);
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  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
286
287
  int timetype = TAXIS_ABSOLUTE;
  int rdate = -1, rtime = -1;
288
  int timeunit;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
289

Uwe Schulzweida's avatar
Uwe Schulzweida committed
290
  len = (int) strlen(timeunits);
291
292
293
  tu = (char *) malloc((len+1)*sizeof(char));
  memcpy(tu, timeunits, (len+1)*sizeof(char));
  ptu = tu;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
294

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

297
298
  timeunit = get_timeunit(len, ptu);
  if ( timeunit == -1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
299
    {
300
      Message("Unsupported TIMEUNIT: %s!", timeunits);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
301
302
303
304
305
306
      return (1);
    }

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

309
      if ( memcmp(ptu, "as", 2) == 0 )
310
        timetype = TAXIS_ABSOLUTE;
311
      else if ( memcmp(ptu, "since", 5) == 0 )
312
        timetype = TAXIS_RELATIVE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
313
314
315

      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
      if ( *ptu )
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
        {
          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 )
            {
334
              scanTimeString(ptu, &rdate, &rtime);
335
336
337
338
339

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

              if ( CDI_Debug )
Deike Kleberg's avatar
Deike Kleberg committed
340
                Message("rdate = %d  rtime = %d", rdate, rtime);
341
342
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
343
344
345
346
347
    }

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

348
349
  free(tu);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
350
  if ( CDI_Debug )
351
    Message("timetype = %d  unit = %d", timetype, timeunit);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
352
353
354
355

  return (0);
}

356
357
static
void cdfGetAttInt(int fileID, int ncvarid, char *attname, int attlen, int *attint)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
358
{
359
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
360
361
  int *pintatt;

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

364
365
  if ( (int)nc_attlen > attlen )
    pintatt = (int *) malloc(nc_attlen*sizeof(int));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
366
  else
367
    pintatt = attint;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
368
369
370

  cdf_get_att_int(fileID, ncvarid, attname, pintatt);

371
372
373
374
375
  if ( (int)nc_attlen > attlen )
    {
      memcpy(attint, pintatt, attlen*sizeof(int));
      free(pintatt);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
376
377
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
378
379
static
void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
380
{
381
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
382
383
  double *pdoubleatt;

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

386
387
  if ( (int)nc_attlen > attlen )
    pdoubleatt = (double *) malloc(nc_attlen*sizeof(double));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
388
  else
389
    pdoubleatt = attdouble;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
390
391
392

  cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);

393
394
395
396
397
  if ( (int)nc_attlen > attlen )
    {
      memcpy(attdouble, pdoubleatt, attlen*sizeof(double));
      free(pdoubleatt);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
398
399
}

400
401
static
void cdfGetAttText(int fileID, int ncvarid, char *attname, int attlen, char *atttext)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
402
{
403
  size_t nc_attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
404
405
  char attbuf[65636];

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

408
  if ( nc_attlen < sizeof(attbuf) )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
409
410
411
    {
      cdf_get_att_text(fileID, ncvarid, attname, attbuf);

412
      attbuf[nc_attlen++] = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
413

414
415
      if ( (int) nc_attlen > attlen ) nc_attlen = attlen;
      memcpy(atttext, attbuf, nc_attlen);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
416
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
417
418
419
420
  else
    {
      atttext[0] = 0;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
421
422
}

423
424
425
426
427
428
429
430
static
int xtypeIsFloat(int xtype)
{
  int isFloat = FALSE;
  if ( xtype == NC_FLOAT || xtype == NC_DOUBLE ) isFloat = TRUE;
  return isFloat;
}

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

436
#if  defined  (HAVE_NETCDF4)
Deike Kleberg's avatar
Deike Kleberg committed
437
  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
438
#endif
Deike Kleberg's avatar
Deike Kleberg committed
439

Uwe Schulzweida's avatar
Uwe Schulzweida committed
440
441
442
443
  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;
444
  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
445
  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
Deike Kleberg's avatar
Deike Kleberg committed
446
#if  defined  (HAVE_NETCDF4)
447
  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
448
449
450
451
452
453
  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
454
455
456
457

  return (datatype);
}

458
static
459
int cdfDefDatatype(int datatype, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
460
461
462
{
  int xtype;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
463
  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
464
465
466
467
468
469
470
    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
471
#if  defined  (HAVE_NETCDF4)
472
473
474
475
      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
476
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
477
478
479
480
481
482
483
484
485
486
487
      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;
488
      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
489
490
491
492
493
      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
494

Uwe Schulzweida's avatar
Uwe Schulzweida committed
495
496
497
  return (xtype);
}

498
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
499
500
501
void defineAttributes(int vlistID, int varID, int fileID, int ncvarID)
{
  int natts, iatt;
502
  int atttype, attlen;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
503
  size_t len;
504
  char attname[1024];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
505
506
507
508
509

  vlistInqNatts(vlistID, varID, &natts);

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

512
513
      if ( attlen == 0 ) continue;

514
      if ( atttype == DATATYPE_TXT )
515
        {
Deike Kleberg's avatar
Deike Kleberg committed
516
517
518
          char *atttxt;
          atttxt = (char *) malloc(attlen*sizeof(char));
          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
519
520
          len = attlen;
          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
Deike Kleberg's avatar
Deike Kleberg committed
521
          free(atttxt);
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
        }
      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
547
548
549
550
    }
}
#endif

551
int cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
552
553
{
  double *data;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
554
  int datasize;
Thomas Jahns's avatar
Thomas Jahns committed
555
  int tsID1, recID1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
556
557
558
  int ivarID, gridID;
  int nmiss;
  int ierr = 0;
559
  int memtype = MEMTYPE_DOUBLE;
Thomas Jahns's avatar
Thomas Jahns committed
560
  int vlistID1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
561

Uwe Schulzweida's avatar
Uwe Schulzweida committed
562
  vlistID1 = streamptr1->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
563

Uwe Schulzweida's avatar
Uwe Schulzweida committed
564
  tsID1 = streamptr1->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
565

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
568
569
570
  ivarID = streamptr1->tsteps[tsID1].records[recID1].varID;

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

Deike Kleberg's avatar
Deike Kleberg committed
572
  datasize = gridInqSize(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
573
574
575
576
577
  /* bug fix for constant netCDF fields */
  if ( datasize < 1048576 ) datasize = 1048576;

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

578
579
  cdfReadRecord(streamptr1, data, &nmiss);
  cdf_write_record(streamptr2, memtype, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
580
581
582
583
584

  free(data);

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
586
/* not used
587
int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
588
589
590
{
  int tsID, recID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
591
592
593
  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
594

595
  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
596
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
597
      streamptr->tsteps[0].curRecID = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
598
599
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
600
601
  *varID   = streamptr->tsteps[0].records[recID].varID;
  *levelID = streamptr->tsteps[0].records[recID].levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
602

Uwe Schulzweida's avatar
Uwe Schulzweida committed
603
604
  streamptr->record->varID   = *varID;
  streamptr->record->levelID = *levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
605
606

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
609
610
611
  return (recID+1);
}
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
612

Uwe Schulzweida's avatar
Uwe Schulzweida committed
613

614
615
616
int cdfDefRecord(stream_t *streamptr)
{
  int ierr = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
617

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
620
621
622
  return (ierr);
}

623
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
624
static
625
void cdfWriteGridTraj(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
626
627
628
629
630
631
{
  int tsID, fileID;
  int lonID, latID, gridindex;
  size_t index;
  double xlon, xlat;
  int vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
632

633
634
  vlistID = streamptr->vlistID;
  fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
635
636

  gridindex = vlistGridIndex(vlistID, gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
637
638
  lonID = streamptr->xdimID[gridindex];
  latID = streamptr->ydimID[gridindex];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
639
640
641

  xlon = gridInqXval(gridID, 0);
  xlat = gridInqYval(gridID, 0);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
642
  tsID = streamptr->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
643
644
645
646
647
648
  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
649
static
650
void cdfReadGridTraj(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
651
652
653
654
655
656
{
  int tsID, fileID;
  int lonID, latID, gridindex;
  size_t index;
  double xlon, xlat;
  int vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
657

658
659
  vlistID = streamptr->vlistID;
  fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
660
661

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
665
  tsID = streamptr->curTsID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
666
667
668
669
670
671
672
673
  index = tsID;

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

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

676
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
677
static
678
679
void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
{
Deike Kleberg's avatar
Deike Kleberg committed
680
#if  defined  (HAVE_NETCDF4)
681
682
683
684
685
686
687
688
689
  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)))
    {
690
      Error("nc_def_var_deflate failed, status = %d", retval);
691
692
693
694
695
696
697
    }
#else
  static int lwarn = TRUE;

  if ( lwarn )
    {
      lwarn = FALSE;
698
      Warning("Deflate compression failed, netCDF4 not available!");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
699
700
701
702
703
    }
#endif
}
#endif

Uwe Schulzweida's avatar
Uwe Schulzweida committed
704
#if  defined(HAVE_LIBNETCDF) && defined(NC_SZIP_NN_OPTION_MASK)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
705
706
707
708
709
static
void cdfDefVarSzip(int ncid, int ncvarid)
{
  int retval;
  /* Set options_mask and bits_per_pixel. */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
710
  int options_mask = NC_SZIP_NN_OPTION_MASK;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
711
712
713
714
715
  int bits_per_pixel = 16;

  if ((retval = nc_def_var_szip(ncid, ncvarid, options_mask, bits_per_pixel)))
    {
      if ( retval == NC_EINVAL )
716
717
718
719
720
721
722
        {
          static int lwarn = TRUE;

          if ( lwarn )
            {
              lwarn = FALSE;
              Warning("netCDF4/Szip compression not compiled in!");
Deike Kleberg's avatar
Deike Kleberg committed
723
            }
724
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
      else
726
        Error("nc_def_var_szip failed, status = %d", retval);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
727
    }
728
729
730
}
#endif

731
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
732
static
733
void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
734
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
  if ( streamptr->vars[varID].defmiss == FALSE )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
736
737
738
739
740
741
742
    {
      int fileID;
      int ncvarid;
      double missval;
      int vlistID;
      int xtype;

743
744
      vlistID = streamptr->vlistID;
      fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
745
      ncvarid = streamptr->vars[varID].ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
746
      missval = vlistInqVarMissval(vlistID, varID);
747

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

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

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

754
755
      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
756

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
759
      streamptr->vars[varID].defmiss = TRUE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
760
761
    }
}
762
#endif
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
763

764
void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
765
766
767
768
769
{
#if  defined  (HAVE_LIBNETCDF)
  int varID;
  int levelID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
771
  varID   = streamptr->record->varID;
  levelID = streamptr->record->levelID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
772

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

775
  cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776
777
778
#endif
}

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
779

780
int cdfReadRecord(stream_t *streamptr, double *data, int *nmiss)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
781
782
783
784
{
  int ierr = 0;
  int levelID, varID, tsID, recID, vrecID;

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
787
788
789
790
791
  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
792

793
  cdfReadVarSliceDP(streamptr, varID, levelID, data, nmiss);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
794
795
796
797

  return (ierr);
}

798
#if  defined  (HAVE_LIBNETCDF)
799
static
800
void cdfDefTimeValue(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
801
802
803
804
805
{
  int fileID;
  double timevalue;
  int ncvarid;
  size_t index;
806
  taxis_t *taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
807

808
  fileID = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
809
810

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
815
  if ( streamptr->ncmode == 1 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
816
817
    {
      cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
818
      streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
819
820
821
822
    }

  index = tsID;

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
826
  ncvarid = streamptr->basetime.ncvarid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
827
828
829
830
831
832
  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
833
      ncvarid = streamptr->basetime.ncvarboundsid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
834

Uwe Schulzweida's avatar
Uwe Schulzweida committed
835
      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
836
837
838
      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
839
      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_ub, &streamptr->tsteps[0].taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
840
841
842
843
844
845
846
847
      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);
  */
}

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

926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
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);

943
#if  defined  (HAVE_LIBNETCDF)
944
  if ( len ) cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
945
#endif
946
947
}

Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
948
static
949
void cdfDefTime(stream_t* streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
950
951
952
953
{
#if  defined  (HAVE_LIBNETCDF)
  int fileID;
  int time_varid;
954
955
956
  int time_dimid;
  int time_bndsid = -1;
  char unitstr[CDI_MAX_NAME];
957
958
  char tmpstr[CDI_MAX_NAME];
  char default_name[] = "time";
959
  char* taxis_name = default_name;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
960
  size_t len;
961
  taxis_t* taxis;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
962

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

965
  fileID = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
966

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

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

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

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

975
976
  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
  streamptr->basetime.ncdimid = time_dimid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
977

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

980
  streamptr->basetime.ncvarid = time_varid;
Deike Kleberg's avatar
Deike Kleberg committed
981
982
983
984

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

985
986
987
  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
988
989
  if ( taxis->has_bounds )
    {
990
991
      time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
      streamptr->basetime.ncvarboundsid = time_bndsid;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
992
993
    }

994
  cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
995
996
997

  len = strlen(unitstr);
  if ( len )
998
999
    {
      cdf_put_att_text(fileID, time_varid, "units", len, unitstr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1000

1001
1002
1003
      if ( taxis->has_bounds )
        cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1004
1005
1006

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

1009
1010
      if ( taxis->has_bounds )
        cdfDefCalendar(fileID, time_bndsid, taxis->calendar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1011
1012
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1013
  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1014
1015
1016
1017
#endif
}


1018
void cdfDefTimestep(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1019
{
1020
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1021
1022
  int vlistID;

1023
  vlistID = streamptr->vlistID;
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1024

1025
  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1026

1027
  cdfDefTimeValue(streamptr, tsID);
1028
#endif
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1029
1030
}

1031
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1032
static
1033
void cdfDefComplex(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1034
{
1035
  char axisname[] = "nc2";
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1036
1037
1038
1039
1040
1041
1042
  int index;
  int dimID = UNDEFID;
  int gridID0, gridtype0, gridindex;
  int ngrids;
  int fileID;
  int dimlen;
  int vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1043

1044
1045
  vlistID = streamptr->vlistID;
  fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1046
1047
1048
1049
1050

  ngrids = vlistNgrids(vlistID);

  for ( index = 0; index < ngrids; index++ )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1051
      if ( streamptr->xdimID[index] != UNDEFID )
1052
1053
1054
        {
          gridID0 = vlistGrid(vlistID, index);
          gridtype0 = gridInqType(gridID0);
1055
          if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
1056
1057
1058
1059
1060
            {
              dimID = streamptr->xdimID[index];
              break;
            }
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1061
1062
1063
1064
1065
1066
    }

  if ( dimID == UNDEFID )
    {
      dimlen = 2;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1067
      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1068
1069
1070
1071

      cdf_def_dim(fileID, axisname, dimlen, &dimID);

      cdf_enddef(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1072
      streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1073
1074
1075
    }

  gridindex = vlistGridIndex(vlistID, gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1076
  streamptr->xdimID[gridindex] = dimID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1077
}
1078
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1079

1080
#if  defined  (HAVE_LIBNETCDF)
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
1081
static
1082
void cdfDefSP(stream_t *streamptr, int gridID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1083
1084
1085
1086
{
  /*
  char longname[] = "Spherical harmonic coefficient";
  */
1087
  char axisname[5] = "nspX";
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1088
1089
1090
1091
1092
1093
1094
1095
  int index, iz = 0;
  int gridID0, gridtype0, gridindex;
  int dimID = UNDEFID;
  int ngrids;
  int fileID;
  int dimlen, dimlen0;
  int vlistID;

1096
1097
  vlistID = streamptr->vlistID;
  fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1098
1099
1100
1101
1102
1103
1104

  ngrids = vlistNgrids(vlistID);

  dimlen = gridInqSize(gridID)/2;

  for ( index = 0; index < ngrids; index++ )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1105
      if ( streamptr->ydimID[index] != UNDEFID )
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
        {
          gridID0 = vlistGrid(vlistID, index);
          gridtype0 = gridInqType(gridID0);
          if ( gridtype0 == GRID_SPECTRAL )
            {
              dimlen0 = gridInqSize(gridID0)/2;
              if ( dimlen == dimlen0 )
                {
                  dimID = streamptr->ydimID[index];
                  break;
                }
              else
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
                iz++;
            }
        }
    }

  if ( dimID == UNDEFID )
    {
      if ( iz == 0 ) axisname[3] = '\0';
      else           sprintf(&axisname[3], "%1d", iz+1);

      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);

      cdf_def_dim(fileID, axisname, dimlen, &dimID);

      cdf_enddef(fileID);
      streamptr->ncmode = 2;
    }

  gridindex = vlistGridIndex(vlistID, gridID);
  streamptr->ydimID[gridindex] = dimID;
}
#endif

#if  defined  (HAVE_LIBNETCDF)
static
1143
void cdfDefFC(stream_t *streamptr, int gridID)
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
{
  char axisname[5] = "nfcX";
  int index, iz = 0;
  int gridID0, gridtype0, gridindex;
  int dimID = UNDEFID;
  int ngrids;
  int fileID;