cdf_write.c 42.4 KB
Newer Older
1
2
#ifdef HAVE_CONFIG_H
#include "config.h"
3
4
5
6
7
8
9
10
11
12
13
#endif

#ifdef HAVE_LIBNETCDF

#include "dmemory.h"
#include "cdi.h"
#include "cdi_int.h"
#include "stream_cdf.h"
#include "cdf.h"
#include "cdf_int.h"
#include "vlist.h"
14
#include "vlist_var.h"
15
16


Uwe Schulzweida's avatar
Uwe Schulzweida committed
17
void cdfDefVarDeflate(int ncid, int ncvarID, int deflate_level)
18
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
19
#ifdef HAVE_NETCDF4
20
21
  int retval;
  /* Set chunking, shuffle, and deflate. */
22
23
  const int shuffle = 1;
  const int deflate = 1;
24
25
26

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
  if ( (retval = nc_def_var_deflate(ncid, ncvarID, shuffle, deflate, deflate_level)) )
28
29
30
31
    {
      Error("nc_def_var_deflate failed, status = %d", retval);
    }
#else
32
  static bool lwarn = true;
33
34
  if ( lwarn )
    {
35
      lwarn = false;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
36
      Warning("Deflate compression failed, NetCDF4 not available!");
37
38
39
40
    }
#endif
}

41
nc_type cdfDefDatatype(int datatype, stream_t *streamptr)
42
{
43
  nc_type xtype = NC_FLOAT;
44

45
  if ( streamptr->filetype == CDI_FILETYPE_NC4 )
46
    {
47
48
49
      if      ( datatype == CDI_DATATYPE_INT8   ) xtype = NC_BYTE;
      else if ( datatype == CDI_DATATYPE_INT16  ) xtype = NC_SHORT;
      else if ( datatype == CDI_DATATYPE_INT32  ) xtype = NC_INT;
50
#ifdef  HAVE_NETCDF4
51
52
53
      else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_UBYTE;
      else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_USHORT;
      else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_UINT;
54
      else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
55
        Error("CDI library does not support complex numbers with NetCDF4/HDF5!");
56
#else
57
58
59
      else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_SHORT;
      else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
      else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
60
61
      else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
        Error("CDI library does not support complex numbers with NetCDF4 classic!");
62
#endif
63
      else if ( datatype == CDI_DATATYPE_FLT64  ) xtype = NC_DOUBLE;
64
      else if ( datatype == CDI_DATATYPE_FLT32  ) xtype = NC_FLOAT;
65
66
67
    }
  else
    {
68
69
70
71
72
73
74
      if      ( datatype == CDI_DATATYPE_INT8   ) xtype = NC_BYTE;
      else if ( datatype == CDI_DATATYPE_INT16  ) xtype = NC_SHORT;
      else if ( datatype == CDI_DATATYPE_INT32  ) xtype = NC_INT;
      else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_SHORT;
      else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
      else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
      else if ( datatype == CDI_DATATYPE_FLT64  ) xtype = NC_DOUBLE;
75
76
77
      else if ( datatype == CDI_DATATYPE_FLT32  ) xtype = NC_FLOAT;
      else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
        Error("CDI library does not support complex numbers with NetCDF classic!");
78
79
80
81
82
83
84
85
    }

  return xtype;
}

static
void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
{
86
  if ( streamptr->vars[varID].defmiss == false )
87
    {
88
89
      const int vlistID = streamptr->vlistID;
      const int fileID  = streamptr->fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
90
      const int ncvarID = streamptr->vars[varID].ncvarid;
91
      const double missval = vlistInqVarMissval(vlistID, varID);
92
93
94

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

95
      nc_type xtype = cdfDefDatatype(dtype, streamptr);
96
97
      if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;

98
99
      if ( lcheck == 0 ||
           streamptr->ncmode != 2 ||
100
           streamptr->filetype == CDI_FILETYPE_NC ||
Uwe Schulzweida's avatar
Uwe Schulzweida committed
101
102
           streamptr->filetype == CDI_FILETYPE_NC2||
           streamptr->filetype == CDI_FILETYPE_NC5 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
103
        cdf_put_att_double(fileID, ncvarID, "_FillValue", xtype, 1, &missval);
104

Uwe Schulzweida's avatar
Uwe Schulzweida committed
105
      cdf_put_att_double(fileID, ncvarID, "missing_value", xtype, 1, &missval);
106
107
108

      if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);

109
      streamptr->vars[varID].defmiss = true;
110
111
112
113
    }
}

static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
114
void cdfDefInstituteGlobal(const stream_t *streamptr)
115
{
116
117
118
  const int vlistID = streamptr->vlistID;
  const int fileID  = streamptr->fileID;
  const int instID  = vlistInqInstitut(vlistID);
119

120
  if ( instID != CDI_UNDEFID )
121
122
123
124
    {
      const char *longname = institutInqLongnamePtr(instID);
      if ( longname )
	{
125
	  const size_t len = strlen(longname);
126
127
128
129
130
131
132
133
134
135
136
	  if ( len > 0 )
	    {
	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
	      cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
	    }
	}
    }
}

