iterator_fallback.c 14.3 KB
Newer Older
1
2
3
4
5
6
7
#include "iterator_fallback.h"

#include "cdi.h"
#include "cdi_int.h"
#include "dmemory.h"

#include <assert.h>
8
#include <limits.h>
9
10
#include <stdlib.h>

11
12
struct CdiFallbackIterator {
  CdiIterator super;
13
  int streamId, vlistId, subtypeId;
14
15
16
17
  char *path;   //needed for clone() & serialize()

  int variableCount, curVariable;
  int curLevelCount, curLevel;
18
  int curSubtypeCount, curSubtype;
19
20
21
22
23
24
25
26
27
  int curTimestep;
};

CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me)
{
  return &me->super;
}


28
//For more information on the condestruct() pattern, see comment in src/iterator_grib.c
29
static CdiFallbackIterator *cdiFallbackIterator_condestruct(CdiFallbackIterator *me, const char *path, int filetype)
30
31
32
{
  if(me) goto destruct;

33
  me = (CdiFallbackIterator *) Malloc(sizeof(*me));
34
35
36
37
38
39
40
41
  baseIterConstruct(&me->super, filetype);

  me->streamId = streamOpenRead(path);
  if(me->streamId == CDI_UNDEFID) goto destructSuper;
  me->vlistId = streamInqVlist(me->streamId);
  if(me->vlistId == CDI_UNDEFID) goto closeStream;
  me->variableCount = vlistNvars(me->vlistId);
  if(me->variableCount <= 0) goto closeStream;
42
43
  me->subtypeId = CDI_UNDEFID;   //Will be set in cdiFallbackIterator_nextField()
  me->curSubtypeCount = -1;      //Will be set in cdiFallbackIterator_nextField()
44
45
46
47
48
  me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()

  //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
  me->curTimestep = 0;
  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
49
50
  me->curVariable = -1;
  me->curSubtype = -1;
51
  me->curLevel = -1;
52
  me->path = path ? strdup(path) : NULL;
53
54
55
56
57
58
59
60
61
  if(!me->path) goto closeStream;

  return me;

// ^        constructor code        ^
// |                                |
// v destructor/error-cleanup code  v

destruct:
62
  Free(me->path);
63
64
65
66
closeStream:
  streamClose(me->streamId);
destructSuper:
  baseIterDestruct(&me->super);
67
  Free(me);
68
69
70
  return NULL;
}

71
CdiIterator *cdiFallbackIterator_new(const char *path, int filetype)
72
{
73
  return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
74
75
}

76
77
//Fetches the info that is derived from the current variable. Most of this is published by the data members in the base class.
static void fetchVariableInfo(CdiFallbackIterator *me)
78
{
79
  //Fetch data that's published via base class data members.
80
81
82
83
84
  me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
  me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
  me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
  int param = vlistInqVarParam(me->vlistId, me->curVariable);
  cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
85
86
87
88
89

  //Fetch the current level and subtype counts.
  me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
  me->subtypeId = vlistInqVarSubtype(me->vlistId, me->curVariable);
  me->curSubtypeCount = (me->subtypeId == CDI_UNDEFID) ? 1 : subtypeInqSize(me->subtypeId);
90
91
}

92
CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
93
{
Thomas Jahns's avatar
Thomas Jahns committed
94
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
95
96

  //Make another stream for this file. This yields an unadvanced iterator.
97
  CdiFallbackIterator *clone = cdiFallbackIterator_condestruct(NULL, me->path, me->super.filetype);
98
99
100
101
102
103
104
  if(!clone) return NULL;

  //Point the clone to the same position in the file.
  clone->variableCount = me->variableCount;
  clone->curVariable = me->curVariable;
  clone->curLevelCount = me->curLevelCount;
  clone->curLevel = me->curLevel;
105
106
  clone->curSubtypeCount = me->curSubtypeCount;
  clone->curSubtype = me->curSubtype;
107
108
109
  clone->curTimestep = me->curTimestep;

  clone->super.isAdvanced = super->isAdvanced;
110
  if(super->isAdvanced) fetchVariableInfo(clone);
111
112
113
114

  return clone;
}

