printinfo.cc 23.1 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
#include <cdi.h>

3
#include "cdo_options.h"
4
#include "cdo_cdi_wrapper.h"
5
#include "cdi_uuid.h"
6
#include "mpmo_color.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
7
8
#include "datetime.h"
#include "compare.h"
9
10
#include "printinfo.h"

11
12
std::string
datetimeToString(int64_t date, int time)
13
14
15
16
17
18
{
  int year, month, day;
  cdiDecodeDate(date, &year, &month, &day);
  int hour, minute, second;
  cdiDecodeTime(time, &hour, &minute, &second);

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  char cstr[64];
  snprintf(cstr, sizeof(cstr), DATE_FORMAT "T" TIME_FORMAT, year, month, day, hour, minute, second);

  return std::string(cstr);
}

std::string
dateToString(int64_t date)
{
  int year, month, day;
  cdiDecodeDate(date, &year, &month, &day);

  char cstr[32];
  snprintf(cstr, sizeof(cstr), DATE_FORMAT, year, month, day);

  return std::string(cstr);
}

std::string
timeToString(int time)
{
  int hour, minute, second;
  cdiDecodeTime(time, &hour, &minute, &second);

  char cstr[32];
  snprintf(cstr, sizeof(cstr), TIME_FORMAT, hour, minute, second);

  return std::string(cstr);
47
48
49
}

const char *
50
comptypeToName(int comptype)
51
{
52
53
54
55
56
57
58
  switch (comptype)
    {
    case CDI_COMPRESS_SZIP: return "szip";
    case CDI_COMPRESS_ZIP: return "zip";
    case CDI_COMPRESS_JPEG: return "jpeg";
    case CDI_COMPRESS_AEC: return "aec";
    }
59
60
61
62
  return " ";
}

void
63
printFiletype(CdoStreamID streamID, int vlistID)
64
{
65
  const auto filetype = cdoInqFiletype(streamID);
66

67
68
69
70
71
  const auto filetypestr = cdi_filetype2str(filetype);
  if (filetypestr == nullptr || *filetypestr == 0)
    printf("  unsupported filetype %d" , filetype);
  else
    printf("%s", filetypestr);
72

73
  // clang-format off
74
  if (filetype == CDI_FILETYPE_SRV || filetype == CDI_FILETYPE_EXT || filetype == CDI_FILETYPE_IEG)
75
    {
76
      switch (cdoInqByteorder(streamID))
77
78
79
	{
	case CDI_BIGENDIAN:    printf("  BIGENDIAN");  break;
	case CDI_LITTLEENDIAN: printf("  LITTLEENDIAN");  break;
80
	default: printf("  byteorder: %d undefined", cdoInqByteorder(streamID));  break;
81
82
83
84
	}
    }
  // clang-format on

Uwe Schulzweida's avatar
Uwe Schulzweida committed
85
86
  const int nvars = vlistNvars(vlistID);
  const int comps[] = { CDI_COMPRESS_ZIP, CDI_COMPRESS_JPEG, CDI_COMPRESS_SZIP, CDI_COMPRESS_AEC };
87
88
89
90
  unsigned kk = 0;
  for (unsigned k = 0; k < sizeof(comps) / sizeof(int); ++k)
    for (int varID = 0; varID < nvars; varID++)
      {
91
        const auto comptype = vlistInqVarCompType(vlistID, varID);
92
93
        if (comptype == comps[k])
          {
94
            printf("%c%s", (kk++ == 0) ? ' ' : '/', comptypeToName(comptype));
95
96
97
98
99
100
101
            break;
          }
      }

  printf("\n");
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
102
static void
103
104
print_xvals(int gridID, int dig)
{
105
  const auto xsize = gridInqXsize(gridID);
106
  if (xsize && gridInqXvals(gridID, NULL))
107
108
    {
      char xname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
109
      int length = CDI_MAX_NAME;
110
111
      cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, xname, &length);
      length = CDI_MAX_NAME;
112
      cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_UNITS, xunits, &length);
113

114
115
116
      const auto xfirst = gridInqXval(gridID, 0);
      const auto xlast = gridInqXval(gridID, xsize - 1);
      const auto xinc = gridInqXinc(gridID);
117
118
119
120
121
122
123
124
125
126
127
128
      fprintf(stdout, "%33s : %.*g", xname, dig, xfirst);
      if (xsize > 1)
        {
          fprintf(stdout, " to %.*g", dig, xlast);
          if (IS_NOT_EQUAL(xinc, 0)) fprintf(stdout, " by %.*g", dig, xinc);
        }
      fprintf(stdout, " %s", xunits);
      if (gridIsCircular(gridID)) fprintf(stdout, "  circular");
      fprintf(stdout, "\n");
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
129
static void
130
131
print_yvals(int gridID, int dig)
{
132
  const auto ysize = gridInqYsize(gridID);
133
  if (ysize && gridInqYvals(gridID, NULL))
134
135
    {
      char yname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
136
      int length = CDI_MAX_NAME;
137
138
      cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, yname, &length);
      length = CDI_MAX_NAME;
139
      cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_UNITS, yunits, &length);
140

141
142
143
      const auto yfirst = gridInqYval(gridID, 0);
      const auto ylast = gridInqYval(gridID, ysize - 1);
      const auto yinc = gridInqYinc(gridID);
144
145
146
      fprintf(stdout, "%33s : %.*g", yname, dig, yfirst);
      if (ysize > 1)
        {
147
          const auto gridtype = gridInqType(gridID);
148
149
150
151
152
153
154
155
156
          fprintf(stdout, " to %.*g", dig, ylast);
          if (IS_NOT_EQUAL(yinc, 0) && gridtype != GRID_GAUSSIAN && gridtype != GRID_GAUSSIAN_REDUCED)
            fprintf(stdout, " by %.*g", dig, yinc);
        }
      fprintf(stdout, " %s", yunits);
      fprintf(stdout, "\n");
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
157
static void
158
159
160
161
162
print_xyvals2D(int gridID, int dig)
{
  if (gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL))
    {
      char xname[CDI_MAX_NAME], yname[CDI_MAX_NAME], xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
163
      int length = CDI_MAX_NAME;
164
165
166
167
      cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, xname, &length);
      length = CDI_MAX_NAME;
      cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, yname, &length);
      length = CDI_MAX_NAME;
