1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #ifdef HAVE_LIBNETCDF
6
7 #include "dmemory.h"
8 #include "cdi.h"
9 #include "cdi_int.h"
10 #include "stream_cdf.h"
11 #include "cdf.h"
12 #include "cdf_int.h"
13 #include "vlist.h"
14 #include "vlist_var.h"
15
16
cdfDefVarDeflate(int ncid,int ncvarID,int deflate_level)17 void cdfDefVarDeflate(int ncid, int ncvarID, int deflate_level)
18 {
19 #ifdef HAVE_NETCDF4
20 // Set chunking, shuffle, and deflate.
21 const int shuffle = 1, deflate = 1;
22
23 if (deflate_level < 1 || deflate_level > 9) deflate_level = 1;
24
25 int status;
26 if ((status = nc_def_var_deflate(ncid, ncvarID, shuffle, deflate, deflate_level)))
27 {
28 Error("nc_def_var_deflate failed; %s", nc_strerror(status));
29 }
30 #else
31 static bool lwarn = true;
32 if (lwarn)
33 {
34 lwarn = false;
35 Warning("Deflate compression failed, NetCDF4 not available!");
36 }
37 #endif
38 }
39
cdfDefVarSzip(int ncid,int ncvarID,int pixels_per_block)40 void cdfDefVarSzip(int ncid, int ncvarID, int pixels_per_block)
41 {
42 #ifdef HAVE_NC_DEF_VAR_SZIP
43 // Set options_mask.
44 /*
45 H5_SZIP_ALLOW_K13_OPTION_MASK 1
46 H5_SZIP_CHIP_OPTION_MASK 2
47 H5_SZIP_EC_OPTION_MASK 4
48 H5_SZIP_NN_OPTION_MASK 32
49 H5_SZIP_ALL_MASKS (H5_SZIP_CHIP_OPTION_MASK|H5_SZIP_EC_OPTION_MASK|H5_SZIP_NN_OPTION_MASK)
50 */
51 int options_mask = 38;
52 int status;
53 if ((status = nc_def_var_szip(ncid, ncvarID, options_mask, pixels_per_block)))
54 Error("nc_def_var_szip failed; %s", nc_strerror(status));
55 #else
56 static bool lwarn = true;
57 if (lwarn)
58 {
59 lwarn = false;
60 Warning("Szip compression failed, NetCDF4/szlib not available!");
61 }
62 #endif
63 }
64
65 #ifdef HAVE_NETCDF4
66 static
cdfTypeComplexFloat(stream_t * streamptr)67 nc_type cdfTypeComplexFloat(stream_t *streamptr)
68 {
69 if (streamptr->nc_complex_float_id == CDI_UNDEFID)
70 {
71 typedef struct complex_float { float r, i; } complex_float;
72 const int fileID = streamptr->fileID;
73 int nc_complex_id;
74 int status;
75 status = nc_def_compound(fileID, sizeof(complex_float), "complex_float", &nc_complex_id);
76 if (status != NC_NOERR) Error("%s", nc_strerror(status));
77 status = nc_insert_compound(fileID, nc_complex_id, "r", NC_COMPOUND_OFFSET(complex_float, r), NC_FLOAT);
78 if (status != NC_NOERR) Error("%s", nc_strerror(status));
79 status = nc_insert_compound(fileID, nc_complex_id, "i", NC_COMPOUND_OFFSET(complex_float, i), NC_FLOAT);
80 if (status != NC_NOERR) Error("%s", nc_strerror(status));
81 streamptr->nc_complex_float_id = nc_complex_id;
82 }
83
84 return (nc_type) streamptr->nc_complex_float_id;
85 }
86
87 static
cdfTypeComplexDouble(stream_t * streamptr)88 nc_type cdfTypeComplexDouble(stream_t *streamptr)
89 {
90 if (streamptr->nc_complex_double_id == CDI_UNDEFID)
91 {
92 typedef struct complex_double { double r, i; } complex_double;
93 const int fileID = streamptr->fileID;
94 int nc_complex_id;
95 int status;
96 status = nc_def_compound(fileID, sizeof(complex_double), "complex_double", &nc_complex_id);
97 if (status != NC_NOERR) Error("%s", nc_strerror(status));
98 status = nc_insert_compound(fileID, nc_complex_id, "r", NC_COMPOUND_OFFSET(complex_double, r), NC_DOUBLE);
99 if (status != NC_NOERR) Error("%s", nc_strerror(status));
100 status = nc_insert_compound(fileID, nc_complex_id, "i", NC_COMPOUND_OFFSET(complex_double, i), NC_DOUBLE);
101 if (status != NC_NOERR) Error("%s", nc_strerror(status));
102 streamptr->nc_complex_double_id = nc_complex_id;
103 }
104
105 return (nc_type) streamptr->nc_complex_double_id;
106 }
107 #endif
108
cdfDefDatatype(int datatype,stream_t * streamptr)109 nc_type cdfDefDatatype(int datatype, stream_t *streamptr)
110 {
111 nc_type xtype = NC_FLOAT;
112
113 if ( streamptr->filetype == CDI_FILETYPE_NC4 )
114 {
115 if ( datatype == CDI_DATATYPE_INT8 ) xtype = NC_BYTE;
116 else if ( datatype == CDI_DATATYPE_INT16 ) xtype = NC_SHORT;
117 else if ( datatype == CDI_DATATYPE_INT32 ) xtype = NC_INT;
118 #ifdef HAVE_NETCDF4
119 else if ( datatype == CDI_DATATYPE_UINT8 ) xtype = NC_UBYTE;
120 else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_USHORT;
121 else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_UINT;
122 else if ( datatype == CDI_DATATYPE_CPX32 ) xtype = cdfTypeComplexFloat(streamptr);
123 else if ( datatype == CDI_DATATYPE_CPX64 ) xtype = cdfTypeComplexDouble(streamptr);
124 #else
125 else if ( datatype == CDI_DATATYPE_UINT8 ) xtype = NC_SHORT;
126 else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
127 else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
128 else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
129 Error("CDI library does not support complex numbers with NetCDF4 classic!");
130 #endif
131 else if ( datatype == CDI_DATATYPE_FLT64 ) xtype = NC_DOUBLE;
132 else if ( datatype == CDI_DATATYPE_FLT32 ) xtype = NC_FLOAT;
133 }
134 else
135 {
136 if ( datatype == CDI_DATATYPE_INT8 ) xtype = NC_BYTE;
137 else if ( datatype == CDI_DATATYPE_INT16 ) xtype = NC_SHORT;
138 else if ( datatype == CDI_DATATYPE_INT32 ) xtype = NC_INT;
139 else if ( datatype == CDI_DATATYPE_UINT8 ) xtype = NC_SHORT;
140 else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
141 else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
142 else if ( datatype == CDI_DATATYPE_FLT64 ) xtype = NC_DOUBLE;
143 else if ( datatype == CDI_DATATYPE_FLT32 ) xtype = NC_FLOAT;
144 else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
145 Error("CDI library does not support complex numbers with NetCDF classic!");
146 }
147
148 return xtype;
149 }
150
151 static
cdfDefVarMissval(stream_t * streamptr,int varID,int dtype,int lcheck)152 void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
153 {
154 if ( streamptr->vars[varID].defmiss == false )
155 {
156 const int vlistID = streamptr->vlistID;
157 const int fileID = streamptr->fileID;
158 const int ncvarID = streamptr->vars[varID].ncvarid;
159 const double missval = vlistInqVarMissval(vlistID, varID);
160
161 if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
162
163 nc_type xtype = cdfDefDatatype(dtype, streamptr);
164 if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
165
166 if ( lcheck == 0 ||
167 streamptr->ncmode != 2 ||
168 streamptr->filetype == CDI_FILETYPE_NC ||
169 streamptr->filetype == CDI_FILETYPE_NC2||
170 streamptr->filetype == CDI_FILETYPE_NC5 )
171 cdf_put_att_double(fileID, ncvarID, "_FillValue", xtype, 1, &missval);
172
173 cdf_put_att_double(fileID, ncvarID, "missing_value", xtype, 1, &missval);
174
175 if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
176
177 streamptr->vars[varID].defmiss = true;
178 }
179 }
180
181 static
cdfDefInstituteGlobal(const stream_t * streamptr)182 void cdfDefInstituteGlobal(const stream_t *streamptr)
183 {
184 const int vlistID = streamptr->vlistID;
185 const int fileID = streamptr->fileID;
186 const int instID = vlistInqInstitut(vlistID);
187
188 if ( instID != CDI_UNDEFID )
189 {
190 const char *longname = institutInqLongnamePtr(instID);
191 if ( longname )
192 {
193 const size_t len = strlen(longname);
194 if ( len > 0 )
195 {
196 if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
197 cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
198 if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
199 }
200 }
201 }
202 }
203
204 static
cdfDefSourceGlobal(const stream_t * streamptr)205 void cdfDefSourceGlobal(const stream_t *streamptr)
206 {
207 const int vlistID = streamptr->vlistID;
208 const int fileID = streamptr->fileID;
209 const int modelID = vlistInqModel(vlistID);
210
211 if ( modelID != CDI_UNDEFID )
212 {
213 const char *longname = modelInqNamePtr(modelID);
214 if ( longname )
215 {
216 size_t len = strlen(longname);
217 if ( len > 0 )
218 {
219 if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
220 cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
221 if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
222 }
223 }
224 }
225 }
226
227 static inline
resizeBuf(void ** buf,size_t * bufSize,size_t reqSize)228 void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
229 {
230 if ( reqSize > *bufSize )
231 {
232 *buf = Realloc(*buf, reqSize);
233 *bufSize = reqSize;
234 }
235 return *buf;
236 }
237
238 static
cdfDefineCellMethods(stream_t * streamptr,int cdiID,int varID,int fileID,int ncvarID)239 void cdfDefineCellMethods(stream_t *streamptr, int cdiID, int varID, int fileID, int ncvarID)
240 {
241 taxis_t *taxis = &streamptr->tsteps[0].taxis;
242 if (!taxis->has_bounds) return;
243
244 const int time_varid = streamptr->basetime.ncvarid;
245 char timeVarName[CDI_MAX_NAME];
246 cdf_inq_varname(fileID, time_varid, timeVarName);
247
248 const int stepType = vlistInqVarTsteptype(cdiID, varID);
249
250 const char *cellMethod = NULL;
251 if (stepType == TSTEP_AVG) cellMethod = "mean";
252 else if (stepType == TSTEP_SUM) cellMethod = "sum";
253 else if (stepType == TSTEP_RANGE) cellMethod = "range";
254 else if (stepType == TSTEP_MIN) cellMethod = "minimum";
255 else if (stepType == TSTEP_MAX) cellMethod = "maximum";
256
257 if (cellMethod)
258 {
259 const char *attname = "cell_methods";
260 char atttxt[CDI_MAX_NAME+10];
261 sprintf(atttxt, "%s: %s", timeVarName, cellMethod);
262 cdf_put_att_text(fileID, ncvarID, attname, strlen(atttxt), atttxt);
263 }
264 }
265
cdfDefineAttributes(int cdiID,int varID,int fileID,int ncvarID)266 void cdfDefineAttributes(int cdiID, int varID, int fileID, int ncvarID)
267 {
268 int atttype, attlen;
269 size_t len;
270 char attname[CDI_MAX_NAME+1];
271 void *attBuf = NULL;
272 size_t attBufSize = 0;
273
274 int natts;
275 cdiInqNatts(cdiID, varID, &natts);
276
277 for ( int iatt = 0; iatt < natts; ++iatt )
278 {
279 cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
280
281 if ( attlen == 0 ) continue;
282
283 if ( atttype == CDI_DATATYPE_TXT )
284 {
285 const size_t attSize = (size_t)attlen*sizeof(char);
286 char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
287 cdiInqAttTxt(cdiID, varID, attname, attlen, atttxt);
288 len = (size_t)attlen;
289 cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
290 }
291 else if ( atttype == CDI_DATATYPE_INT8 || atttype == CDI_DATATYPE_UINT8 ||
292 atttype == CDI_DATATYPE_INT16 || atttype == CDI_DATATYPE_UINT16 ||
293 atttype == CDI_DATATYPE_INT32 || atttype == CDI_DATATYPE_UINT32 )
294 {
295 const size_t attSize = (size_t)attlen*sizeof(int);
296 int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
297 cdiInqAttInt(cdiID, varID, attname, attlen, &attint[0]);
298 len = (size_t)attlen;
299 nc_type xtype = (atttype == CDI_DATATYPE_INT8) ? NC_BYTE :
300 (atttype == CDI_DATATYPE_INT16) ? NC_SHORT :
301 #ifdef HAVE_NETCDF4
302 (atttype == CDI_DATATYPE_UINT8) ? NC_UBYTE :
303 (atttype == CDI_DATATYPE_UINT16) ? NC_USHORT :
304 (atttype == CDI_DATATYPE_UINT32) ? NC_UINT :
305 #endif
306 NC_INT;
307 cdf_put_att_int(fileID, ncvarID, attname, xtype, len, attint);
308 }
309 else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
310 {
311 const size_t attSize = (size_t)attlen * sizeof(double);
312 double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
313 cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
314 len = (size_t)attlen;
315 if ( atttype == CDI_DATATYPE_FLT32 )
316 {
317 float attflt_sp[8];
318 float *pattflt_sp = (len > 8) ? (float*) malloc(len*sizeof(float)) : attflt_sp;
319 for ( size_t i = 0; i < len; ++i ) pattflt_sp[i] = (float)attflt[i];
320 cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, pattflt_sp);
321 if (len > 8) free(pattflt_sp);
322 }
323 else
324 cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
325 }
326 }
327
328 Free(attBuf);
329 }
330
331 static
cdfDefineInstituteName(int vlistID,int varID,int fileID,int ncvarID)332 void cdfDefineInstituteName(int vlistID, int varID, int fileID, int ncvarID)
333 {
334 const int instID = vlistInqVarInstitut(vlistID, varID);
335 if (instID != CDI_UNDEFID)
336 {
337 const char *name = institutInqNamePtr(instID);
338 if (name) cdf_put_att_text(fileID, ncvarID, "institution", strlen(name), name);
339 }
340 }
341
342 static
cdfDefGlobalAtts(stream_t * streamptr)343 void cdfDefGlobalAtts(stream_t *streamptr)
344 {
345 if ( streamptr->globalatts ) return;
346
347 const int vlistID = streamptr->vlistID;
348 const int fileID = streamptr->fileID;
349
350 cdfDefSourceGlobal(streamptr);
351 cdfDefInstituteGlobal(streamptr);
352
353 int natts;
354 cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
355
356 if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
357
358 cdfDefineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
359
360 if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
361
362 streamptr->globalatts = 1;
363 }
364
365 static
cdf_get_gmapvarname(int gridID,char * gmapvarname)366 void cdf_get_gmapvarname(int gridID, char *gmapvarname)
367 {
368 int length = CDI_MAX_NAME;
369 int pgridID = gridID;
370 cdiInqKeyString(pgridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, gmapvarname, &length);
371
372 if (!gmapvarname[0])
373 {
374 length = CDI_MAX_NAME;
375 pgridID = gridInqProj(gridID);
376 if (pgridID != CDI_UNDEFID) cdiInqKeyString(pgridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, gmapvarname, &length);
377 }
378 }
379
380 static
nc_grid_index(stream_t * streamptr,int gridID)381 int nc_grid_index(stream_t *streamptr, int gridID)
382 {
383 int index = 0;
384 const int vlistID = streamptr->vlistID;
385 const int ngrids = vlistNgrids(vlistID);
386 for ( index = 0; index < ngrids; ++index )
387 if ( streamptr->ncgrid[index].gridID == gridID ) break;
388
389 assert(index < ngrids);
390
391 return index;
392 }
393
394 static
xtype2ppb(nc_type xtype)395 int xtype2ppb(nc_type xtype)
396 {
397 int ppb = 32;
398
399 if (xtype == NC_BYTE) ppb = 8;
400 else if (xtype == NC_SHORT) ppb = 16;
401 #ifdef HAVE_NETCDF4
402 else if (xtype == NC_UBYTE) ppb = 8;
403 else if (xtype == NC_USHORT) ppb = 16;
404 #endif
405
406 return ppb;
407 }
408
409 static
cdfDefVarCompression(const stream_t * streamptr,int ncvarID,bool lchunk,nc_type xtype)410 void cdfDefVarCompression(const stream_t *streamptr, int ncvarID, bool lchunk, nc_type xtype)
411 {
412 if ( streamptr->comptype == CDI_COMPRESS_ZIP )
413 {
414 if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
415 {
416 cdfDefVarDeflate(streamptr->fileID, ncvarID, streamptr->complevel);
417 }
418 else
419 {
420 if ( lchunk )
421 {
422 static bool lwarn = true;
423 if ( lwarn )
424 {
425 lwarn = false;
426 Warning("Deflate compression is only available for NetCDF4!");
427 }
428 }
429 }
430 }
431 else if ( streamptr->comptype == CDI_COMPRESS_SZIP )
432 {
433 if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
434 {
435 cdfDefVarSzip(streamptr->fileID, ncvarID, xtype2ppb(xtype));
436 }
437 else
438 {
439 if ( lchunk )
440 {
441 static bool lwarn = true;
442 if ( lwarn )
443 {
444 lwarn = false;
445 Warning("SZIP compression is only available for NetCDF4!");
446 }
447 }
448 }
449 }
450 }
451
452 static
cdfDefVarPacking(const stream_t * streamptr,int ncvarID,nc_type xtype,int vlistID,int varID)453 void cdfDefVarPacking(const stream_t *streamptr, int ncvarID, nc_type xtype, int vlistID, int varID)
454 {
455 // if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT )
456 {
457 const double addoffset = vlistInqVarAddoffset(vlistID, varID);
458 const double scalefactor = vlistInqVarScalefactor(vlistID, varID);
459 const bool laddoffset = IS_NOT_EQUAL(addoffset, 0);
460 const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
461
462 if ( laddoffset || lscalefactor )
463 {
464 nc_type astype = (xtype == NC_FLOAT) ? NC_FLOAT : NC_DOUBLE;
465 if ( (astype == NC_DOUBLE) &&
466 IS_EQUAL(addoffset, (double) ((float) addoffset)) &&
467 IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
468 {
469 astype = NC_FLOAT;
470 }
471
472 cdf_put_att_double(streamptr->fileID, ncvarID, "add_offset", astype, 1, &addoffset);
473 cdf_put_att_double(streamptr->fileID, ncvarID, "scale_factor", astype, 1, &scalefactor);
474 }
475 }
476 }
477
478 static
cdfAppendCoordinates(int fileID,int ncvarID,char coordinates[CDI_MAX_NAME])479 void cdfAppendCoordinates(int fileID, int ncvarID, char coordinates[CDI_MAX_NAME])
480 {
481 if (ncvarID != CDI_UNDEFID)
482 {
483 size_t len = strlen(coordinates);
484 if (len) coordinates[len++] = ' ';
485 cdf_inq_varname(fileID, ncvarID, coordinates+len);
486 }
487 }
488
489 static
cdfDefineCoordinates(const stream_t * streamptr,int ncvarID,int nczvarID,int gridtype,int gridID,int gridindex,int xid,int yid,size_t gridsize,char axis[5],size_t iax)490 void cdfDefineCoordinates(const stream_t *streamptr, int ncvarID, int nczvarID, int gridtype, int gridID, int gridindex,
491 int xid, int yid, size_t gridsize, char axis[5], size_t iax)
492 {
493 const int fileID = streamptr->fileID;
494
495 if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT &&
496 gridtype != GRID_PROJECTION && gridtype != GRID_CURVILINEAR && gridtype != GRID_CHARXY )
497 {
498 const size_t len = strlen(gridNamePtr(gridtype));
499 if ( len > 0 ) cdf_put_att_text(fileID, ncvarID, "CDI_grid_type", len, gridNamePtr(gridtype));
500 }
501
502 char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
503 cdf_get_gmapvarname(gridID, gmapvarname);
504 if ( gmapvarname[0] ) cdf_put_att_text(fileID, ncvarID, "grid_mapping", strlen(gmapvarname), gmapvarname);
505
506 if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
507 {
508 const int numLPE = gridInqNP(gridID);
509 if (numLPE > 0)
510 cdf_put_att_int(fileID, ncvarID, "CDI_grid_num_LPE", NC_INT, 1, &numLPE);
511 }
512
513 if ( gridtype == GRID_GAUSSIAN_REDUCED )
514 {
515 const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
516 if (ncyvarID != CDI_UNDEFID)
517 {
518 char name[CDI_MAX_NAME]; name[0] = 0;
519 cdf_inq_varname(fileID, ncyvarID, name);
520 const size_t len = strlen(name);
521 cdf_put_att_text(fileID, ncvarID, "CDI_grid_latitudes", len, name);
522 }
523
524 const int ncrpvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_RP];
525 if (ncrpvarID != CDI_UNDEFID)
526 {
527 char name[CDI_MAX_NAME]; name[0] = 0;
528 cdf_inq_varname(fileID, ncrpvarID, name);
529 const size_t len = strlen(name);
530 cdf_put_att_text(fileID, ncvarID, "CDI_grid_reduced_points", len, name);
531 }
532 }
533
534 // define coordinates attribute
535
536 char coordinates[CDI_MAX_NAME]; coordinates[0] = 0;
537
538 if (nczvarID != CDI_UNDEFID) cdfAppendCoordinates(fileID, nczvarID, coordinates);
539
540 if ( gridtype == GRID_TRAJECTORY )
541 {
542 cdf_put_att_text(fileID, ncvarID, "coordinates", 9, "tlon tlat");
543 }
544 else if ( gridtype == GRID_LONLAT && xid == CDI_UNDEFID && yid == CDI_UNDEFID && gridsize == 1 )
545 {
546 const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
547 const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
548 cdfAppendCoordinates(fileID, ncyvarID, coordinates);
549 cdfAppendCoordinates(fileID, ncxvarID, coordinates);
550 }
551 else if ( gridtype == GRID_GAUSSIAN_REDUCED )
552 {
553 /*
554 const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
555 const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
556 cdfAppendCoordinates(fileID, ncyvarID, coordinates);
557 cdfAppendCoordinates(fileID, ncxvarID, coordinates);
558 */
559 }
560 else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
561 {
562 const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
563 const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
564 const int ncavarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_A];
565 // CMOR order: coordinates = "lat lon"
566 if ( CDI_Coordinates_Lon_Lat )
567 {
568 cdfAppendCoordinates(fileID, ncxvarID, coordinates);
569 cdfAppendCoordinates(fileID, ncyvarID, coordinates);
570 }
571 else
572 {
573 cdfAppendCoordinates(fileID, ncyvarID, coordinates);
574 cdfAppendCoordinates(fileID, ncxvarID, coordinates);
575 }
576
577 if ( ncavarID != CDI_UNDEFID )
578 {
579 char cellarea[CDI_MAX_NAME] = "area: ";
580 size_t len = strlen(cellarea);
581 cdf_inq_varname(fileID, ncavarID, cellarea+len);
582 len = strlen(cellarea);
583 cdf_put_att_text(fileID, ncvarID, "cell_measures", len, cellarea);
584 }
585
586 if ( gridtype == GRID_UNSTRUCTURED )
587 {
588 int position = gridInqPosition(gridID);
589 if ( position > 0 )
590 cdf_put_att_int(fileID, ncvarID, "number_of_grid_in_reference", NC_INT, 1, &position);
591 }
592 }
593 else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
594 {
595 axis[iax++] = '-';
596 axis[iax++] = '-';
597 cdf_put_att_text(fileID, ncvarID, "axis", iax, axis);
598 int gridTruncation = gridInqTrunc(gridID);
599 cdf_put_att_int(fileID, ncvarID, "truncation", NC_INT, 1, &gridTruncation);
600 }
601 else if ( gridtype == GRID_CHARXY )
602 {
603 if ( gridInqXIsc(gridID) )
604 {
605 const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
606 cdfAppendCoordinates(fileID, ncxvarID, coordinates);
607 }
608 else if ( gridInqYIsc(gridID) )
609 {
610 const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
611 cdfAppendCoordinates(fileID, ncyvarID, coordinates);
612 }
613 }
614
615 const size_t len = strlen(coordinates);
616 if ( len ) cdf_put_att_text(fileID, ncvarID, "coordinates", len, coordinates);
617 }
618
619 static
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)620 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)
621 {
622 const int fileID = streamptr->fileID;
623 const int vlistID = streamptr->vlistID;
624
625 size_t iax = *piax;
626 int ndims = 0;
627
628 for (int i = 0; i < 4; ++i) chunks[i] = 0;
629
630 size_t xsize = 0, ysize = 0;
631 if ( xid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
632 if ( yid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
633
634 const int timetype = vlistInqVarTimetype(vlistID, varID);
635 if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
636 {
637 const int tid = streamptr->basetime.ncdimid;
638 if (tid == CDI_UNDEFID) Error("Internal problem, time undefined!");
639 axis[iax++] = 'T';
640 chunks[ndims] = 1;
641 dims[ndims] = tid;
642 ndims++;
643 }
644
645 int chunktype = vlistInqVarChunkType(vlistID, varID);
646 const size_t chunk_size_max = 65536;
647 const size_t chunk_size_lim = 1073741823;
648 if ( chunktype != CDI_CHUNK_LINES && gridsize > chunk_size_lim )
649 {
650 if ( CDI_Debug ) fprintf(stderr, "gridsize > %zu, changed chunktype to CDI_CHUNK_LINES!\n", chunk_size_lim);
651 chunktype = CDI_CHUNK_LINES;
652 }
653
654 for ( int id = 0; id < 3; ++id )
655 {
656 if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
657 {
658 axis[iax++] = 'Z';
659 chunks[ndims] = 1;
660 dims[ndims] = zid;
661 ndims++;
662 }
663 else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
664 {
665 if ( chunktype == CDI_CHUNK_AUTO )
666 chunks[ndims] = (chunk_size_max > gridsize) ? ysize : chunk_size_max/xsize;
667 else
668 chunks[ndims] = (chunktype == CDI_CHUNK_LINES) ? 1 : ysize;
669 dims[ndims] = yid;
670 ndims++;
671 }
672 else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
673 {
674 if ( chunktype == CDI_CHUNK_AUTO && yid == CDI_UNDEFID )
675 chunks[ndims] = (chunk_size_max > xsize) ? xsize : chunk_size_max;
676 else
677 chunks[ndims] = (xsize > chunk_size_lim) ? chunk_size_lim : xsize;
678 dims[ndims] = xid;
679 ndims++;
680 }
681 }
682
683 if ( CDI_Debug )
684 fprintf(stderr, "lchunk %d chunktype %d chunks %zu %zu %zu %zu\n", lchunk, chunktype, chunks[0], chunks[1], chunks[2], chunks[3]);
685
686 *piax = iax;
687 return ndims;
688 }
689
690 static
cdfDefineAttrLeveltype(int fileID,int ncvarID,int zaxisID,int zaxistype)691 void cdfDefineAttrLeveltype(int fileID, int ncvarID, int zaxisID, int zaxistype)
692 {
693 if ( zaxistype == ZAXIS_CLOUD_BASE ||
694 zaxistype == ZAXIS_CLOUD_TOP ||
695 zaxistype == ZAXIS_ISOTHERM_ZERO ||
696 zaxistype == ZAXIS_TROPOPAUSE ||
697 zaxistype == ZAXIS_TOA ||
698 zaxistype == ZAXIS_SEA_BOTTOM ||
699 zaxistype == ZAXIS_LAKE_BOTTOM ||
700 zaxistype == ZAXIS_SEDIMENT_BOTTOM ||
701 zaxistype == ZAXIS_SEDIMENT_BOTTOM_TA ||
702 zaxistype == ZAXIS_SEDIMENT_BOTTOM_TW ||
703 zaxistype == ZAXIS_MIX_LAYER ||
704 zaxistype == ZAXIS_ATMOSPHERE )
705 {
706 char varname[CDI_MAX_NAME];
707 int length = CDI_MAX_NAME;
708 cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, varname, &length);
709 cdf_put_att_text(fileID, ncvarID, "level_type", strlen(varname), varname);
710 }
711 }
712
713 static
cdfDefineAttrEnsemble(int fileID,int ncvarID,int vlistID,int varID)714 void cdfDefineAttrEnsemble(int fileID, int ncvarID, int vlistID, int varID)
715 {
716 int perturbationNumber, numberOfForecastsInEnsemble, typeOfEnsembleForecast;
717 if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, &perturbationNumber) == 0 )
718 cdf_put_att_int(fileID, ncvarID, "realization", NC_INT, 1, &perturbationNumber);
719 if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, &numberOfForecastsInEnsemble) == 0 )
720 cdf_put_att_int(fileID, ncvarID, "ensemble_members", NC_INT, 1, &numberOfForecastsInEnsemble);
721 if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, &typeOfEnsembleForecast) == 0 )
722 cdf_put_att_int(fileID, ncvarID, "forecast_init_type", NC_INT, 1, &typeOfEnsembleForecast);
723 }
724
725 static
cdfCheckVarname(int fileID,char name[CDI_MAX_NAME])726 void cdfCheckVarname(int fileID, char name[CDI_MAX_NAME])
727 {
728 if ( name[0] )
729 {
730 int ncvarID;
731 char varname[CDI_MAX_NAME];
732 sprintf(varname, "%s", name);
733 char *varname2 = varname+strlen(varname);
734 unsigned iz = 0;
735
736 do
737 {
738 if ( iz ) sprintf(varname2, "_%u", iz+1);
739
740 if ( nc_inq_varid(fileID, varname, &ncvarID) != NC_NOERR ) break;
741
742 ++iz;
743 }
744 while ( iz <= 99 );
745
746 if (iz > 99) Error("Variable name %s already exsist!", name);
747
748 if ( strcmp(name, varname) != 0 )
749 Warning("Changed %s entry of variable name '%s' to '%s'!", (iz==1)?"double":"multiple", name, varname);
750
751 strcpy(name, varname);
752 }
753 }
754
755 static
cdfGenVarname(int fileID,char name[CDI_MAX_NAME],int pnum,int pcat,int * pdis,int * pcode)756 void cdfGenVarname(int fileID, char name[CDI_MAX_NAME], int pnum, int pcat, int *pdis, int *pcode)
757 {
758 char varname[CDI_MAX_NAME];
759
760 int code = *pcode;
761 if ( code < 0 ) code = -code;
762 if ( pnum < 0 ) pnum = -pnum;
763
764 if ( *pdis == 255 )
765 sprintf(varname, "var%d", code);
766 else
767 sprintf(varname, "param%d.%d.%d", pnum, pcat, *pdis);
768
769 char *varname2 = varname+strlen(varname);
770 int ncvarID;
771 unsigned iz = 0;
772
773 do
774 {
775 if ( iz ) sprintf(varname2, "_%u", iz+1);
776
777 if ( nc_inq_varid(fileID, varname, &ncvarID) != NC_NOERR ) break;
778
779 ++iz;
780 }
781 while ( iz <= 99 );
782
783 if (iz > 99) Error("Variable name %s already exsist!", name);
784
785 strcpy(name, varname);
786 *pcode = 0;
787 *pdis = 255;
788 }
789
790 static
cdfDefVar(stream_t * streamptr,int varID)791 int cdfDefVar(stream_t *streamptr, int varID)
792 {
793 if (streamptr->vars[varID].ncvarid != CDI_UNDEFID)
794 return streamptr->vars[varID].ncvarid;
795
796 const int fileID = streamptr->fileID;
797 if (CDI_Debug) Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
798
799 const int vlistID = streamptr->vlistID;
800 const int param = vlistInqVarParam(vlistID, varID);
801 int code = vlistInqVarCode(vlistID, varID);
802 int pnum, pcat, pdis;
803 cdiDecodeParam(param, &pnum, &pcat, &pdis);
804
805 const int gridID = vlistInqVarGrid(vlistID, varID);
806 const size_t gridsize = gridInqSize(gridID);
807 const int gridtype = gridInqType(gridID);
808 const int gridindex = nc_grid_index(streamptr, gridID);
809 const int xid = (gridtype != GRID_TRAJECTORY) ? streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] : CDI_UNDEFID;
810 const int yid = (gridtype != GRID_TRAJECTORY && gridtype != GRID_GAUSSIAN_REDUCED) ?
811 streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y] : CDI_UNDEFID;
812
813 const int zaxisID = vlistInqVarZaxis(vlistID, varID);
814 const int zaxistype = zaxisInqType(zaxisID);
815 const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
816 const int zid = streamptr->zaxisID[zaxisindex];
817
818 int dimorder[3]; // ZYX and ZXY
819 vlistInqVarDimorder(vlistID, varID, &dimorder);
820 const bool lchunk = (dimorder[0] == 3) ? (gridsize >= 32) : false;
821
822 if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=CDI_UNDEFID)+(yid!=CDI_UNDEFID)+(zid!=CDI_UNDEFID)) )
823 {
824 printf("zid=%d yid=%d xid=%d\n", zid, yid, xid);
825 Error("Internal problem, dimension order missing!");
826 }
827
828 size_t iax = 0;
829 char axis[5];
830 int dims[4];
831 size_t chunks[4];
832 int ndims = cdfDefineDimsAndChunks(streamptr, varID, xid, yid, zid, gridsize, dimorder, dims, lchunk, chunks, axis, &iax);
833
834 char name[CDI_MAX_NAME];
835 int length = CDI_MAX_NAME;
836 cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
837
838 char longname[CDI_MAX_NAME];
839 vlistInqVarLongname(vlistID, varID, longname);
840
841 char units[CDI_MAX_NAME];
842 vlistInqVarUnits(vlistID, varID, units);
843
844 char stdname[CDI_MAX_NAME];
845 length = CDI_MAX_NAME;
846 cdiInqKeyString(vlistID, varID, CDI_KEY_STDNAME, stdname, &length);
847
848 const int tableID = vlistInqVarTable(vlistID, varID);
849 if (!name[0]) tableInqEntry(tableID, code, -1, name, longname, units);
850 if (name[0]) cdfCheckVarname(fileID, name);
851 else cdfGenVarname(fileID, name, pnum, pcat, &pdis, &code);
852
853 const int dtype = vlistInqVarDatatype(vlistID, varID);
854 const nc_type xtype = cdfDefDatatype(dtype, streamptr);
855
856 int ncvarID = -1;
857 cdf_def_var(fileID, name, xtype, ndims, dims, &ncvarID);
858
859 #ifdef HAVE_NETCDF4
860 if (lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C))
861 cdf_def_var_chunking(fileID, ncvarID, NC_CHUNKED, chunks);
862 #endif
863
864 cdfDefVarCompression(streamptr, ncvarID, lchunk, xtype);
865
866 if ( *stdname ) cdf_put_att_text(fileID, ncvarID, "standard_name", strlen(stdname), stdname);
867 if ( *longname ) cdf_put_att_text(fileID, ncvarID, "long_name", strlen(longname), longname);
868 if ( *units ) cdf_put_att_text(fileID, ncvarID, "units", strlen(units), units);
869
870 if ( code > 0 && pdis == 255 )
871 cdf_put_att_int(fileID, ncvarID, "code", NC_INT, 1, &code);
872
873 if ( pdis != 255 )
874 {
875 char paramstr[32];
876 cdiParamToString(param, paramstr, sizeof(paramstr));
877 cdf_put_att_text(fileID, ncvarID, "param", strlen(paramstr), paramstr);
878 }
879
880 if ( tableID != CDI_UNDEFID )
881 {
882 int tablenum = tableInqNum(tableID);
883 if (tablenum > 0) cdf_put_att_int(fileID, ncvarID, "table", NC_INT, 1, &tablenum);
884 }
885
886 const bool zaxisIsScalar = (zid == CDI_UNDEFID) ? (zaxisInqScalar(zaxisID) > 0) : false;
887 const int nczvarID = (zaxisIsScalar || zaxistype == ZAXIS_CHAR) ? streamptr->nczvarID[zaxisindex] : CDI_UNDEFID;
888
889 cdfDefineCoordinates(streamptr, ncvarID, nczvarID, gridtype, gridID, gridindex, xid, yid, gridsize, axis, iax);
890
891 cdfDefVarPacking(streamptr, ncvarID, xtype, vlistID, varID);
892
893 if ( dtype == CDI_DATATYPE_UINT8 && xtype == NC_BYTE )
894 {
895 const int validrange[2] = {0, 255};
896 cdf_put_att_int(fileID, ncvarID, "valid_range", NC_SHORT, 2, validrange);
897 cdf_put_att_text(fileID, ncvarID, "_Unsigned", 4, "true");
898 }
899
900 streamptr->vars[varID].ncvarid = ncvarID;
901
902 if ( vlistInqVarMissvalUsed(vlistID, varID) )
903 cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);
904
905 if (zid == CDI_UNDEFID) cdfDefineAttrLeveltype(fileID, ncvarID, zaxisID, zaxistype);
906
907 cdfDefineAttrEnsemble(fileID, ncvarID, vlistID, varID);
908
909 // Attribute: cell_methods
910 cdfDefineCellMethods(streamptr, vlistID, varID, fileID, ncvarID);
911
912 // Attributes
913 cdfDefineAttributes(vlistID, varID, fileID, ncvarID);
914
915 // Institute
916 if (vlistInqInstitut(vlistID) == CDI_UNDEFID) cdfDefineInstituteName(vlistID, varID, fileID, ncvarID);
917
918 return ncvarID;
919 }
920
921
cdfEndDef(stream_t * streamptr)922 void cdfEndDef(stream_t *streamptr)
923 {
924 cdfDefGlobalAtts(streamptr);
925
926 if ( streamptr->accessmode == 0 )
927 {
928 const int fileID = streamptr->fileID;
929 if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
930
931 const int nvars = streamptr->nvars;
932 for ( int varID = 0; varID < nvars; varID++ )
933 cdfDefVar(streamptr, varID);
934
935 if ( streamptr->ncmode == 2 )
936 {
937 if ( CDI_Netcdf_Hdr_Pad == 0UL )
938 cdf_enddef(fileID);
939 else
940 cdf__enddef(fileID, CDI_Netcdf_Hdr_Pad);
941 }
942
943 streamptr->accessmode = 1;
944 }
945 }
946
947 static
cdfWriteGridTraj(stream_t * streamptr,int gridID)948 void cdfWriteGridTraj(stream_t *streamptr, int gridID)
949 {
950 const int gridindex = nc_grid_index(streamptr, gridID);
951 const int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
952 const int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
953 const size_t index = (size_t)streamptr->curTsID;
954
955 const double xlon = gridInqXval(gridID, 0);
956 const double xlat = gridInqYval(gridID, 0);
957
958 cdf_put_var1_double(streamptr->fileID, lonID, &index, &xlon);
959 cdf_put_var1_double(streamptr->fileID, latID, &index, &xlat);
960 }
961
962 static
cdf_write_var_data(int fileID,int vlistID,int varID,int ncvarID,int dtype,size_t nvals,size_t xsize,size_t ysize,bool swapxy,size_t * start,size_t * count,int memtype,const void * data,size_t nmiss)963 void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, size_t nvals, size_t xsize, size_t ysize,
964 bool swapxy, size_t *start, size_t *count, int memtype, const void *data, size_t nmiss)
965 {
966 const double *pdata_dp = (const double *) data;
967 double *mdata_dp = NULL;
968 double *sdata_dp = NULL;
969 const float *pdata_sp = (const float *) data;
970 float *mdata_sp = NULL;
971 float *sdata_sp = NULL;
972
973 /* if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 ) */
974 {
975 const double missval = vlistInqVarMissval(vlistID, varID);
976 const double addoffset = vlistInqVarAddoffset(vlistID, varID);
977 const double scalefactor = vlistInqVarScalefactor(vlistID, varID);
978 const bool laddoffset = IS_NOT_EQUAL(addoffset, 0);
979 const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
980
981 if ( laddoffset || lscalefactor )
982 {
983 if ( memtype == MEMTYPE_FLOAT )
984 {
985 mdata_sp = (float *) Malloc(nvals*sizeof(float));
986 memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
987 pdata_sp = mdata_sp;
988
989 if ( nmiss > 0 )
990 {
991 for ( size_t i = 0; i < nvals; i++ )
992 {
993 double temp = mdata_sp[i];
994 if ( !DBL_IS_EQUAL(temp, missval) )
995 {
996 if ( laddoffset ) temp -= addoffset;
997 if ( lscalefactor ) temp /= scalefactor;
998 mdata_sp[i] = (float)temp;
999 }
1000 }
1001 }
1002 else
1003 {
1004 for ( size_t i = 0; i < nvals; i++ )
1005 {
1006 double temp = mdata_sp[i];
1007 if ( laddoffset ) temp -= addoffset;
1008 if ( lscalefactor ) temp /= scalefactor;
1009 mdata_sp[i] = (float)temp;
1010 }
1011 }
1012 }
1013 else
1014 {
1015 mdata_dp = (double *) Malloc(nvals*sizeof(double));
1016 memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
1017 pdata_dp = mdata_dp;
1018
1019 if ( nmiss > 0 )
1020 {
1021 for ( size_t i = 0; i < nvals; i++ )
1022 {
1023 if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
1024 {
1025 if ( laddoffset ) mdata_dp[i] -= addoffset;
1026 if ( lscalefactor ) mdata_dp[i] /= scalefactor;
1027 }
1028 }
1029 }
1030 else
1031 {
1032 for ( size_t i = 0; i < nvals; i++ )
1033 {
1034 if ( laddoffset ) mdata_dp[i] -= addoffset;
1035 if ( lscalefactor ) mdata_dp[i] /= scalefactor;
1036 }
1037 }
1038 }
1039 }
1040
1041 if ( dtype == CDI_DATATYPE_UINT8 || dtype == CDI_DATATYPE_INT8 ||
1042 dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
1043 {
1044 if ( memtype == MEMTYPE_FLOAT )
1045 {
1046 if ( mdata_sp == NULL )
1047 {
1048 mdata_sp = (float *) Malloc(nvals*sizeof(float));
1049 memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
1050 pdata_sp = mdata_sp;
1051 }
1052
1053 for ( size_t i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
1054
1055 if ( dtype == CDI_DATATYPE_UINT8 )
1056 {
1057 nc_type xtype;
1058 cdf_inq_vartype(fileID, ncvarID, &xtype);
1059 if ( xtype == NC_BYTE )
1060 {
1061 for ( size_t i = 0; i < nvals; ++i )
1062 if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
1063 }
1064 }
1065 }
1066 else
1067 {
1068 if ( mdata_dp == NULL )
1069 {
1070 mdata_dp = (double *) Malloc(nvals*sizeof(double));
1071 memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
1072 pdata_dp = mdata_dp;
1073 }
1074
1075 for ( size_t i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
1076
1077 if ( dtype == CDI_DATATYPE_UINT8 )
1078 {
1079 nc_type xtype;
1080 cdf_inq_vartype(fileID, ncvarID, &xtype);
1081 if ( xtype == NC_BYTE )
1082 {
1083 for ( size_t i = 0; i < nvals; ++i )
1084 if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
1085 }
1086 }
1087 }
1088 }
1089
1090 if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
1091 {
1092 double fmin = 1.0e200;
1093 double fmax = -1.0e200;
1094 for ( size_t i = 0; i < nvals; ++i )
1095 {
1096 if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
1097 {
1098 if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
1099 if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
1100 }
1101 }
1102 Message("nvals = %zu, nmiss = %d, missval = %g, minval = %g, maxval = %g",
1103 nvals, nmiss, missval, fmin, fmax);
1104 }
1105 }
1106
1107 if ( swapxy ) // implemented only for cdf_write_var_slice()
1108 {
1109 size_t gridsize = xsize*ysize;
1110 if ( memtype == MEMTYPE_FLOAT )
1111 {
1112 sdata_sp = (float *) Malloc(gridsize*sizeof(float));
1113 for ( size_t j = 0; j < ysize; ++j )
1114 for ( size_t i = 0; i < xsize; ++i )
1115 sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
1116 pdata_sp = sdata_sp;
1117 }
1118 else
1119 {
1120 sdata_dp = (double *) Malloc(gridsize*sizeof (double));
1121 for ( size_t j = 0; j < ysize; ++j )
1122 for ( size_t i = 0; i < xsize; ++i )
1123 sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
1124 pdata_dp = sdata_dp;
1125 }
1126 }
1127
1128 if (dtype == CDI_DATATYPE_CPX32 || dtype == CDI_DATATYPE_CPX64)
1129 {
1130 void *pdata = (memtype == MEMTYPE_FLOAT) ? (void*)pdata_sp : (void*)pdata_dp;
1131 float *cdata_sp = NULL;
1132 double *cdata_dp = NULL;
1133 if (memtype == MEMTYPE_FLOAT && dtype == CDI_DATATYPE_CPX64)
1134 {
1135 cdata_dp = (double *) Malloc(2*nvals*sizeof(double));
1136 for (size_t i = 0; i < nvals; i++)
1137 {
1138 cdata_dp[2*i] = (double)(pdata_sp[2*i]);
1139 cdata_dp[2*i+1] = (double)(pdata_sp[2*i+1]);
1140 }
1141 pdata = cdata_dp;
1142 }
1143 else if (memtype == MEMTYPE_DOUBLE && dtype == CDI_DATATYPE_CPX32)
1144 {
1145 cdata_sp = (float *) Malloc(2*nvals*sizeof(float));
1146 for (size_t i = 0; i < nvals; i++)
1147 {
1148 cdata_sp[2*i] = (float)(pdata_dp[2*i]);
1149 cdata_sp[2*i+1] = (float)(pdata_dp[2*i+1]);
1150 }
1151 pdata = cdata_sp;
1152 }
1153
1154 cdf_put_vara(fileID, ncvarID, start, count, pdata);
1155 if (cdata_sp) Free(cdata_sp);
1156 if (cdata_dp) Free(cdata_dp);
1157 }
1158 else
1159 {
1160 if ( memtype == MEMTYPE_FLOAT )
1161 cdf_put_vara_float(fileID, ncvarID, start, count, pdata_sp);
1162 else
1163 cdf_put_vara_double(fileID, ncvarID, start, count, pdata_dp);
1164 }
1165
1166 if ( mdata_dp ) Free(mdata_dp);
1167 if ( sdata_dp ) Free(sdata_dp);
1168 if ( mdata_sp ) Free(mdata_sp);
1169 if ( sdata_sp ) Free(sdata_sp);
1170 }
1171
1172 static
cdfGetXYZid(stream_t * streamptr,int gridID,int zaxisID,int * xid,int * yid,int * zid)1173 void cdfGetXYZid(stream_t *streamptr, int gridID, int zaxisID, int *xid, int *yid, int *zid)
1174 {
1175 *xid = CDI_UNDEFID;
1176 *yid = CDI_UNDEFID;
1177
1178 const int gridtype = gridInqType(gridID);
1179 if (gridtype == GRID_TRAJECTORY)
1180 {
1181 cdfWriteGridTraj(streamptr, gridID);
1182 }
1183 else
1184 {
1185 const int gridindex = nc_grid_index(streamptr, gridID);
1186 *xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
1187 if (gridtype != GRID_GAUSSIAN_REDUCED)
1188 *yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
1189 }
1190
1191 const int vlistID = streamptr->vlistID;
1192 const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
1193 *zid = streamptr->zaxisID[zaxisindex];
1194 }
1195
1196 static
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)1197 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)
1198 {
1199 size_t ndims = 0;
1200 *xsize = 0;
1201 *ysize = 0;
1202
1203 const int vlistID = streamptr->vlistID;
1204 const int fileID = streamptr->fileID;
1205
1206 const long ntsteps = streamptr->ntsteps;
1207 if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
1208
1209 const int timetype = vlistInqVarTimetype(vlistID, varID);
1210
1211 if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
1212 {
1213 start[ndims] = (size_t)ntsteps - 1;
1214 count[ndims] = 1;
1215 ndims++;
1216 }
1217
1218 if ( zid != CDI_UNDEFID )
1219 {
1220 const int zaxisID = vlistInqVarZaxis(vlistID, varID);
1221 start[ndims] = 0;
1222 count[ndims] = (size_t)zaxisInqSize(zaxisID);
1223 ndims++;
1224 }
1225
1226 if ( yid != CDI_UNDEFID )
1227 {
1228 start[ndims] = 0;
1229 size_t size;
1230 cdf_inq_dimlen(fileID, yid, &size);
1231 /* count[ndims] = gridInqYsize(gridID); */
1232 count[ndims] = size;
1233 ndims++;
1234 }
1235
1236 if ( xid != CDI_UNDEFID )
1237 {
1238 start[ndims] = 0;
1239 size_t size;
1240 cdf_inq_dimlen(fileID, xid, &size);
1241 /* count[ndims] = gridInqXsize(gridID); */
1242 count[ndims] = size;
1243 ndims++;
1244 }
1245
1246 if ( CDI_Debug )
1247 for (size_t idim = 0; idim < ndims; idim++)
1248 Message("dim = %d start = %d count = %d", idim, start[idim], count[idim]);
1249 }
1250
cdf_write_var(stream_t * streamptr,int varID,int memtype,const void * data,size_t nmiss)1251 void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
1252 {
1253 if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
1254
1255 if ( CDI_Debug ) Message("streamID = %d varID = %d", streamptr->self, varID);
1256
1257 const int vlistID = streamptr->vlistID;
1258 const int fileID = streamptr->fileID;
1259
1260 const int ncvarID = cdfDefVar(streamptr, varID);
1261
1262 const int gridID = vlistInqVarGrid(vlistID, varID);
1263 const int zaxisID = vlistInqVarZaxis(vlistID, varID);
1264
1265 int xid, yid, zid;
1266 cdfGetXYZid(streamptr, gridID, zaxisID, &xid, &yid, &zid);
1267
1268 size_t xsize, ysize;
1269 size_t start[5], count[5];
1270 cdfDefineStartAndCount(streamptr, varID, xid, yid, zid, start, count, &xsize, &ysize);
1271
1272 if ( streamptr->ncmode == 1 )
1273 {
1274 cdf_enddef(fileID);
1275 streamptr->ncmode = 2;
1276 }
1277
1278 const int dtype = vlistInqVarDatatype(vlistID, varID);
1279
1280 if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
1281
1282 const size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
1283
1284 bool swapxy = false;
1285 cdf_write_var_data(fileID, vlistID, varID, ncvarID, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
1286 }
1287
1288 static
cdfDefineStartAndCountChunk(stream_t * streamptr,const int rect[][2],int varID,int xid,int yid,int zid,size_t start[5],size_t count[5],size_t * xsize,size_t * ysize)1289 void cdfDefineStartAndCountChunk(stream_t *streamptr, const int rect[][2], int varID, int xid, int yid, int zid, size_t start[5], size_t count[5], size_t *xsize, size_t *ysize)
1290 {
1291 size_t ndims = 0;
1292 *xsize = 0;
1293 *ysize = 0;
1294
1295 const int vlistID = streamptr->vlistID;
1296 const int fileID = streamptr->fileID;
1297
1298 const long ntsteps = streamptr->ntsteps;
1299 if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
1300
1301 const int timetype = vlistInqVarTimetype(vlistID, varID);
1302
1303 if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
1304 {
1305 start[ndims] = (size_t)ntsteps - 1;
1306 count[ndims] = 1;
1307 ndims++;
1308 }
1309
1310 if ( zid != CDI_UNDEFID )
1311 {
1312 const int zaxisID = vlistInqVarZaxis(vlistID, varID);
1313 int size = zaxisInqSize(zaxisID);
1314 xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1] && rect[2][1] <= size);
1315 start[ndims] = (size_t)rect[2][0];
1316 count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
1317 ndims++;
1318 }
1319
1320 if ( yid != CDI_UNDEFID )
1321 {
1322 size_t size;
1323 cdf_inq_dimlen(fileID, yid, &size);
1324 xassert(rect[1][0] >= 0 && rect[1][0] <= rect[1][1] && (size_t)rect[1][1] <= size);
1325 start[ndims] = (size_t)rect[1][0];
1326 count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
1327 ndims++;
1328 }
1329
1330 if ( xid != CDI_UNDEFID )
1331 {
1332 size_t size;
1333 cdf_inq_dimlen(fileID, xid, &size);
1334 xassert(rect[0][0] >= 0 && rect[0][0] <= rect[0][1] && (size_t)rect[0][1] <= size);
1335 start[ndims] = (size_t)rect[0][0];
1336 count[ndims] = (size_t)rect[0][1] - (size_t)rect[0][0] + 1;
1337 ndims++;
1338 }
1339
1340 if ( CDI_Debug )
1341 for (size_t idim = 0; idim < ndims; idim++)
1342 Message("dim = %d start = %d count = %d", idim, start[idim], count[idim]);
1343 }
1344
cdf_write_var_chunk(stream_t * streamptr,int varID,int memtype,const int rect[][2],const void * data,size_t nmiss)1345 void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
1346 const int rect[][2], const void *data, size_t nmiss)
1347 {
1348 if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
1349
1350 const int streamID = streamptr->self;
1351
1352 if ( CDI_Debug )
1353 Message("streamID = %d varID = %d", streamID, varID);
1354
1355 const int vlistID = streamInqVlist(streamID);
1356 const int fileID = streamInqFileID(streamID);
1357
1358 const int ncvarID = cdfDefVar(streamptr, varID);
1359
1360 const int gridID = vlistInqVarGrid(vlistID, varID);
1361 const int zaxisID = vlistInqVarZaxis(vlistID, varID);
1362
1363 int xid, yid, zid;
1364 cdfGetXYZid(streamptr, gridID, zaxisID, &xid, &yid, &zid);
1365
1366 size_t xsize, ysize;
1367 size_t start[5], count[5];
1368 cdfDefineStartAndCountChunk(streamptr, rect, varID, xid, yid, zid, start, count, &xsize, &ysize);
1369
1370 if ( streamptr->ncmode == 1 )
1371 {
1372 cdf_enddef(fileID);
1373 streamptr->ncmode = 2;
1374 }
1375
1376 const int dtype = vlistInqVarDatatype(vlistID, varID);
1377
1378 if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
1379
1380 const size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
1381
1382 bool swapxy = false;
1383 cdf_write_var_data(fileID, vlistID, varID, ncvarID, dtype, nvals,
1384 xsize, ysize, swapxy, start, count, memtype, data, nmiss);
1385 }
1386
1387 static
cdfDefineStartAndCountSlice(stream_t * streamptr,int varID,int levelID,int dimorder[3],int xid,int yid,int zid,size_t start[5],size_t count[5],size_t * xsize,size_t * ysize)1388 void cdfDefineStartAndCountSlice(stream_t *streamptr, int varID, int levelID, int dimorder[3], int xid, int yid, int zid, size_t start[5], size_t count[5], size_t *xsize, size_t *ysize)
1389 {
1390 size_t ndims = 0;
1391 *xsize = 0;
1392 *ysize = 0;
1393
1394 const int vlistID = streamptr->vlistID;
1395 const int fileID = streamptr->fileID;
1396
1397 const long ntsteps = streamptr->ntsteps;
1398 if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
1399
1400 const int timetype = vlistInqVarTimetype(vlistID, varID);
1401
1402 if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
1403 {
1404 start[ndims] = (size_t)ntsteps - 1;
1405 count[ndims] = 1;
1406 ndims++;
1407 }
1408
1409 for ( int id = 0; id < 3; ++id )
1410 {
1411 if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
1412 {
1413 start[ndims] = (size_t)levelID;
1414 count[ndims] = 1;
1415 ndims++;
1416 }
1417 else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
1418 {
1419 start[ndims] = 0;
1420 cdf_inq_dimlen(fileID, yid, ysize);
1421 count[ndims] = *ysize;
1422 ndims++;
1423 }
1424 else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
1425 {
1426 start[ndims] = 0;
1427 cdf_inq_dimlen(fileID, xid, xsize);
1428 count[ndims] = *xsize;
1429 ndims++;
1430 }
1431 }
1432
1433 if ( CDI_Debug )
1434 for (size_t idim = 0; idim < ndims; idim++)
1435 Message("dim = %d start = %d count = %d", idim, start[idim], count[idim]);
1436 }
1437
1438
cdf_write_var_slice(stream_t * streamptr,int varID,int levelID,int memtype,const void * data,size_t nmiss)1439 void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
1440 {
1441 if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
1442
1443 if ( CDI_Debug ) Message("streamID = %d varID = %d", streamptr->self, varID);
1444
1445 const int vlistID = streamptr->vlistID;
1446 const int fileID = streamptr->fileID;
1447
1448 const int ncvarID = cdfDefVar(streamptr, varID);
1449
1450 const int gridID = vlistInqVarGrid(vlistID, varID);
1451 const int zaxisID = vlistInqVarZaxis(vlistID, varID);
1452
1453 int xid, yid, zid;
1454 cdfGetXYZid(streamptr, gridID, zaxisID, &xid, &yid, &zid);
1455
1456 int dimorder[3];
1457 vlistInqVarDimorder(vlistID, varID, &dimorder);
1458 const bool swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != CDI_UNDEFID && yid != CDI_UNDEFID;
1459
1460 size_t xsize, ysize;
1461 size_t start[5], count[5];
1462 cdfDefineStartAndCountSlice(streamptr, varID, levelID, dimorder, xid, yid, zid, start, count, &xsize, &ysize);
1463
1464 const int dtype = vlistInqVarDatatype(vlistID, varID);
1465
1466 if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
1467
1468 const size_t nvals = gridInqSize(gridID);
1469
1470 cdf_write_var_data(fileID, vlistID, varID, ncvarID, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
1471 }
1472
1473
cdf_write_record(stream_t * streamptr,int memtype,const void * data,size_t nmiss)1474 void cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
1475 {
1476 const int varID = streamptr->record->varID;
1477 const int levelID = streamptr->record->levelID;
1478 cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
1479 }
1480
1481 #endif
1482
1483 /*
1484 * Local Variables:
1485 * c-file-style: "Java"
1486 * c-basic-offset: 2
1487 * indent-tabs-mode: nil
1488 * show-trailing-whitespace: t
1489 * require-trailing-newline: t
1490 * End:
1491 */
1492