115
char *cdiFallbackIterator_serialize(CdiIterator *super)
116
{
Thomas Jahns's avatar
Thomas Jahns committed
117
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
118

119
  char *escapedPath = cdiEscapeSpaces(me->path);
120
  char *result = (char *) Malloc(strlen(escapedPath)
121
122
                         + 7 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
  sprintf(result, "%s %d %d %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curSubtypeCount, me->curSubtype, me->curTimestep);
123
  Free(escapedPath);
124
125
126
  return result;
}

127
CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
128
{
129
  CdiFallbackIterator *me = (CdiFallbackIterator *) Malloc(sizeof(*me));
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  if(!me) goto fail;

  description = baseIter_constructFromString(&me->super, description);

  while(*description == ' ') description++;
  me->path = cdiUnescapeSpaces(description, &description);
  if(!me->path) goto destructSuper;

  me->streamId = streamOpenRead(me->path);
  if(me->streamId == CDI_UNDEFID) goto freePath;
  me->vlistId = streamInqVlist(me->streamId);
  if(me->vlistId == CDI_UNDEFID) goto closeStream;

  //This reads one variable from the description string, does error checking, and advances the given string pointer.
144
#define decodeValue(variable, description) do \
145
    { \
146
      const char *savedStart = description; \
147
148
149
150
151
152
153
154
155
      long long decodedValue = strtoll(description, (char**)&description, 0);   /*The cast is a workaround for the wrong signature of strtoll().*/ \
      variable = (int)decodedValue; \
      if(savedStart == description) goto closeStream; \
      if((long long)decodedValue != (long long)variable) goto closeStream; \
    } while(0)
  decodeValue(me->variableCount, description);
  decodeValue(me->curVariable, description);
  decodeValue(me->curLevelCount, description);
  decodeValue(me->curLevel, description);
156
157
  decodeValue(me->curSubtypeCount, description);
  decodeValue(me->curSubtype, description);
158
  decodeValue(me->curTimestep, description);
159
#undef decodeValue
160
161

  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
162
  if(me->super.isAdvanced) fetchVariableInfo(me);
163
164
165
166
167
168

  return me;

closeStream:
  streamClose(me->streamId);
freePath:
169
  Free(me->path);
170
171
destructSuper:
  baseIterDestruct(&me->super);
172
  Free(me);
173
174
175
176
fail:
  return NULL;
}

177
static int advance(CdiFallbackIterator *me)
178
179
{
  me->curLevel++;
180
  if(me->curLevel >= me->curLevelCount)
181
182
    {
      me->curLevel = 0;
183
184
      me->curSubtype++;
      if(me->curSubtype >= me->curSubtypeCount)
185
        {
186
187
188
189
190
191
192
193
          me->curSubtype = 0;
          me->curVariable++;
          if(me->curVariable >= me->variableCount)
            {
              me->curVariable = 0;
              me->curTimestep++;
              if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
            }
194
195
196
197
198
        }
    }
  return CDI_NOERR;
}

199
int cdiFallbackIterator_nextField(CdiIterator *super)
200
{
Thomas Jahns's avatar
Thomas Jahns committed
201
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
202
203
204
  int result = advance(me);
  if(result) return result;

205
  if(!me->curLevel && !me->curSubtype) fetchVariableInfo(me);   //Check whether we are processing a new variable/timestep and fetch the information that may have changed in this case.
206
207
208
  return CDI_NOERR;
}

209
char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
210
{
Thomas Jahns's avatar
Thomas Jahns committed
211
  CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
212
213

  //retrieve the time information
214
  int taxisId = vlistInqTaxis(me->vlistId);
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  int date = 0, time = 0;
  switch(timeType)
    {
      case kCdiTimeType_referenceTime:
        date = taxisInqRdate(taxisId);
        time = taxisInqRtime(taxisId);
        break;

      case kCdiTimeType_startTime:
        date = taxisInqVdate(taxisId);
        time = taxisInqVtime(taxisId);
        break;

      case kCdiTimeType_endTime:
        return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.

      default:
        assert(0 && "internal error, please report this bug");
    }

  //decode the time information and reencode it into an ISO-compliant string
236
237
238
  int year, month, day, hour, minute, second;
  cdiDecodeDate(date, &year, &month, &day);
  cdiDecodeTime(time, &hour, &minute, &second);
239
  char *result
240
    = (char *) Malloc(   4+1 +2+1 +2+1 +2+1 +2+1 +2+4+1);
241
  sprintf(result,     "%04d-%02d-%02dT%02d:%02d:%02d.000", year, month, day, hour, minute, second);
242
  return result;
243
244
}

245
int cdiFallbackIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
246
{
Thomas Jahns's avatar
Thomas Jahns committed
247
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
248
  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
Thomas Jahns's avatar
Thomas Jahns committed
249
  (void)levelSelector;
250
#define copyString(outPointer, key) do \
251
252
253
254
    { \
      if(outPointer) \
        { \
          char tempBuffer[CDI_MAX_NAME]; \
255
256
          int length = CDI_MAX_NAME;     \
          cdiInqKeyString(zaxisId, CDI_GLOBAL, key, tempBuffer, &length); \
257
          *outPointer = strdup(tempBuffer); \
258
259
260
        } \
    } \
  while(0)
261
262
263
264
  copyString(outName, CDI_KEY_NAME);
  copyString(outLongName, CDI_KEY_LONGNAME);
  copyString(outStdName, CDI_KEY_STDNAME);
  copyString(outUnit, CDI_KEY_UNITS);
265
#undef copyString
266
267
268
  int ltype = 0;
  cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
  return ltype;
269
270
}

271
int cdiFallbackIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
272
{
Thomas Jahns's avatar
Thomas Jahns committed
273
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);

  //handle NULL pointers once and for all
  double trash;
  if(!outValue1) outValue1 = &trash;
  if(!outValue2) outValue2 = &trash;

  //get the level value
  if(levelSelector)
    {
      *outValue1 = (zaxisInqLbounds(zaxisId, NULL))
                 ? zaxisInqLbound(zaxisId, me->curLevel)
                 : zaxisInqLevel(zaxisId, me->curLevel);
    }
  else
    {
      *outValue1 = (zaxisInqUbounds(zaxisId, NULL))
                 ? zaxisInqUbound(zaxisId, me->curLevel)
                 : zaxisInqLevel(zaxisId, me->curLevel);
    }
  *outValue2 = 0.0;

  //if this is a hybrid zaxis, lookup the coordinates in the vertical coordinate table
  ssize_t intLevel = (ssize_t)(2**outValue1);
  if(0 <= intLevel && intLevel < zaxisInqVctSize(zaxisId) - 1)
    {
300
      const double *coordinateTable = zaxisInqVctPtr(zaxisId);
301
302
303
304
305
306
      *outValue1 = coordinateTable[intLevel];
      *outValue2 = coordinateTable[intLevel + 1];
    }
  return CDI_NOERR;
}

307
int cdiFallbackIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
308
{
Thomas Jahns's avatar
Thomas Jahns committed
309
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
310
  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
311
312
  int ltype = 0;
  cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
313
314
315
316
317
318
  if (ltype != ZAXIS_HYBRID) return CDI_EINVAL;
  if (outVgridNumber)
    {
      *outVgridNumber = 0;
      cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, outVgridNumber);
    }
319
320
321
322
323
  if (outLevelCount)
    {
      *outLevelCount = 0;
      cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_NLEV, outLevelCount);
    }