168
169
170
      cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_UNITS, xunits, &length);
      length = CDI_MAX_NAME;
      cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_UNITS, yunits, &length);
171

172
      const auto gridsize = gridInqSize(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
173
      Varray<double> xvals2D(gridsize), yvals2D(gridsize);
174

175
176
      gridInqXvals(gridID, xvals2D.data());
      gridInqYvals(gridID, yvals2D.data());
177

178
179
      const auto xmm = varrayMinMax(gridsize, xvals2D);
      const auto ymm = varrayMinMax(gridsize, yvals2D);
180

181
      double xinc = 0, yinc = 0;
182
      const auto gridtype = gridInqType(gridID);
183
184
      if (gridtype == GRID_CURVILINEAR)
        {
185
186
          const auto xsize = gridInqXsize(gridID);
          const auto ysize = gridInqYsize(gridID);
187
188
          if (xsize > 1)
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
189
              Varray<double> xvals(xsize);
190
              for (size_t i = 0; i < xsize; ++i) xvals[i] = xvals2D[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
191
              xinc = fabs(xvals[xsize - 1] - xvals[0]) / (xsize - 1);
192
              for (size_t i = 1; i < xsize; i++)
193
                if (fabs(fabs(xvals[i - 1] - xvals[i]) - xinc) > 0.005 * xinc)
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
                  {
                    xinc = 0;
                    break;
                  }
              if (IS_NOT_EQUAL(xinc, 0))
                {
                  for (size_t i = 1; i < ysize; i++)
                    if (IS_NOT_EQUAL(xvals2D[i * xsize], xvals2D[0])
                        || IS_NOT_EQUAL(xvals2D[(i + 1) * xsize - 1], xvals2D[xsize - 1]))
                      {
                        xinc = 0;
                        break;
                      }
                }
            }
          if (ysize > 1)
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
211
              Varray<double> yvals(ysize);
212
              for (size_t i = 0; i < ysize; ++i) yvals[i] = yvals2D[i * xsize];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
213
              yinc = fabs(yvals[ysize - 1] - yvals[0]) / (ysize - 1);
214
              for (size_t i = 1; i < ysize; i++)
215
                if (fabs(fabs(yvals[i - 1] - yvals[i]) - yinc) > 0.005 * yinc)
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
                  {
                    yinc = 0;
                    break;
                  }
              if (IS_NOT_EQUAL(yinc, 0))
                {
                  for (size_t i = 1; i < xsize; i++)
                    if (IS_NOT_EQUAL(yvals2D[i], yvals2D[0])
                        || IS_NOT_EQUAL(yvals2D[(ysize - 1) * xsize + i], yvals2D[(ysize - 1) * xsize]))
                      {
                        yinc = 0;
                        break;
                      }
                }
            }
        }