static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
137
void cdfDefSourceGlobal(const stream_t *streamptr)
138
{
139
140
141
  const int vlistID = streamptr->vlistID;
  const int fileID  = streamptr->fileID;
  const int modelID = vlistInqModel(vlistID);
142

143
  if ( modelID != CDI_UNDEFID )
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    {
      const char *longname = modelInqNamePtr(modelID);
      if ( longname )
	{
          size_t len = strlen(longname);
	  if ( len > 0 )
	    {
	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
	      cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
	    }
	}
    }
}

static inline
void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
{
162
  if ( reqSize > *bufSize )
163
164
165
166
167
168
169
    {
      *buf = Realloc(*buf, reqSize);
      *bufSize = reqSize;
    }
  return *buf;
}

170
171

void cdfDefineAttributes(int cdiID, int varID, int fileID, int ncvarID)
172
173
174
175
176
177
178
179
{
  int atttype, attlen;
  size_t len;
  char attname[CDI_MAX_NAME+1];
  void *attBuf = NULL;
  size_t attBufSize = 0;

  int natts;
180
  cdiInqNatts(cdiID, varID, &natts);
181

182
  for ( int iatt = 0; iatt < natts; ++iatt )
183
    {
184
      cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
185
186
187

      if ( attlen == 0 ) continue;

188
      if ( atttype == CDI_DATATYPE_TXT )
189
190
191
        {
          size_t attSize = (size_t)attlen*sizeof(char);
          char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
192
          cdiInqAttTxt(cdiID, varID, attname, attlen, atttxt);
193
194
195
          len = (size_t)attlen;
          cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
        }
196
197
198
      else if ( atttype == CDI_DATATYPE_INT8  || atttype == CDI_DATATYPE_UINT8  ||
                atttype == CDI_DATATYPE_INT16 || atttype == CDI_DATATYPE_UINT16 ||
                atttype == CDI_DATATYPE_INT32 || atttype == CDI_DATATYPE_UINT32 )
199
200
201
        {
          size_t attSize = (size_t)attlen*sizeof(int);
          int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
202
          cdiInqAttInt(cdiID, varID, attname, attlen, &attint[0]);
203
          len = (size_t)attlen;
204
205
          nc_type xtype = (atttype == CDI_DATATYPE_INT8)  ? NC_BYTE :
                          (atttype == CDI_DATATYPE_INT16) ? NC_SHORT :
Uwe Schulzweida's avatar
Uwe Schulzweida committed
206
#ifdef  HAVE_NETCDF4
207
208
209
                          (atttype == CDI_DATATYPE_UINT8)  ? NC_UBYTE :
                          (atttype == CDI_DATATYPE_UINT16) ? NC_USHORT :
                          (atttype == CDI_DATATYPE_UINT32) ? NC_UINT :
210
211
212
#endif
                          NC_INT;
          cdf_put_att_int(fileID, ncvarID, attname, xtype, len, attint);
213
        }
214
      else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
215
216
217
        {
          size_t attSize = (size_t)attlen * sizeof(double);
          double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
218
          cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
219
          len = (size_t)attlen;
220
          if ( atttype == CDI_DATATYPE_FLT32 )
221
            {
222
223
224
225
226
              float attflt_sp[8];
              float *pattflt_sp = (len > 8) ? (float*) malloc(len*sizeof(float)) : attflt_sp;
              for ( size_t i = 0; i < len; ++i ) pattflt_sp[i] = (float)attflt[i];
              cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, pattflt_sp);
              if (len > 8) free(pattflt_sp);
227
228
229
230
231
            }
          else
            cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
        }
    }
232

233
234
235
  Free(attBuf);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
static
void cdfDefineInstituteName(int vlistID, int varID, int fileID, int ncvarID)
{
  const int instID = vlistInqVarInstitut(vlistID, varID);
  if ( instID != CDI_UNDEFID)
    {
      const char *name = institutInqNamePtr(instID);
      if ( name )
        {
          const size_t len = strlen(name);
          cdf_put_att_text(fileID, ncvarID, "institution", len, name);
        }
    }
}

251
252
253
254
255
static
void cdfDefGlobalAtts(stream_t *streamptr)
{
  if ( streamptr->globalatts ) return;

256
257
  const int vlistID = streamptr->vlistID;
  const int fileID  = streamptr->fileID;
258

Uwe Schulzweida's avatar
Uwe Schulzweida committed
259
260
  cdfDefSourceGlobal(streamptr);
  cdfDefInstituteGlobal(streamptr);
261
262

  int natts;
263
  cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
264
265
266

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

267
  cdfDefineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
268
269
270
271
272
273

  if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);

  streamptr->globalatts = 1;
}

