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

#include "cdi.h"
#include "cdi_int.h"
#include "stream_grb.h"
#include "stream_cdf.h"
#include "stream_srv.h"
#include "stream_ext.h"
#include "stream_ieg.h"
12
#include "dmemory.h"
13
14
15
16
#include "namespace.h"


/* the single image implementation */
17
int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
18
{
19
20
21
22
  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
  // A value > 0 is returned in this case, otherwise it returns zero.
  int status = 0;

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);

  check_parg(data);

  stream_t *streamptr = stream_to_pointer(streamID);
  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
    Error("Writing of non-trivial subtypes not yet implemented!");

  // check taxis
  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);

  int filetype = streamptr->filetype;

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
39
40
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:
41
42
43
44
45
46
      {
        grb_write_var(streamptr, varID, memtype, data, nmiss);
	break;
      }
#endif
#if  defined  (HAVE_LIBSERVICE)
47
    case CDI_FILETYPE_SRV:
48
      {
49
        if ( memtype == MEMTYPE_FLOAT ) return 1;
50
51
52
53
54
        srvWriteVarDP(streamptr, varID, (double *)data);
	break;
      }
#endif
#if  defined  (HAVE_LIBEXTRA)
55
    case CDI_FILETYPE_EXT:
56
      {
57
        if ( memtype == MEMTYPE_FLOAT ) return 1;
58
59
60
61
62
        extWriteVarDP(streamptr, varID, (double *)data);
	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
63
    case CDI_FILETYPE_IEG:
64
      {
65
        if ( memtype == MEMTYPE_FLOAT ) return 1;
66
67
68
69
70
        iegWriteVarDP(streamptr, varID, (double *)data);
	break;
      }
#endif
#if  defined  (HAVE_LIBNETCDF)
71
72
73
74
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
75
      {
76
        cdf_write_var(streamptr, varID, memtype, data, nmiss);
77
78
79
80
81
82
83
84
85
	break;
      }
#endif
    default:
      {
	Error("%s support not compiled in!", strfiletype(filetype));
	break;
      }
    }
86
87

  return status;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
}

/*
@Function  streamWriteVar
@Title     Write a variable

@Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
@Parameter
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
    @Item  varID     Variable identifier.
    @Item  data      Pointer to a block of double precision floating point data values to be written.
    @Item  nmiss     Number of missing values.

@Description
The function streamWriteVar writes the values of one time step of a variable to an open dataset.
The values are converted to the external data type of the variable, if necessary.
@EndFunction
*/
void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
{
108
  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, int nmiss)
109
110
    = (void (*)(int, int, int, const void *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
111

112
  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
}

/*
@Function  streamWriteVarF
@Title     Write a variable

@Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
@Parameter
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
    @Item  varID     Variable identifier.
    @Item  data      Pointer to a block of single precision floating point data values to be written.
    @Item  nmiss     Number of missing values.

@Description
The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
The values are converted to the external data type of the variable, if necessary.
@EndFunction
*/
void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
{
133
  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, int nmiss)
134
    = (int (*)(int, int, int, const void *, int))
135
    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
136

137
138
139
  if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
    {
      // In case the file format does not support single precision writing,
140
141
142
143
144
      // we fall back to double precision writing, converting the data
      // on the fly.
      int vlistID = streamInqVlist(streamID);
      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
145
146
147
148
149
      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
      myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) conversionBuffer, nmiss);
      Free(conversionBuffer);
    }
150
151
152
}

static
153
int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
154
{
155
156
157
158
  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
  // A value > 0 is returned in this case, otherwise it returns zero.
  int status = 0;

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);

  check_parg(data);

  stream_t *streamptr = stream_to_pointer(streamID);
  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
    Error("Writing of non-trivial subtypes not yet implemented!");

  // check taxis
  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);

  int filetype = streamptr->filetype;

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
175
176
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:
177
178
179
180
181
182
      {
        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
	break;
      }
#endif
#if  defined  (HAVE_LIBSERVICE)
183
    case CDI_FILETYPE_SRV:
184
      {
185
        if ( memtype == MEMTYPE_FLOAT ) return 1;
186
187
188
189
190
        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
	break;
      }
#endif
#if  defined  (HAVE_LIBEXTRA)
191
    case CDI_FILETYPE_EXT:
192
      {
193
        if ( memtype == MEMTYPE_FLOAT ) return 1;
194
195
196
197
198
        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
199
    case CDI_FILETYPE_IEG:
200
      {
201
        if ( memtype == MEMTYPE_FLOAT ) return 1;
202
203
204
205
206
        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
	break;
      }
#endif
#if  defined  (HAVE_LIBNETCDF)
207
208
209
210
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
211
212
213
214
215
216
217
218
219
      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
      break;
#endif
    default:
      {
	Error("%s support not compiled in!", strfiletype(filetype));
	break;
      }
    }
220
221

  return status;
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
}

