Output.cc 17.1 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
3
4
/*
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.

Uwe Schulzweida's avatar
Uwe Schulzweida committed
5
  Copyright (C) 2003-2019 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6
7
8
9
10
11
12
13
14
15
16
17
18
  See COPYING file for copying and redistribution conditions.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/

/*
19
   This module contains the following operators:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
20

21
22
23
24
25
      Output     output          ASCII output
      Output     outputf         Formatted output
      Output     outputint       Integer output
      Output     outputsrv       SERVICE output
      Output     outputext       EXTRA output
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26
      Output     outputtab       Table output
27
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
28

Ralf Mueller's avatar
Ralf Mueller committed
29
#include <cdi.h>
Oliver Heidmann's avatar
Oliver Heidmann committed
30

31
#include "cdo_int.h"
32
#include "param_conversion.h"
33
#include <mpim_grid.h>
34
#include "gridreference.h"
Oliver Heidmann's avatar
Oliver Heidmann committed
35
#include "printinfo.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
36

Uwe Schulzweida's avatar
Uwe Schulzweida committed
37
static void
38
outputarr(int dig, size_t gridsize, std::vector<double> &array)
39
40
41
{
  for (size_t i = 0; i < gridsize; i++)
    {
42
      fprintf(stdout, "  arr[%zu] = %.*g;\n", i, dig, array[i]);
43
44
45
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
46
47
static void
outputsp(size_t gridsize, std::vector<double> &array, long ntr)
48
{
49
50
  double minval, maxval;
  arrayMinMax(gridsize, array.data(), minval, maxval);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
51
  if (/* T11 */ minval >= -1 && maxval <= 12)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    {
      double *spc = array.data();
      for (long m = 0; m <= ntr; m++)
        {
          for (long n = m; n <= ntr; n++)
            {
              fprintf(stdout, "%3d", (int) *spc++);
              fprintf(stdout, "%3d", (int) *spc++);
            }
          fprintf(stdout, "\n");
        }
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
66
67
static void
output(size_t gridsize, std::vector<double> &array)
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{
  int nout = 0;
  for (size_t i = 0; i < gridsize; i++)
    {
      if (nout == 6)
        {
          nout = 0;
          fprintf(stdout, "\n");
        }
      fprintf(stdout, " %12.6g", array[i]);
      nout++;
    }
  fprintf(stdout, "\n");
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
83
84
85
static void
outputxyz(size_t gridsize, std::vector<double> &array, double missval, size_t nlon, size_t nlat, std::vector<double> &lon,
          std::vector<double> &lat)
86
87
88
89
90
91
92
93
94
95
96
{
  double fmin = 0;
  double x, y, z;
  for (size_t i = 0; i < gridsize; i++)
    if (!DBL_IS_EQUAL(array[i], missval))
      {
        if (array[i] < fmin) fmin = array[i];
        fprintf(stdout, "%g\t%g\t%g\t%g\n", lon[i], lat[i], array[i], array[i]);
      }
  const char *fname = "frontplane.xyz";
  FILE *fp = fopen(fname, "w");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
97
  if (fp == nullptr) cdoAbort("Open failed on %s", fname);
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  // first front plane
  double dx = (lon[1] - lon[0]);
  double x0 = lon[0] - dx / 2;
  double y0 = lat[0] - dx / 2;
  double z0 = fmin;
  fprintf(fp, ">\n");
  for (size_t i = 0; i < nlon; ++i)
    {
      x = x0;
      y = y0;
      z = z0;
      fprintf(fp, "%g %g %g\n", x, y, z);
      x = x0;
      y = y0;
      z = array[i];
      fprintf(fp, "%g %g %g\n", x, y, z);
      x = x0 + dx;
      y = y0;
      fprintf(fp, "%g %g %g\n", x, y, z);
      x0 = x; /*y0 = y0;*/
      z0 = z;
    }
  x = x0;
  y = y0;
  z = fmin;
  fprintf(fp, "%g %g %g\n", x, y, z);
  x = lon[0] - dx / 2;
  fprintf(fp, "%g %g %g\n", x, y, z);

  // second front plane
  x0 = lon[0] - dx / 2;
  y0 = lat[0] - dx / 2;
  z0 = fmin;
  fprintf(fp, ">\n");
  for (size_t i = 0; i < nlat; ++i)
    {
      x = x0;
      y = y0;
      z = z0;
      fprintf(fp, "%g %g %g\n", x, y, z);
      x = x0;
      y = y0;
      z = array[i * nlon];
      fprintf(fp, "%g %g %g\n", x, y, z);
      x = x0;
      y = y0 + dx;
      fprintf(fp, "%g %g %g\n", x, y, z);
      /*x0 = x0;*/ y0 = y;
      z0 = z;
    }
  x = x0;
  y = y0;
  z = fmin;
  fprintf(fp, "%g %g %g\n", x, y, z);
  y = lat[0] - dx / 2;
  fprintf(fp, "%g %g %g\n", x, y, z);

  fclose(fp);
}

158
159
void *
Output(void *process)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
160
{
161
162
  int varID;
  int gridID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
163
164
  int nrecs;
  int levelID;
165
  size_t nmiss;
166
  int nelem = 1;
167
  int len;
168
  int index;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
169
  const char *format = nullptr;
170
171
  char paramstr[32];
  char vdatestr[32], vtimestr[32];
172
  std::vector<double> grid_center_lon, grid_center_lat;
173
  char name[CDI_MAX_NAME];
174
  int year, month, day;
175
176
  std::vector<int> keys;
  int nkeys = 0, k;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
  int nKeys;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
178
179

  // clang-format off
Uwe Schulzweida's avatar
Uwe Schulzweida committed
180
181
  int Keylen[]           = {      0,        8,      11,      4,      8,     6,     6,     6,     6,      4,      4,          6,     10,      8,      5,       2,     2 };
  enum                     {knohead,   kvalue,  kparam,  kcode,  kname,  klon,  klat,  klev,  kbin,  kxind,  kyind,  ktimestep,  kdate,  ktime,  kyear,  kmonth,  kday };
182
  const char *Keynames[] = {"nohead",  "value", "param", "code", "name", "lon", "lat", "lev", "bin", "xind", "yind", "timestep", "date", "time", "year", "month", "day"};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
183

Uwe Schulzweida's avatar
Uwe Schulzweida committed
184

185
  cdoInitialize(process);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
186

Uwe Schulzweida's avatar
Uwe Schulzweida committed
187
188
189
190
191
192
193
194
195
196
  int OUTPUT    = cdoOperatorAdd("output",    0, 1, nullptr);
  int OUTPUTINT = cdoOperatorAdd("outputint", 0, 0, nullptr);
  int OUTPUTSRV = cdoOperatorAdd("outputsrv", 0, 0, nullptr);
  int OUTPUTEXT = cdoOperatorAdd("outputext", 0, 0, nullptr);
  int OUTPUTF   = cdoOperatorAdd("outputf",   0, 0, nullptr);
  int OUTPUTTS  = cdoOperatorAdd("outputts",  0, 0, nullptr);
  int OUTPUTFLD = cdoOperatorAdd("outputfld", 0, 0, nullptr);
  int OUTPUTARR = cdoOperatorAdd("outputarr", 0, 0, nullptr);
  int OUTPUTXYZ = cdoOperatorAdd("outputxyz", 0, 0, nullptr);
  int OUTPUTTAB = cdoOperatorAdd("outputtab", 0, 0, nullptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
197
  // clang-format on
Uwe Schulzweida's avatar
Uwe Schulzweida committed
198

199
200
  UNUSED(OUTPUT);

201
  int operatorID = cdoOperatorID();
202
  bool opercplx = cdoOperatorF2(operatorID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
203

204
  if (operatorID == OUTPUTF)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
205
    {
206
207
      operatorInputArg("format and number of elements [optional]");

208
      if (operatorArgc() < 1) cdoAbort("Too few arguments!");
209

Uwe Schulzweida's avatar
Uwe Schulzweida committed
210
      format = operatorArgv()[0];
211
      if (operatorArgc() == 2) nelem = parameter2int(operatorArgv()[1]);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
212
    }
213
  else if (operatorID == OUTPUTTAB)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
214
    {
215
216
      bool lhead = true;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
217
      operatorInputArg("keys to print");
218

219
      int npar = operatorArgc();
220
      char **parnames = operatorArgv();
Uwe Schulzweida's avatar
Uwe Schulzweida committed
221

222
      if (Options::cdoVerbose)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
223
        for (int i = 0; i < npar; i++) cdoPrint("key %d = %s", i + 1, parnames[i]);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
224

225
      keys.resize(npar);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
226
      nkeys = 0;
227
228
229
230
231
232
233
234
235
236
      nKeys = sizeof(Keynames) / sizeof(char *);
      for (int i = 0; i < npar; i++)
        {
          for (k = 0; k < nKeys; ++k)
            {
              //	      len = strlen(parnames[i]);
              len = strlen(Keynames[k]);
              if (len < 3) len = 3;
              if (strncmp(parnames[i], Keynames[k], len) == 0)
                {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
237
                  int len2 = strlen(parnames[i]);
238
                  if (len2 > len && parnames[i][len] != ':')
239
                    cdoAbort("Key parameter >%s< contains invalid character at position %d!", parnames[i], len + 1);
240
241
242
243
244
245

                  if (k == knohead)
                    lhead = false;
                  else
                    {
                      keys[nkeys++] = k;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
246
                      if (len2 > len && parnames[i][len] == ':' && isdigit(parnames[i][len + 1]))
247
248
249
250
251
252
253
254
255
                        Keylen[k] = atoi(&parnames[i][len + 1]);
                    }
                  break;
                }
            }

          if (k == nKeys) cdoAbort("Key %s unsupported!", parnames[i]);
        }

256
      if (Options::cdoVerbose)
257
        for (k = 0; k < nkeys; ++k)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
258
          cdoPrint("keynr = %d  keyid = %d  keylen = %d  keyname = %s", k, keys[k], Keylen[keys[k]], Keynames[keys[k]]);
259
260
261
262
263
264
265
266
267
268
269
270

      if (lhead)
        {
          fprintf(stdout, "#");
          for (k = 0; k < nkeys; ++k)
            {
              len = Keylen[keys[k]];
              //   if ( k == 0 ) len -= 1;
              fprintf(stdout, "%*s ", len, Keynames[keys[k]]);
            }
          fprintf(stdout, "\n");
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
271
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
272

273
  for (int indf = 0; indf < cdoStreamCnt(); indf++)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
274
    {
275
      int streamID = cdoStreamOpenRead(cdoStreamName(indf));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
276

277
      int vlistID = cdoStreamInqVlist(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
278

279
280
      int ngrids = vlistNgrids(vlistID);
      int ndiffgrids = 0;
281
282
      for (index = 1; index < ngrids; index++)
        if (vlistGrid(vlistID, 0) != vlistGrid(vlistID, index)) ndiffgrids++;
283

284
      if (ndiffgrids > 0) cdoAbort("Too many different grids!");
285

286
      gridID = vlistGrid(vlistID, 0);
287
      int gridtype = gridInqType(gridID);
288
289
      size_t gridsize = gridInqSize(gridID);
      size_t nwpv = (vlistNumber(vlistID) == CDI_COMP) ? 2 : 1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
290
      if (nwpv == 2 && !opercplx) cdoAbort("Fields with complex numbers are not supported by this operator!");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
291
      size_t gridsizemax = nwpv * gridInqSize(gridID);
292
      std::vector<double> array(gridsizemax);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
293

Uwe Schulzweida's avatar
Uwe Schulzweida committed
294
      if (operatorID == OUTPUTFLD || operatorID == OUTPUTXYZ || operatorID == OUTPUTTAB)
295
        {
296
          if (gridtype == GRID_GME) gridID = gridToUnstructured(gridID, 0);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
297

298
          if (gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR) gridID = gridToCurvilinear(gridID, 0);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
299

300
301
          if (gridtype == GRID_UNSTRUCTURED)
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
302
              if (gridInqYvals(gridID, nullptr) == 0 || gridInqXvals(gridID, nullptr) == 0)
303
304
305
306
307
308
309
310
                {
                  if (gridInqNumber(gridID) > 0)
                    {
                      gridID = referenceToGrid(gridID);
                      if (gridID == -1) cdoAbort("Reference to source grid not found!");
                    }
                }
            }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
311

Uwe Schulzweida's avatar
Uwe Schulzweida committed
312
          if (gridInqYvals(gridID, nullptr) == 0 || gridInqXvals(gridID, nullptr) == 0)
313
            cdoAbort("Cell center coordinates missing!");
314

315
316
317
318
          grid_center_lon.resize(gridsize);
          grid_center_lat.resize(gridsize);
          gridInqXvals(gridID, grid_center_lon.data());
          gridInqYvals(gridID, grid_center_lat.data());
Uwe Schulzweida's avatar
Uwe Schulzweida committed
319

320
321
322
323
324
325
          // Convert lat/lon units if required
          char units[CDI_MAX_NAME];
          gridInqXunits(gridID, units);
          grid_to_degree(units, gridsize, grid_center_lon.data(), "grid center lon");
          gridInqYunits(gridID, units);
          grid_to_degree(units, gridsize, grid_center_lat.data(), "grid center lat");
326
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
327

328
329
      int tsID = 0;
      int taxisID = vlistInqTaxis(vlistID);
330
331
      while ((nrecs = cdoStreamInqTimestep(streamID, tsID)))
        {
332
          int64_t vdate = taxisInqVdate(taxisID);
333
334
335
336
337
338
339
340
          int vtime = taxisInqVtime(taxisID);
          date2str(vdate, vdatestr, sizeof(vdatestr));
          time2str(vtime, vtimestr, sizeof(vtimestr));

          cdiDecodeDate(vdate, &year, &month, &day);

          for (int recID = 0; recID < nrecs; recID++)
            {
341
              cdoInqRecord(streamID, &varID, &levelID);
342
343

              vlistInqVarName(vlistID, varID, name);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
344
345
346
347
348
349
350
351
              const int param = vlistInqVarParam(vlistID, varID);
              const int code = vlistInqVarCode(vlistID, varID);
              const int gridID = vlistInqVarGrid(vlistID, varID);
              const int zaxisID = vlistInqVarZaxis(vlistID, varID);
              const int datatype = vlistInqVarDatatype(vlistID, varID);
              const int dig = (datatype == CDI_DATATYPE_FLT64) ? Options::CDO_dbl_digits : Options::CDO_flt_digits;
              const size_t nwpv = (vlistInqVarNumber(vlistID, varID) == CDI_COMP) ? 2 : 1;
              const size_t gridsize = nwpv * gridInqSize(gridID);
352
353
              size_t nlon = gridInqXsize(gridID);
              size_t nlat = gridInqYsize(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
354
355
              const double level = cdoZaxisInqLevel(zaxisID, levelID);
              const double missval = vlistInqVarMissval(vlistID, varID);
356
357
358
359
360
361
362
363
364

              cdiParamToString(param, paramstr, sizeof(paramstr));

              if (nlon * nlat != gridsize)
                {
                  nlon = gridsize;
                  nlat = 1;
                }

365
              cdoReadRecord(streamID, array.data(), &nmiss);
366
367

              if (operatorID == OUTPUTSRV)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
368
                fprintf(stdout, "%4d %8g %8ld %4d %8zu %8zu %d %d\n", code, level, (long)vdate, vtime, nlon, nlat, 0, 0);
369

370
              if (operatorID == OUTPUTEXT) fprintf(stdout, "%8lld %4d %8g %8zu\n", vdate, code, level, gridsize);
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

              if (operatorID == OUTPUTINT)
                {
                  int nout = 0;
                  for (size_t i = 0; i < gridsize; i++)
                    {
                      if (nout == 8)
                        {
                          nout = 0;
                          fprintf(stdout, "\n");
                        }
                      fprintf(stdout, " %8d", (int) array[i]);
                      nout++;
                    }
                  fprintf(stdout, "\n");
                }
              else if (operatorID == OUTPUTF)
                {
                  int nout = 0;
                  for (size_t i = 0; i < gridsize; i++)
                    {
                      if (nout == nelem)
                        {
                          nout = 0;
                          fprintf(stdout, "\n");
                        }
                      fprintf(stdout, format, array[i]);
                      nout++;
                    }
                  fprintf(stdout, "\n");
                }
              else if (operatorID == OUTPUTTS)
                {
                  char vdatestr[32], vtimestr[32];

Uwe Schulzweida's avatar
Uwe Schulzweida committed
406
                  if (gridsize > 1) cdoAbort("operator works only with one gridpoint!");
407
408
409
410

                  date2str(vdate, vdatestr, sizeof(vdatestr));
                  time2str(vtime, vtimestr, sizeof(vtimestr));

411
                  fprintf(stdout, "%s %s %.*g\n", vdatestr, vtimestr, dig, array[0]);
412
413
414
415
416
                }
              else if (operatorID == OUTPUTFLD)
                {
                  int hour, minute, second;
                  cdiDecodeTime(vtime, &hour, &minute, &second);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
417
                  double xdate = vdate - (vdate / 100) * 100 + (hour * 3600 + minute * 60 + second) / 86400.;
418
419
                  for (size_t i = 0; i < gridsize; i++)
                    if (!DBL_IS_EQUAL(array[i], missval))
420
                      fprintf(stdout, "%g\t%g\t%g\t%.*g\n", xdate, grid_center_lat[i], grid_center_lon[i], dig, array[i]);
421
422
423
                }
              else if (operatorID == OUTPUTTAB)
                {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
424
425
                  const bool l2d = (gridtype == GRID_CURVILINEAR);
                  const int xsize = gridInqXsize(gridID);
426
427
428
429
430
431
432
433
434
435
436
                  // int ysize = gridInqYsize(gridID);

                  for (size_t i = 0; i < gridsize; i++)
                    {
                      int yind = i;
                      int xind = i;
                      if (l2d)
                        {
                          yind /= xsize;
                          xind -= yind * xsize;
                        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
437
438
                      const double lon = grid_center_lon[i];
                      const double lat = grid_center_lat[i];
439
440
441
442
443

                      for (k = 0; k < nkeys; ++k)
                        {
                          len = Keylen[keys[k]];
                          switch (keys[k])
444
                            {
445
                            case kvalue: fprintf(stdout, "%*.*g ", len, dig, array[i]); break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
446
447
448
                            case kparam: fprintf(stdout, "%*s ", len, paramstr); break;
                            case kcode: fprintf(stdout, "%*d ", len, code); break;
                            case kname: fprintf(stdout, "%*s ", len, name); break;
449
450
                            case klon: fprintf(stdout, "%*g ", len, lon); break;
                            case klat: fprintf(stdout, "%*g ", len, lat); break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
451
452
453
454
455
456
457
458
459
                            case klev: fprintf(stdout, "%*g ", len, level); break;
                            case kbin: fprintf(stdout, "%*g ", len, level); break;
                            case kxind: fprintf(stdout, "%*d ", len, xind + 1); break;
                            case kyind: fprintf(stdout, "%*d ", len, yind + 1); break;
                            case ktimestep: fprintf(stdout, "%*d ", len, tsID + 1); break;
                            case kdate: fprintf(stdout, "%*s ", len, vdatestr); break;
                            case ktime: fprintf(stdout, "%*s ", len, vtimestr); break;
                            case kyear: fprintf(stdout, "%*d ", len, year); break;
                            case kmonth: fprintf(stdout, "%*d ", len, month); break;
460
                            case kday: fprintf(stdout, "%*d ", len, day); break;
461
462
                            }
                        }
463
464
465
466
467
468
469
                      fprintf(stdout, "\n");
                    }
                }
              else if (operatorID == OUTPUTXYZ)
                {
                  if (tsID == 0 && recID == 0)
                    {
470
                      outputxyz(gridsize, array, missval, nlon, nlat, grid_center_lon, grid_center_lat);
471
472
473
474
                    }
                }
              else if (operatorID == OUTPUTARR)
                {
475
                  outputarr(dig, gridsize, array);
476
477
478
479
480
                }
              else
                {
                  if (gridInqType(gridID) == GRID_SPECTRAL && gridsize <= 156)
                    {
481
                      outputsp(gridsize, array, gridInqTrunc(gridID));
482
483
484
                    }
                  else
                    {
485
                      output(gridsize, array);
486
487
488
489
490
491
                    }
                }
            }

          tsID++;
        }
492

493
      cdoStreamClose(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
494
495
496
497
    }

  cdoFinish();

Uwe Schulzweida's avatar
Uwe Schulzweida committed
498
  return nullptr;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
499
}