274
275
276
static
void cdf_get_gmapvarname(int gridID, char *gmapvarname)
{
277
  int pgridID = gridID;
278
  char mapping[CDI_MAX_NAME]; mapping[0] = 0;
279
  cdiGridInqKeyStr(pgridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
280
281
282
283

  if ( !mapping[0] )
    {
      int projID = gridInqProj(gridID);
284
285
286
      if ( projID != CDI_UNDEFID )
        {
          pgridID = projID;
287
          cdiGridInqKeyStr(pgridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
288
        }
289
290
291
    }

  if ( mapping[0] )
292
    cdiGridInqKeyStr(pgridID, CDI_KEY_MAPPING, CDI_MAX_NAME, gmapvarname);
293
294
}

295
296
297
298
299
300
301
302
303
304
305
306
307
308
static
int nc_grid_index(stream_t *streamptr, int gridID)
{
  int index = 0;
  int vlistID = streamptr->vlistID;
  int ngrids = vlistNgrids(vlistID);
  for ( index = 0; index < ngrids; ++index )
    if ( streamptr->ncgrid[index].gridID == gridID ) break;

  assert(index < ngrids);

  return index;
}

309
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
310
void cdfDefVarCompression(const stream_t *streamptr, int ncvarID, bool lchunk)
311
312
313
314
315
{
  if ( streamptr->comptype == CDI_COMPRESS_ZIP )
    {
      if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
316
          cdfDefVarDeflate(streamptr->fileID, ncvarID, streamptr->complevel);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
        }
      else
        {
          if ( lchunk )
            {
              static bool lwarn = true;
              if ( lwarn )
                {
                  lwarn = false;
                  Warning("Deflate compression is only available for NetCDF4!");
                }
            }
        }
    }
}

333
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
334
void cdfDefVarPacking(const stream_t *streamptr, int ncvarID, nc_type xtype, int vlistID, int varID)
335
{
336
  //  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT )
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    {
      const double addoffset   = vlistInqVarAddoffset(vlistID, varID);
      const double scalefactor = vlistInqVarScalefactor(vlistID, varID);
      const bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
      const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);

      if ( laddoffset || lscalefactor )
        {
          nc_type astype = (xtype == NC_FLOAT) ? NC_FLOAT : NC_DOUBLE;
          if ( (astype == NC_DOUBLE) &&
               IS_EQUAL(addoffset,   (double) ((float) addoffset)) &&
               IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
            {
              astype = NC_FLOAT;
            }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
353
354
          cdf_put_att_double(streamptr->fileID, ncvarID, "add_offset",   astype, 1, &addoffset);
          cdf_put_att_double(streamptr->fileID, ncvarID, "scale_factor", astype, 1, &scalefactor);
355
356
357
358
        }
    }
}

359
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
360
void cdfAppendCoordinates(int fileID, int ncvarID, char coordinates[CDI_MAX_NAME])
361
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
362
  if (ncvarID != CDI_UNDEFID)
363
    {
364
365
      size_t len = strlen(coordinates);
      if (len) coordinates[len++] = ' ';
Uwe Schulzweida's avatar
Uwe Schulzweida committed
366
      cdf_inq_varname(fileID, ncvarID, coordinates+len);
367
368
369
    }
}

370
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
371
void cdfDefineCoordinates(const stream_t *streamptr, int ncvarID, int nczvarID, int gridtype, int gridID, int gridindex,
372
                          int xid, int yid, size_t gridsize, char axis[5], size_t iax)