/*
@Function  streamWriteVarSlice
@Title     Write a horizontal slice of a variable

@Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
@Parameter
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
    @Item  varID     Variable identifier.
    @Item  levelID   Level identifier.
    @Item  data      Pointer to a block of double precision floating point data values to be written.
    @Item  nmiss     Number of missing values.

@Description
The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
The values are converted to the external data type of the variable, if necessary.
@EndFunction
*/
void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
{
243
  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
}

/*
@Function  streamWriteVarSliceF
@Title     Write a horizontal slice of a variable

@Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
@Parameter
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
    @Item  varID     Variable identifier.
    @Item  levelID   Level identifier.
    @Item  data      Pointer to a block of single precision floating point data values to be written.
    @Item  nmiss     Number of missing values.

@Description
The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
The values are converted to the external data type of the variable, if necessary.
@EndFunction
*/
void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
{
265
266
  if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
    {
267
      // In case the file format does not support single precision writing,
268
269
270
271
      // we fall back to double precision writing, converting the data on the fly.
      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
Thomas Jahns's avatar
Thomas Jahns committed
272
      streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
273
274
      Free(conversionBuffer);
    }
275
276
277
}


278
279
void streamWriteVarChunk(int streamID, int varID,
                         const int rect[][2], const double *data, int nmiss)
280
281
{
  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
282
                                    const int rect[][2], const void *data, int nmiss)
283
284
285
286
287
288
    = (void (*)(int, int, int, const int [][2], const void *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
}

/* single image implementation */
289
290
void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
                             const int rect[][2], const void *data, int nmiss)
291
292
293
294
295
296
297
298
299
300
301
302
{
  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);

  stream_t *streamptr = stream_to_pointer(streamID);

  // streamDefineTaxis(streamID);

  int filetype = streamptr->filetype;

  switch (filetype)
    {
#if defined (HAVE_LIBGRIB)
303
304
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:
305
306
#endif
#if defined (HAVE_LIBSERVICE)
307
    case CDI_FILETYPE_SRV:
308
309
#endif
#if defined (HAVE_LIBEXTRA)
310
    case CDI_FILETYPE_EXT:
311
312
#endif
#if defined (HAVE_LIBIEG)
313
    case CDI_FILETYPE_IEG:
314
315
316
317
318
319
320
321
#endif
#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
      xabort("streamWriteVarChunk not implemented for filetype %s!",
             strfiletype(filetype));
      break;
#endif
#if  defined  (HAVE_LIBNETCDF)
322
323
324
325
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
326
327
328
329
330
331
332
333
      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
      break;
#endif
    default:
      Error("%s support not compiled in!", strfiletype(filetype));
      break;
    }
}
334
335

static
336
int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
337
{
338
339
340
341
  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
  // A value > 0 is returned in this case, otherwise it returns zero.
  int status = 0;

342
343
344
345
346
347
348
  check_parg(data);

  stream_t *streamptr = stream_to_pointer(streamID);

  switch (streamptr->filetype)
    {
#if  defined  (HAVE_LIBGRIB)
349
350
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:
351
352
353
354
      grb_write_record(streamptr, memtype, data, nmiss);
      break;
#endif
#if  defined  (HAVE_LIBSERVICE)
355
    case CDI_FILETYPE_SRV:
356
      if ( memtype == MEMTYPE_FLOAT ) return 1;
357
358
359
360
      srvWriteRecord(streamptr, (const double *)data);
      break;
#endif
#if  defined  (HAVE_LIBEXTRA)
361
    case CDI_FILETYPE_EXT:
362
      if ( memtype == MEMTYPE_FLOAT ) return 1;
363
364
365
366
      extWriteRecord(streamptr, (const double *)data);
      break;
#endif
#if  defined  (HAVE_LIBIEG)
367
    case CDI_FILETYPE_IEG:
368
      if ( memtype == MEMTYPE_FLOAT ) return 1;
369
370
371
372
      iegWriteRecord(streamptr, (const double *)data);
      break;
#endif
#if  defined  (HAVE_LIBNETCDF)
373
374
375
376
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
377
378
379
380
381
382
383
384
385
386
387
      {
	cdf_write_record(streamptr, memtype, data, nmiss);
	break;
      }
#endif
    default:
      {
	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
	break;
      }
    }
388
389

  return status;
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
}

/*
@Function  streamWriteRecord
@Title     Write a horizontal slice of a variable

@Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
@Parameter
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
    @Item  data      Pointer to a block of double precision floating point data values to be written.
    @Item  nmiss     Number of missing values.

@Description
The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
The values are converted to the external data type of the variable, if necessary.
@EndFunction
*/
void streamWriteRecord(int streamID, const double *data, int nmiss)
{
  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
}

412

413
414
void streamWriteRecordF(int streamID, const float *data, int nmiss)
{
415
416
  if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
    {
417
      // In case the file format does not support single precision writing,
418
419
      // we fall back to double precision writing, converting the data on the fly.
      stream_t *streamptr = stream_to_pointer(streamID);
420
      int varID = streamptr->record->varID;
421
422
423
      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
Thomas Jahns's avatar
Thomas Jahns committed
424
      streamWriteRecord(streamID, conversionBuffer, nmiss);
425
426
      Free(conversionBuffer);
    }
427
428
}