233
234
      fprintf(stdout, "%33s : %.*g", xname, dig, xmm.min);
      if (gridsize > 1) fprintf(stdout, " to %.*g", dig, xmm.max);
235
236
237
238
      if (IS_NOT_EQUAL(xinc, 0)) fprintf(stdout, " by %.*g", dig, xinc);
      fprintf(stdout, " %s", xunits);
      if (gridIsCircular(gridID)) fprintf(stdout, "  circular");
      fprintf(stdout, "\n");
239
240
      fprintf(stdout, "%33s : %.*g", yname, dig, ymm.min);
      if (gridsize > 1) fprintf(stdout, " to %.*g", dig, ymm.max);
241
242
243
244
245
246
      if (IS_NOT_EQUAL(yinc, 0)) fprintf(stdout, " by %.*g", dig, yinc);
      fprintf(stdout, " %s", yunits);
      fprintf(stdout, "\n");
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
247
static void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
248
printGridNumPoints(int gridtype, int gridID, size_t gridsize, size_t xsize, size_t ysize)
249
250
251
252
{
  fprintf(stdout, "points=%zu", gridsize);
  if (gridtype == GRID_GAUSSIAN_REDUCED)
    fprintf(stdout, "  nlat=%zu", ysize);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
253
  else if (xsize && ysize)
254
255
    fprintf(stdout, " (%zux%zu)", xsize, ysize);

256
  const auto numLPE = gridInqNP(gridID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
257
258
259
260
261
  if (numLPE > 0)
    {
      if (gridtype == GRID_GAUSSIAN) fprintf(stdout, "  F%d", numLPE);
      if (gridtype == GRID_GAUSSIAN_REDUCED) fprintf(stdout, "  N%d", numLPE);
    }
262
  reset_text_color(stdout);
263
264
265

  fprintf(stdout, "\n");
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
266
267

static void
268
printGridInfoKernel(int gridID, int index, int lproj)
269
{
270
  const int dig = Options::CDO_flt_digits;
271
  const auto gridtype = gridInqType(gridID);
272
273
274
275

  if (lproj && gridtype != GRID_PROJECTION)
    fprintf(stderr, "Internal problem (%s): sub grid not equal GRID_PROJECTION!\n", __func__);

276
  const auto trunc = gridInqTrunc(gridID);
277
  const auto gridsize = gridInqSize(gridID);
278
279
  const auto xsize = gridInqXsize(gridID);
  const auto ysize = gridInqYsize(gridID);
280
281
282
283

  if (!lproj)
    {
      fprintf(stdout, "  %4d : ", index + 1);
284
      set_text_color(stdout, BLUE);
285
      fprintf(stdout, "%-24s", gridNamePtr(gridtype));
286
      reset_text_color(stdout);
287
288
289
290
291
292
293
294
295
      fprintf(stdout, " : ");
    }

  if (gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION || gridtype == GRID_GENERIC || gridtype == GRID_CHARXY
      || gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED)
    {
      if (!lproj)

        {
296
          set_text_color(stdout, GREEN);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
297
          printGridNumPoints(gridtype, gridID, gridsize, xsize, ysize);
298
299
        }

300
301
302
303
      char gmapname[CDI_MAX_NAME];
      int length = CDI_MAX_NAME;
      cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
      if (gridtype == GRID_PROJECTION || gmapname[0])
304
        {
305
          if (gmapname[0] == 0) strcpy(gmapname, "undefined");
306
          set_text_color(stdout, BLUE);
307
          fprintf(stdout, "         %24s", "mapping");
308
          reset_text_color(stdout);
309
          fprintf(stdout, " : ");
310
          set_text_color(stdout, GREEN);
311
          fprintf(stdout, "%s\n", gmapname);
312
          reset_text_color(stdout);
313
314
        }

315
      if (gridtype != GRID_GAUSSIAN_REDUCED) print_xvals(gridID, dig);
316
317
318
319
320
      print_yvals(gridID, dig);

      if (gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL))
        {
          fprintf(stdout, "%33s :", "available");
321
322
323
324
325
326
          if (gridtype == GRID_GAUSSIAN_REDUCED && gridInqXvals(gridID, NULL)) fprintf(stdout, " xvals");
          // clang-format off
          if      (gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL)) fprintf(stdout, " cellbounds");
          else if (gridInqXbounds(gridID, NULL)) fprintf(stdout, " xbounds");
          else if (gridInqYbounds(gridID, NULL)) fprintf(stdout, " ybounds");
          // clang-format on
327
328
329
330
331
332
333
          if (gridHasArea(gridID)) fprintf(stdout, " area");
          if (gridInqMask(gridID, NULL)) fprintf(stdout, " mask");
          fprintf(stdout, "\n");
        }
    }
  else if (gridtype == GRID_SPECTRAL)
    {
334
      set_text_color(stdout, GREEN);
335
      fprintf(stdout, "points=%zu  nsp=%zu  T%d", gridsize, gridsize / 2, trunc);
336
      if (gridInqComplexPacking(gridID)) fprintf(stdout, "  complexPacking");
337
      reset_text_color(stdout);
338
339
340
341
      fprintf(stdout, "\n");
    }
  else if (gridtype == GRID_FOURIER)
    {
342
      set_text_color(stdout, GREEN);
343
      fprintf(stdout, "points=%zu  nfc=%zu  T%d\n", gridsize, gridsize / 2, trunc);
344
      reset_text_color(stdout);
345
346
347
348
349
    }
  else if (gridtype == GRID_GME)
    {
      int nd, ni, ni2, ni3;
      gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
350
      set_text_color(stdout, GREEN);
351
      fprintf(stdout, "points=%zu  nd=%d  ni=%d\n", gridsize, nd, ni);
352
      reset_text_color(stdout);
353
354
355
    }
  else if (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
    {
356
      set_text_color(stdout, GREEN);
357
358
359
360
361
362
      if (gridtype == GRID_CURVILINEAR)
        fprintf(stdout, "points=%zu (%zux%zu)", gridsize, xsize, ysize);
      else
        fprintf(stdout, "points=%zu", gridsize);

      if (gridtype == GRID_UNSTRUCTURED && gridInqNvertex(gridID) > 0) fprintf(stdout, "  nvertex=%d", gridInqNvertex(gridID));
363
      reset_text_color(stdout);
364
365
366
367
368

      fprintf(stdout, "\n");

      if (gridtype == GRID_UNSTRUCTURED)
        {
369
370
          int number = 0;
          cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, &number);
371
372
          int position = 0;
          cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDINREFERENCE, &position);
373
374
          if (number > 0) fprintf(stdout, "%33s : number=%d  position=%d\n", "grid", number, position);

375
          int length = 0;
376
          if (CDI_NOERR == cdiInqKeyLen(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, &length))
377
378
            {
              char reference_link[8192];
379
              cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, reference_link, &length);
380
381
382
383
384
385
386
387
              fprintf(stdout, "%33s : %s\n", "uri", reference_link);
            }
        }

      print_xyvals2D(gridID, dig);
    }
  else /* if ( gridtype == GRID_GENERIC ) */
    {
388
      set_text_color(stdout, GREEN);
389
390
391
392
      if (ysize == 0)
        fprintf(stdout, "points=%zu\n", gridsize);
      else
        fprintf(stdout, "points=%zu (%zux%zu)\n", gridsize, xsize, ysize);
393
      reset_text_color(stdout);
394
395
396
397
398
399
400
401
402
403
404
405
406
407
    }

  if (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
    {
      if (gridHasArea(gridID) || gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL))
        {
          fprintf(stdout, "%33s :", "available");
          if (gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL)) fprintf(stdout, " cellbounds");
          if (gridHasArea(gridID)) fprintf(stdout, " area");
          if (gridInqMask(gridID, NULL)) fprintf(stdout, " mask");
          fprintf(stdout, "\n");
        }
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
408
  unsigned char uuidOfHGrid[CDI_UUID_SIZE] = { 0 };