373
{
374
375
  const int fileID  = streamptr->fileID;

376
377
378
379
  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT && gridtype != GRID_GAUSSIAN &&
       gridtype != GRID_PROJECTION && gridtype != GRID_CURVILINEAR && gridtype != GRID_CHARXY )
    {
      const size_t len = strlen(gridNamePtr(gridtype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
380
      if ( len > 0 ) cdf_put_att_text(fileID, ncvarID, "CDI_grid_type", len, gridNamePtr(gridtype));
381
382
383
384
    }

  char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
  cdf_get_gmapvarname(gridID, gmapvarname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
385
  if ( gmapvarname[0] ) cdf_put_att_text(fileID, ncvarID, "grid_mapping", strlen(gmapvarname), gmapvarname);
386

387
388
389
390
391
392
  if ( gridtype == GRID_GAUSSIAN_REDUCED )
    {
      const int numLPE = gridInqNP(gridID);
      if (numLPE > 0)
        cdf_put_att_int(fileID, ncvarID, "CDI_grid_num_LPE", NC_INT, 1, &numLPE);

393
394
395
396
397
398
399
400
401
      const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
      if (ncyvarID != CDI_UNDEFID)
        {
          char name[CDI_MAX_NAME]; name[0] = 0;
          cdf_inq_varname(fileID, ncyvarID, name);
          size_t len = strlen(name);
          cdf_put_att_text(fileID, ncvarID, "CDI_grid_latitudes", len, name);
        }

402
403
404
405
406
407
408
409
410
411
      const int ncrpvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_RP];
      if (ncrpvarID != CDI_UNDEFID)
        {
          char name[CDI_MAX_NAME]; name[0] = 0;
          cdf_inq_varname(fileID, ncrpvarID, name);
          size_t len = strlen(name);
          cdf_put_att_text(fileID, ncvarID, "CDI_grid_reduced_points", len, name);
        }
    }

412
413
414
415
416
417
  // define coordinates attribute

  char coordinates[CDI_MAX_NAME]; coordinates[0] = 0;

  if (nczvarID != CDI_UNDEFID) cdfAppendCoordinates(fileID, nczvarID, coordinates);

418
419
  if ( gridtype == GRID_TRAJECTORY )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
420
      cdf_put_att_text(fileID, ncvarID, "coordinates", 9, "tlon tlat");
421
422
423
424
425
426
427
428
    }
  else if ( gridtype == GRID_LONLAT && xid == CDI_UNDEFID && yid == CDI_UNDEFID && gridsize == 1 )
    {
      const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
      const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
      cdfAppendCoordinates(fileID, ncyvarID, coordinates);
      cdfAppendCoordinates(fileID, ncxvarID, coordinates);
    }
429
430
  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
    {
431
      /*
432
433
434
435
      const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
      const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
      cdfAppendCoordinates(fileID, ncyvarID, coordinates);
      cdfAppendCoordinates(fileID, ncxvarID, coordinates);
436
      */
437
    }
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
    {
      char cellarea[CDI_MAX_NAME] = "area: ";
      const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
      const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
      const int ncavarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_A];
      // CMOR order: coordinates = "lat lon"
      if ( cdiCoordinatesLonLat )
        {
          cdfAppendCoordinates(fileID, ncxvarID, coordinates);
          cdfAppendCoordinates(fileID, ncyvarID, coordinates);
        }
      else
        {
          cdfAppendCoordinates(fileID, ncyvarID, coordinates);
          cdfAppendCoordinates(fileID, ncxvarID, coordinates);
        }

      if ( ncavarID != CDI_UNDEFID )
        {
          size_t len = strlen(cellarea);
          cdf_inq_varname(fileID, ncavarID, cellarea+len);
          len = strlen(cellarea);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
461
          cdf_put_att_text(fileID, ncvarID, "cell_measures", len, cellarea);
462
463
464
465
466
467
        }

      if ( gridtype == GRID_UNSTRUCTURED )
        {
          int position = gridInqPosition(gridID);
          if ( position > 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
468
            cdf_put_att_int(fileID, ncvarID, "number_of_grid_in_reference", NC_INT, 1, &position);
469
470
471
472
473
474
        }
    }
  else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
    {
      axis[iax++] = '-';
      axis[iax++] = '-';
Uwe Schulzweida's avatar
Uwe Schulzweida committed
475
      cdf_put_att_text(fileID, ncvarID, "axis", iax, axis);
476
      int gridTruncation = gridInqTrunc(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
477
      cdf_put_att_int(fileID, ncvarID, "truncation", NC_INT, 1, &gridTruncation);
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
    }
  else if ( gridtype == GRID_CHARXY )
    {
      if ( gridInqXIsc(gridID) )
        {
          const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
          cdfAppendCoordinates(fileID, ncxvarID, coordinates);
        }
      else if ( gridInqYIsc(gridID) )
        {
          const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
          cdfAppendCoordinates(fileID, ncyvarID, coordinates);
        }
    }

493
  const size_t len = strlen(coordinates);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
494
  if ( len ) cdf_put_att_text(fileID, ncvarID, "coordinates", len, coordinates);
495
496
}

497
static
498
499
500
501
502
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
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
int cdfDefineDimsAndChunks(const stream_t *streamptr, int varID, int xid, int yid, int zid, size_t gridsize, const int dimorder[3], int dims[4], bool lchunk, size_t chunks[4], char axis[5], size_t *piax)
{
  const int fileID  = streamptr->fileID;
  const int vlistID = streamptr->vlistID;

  size_t iax = *piax;
  int ndims = 0;

  for (int i = 0; i < 4; ++i) chunks[i] = 0;

  size_t xsize = 0, ysize = 0;
  if ( xid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
  if ( yid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);

  const int timetype = vlistInqVarTimetype(vlistID, varID);
  if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
    {
      const int tid = streamptr->basetime.ncdimid;
      if (tid == CDI_UNDEFID) Error("Internal problem, time undefined!");
      axis[iax++] = 'T';
      chunks[ndims] = 1;
      dims[ndims] = tid;
      ndims++;
    }

  int chunktype = vlistInqVarChunkType(vlistID, varID);
  size_t chunk_size_max = 65536;
  if ( chunktype != CDI_CHUNK_LINES && gridsize > INT32_MAX )
    {
      if ( CDI_Debug ) fprintf(stderr, "gridsize > %d, changed chunktype to CDI_CHUNK_LINES!\n", INT32_MAX);
      chunktype = CDI_CHUNK_LINES;
    }

  for ( int id = 0; id < 3; ++id )
    {
      if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
        {
          axis[iax++] = 'Z';
          chunks[ndims] = 1;
          dims[ndims] = zid;
          ndims++;
        }
      else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
        {
          if ( chunktype == CDI_CHUNK_AUTO )
            chunks[ndims] = (chunk_size_max > gridsize) ? ysize : chunk_size_max/xsize;
          else
            chunks[ndims] = (chunktype == CDI_CHUNK_LINES) ? 1 : ysize;
          dims[ndims] = yid;
          ndims++;
        }
      else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
        {
          if ( chunktype == CDI_CHUNK_AUTO && yid == CDI_UNDEFID )
            chunks[ndims] = (chunk_size_max > xsize) ? xsize : chunk_size_max;
          else
            chunks[ndims] = (xsize > INT32_MAX) ? INT32_MAX : xsize;
          dims[ndims] = xid;
          ndims++;
        }
    }

  if ( CDI_Debug )
    fprintf(stderr, "lchunk %d chunktype %d  chunks %zu %zu %zu %zu\n", lchunk, chunktype, chunks[0], chunks[1], chunks[2], chunks[3]);

563
  *piax = iax;
564
565
566
567
  return ndims;
}

static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
568
void cdfDefineAttrLeveltype(int fileID, int ncvarID, int zaxisID, int zaxistype)
569
570
571
572
573
574
575
576
577
578
579
580
581
{
  if ( zaxistype == ZAXIS_CLOUD_BASE          ||
       zaxistype == ZAXIS_CLOUD_TOP           ||
       zaxistype == ZAXIS_ISOTHERM_ZERO       ||
       zaxistype == ZAXIS_TOA                 ||
       zaxistype == ZAXIS_SEA_BOTTOM          ||
       zaxistype == ZAXIS_LAKE_BOTTOM         ||
       zaxistype == ZAXIS_SEDIMENT_BOTTOM     ||
       zaxistype == ZAXIS_SEDIMENT_BOTTOM_TA  ||
       zaxistype == ZAXIS_SEDIMENT_BOTTOM_TW  ||
       zaxistype == ZAXIS_MIX_LAYER           ||
       zaxistype == ZAXIS_ATMOSPHERE )
    {
582
      char varname[CDI_MAX_NAME];
583
      zaxisInqName(zaxisID, varname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
584
      cdf_put_att_text(fileID, ncvarID, "level_type", strlen(varname), varname);
585
586
587
    }
}

588
static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
589
void cdfDefineAttrEnsemble(int fileID, int ncvarID, int vlistID, int varID)
590
591
592
{
  int perturbationNumber, numberOfForecastsInEnsemble, typeOfEnsembleForecast;
  if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, &perturbationNumber) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
593
    cdf_put_att_int(fileID, ncvarID, "realization", NC_INT, 1, &perturbationNumber);
594
  if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, &numberOfForecastsInEnsemble) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
595
    cdf_put_att_int(fileID, ncvarID, "ensemble_members", NC_INT, 1, &numberOfForecastsInEnsemble);
596
  if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, &typeOfEnsembleForecast) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
597
    cdf_put_att_int(fileID, ncvarID, "forecast_init_type", NC_INT, 1, &typeOfEnsembleForecast);
598
599
}