324
325
326
327
328
329
  if (outUuid)
    {
      int length = CDI_UUID_SIZE;
      memset(outUuid, 0, length);
      cdiInqKeyBytes(zaxisId, CDI_GLOBAL, CDI_KEY_UUID, outUuid, &length);
    }
330
331
332
  return CDI_NOERR;
}

333
334
int cdiFallbackIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
{
Thomas Jahns's avatar
Thomas Jahns committed
335
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
336
#ifndef __cplusplus
337
338
  if(!outTileIndex) outTileIndex = &(int){0};
  if(!outTileAttribute) outTileAttribute = &(int){0};
339
340
341
342
343
#else
  int dummy = 0;
  if(!outTileIndex) outTileIndex = &dummy;
  if(!outTileAttribute) outTileAttribute = &dummy;
#endif
344
345

  int error = CDI_NOERR;
346
347
348
349
350
351
352
353
354
  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
    {
      error = CDI_EINVAL;
    }
  else
    {
      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileIndex", outTileIndex)) error = CDI_EINVAL;
      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileAttribute", outTileAttribute)) error = CDI_EINVAL;
    }
355
356
357
358
359
360
  if(error) *outTileIndex = *outTileAttribute = -1; //Guarantee defined values in case of an error.
  return error;
}

int cdiFallbackIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
{
Thomas Jahns's avatar
Thomas Jahns committed
361
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
362
#ifndef __cplusplus
363
364
  if(!outTileCount) outTileCount = &(int){0};
  if(!outTileAttributeCount) outTileAttributeCount = &(int){0};
365
366
367
368
369
#else
  int temp = 0;
  if(!outTileCount) outTileCount = &temp;
  if(!outTileAttributeCount) outTileAttributeCount = &temp;
#endif
370
371

  int error = CDI_NOERR;
372
373
374
375
376
377
378
379
380
  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
    {
      error = CDI_EINVAL;
    }
  else
    {
      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTiles", outTileCount)) error = CDI_EINVAL;
      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTileAttributes", outTileAttributeCount)) error = CDI_EINVAL;
    }
381
382
383
384
  if(error) *outTileCount = *outTileAttributeCount = -1; //Guarantee defined values in case of an error.
  return CDI_NOERR;
}

385
char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
386
{
Thomas Jahns's avatar
Thomas Jahns committed
387
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
388
389
390
  return vlistCopyVarName(me->vlistId, me->curVariable);
}

391
void cdiFallbackIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
392
{
Thomas Jahns's avatar
Thomas Jahns committed
393
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
394
  size_t missingValues = 0;
395
  streamReadVarSlice(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
396
  if(nmiss) *nmiss = (size_t)missingValues;
397
398
}

399
void cdiFallbackIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
400
{
Thomas Jahns's avatar
Thomas Jahns committed
401
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
402
  size_t missingValues = 0;
403
  streamReadVarSliceF(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
404
  if(nmiss) *nmiss = (size_t)missingValues;
405
406
}

407
void cdiFallbackIterator_delete(CdiIterator *super)
408
{
Thomas Jahns's avatar
Thomas Jahns committed
409
  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
410
  cdiFallbackIterator_condestruct(me, NULL, 0);
411
}
412
413
414
415
416
417
418
419
420
421

/*
 * Local Variables:
 * c-file-style: "Java"
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * show-trailing-whitespace: t
 * require-trailing-newline: t
 * End:
 */