409
410
  int length = CDI_UUID_SIZE;
  cdiInqKeyBytes(gridID, CDI_GLOBAL, CDI_KEY_UUID, uuidOfHGrid, &length);
411
412
413
414
415
  if (!cdiUUIDIsNull(uuidOfHGrid))
    {
      char uuidOfHGridStr[37];
      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
      if (uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36)
416
        fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
417
418
419
420
421
422
    }
}

void
printGridInfo(int vlistID)
{
423
  const auto ngrids = vlistNgrids(vlistID);
424
425
  for (int index = 0; index < ngrids; index++)
    {
426
      const auto gridID = vlistGrid(vlistID, index);
427
      printGridInfoKernel(gridID, index, false);
428
      const auto projID = gridInqProj(gridID);
429
430
431
432
      if (projID != CDI_UNDEFID) printGridInfoKernel(projID, index, true);
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
433
static void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
434
printZaxisBoundsInfo(const int zaxisID, const int dig, const int levelsize, const double zinc, const char *zunits)
435
{
436
437
  auto level1 = zaxisInqLbound(zaxisID, 0);
  auto level2 = zaxisInqUbound(zaxisID, 0);
438
  if (!(levelsize == 1 && IS_EQUAL(level1, level2) && fabs(level1) <= 0))
Uwe Schulzweida's avatar
Uwe Schulzweida committed
439
    {
440
441
442
443
444
445
446
447
448
449
450
      fprintf(stdout, "%33s : ", "bounds");
      fprintf(stdout, "%.*g-%.*g", dig, level1, dig, level2);
      if (levelsize > 1)
        {
          level1 = zaxisInqLbound(zaxisID, levelsize - 1);
          level2 = zaxisInqUbound(zaxisID, levelsize - 1);
          fprintf(stdout, " to %.*g-%.*g", dig, level1, dig, level2);
          if (IS_NOT_EQUAL(zinc, 0)) fprintf(stdout, " by %.*g", dig, zinc);
        }
      fprintf(stdout, " %s", zunits);
      fprintf(stdout, "\n");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
451
    }
452
453
454
455
456
457
458
459
}

static bool
zaxisTypeIsSingleLayer(int zaxistype)
{
  switch (zaxistype)
    {
    case ZAXIS_MEANSEA:
460
    case ZAXIS_TROPOPAUSE:
461
462
463
464
465
466
467
468
469
470
    case ZAXIS_TOA:
    case ZAXIS_SEA_BOTTOM:
    case ZAXIS_ATMOSPHERE:
    case ZAXIS_CLOUD_BASE:
    case ZAXIS_CLOUD_TOP:
    case ZAXIS_ISOTHERM_ZERO:
    case ZAXIS_LAKE_BOTTOM:
    case ZAXIS_SEDIMENT_BOTTOM:
    case ZAXIS_SEDIMENT_BOTTOM_TA:
    case ZAXIS_SEDIMENT_BOTTOM_TW:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
471
    case ZAXIS_SURFACE: return true;
472
473
474
    }

  return false;
475
476
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
477
static void
478
printZaxisLevelInfo(const int levelsize, const int zaxisID, const int zaxistype, double &zinc, const int dig, const char *zname,
479
                    const char *zunits)
480
{
481
  Varray<double> levels(levelsize);
482
  zaxisInqLevels(zaxisID, levels.data());
483

484
  if (!(zaxisTypeIsSingleLayer(zaxistype) && levelsize == 1 && fabs(levels[0]) <= 0))
Uwe Schulzweida's avatar
Uwe Schulzweida committed
485
    {
486
487
      const auto zfirst = levels[0];
      const auto zlast = levels[levelsize - 1];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
488
489
490
491
492
493
494
495
496
497
      if (levelsize > 2)
        {
          zinc = (levels[levelsize - 1] - levels[0]) / (levelsize - 1);
          for (int levelID = 2; levelID < levelsize; ++levelID)
            if (fabs(fabs(levels[levelID] - levels[levelID - 1]) - zinc) > 0.001 * zinc)
              {
                zinc = 0;
                break;
              }
        }
498

Uwe Schulzweida's avatar
Uwe Schulzweida committed
499
500
501
502
503
504
505
506
507
      fprintf(stdout, "%33s : %.*g", zname, dig, zfirst);
      if (levelsize > 1)
        {
          fprintf(stdout, " to %.*g", dig, zlast);
          if (IS_NOT_EQUAL(zinc, 0)) fprintf(stdout, " by %.*g", dig, zinc);
        }
      fprintf(stdout, " %s", zunits);
      fprintf(stdout, "\n");
    }
508
509
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
510
static void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
511
printZaxisHybridInfo(const int zaxisID)
512
513
{
  char psname[CDI_MAX_NAME];
514
515
  int length = CDI_MAX_NAME;
  cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_PSNAME, psname, &length);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
516
  const int vctsize = zaxisInqVctSize(zaxisID);
517
518
519
520
521
522
523
524
525
  if (vctsize || psname[0])
    {
      fprintf(stdout, "%33s :", "available");
      if (vctsize) fprintf(stdout, " vct");
      if (psname[0]) fprintf(stdout, "  ps: %s", psname);
      fprintf(stdout, "\n");
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
526
static void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
527
printZaxisGenericInfo(const int ltype, const int zaxistype, const char *zaxisname)
528
529
530
531
532
533
534
535
536
537
538
{
  if (zaxistype == ZAXIS_GENERIC && ltype != 0)
    {
      fprintf(stdout, "%-12s (ltype=%3d)", zaxisname, ltype);
    }
  else
    {
      fprintf(stdout, "%-24s", zaxisname);
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
539
static void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
540
printZaxisReferenceInfo(const int zaxisID)
541
{
542
  int number = 0;
543
/*  cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, &number)*/
544
545
546
547
548
549
550
  if (number > 0)
    {
      fprintf(stdout, "%33s : ", "zaxis");
      fprintf(stdout, "number=%d\n", number);
    }

  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
551
  int length = CDI_UUID_SIZE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
552
  cdiInqKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuidOfVGrid, &length);
553
554
555
556
557
558
559
560
561
562
563
  if (!cdiUUIDIsNull(uuidOfVGrid))
    {
      char uuidOfVGridStr[37];
      cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
      if (uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36)
        {
          fprintf(stdout, "%33s : ", "uuid");
          fprintf(stdout, "%s\n", uuidOfVGridStr);
        }
    }
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
564

565
566
567
void
printZaxisInfo(int vlistID)
{
568
  const auto dig = Options::CDO_flt_digits;
569
570
  char zaxisname[CDI_MAX_NAME], zname[CDI_MAX_NAME], zunits[CDI_MAX_NAME];

571
  const auto nzaxis = vlistNzaxis(vlistID);
572
573
  for (int index = 0; index < nzaxis; index++)
    {
574
575
576
      const auto zaxisID = vlistZaxis(vlistID, index);
      const auto zaxistype = zaxisInqType(zaxisID);
      const auto levelsize = zaxisInqSize(zaxisID);
577
578
579
      int ltype = 0, ltype2 = -1;
      cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
      cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFSECONDFIXEDSURFACE, &ltype2);
580
581

      zaxisName(zaxistype, zaxisname);
582
583
      int length = CDI_MAX_NAME;
      cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, zname, &length);
584
585
      length = CDI_MAX_NAME;
      cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, zunits, &length);
586
587
588
      zunits[12] = 0;

      fprintf(stdout, "  %4d : ", vlistZaxisIndex(vlistID, zaxisID) + 1);
589
      set_text_color(stdout, BLUE);
590
591
      printZaxisGenericInfo(ltype, zaxistype, zaxisname);

592
      reset_text_color(stdout);
593
594
595

      fprintf(stdout, " :");

596
      set_text_color(stdout, GREEN);
597
      fprintf(stdout, " levels=%d", levelsize);
598
      const int zscalar = (levelsize == 1) ? zaxisInqScalar(zaxisID) : false;
599
      if (zscalar) fprintf(stdout, "  scalar");
600
      reset_text_color(stdout);
601
602
      fprintf(stdout, "\n");

603
      double zinc = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
604
      if (zaxisInqLevels(zaxisID, NULL)) printZaxisLevelInfo(levelsize, zaxisID, zaxistype, zinc, dig, zname, zunits);
605
606

      if (zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL))
607
        printZaxisBoundsInfo(zaxisID, dig, levelsize, zinc, zunits);
608

Uwe Schulzweida's avatar
Uwe Schulzweida committed
609
      if (zaxistype == ZAXIS_HYBRID) printZaxisHybridInfo(zaxisID);
610

Uwe Schulzweida's avatar
Uwe Schulzweida committed
611
      if (zaxistype == ZAXIS_REFERENCE) printZaxisReferenceInfo(zaxisID);
612

Uwe Schulzweida's avatar
Uwe Schulzweida committed
613
      if (ltype != ltype2 && ltype2 != -1) fprintf(stdout, "%33s : %d\n", "typeOfSecondFixedSurface", ltype2);
614
615
616
617
618
619
    }
}

void
printSubtypeInfo(int vlistID)
{
620
  const auto nsubtypes = vlistNsubtypes(vlistID);
621
622
  for (int index = 0; index < nsubtypes; index++)
    {
623
624
      const auto subtypeID = vlistSubtype(vlistID, index);
      const auto subtypesize = subtypeInqSize(subtypeID);
625
626
627
628
629
630
631
      // subtypePrint(subtypeID);
      fprintf(stdout, "  %4d : %-24s :", vlistSubtypeIndex(vlistID, subtypeID) + 1, "tiles");
      fprintf(stdout, " ntiles=%d", subtypesize);
      fprintf(stdout, "\n");
    }
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
632
static int
Uwe Schulzweida's avatar
Uwe Schulzweida committed
633
printDateTime(int ntimeout, const int64_t vdate, const int vtime)
634
635
636
637
638
639
640
{
  if (ntimeout == 4)
    {
      ntimeout = 0;
      fprintf(stdout, "\n");
    }

641
  fprintf(stdout, " %s %s", dateToString(vdate).c_str(), timeToString(vtime).c_str());
642
643
644
645
646
647
648

  return ++ntimeout;
}

#define NUM_TIMESTEP 60
#define MAX_DOTS 80

Uwe Schulzweida's avatar
Uwe Schulzweida committed
649
static int
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
printDot(int ndotout, int *nfact, int *ncout)
{
  // printf("ncout %d %d %d\n",*ncout, (*ncout)%(*nfact), *nfact);
  if ((*ncout) % (*nfact) == 0)
    {
      if (ndotout == MAX_DOTS)
        {
          *ncout = 0;
          ndotout = 0;
          fprintf(stdout, "\n   ");
          (*nfact) *= 10;
        }

      fprintf(stdout, ".");
      fflush(stdout);
      ndotout++;
    }

  (*ncout)++;

  return ndotout;
}

void
674
printTimesteps(CdoStreamID streamID, int taxisID, int verbose)
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
{
  int nrecs;
  struct datetime
  {
    int64_t vdate;
    int vtime;
    struct datetime *next;
  };
  struct datetime vdatetime[NUM_TIMESTEP];
  struct datetime *next_vdatetime = vdatetime;

  for (int i = 0; i < NUM_TIMESTEP - 1; ++i) vdatetime[i].next = &vdatetime[i + 1];
  vdatetime[NUM_TIMESTEP - 1].next = &vdatetime[0];

  int ntimeout = 0;
  int ndotout = 0;
  int nvdatetime = 0;
  int ncout = 0;
  int nfact = 1;
  int tsID = 0;

  DateTimeList dtlist;
697
  while ((nrecs = cdoStreamInqTimestep(streamID, tsID)))
698
699
    {
      dtlist.taxisInqTimestep(taxisID, 0);
700
701
      const auto vdate = dtlist.getVdate(0);
      const auto vtime = dtlist.getVtime(0);
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742

      if (verbose || tsID < NUM_TIMESTEP)
        {
          ntimeout = printDateTime(ntimeout, vdate, vtime);
        }
      else
        {
          if (tsID == 2 * NUM_TIMESTEP) fprintf(stdout, "\n   ");
          if (tsID >= 2 * NUM_TIMESTEP) ndotout = printDot(ndotout, &nfact, &ncout);

          if (nvdatetime < NUM_TIMESTEP)
            {
              vdatetime[nvdatetime].vdate = vdate;
              vdatetime[nvdatetime].vtime = vtime;
              nvdatetime++;
            }
          else
            {
              next_vdatetime->vdate = vdate;
              next_vdatetime->vtime = vtime;
              next_vdatetime = next_vdatetime->next;
            }
        }

      tsID++;
    }

  if (nvdatetime)
    {
      fprintf(stdout, "\n");

      ntimeout = 0;
      int toff = 0;
      if (tsID > 2 * NUM_TIMESTEP)
        {
          toff = tsID % 4;
          if (toff > 0) toff = 4 - toff;
          for (int i = 0; i < toff; ++i) next_vdatetime = next_vdatetime->next;
        }
      for (int i = toff; i < nvdatetime; ++i)
        {
743
744
          const auto vdate = next_vdatetime->vdate;
          const auto vtime = next_vdatetime->vtime;
745
746
747
748
749
          ntimeout = printDateTime(ntimeout, vdate, vtime);
          next_vdatetime = next_vdatetime->next;
        }
    }
}