600
601
602
603
604
static
void cdfCheckVarname(int fileID, char name[CDI_MAX_NAME])
{
  if ( name[0] )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
605
      int ncvarID;
606
607
608
609
610
611
612
613
614
      char varname[CDI_MAX_NAME];
      sprintf(varname, "%s", name);
      char *varname2 = varname+strlen(varname);
      unsigned iz = 0;

      do
        {
          if ( iz ) sprintf(varname2, "_%u", iz+1);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
615
          if ( nc_inq_varid(fileID, varname, &ncvarID) != NC_NOERR ) break;
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644

          ++iz;
        }
      while ( iz <= 99 );

      if (iz > 99) Error("Variable name %s already exsist!", name);

      if ( strcmp(name, varname) != 0 )
        Warning("Changed %s entry of variable name '%s' to '%s'!", (iz==1)?"double":"multiple", name, varname);

      strcpy(name, varname);
    }
}

static
void cdfGenVarname(int fileID, char name[CDI_MAX_NAME], int pnum, int pcat, int *pdis, int *pcode)
{
  char varname[CDI_MAX_NAME];

  int code = *pcode;
  if ( code < 0 ) code = -code;
  if ( pnum < 0 ) pnum = -pnum;

  if ( *pdis == 255 )
    sprintf(varname, "var%d", code);
  else
    sprintf(varname, "param%d.%d.%d", pnum, pcat, *pdis);

  char *varname2 = varname+strlen(varname);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
645
  int ncvarID;
646
647
648
649
650
651
  unsigned iz = 0;

  do
    {
      if ( iz ) sprintf(varname2, "_%u", iz+1);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
652
      if ( nc_inq_varid(fileID, varname, &ncvarID) != NC_NOERR ) break;
653
654
655
656
657
658
659
660
661
662
663
664

      ++iz;
    }
  while ( iz <= 99 );

  if (iz > 99) Error("Variable name %s already exsist!", name);

  strcpy(name, varname);
  *pcode = 0;
  *pdis = 255;
}

665
666
667
static
int cdfDefVar(stream_t *streamptr, int varID)
{
668
669
  if (streamptr->vars[varID].ncvarid != CDI_UNDEFID)
    return streamptr->vars[varID].ncvarid;
670

671
  const int fileID  = streamptr->fileID;
672
  if (CDI_Debug) Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
673

674
675
676
  const int vlistID = streamptr->vlistID;
  const int param = vlistInqVarParam(vlistID, varID);
  int code = vlistInqVarCode(vlistID, varID);
677
678
679
  int pnum, pcat, pdis;
  cdiDecodeParam(param, &pnum, &pcat, &pdis);

680
  const int gridID = vlistInqVarGrid(vlistID, varID);
681
682
683
  const size_t gridsize = gridInqSize(gridID);
  const int gridtype = gridInqType(gridID);
  const int gridindex = nc_grid_index(streamptr, gridID);
684
  const int xid = (gridtype != GRID_TRAJECTORY) ? streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] : CDI_UNDEFID;
685
686
  const int yid = (gridtype != GRID_TRAJECTORY && gridtype != GRID_GAUSSIAN_REDUCED) ?
    streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y] : CDI_UNDEFID;
687

688
  const int zaxisID = vlistInqVarZaxis(vlistID, varID);
689
  const int zaxistype = zaxisInqType(zaxisID);
690
691
  const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
  const int zid = streamptr->zaxisID[zaxisindex];
692

693
694
695
  int dimorder[3]; // ZYX and ZXY
  vlistInqVarDimorder(vlistID, varID, &dimorder);
  const bool lchunk = (dimorder[0] == 3) ? (gridsize >= 16) : false;
696

697
  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=CDI_UNDEFID)+(yid!=CDI_UNDEFID)+(zid!=CDI_UNDEFID)) )
698
699
700
701
702
    {
      printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
      Error("Internal problem, dimension order missing!");
    }

703
704
705
706
707
  size_t iax = 0;
  char axis[5];
  int dims[4];
  size_t chunks[4];
  int ndims = cdfDefineDimsAndChunks(streamptr, varID, xid, yid, zid, gridsize, dimorder, dims, lchunk, chunks, axis, &iax);
708

709
  char name[CDI_MAX_NAME]; name[0] = 0;
710
711
  if ( vlistInqVarNamePtr(vlistID, varID) ) vlistInqVarName(vlistID, varID, name);

712
713
714
715
716
717
  char longname[CDI_MAX_NAME]; longname[0] = 0;
  char stdname[CDI_MAX_NAME]; stdname[0] = 0;
  char units[CDI_MAX_NAME]; units[0] = 0;
  vlistInqVarLongname(vlistID, varID, longname);
  vlistInqVarStdname(vlistID, varID, stdname);
  vlistInqVarUnits(vlistID, varID, units);
718

719
  const int tableID  = vlistInqVarTable(vlistID, varID);
720
721
722
  if (!name[0]) tableInqEntry(tableID, code, -1, name, longname, units);
  if (name[0]) cdfCheckVarname(fileID, name);
  else         cdfGenVarname(fileID, name, pnum, pcat, &pdis, &code);
723

724
725
  const int dtype = vlistInqVarDatatype(vlistID, varID);
  const nc_type xtype = cdfDefDatatype(dtype, streamptr);
726

Uwe Schulzweida's avatar
Uwe Schulzweida committed
727
728
  int ncvarID = -1;
  cdf_def_var(fileID, name, xtype, ndims, dims, &ncvarID);
729

Uwe Schulzweida's avatar
Uwe Schulzweida committed
730
#ifdef  HAVE_NETCDF4
731
  if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
732
    cdf_def_var_chunking(fileID, ncvarID, NC_CHUNKED, chunks);
733
734
#endif

Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
  cdfDefVarCompression(streamptr, ncvarID, lchunk);
736

Uwe Schulzweida's avatar
Uwe Schulzweida committed
737
738
739
  if ( *stdname )  cdf_put_att_text(fileID, ncvarID, "standard_name", strlen(stdname), stdname);
  if ( *longname ) cdf_put_att_text(fileID, ncvarID, "long_name", strlen(longname), longname);
  if ( *units )    cdf_put_att_text(fileID, ncvarID, "units", strlen(units), units);
740
741

  if ( code > 0 && pdis == 255 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
742
    cdf_put_att_int(fileID, ncvarID, "code", NC_INT, 1, &code);
743
744
745
746
747

  if ( pdis != 255 )
    {
      char paramstr[32];
      cdiParamToString(param, paramstr, sizeof(paramstr));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
      cdf_put_att_text(fileID, ncvarID, "param", strlen(paramstr), paramstr);
749
750
    }

751
  if ( tableID != CDI_UNDEFID )
752
    {
753
      int tablenum = tableInqNum(tableID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
      if (tablenum > 0) cdf_put_att_int(fileID, ncvarID, "table", NC_INT, 1, &tablenum);
755
756
    }

757
  const bool zaxisIsScalar = (zid == CDI_UNDEFID) ? (zaxisInqScalar(zaxisID) > 0) : false;
758
  const int nczvarID = (zaxisIsScalar || zaxistype == ZAXIS_CHAR) ? streamptr->nczvarID[zaxisindex] : CDI_UNDEFID;
759

Uwe Schulzweida's avatar
Uwe Schulzweida committed
760
  cdfDefineCoordinates(streamptr, ncvarID, nczvarID, gridtype, gridID, gridindex, xid, yid, gridsize, axis, iax);
761

Uwe Schulzweida's avatar
Uwe Schulzweida committed
762
  cdfDefVarPacking(streamptr, ncvarID, xtype, vlistID, varID);
763

764
  if ( dtype == CDI_DATATYPE_UINT8 && xtype == NC_BYTE )
765
    {
766
      const int validrange[2] = {0, 255};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
767
768
      cdf_put_att_int(fileID, ncvarID, "valid_range", NC_SHORT, 2, validrange);
      cdf_put_att_text(fileID, ncvarID, "_Unsigned", 4, "true");
769
770
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
771
  streamptr->vars[varID].ncvarid = ncvarID;
772
773
774
775

  if ( vlistInqVarMissvalUsed(vlistID, varID) )
    cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
776
  if (zid == CDI_UNDEFID) cdfDefineAttrLeveltype(fileID, ncvarID, zaxisID, zaxistype);
777

Uwe Schulzweida's avatar
Uwe Schulzweida committed
778
  cdfDefineAttrEnsemble(fileID, ncvarID, vlistID, varID);
779

780
  // Attributes
Uwe Schulzweida's avatar
Uwe Schulzweida committed
781
782
783
784
  cdfDefineAttributes(vlistID, varID, fileID, ncvarID);

  // Institute
  cdfDefineInstituteName(vlistID, varID, fileID, ncvarID);
785

Uwe Schulzweida's avatar
Uwe Schulzweida committed
786
  return ncvarID;
787
788
789
790
791
792
793
794
795
}


void cdfEndDef(stream_t *streamptr)
{
  cdfDefGlobalAtts(streamptr);

  if ( streamptr->accessmode == 0 )
    {
796
      const int fileID = streamptr->fileID;
797
798
      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);

799
      const int nvars = streamptr->nvars;
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
      for ( int varID = 0; varID < nvars; varID++ )
	cdfDefVar(streamptr, varID);

      if ( streamptr->ncmode == 2 )
        {
          if ( CDI_netcdf_hdr_pad == 0UL )
            cdf_enddef(fileID);
          else
            cdf__enddef(fileID, CDI_netcdf_hdr_pad);
        }

      streamptr->accessmode = 1;
    }
}

static
void cdfWriteGridTraj(stream_t *streamptr, int gridID)
{
818
819
820
  const int gridindex = nc_grid_index(streamptr, gridID);
  const int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
  const int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
821
822
  const int tsID = streamptr->curTsID;
  size_t index = (size_t)tsID;
823
824
825
826

  double xlon = gridInqXval(gridID, 0);
  double xlat = gridInqYval(gridID, 0);

827
828
  cdf_put_var1_double(streamptr->fileID, lonID, &index, &xlon);
  cdf_put_var1_double(streamptr->fileID, latID, &index, &xlat);
829
830
831
}

static
Uwe Schulzweida's avatar
Uwe Schulzweida committed
832
void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, size_t nvals, size_t xsize, size_t ysize,
833
                        bool swapxy, size_t *start, size_t *count, int memtype, const void *data, size_t nmiss)
834
835
836
837
838
839
840
841
{
  const double *pdata_dp = (const double *) data;
  double *mdata_dp = NULL;
  double *sdata_dp = NULL;
  const float *pdata_sp = (const float *) data;
  float *mdata_sp = NULL;
  float *sdata_sp = NULL;

842
  /*  if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 ) */
843
    {
844
845
846
847
848
      const double missval      = vlistInqVarMissval(vlistID, varID);
      const double addoffset    = vlistInqVarAddoffset(vlistID, varID);
      const double scalefactor  = vlistInqVarScalefactor(vlistID, varID);
      const bool laddoffset     = IS_NOT_EQUAL(addoffset, 0);
      const bool lscalefactor   = IS_NOT_EQUAL(scalefactor, 1);
849
850
851
852
853

      if ( laddoffset || lscalefactor )
        {
          if ( memtype == MEMTYPE_FLOAT )
            {
854
855
              mdata_sp = (float *) Malloc(nvals*sizeof(float));
              memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
856
857
858
859
              pdata_sp = mdata_sp;

              if ( nmiss > 0 )
                {
860
                  for ( size_t i = 0; i < nvals; i++ )
861
862
863
864
865
866
867
868
869
870
871
872
                    {
                      double temp = mdata_sp[i];
                      if ( !DBL_IS_EQUAL(temp, missval) )
                        {
                          if ( laddoffset )   temp -= addoffset;
                          if ( lscalefactor ) temp /= scalefactor;
                          mdata_sp[i] = (float)temp;
                        }
                    }
                }
              else
                {
873
                  for ( size_t i = 0; i < nvals; i++ )
874
875
876
877
878
879
880
881
882
883
                    {
                      double temp = mdata_sp[i];
                      if ( laddoffset )   temp -= addoffset;
                      if ( lscalefactor ) temp /= scalefactor;
                      mdata_sp[i] = (float)temp;
                    }
                }
            }
          else
            {
884
885
              mdata_dp = (double *) Malloc(nvals*sizeof(double));
              memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
886
887
888
889
              pdata_dp = mdata_dp;

              if ( nmiss > 0 )
                {
890
                  for ( size_t i = 0; i < nvals; i++ )
891
892
893
894
895
896
897
898
899
900
                    {
                      if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
                        {
                          if ( laddoffset )   mdata_dp[i] -= addoffset;
                          if ( lscalefactor ) mdata_dp[i] /= scalefactor;
                        }
                    }
                }
              else
                {
901
                  for ( size_t i = 0; i < nvals; i++ )
902
903
904
905
906
907
908
909
                    {
                      if ( laddoffset )   mdata_dp[i] -= addoffset;
                      if ( lscalefactor ) mdata_dp[i] /= scalefactor;
                    }
                }
            }
        }

910
911
      if ( dtype == CDI_DATATYPE_UINT8 || dtype == CDI_DATATYPE_INT8 ||
           dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
912
913
914
915
916
        {
          if ( memtype == MEMTYPE_FLOAT )
            {
              if ( mdata_sp == NULL )
                {
917
918
                  mdata_sp = (float *) Malloc(nvals*sizeof(float));
                  memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
919
920
921
                  pdata_sp = mdata_sp;
                }

922
              for ( size_t i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
923

924
              if ( dtype == CDI_DATATYPE_UINT8 )
925
926
                {
                  nc_type xtype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
927
                  cdf_inq_vartype(fileID, ncvarID, &xtype);
928
929
                  if ( xtype == NC_BYTE )
                    {
930
                      for ( size_t i = 0; i < nvals; ++i )
931
932
933
934
935
936
937
938
                        if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
                    }
                }
            }
          else
            {
              if ( mdata_dp == NULL )
                {
939
940
                  mdata_dp = (double *) Malloc(nvals*sizeof(double));
                  memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
941
942
943
                  pdata_dp = mdata_dp;
                }

944
              for ( size_t i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
945

946
              if ( dtype == CDI_DATATYPE_UINT8 )
947
948
                {
                  nc_type xtype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
949
                  cdf_inq_vartype(fileID, ncvarID, &xtype);
950
951
                  if ( xtype == NC_BYTE )
                    {
952
                      for ( size_t i = 0; i < nvals; ++i )
953
954
955
956
957
958
959
960
                        if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
                    }
                }
            }
        }

      if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
        {
961
962
          double fmin =  1.0e200;
          double fmax = -1.0e200;
963
          for ( size_t i = 0; i < nvals; ++i )
964
965
966
967
968
969
970
            {
              if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
                {
                  if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
                  if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
                }
            }
971
          Message("nvals = %zu, nmiss = %d, missval = %g, minval = %g, maxval = %g",
972
973
974
975
                  nvals, nmiss, missval, fmin, fmax);
        }
    }

976
  if ( swapxy ) // implemented only for cdf_write_var_slice()
977
    {
978
      size_t gridsize = xsize*ysize;
979
980
      if ( memtype == MEMTYPE_FLOAT )
        {
981
          sdata_sp = (float *) Malloc(gridsize*sizeof(float));
982
983
984
985
986
987
988
          for ( size_t j = 0; j < ysize; ++j )
            for ( size_t i = 0; i < xsize; ++i )
              sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
          pdata_sp = sdata_sp;
        }
      else
        {
989
          sdata_dp = (double *) Malloc(gridsize*sizeof (double));
990
991
992
993
994
995
996
997
          for ( size_t j = 0; j < ysize; ++j )
            for ( size_t i = 0; i < xsize; ++i )
              sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
          pdata_dp = sdata_dp;
        }
    }

  if ( memtype == MEMTYPE_FLOAT )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
998
    cdf_put_vara_float(fileID, ncvarID, start, count, pdata_sp);
999
  else
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1000
    cdf_put_vara_double(fileID, ncvarID, start, count, pdata_dp);
1001
1002
1003
1004
1005
1006
1007

  if ( mdata_dp ) Free(mdata_dp);
  if ( sdata_dp ) Free(sdata_dp);
  if ( mdata_sp ) Free(mdata_sp);
  if ( sdata_sp ) Free(sdata_sp);
}

1008
1009
1010
1011
1012
1013
static
void cdfGetXYZid(stream_t *streamptr, int gridID, int zaxisID, int *xid, int *yid, int *zid)
{
  *xid = CDI_UNDEFID;
  *yid = CDI_UNDEFID;

1014
1015
  const int gridtype = gridInqType(gridID);
  if (gridtype == GRID_TRAJECTORY)
1016
1017
1018
1019
1020
1021
1022
    {
      cdfWriteGridTraj(streamptr, gridID);
    }
  else
    {
      const int gridindex = nc_grid_index(streamptr, gridID);
      *xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
1023
1024
      if (gridtype != GRID_GAUSSIAN_REDUCED)
        *yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
1025
1026
1027
1028
1029
1030
    }

  const int vlistID = streamptr->vlistID;
  const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
  *zid = streamptr->zaxisID[zaxisindex];
}
1031

1032
1033
static
void cdfDefineStartAndCount(stream_t *streamptr, int varID, int xid, int yid, int zid, size_t start[5], size_t count[5], size_t *xsize, size_t *ysize)
1034
{
Thomas Jahns's avatar
Thomas Jahns committed
1035
  size_t ndims = 0;
1036
1037
  *xsize = 0;
  *ysize = 0;
1038

1039
1040
  const int vlistID = streamptr->vlistID;
  const int fileID  = streamptr->fileID;
1041

1042
  const long ntsteps = streamptr->ntsteps;
1043
1044
  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);

1045
  const int timetype = vlistInqVarTimetype(vlistID, varID);
1046

1047
  if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
1048
1049
1050
1051
1052
    {
      start[ndims] = (size_t)ntsteps - 1;
      count[ndims] = 1;
      ndims++;
    }
1053

1054
  if ( zid != CDI_UNDEFID )
1055
    {
1056
      const int zaxisID = vlistInqVarZaxis(vlistID, varID);
1057
1058
1059
1060
      start[ndims] = 0;
      count[ndims] = (size_t)zaxisInqSize(zaxisID);
      ndims++;
    }
1061

1062
  if ( yid != CDI_UNDEFID )
1063
1064
    {
      start[ndims] = 0;
1065
      size_t size;
1066
1067
1068
1069
1070
      cdf_inq_dimlen(fileID, yid, &size);
      /*      count[ndims] = gridInqYsize(gridID); */
      count[ndims] = size;
      ndims++;
    }
1071

1072
  if ( xid != CDI_UNDEFID )
1073
1074
    {
      start[ndims] = 0;
1075
      size_t size;
1076
1077
1078
1079
1080
1081
1082
      cdf_inq_dimlen(fileID, xid, &size);
      /*      count[ndims] = gridInqXsize(gridID); */
      count[ndims] = size;
      ndims++;
    }

  if ( CDI_Debug )
Thomas Jahns's avatar
Thomas Jahns committed
1083
    for (size_t idim = 0; idim < ndims; idim++)
1084
      Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
}

void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
{
  if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);

  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);

  const int vlistID = streamptr->vlistID;
  const int fileID  = streamptr->fileID;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1096