sellist.cc 10.6 KB
Newer Older
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-2020 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
6
7
8
9
10
11
12
13
14
15
16
  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.
*/
Oliver Heidmann's avatar
Oliver Heidmann committed
17
18

#include <cassert>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
19
#include <cmath>
Oliver Heidmann's avatar
Oliver Heidmann committed
20

21
#include "dmemory.h"
22
#include "param_conversion.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
23
#include "sellist.h"
24
#include "util_wildcards.h"
25
#include "cdo_output.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26

Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
// #define SELDEBUG 1
Uwe Schulzweida's avatar
Uwe Schulzweida committed
28

Uwe Schulzweida's avatar
Uwe Schulzweida committed
29
30
void
sellist_init(SelectList &sellist, KVList &kvlist)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
31
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
32
  sellist.resize(kvlist.size());
Uwe Schulzweida's avatar
Uwe Schulzweida committed
33
34

  int i = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
35
  for (const auto &kv : kvlist)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
36
    {
37
      auto &e = sellist[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
38
39
40
      e.key = kv.key;
      e.nvalues = kv.nvalues;
      e.values.resize(kv.nvalues);
41
      for (int k = 0; k < kv.nvalues; ++k) e.values[k] = kv.values[k];
42
#ifdef SELDEBUG
Uwe Schulzweida's avatar
Uwe Schulzweida committed
43
44
      printf("%s =", e.key.c_str());
      for (int ii = 0; ii < e.nvalues; ++ii) printf(" '%s'", e.values[ii].c_str());
Uwe Schulzweida's avatar
Uwe Schulzweida committed
45
      printf("\n");
46
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
47
48
49
      ++i;
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
50
  for (i = 0; i < (int) sellist.size(); ++i)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
51
    {
52
      auto &e = sellist[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
53
54
      e.flag = nullptr;
      e.cvalues = nullptr;
55
#ifdef SELDEBUG
Uwe Schulzweida's avatar
Uwe Schulzweida committed
56
57
      printf("%s =", e.key.c_str());
      for (int ii = 0; ii < e.nvalues; ++ii) printf(" '%s'", e.values[ii].c_str());
Uwe Schulzweida's avatar
Uwe Schulzweida committed
58
      printf("\n");
59
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
60
61
62
    }
}

63
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
64
sellist_destroy(SelectList &sellist)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
65
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
66
  for (int i = 0; i < (int) sellist.size(); ++i)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
67
    {
68
      auto &e = sellist[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
69
70
71
      if (e.txt) Free(e.txt);
      if (e.flag) Free(e.flag);
      if (e.cvalues) Free(e.cvalues);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
72
73
74
    }
}

75
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
76
sellist_verify(SelectList &sellist)
77
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
78
  for (int i = 0; i < (int) sellist.size(); ++i)
79
    {
80
      const auto &e = sellist[i];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
81
      if (e.type == 0) cdoAbort("Unsupported selection keyword: '%s'!", e.key.c_str());
82
83
84
    }
}

85
int
Uwe Schulzweida's avatar
Uwe Schulzweida committed
86
sellist_add(SelectList &sellist, const char *txt, const char *name, int type)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
87
{
88
  int idx = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
89

Uwe Schulzweida's avatar
Uwe Schulzweida committed
90
  for (int i = 0; i < (int) sellist.size(); ++i)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
91
    {
92
93
      const auto &key = sellist[i].key;
      if (key == name)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
94
95
96
97
98
99
        {
          idx = i;
          break;
        }
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
100
  if (idx >= 0 && idx < (int) sellist.size())
Uwe Schulzweida's avatar
Uwe Schulzweida committed
101
    {
102
      auto &e = sellist[idx];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
103
104
      e.type = type;
      e.txt = strdup(txt);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
105
      if (e.nvalues && e.cvalues == nullptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
106
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
107
          switch (type)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
108
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
109
110
111
            case SELLIST_INT: e.cvalues = Malloc(e.nvalues * sizeof(int)); break;
            case SELLIST_FLT: e.cvalues = Malloc(e.nvalues * sizeof(double)); break;
            case SELLIST_WORD: e.cvalues = Malloc(e.nvalues * sizeof(char *)); break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
112
113
            }
        }
114

Uwe Schulzweida's avatar
Uwe Schulzweida committed
115
      int j = 0;
116
      const auto nvalues = e.nvalues;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
117
      for (int i = 0; i < nvalues; ++i) switch (type)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
118
119
          {
          case SELLIST_INT:
120
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
121
              int first, last, inc;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
122
              split_intstring(e.values[i].c_str(), first, last, inc);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
123
124

              if (first == last)
125
                {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
126
                  ((int *) e.cvalues)[j++] = first;
127
                }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
128
              else
129
                {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
130
131
132
                  int k = 0;
                  if (inc >= 0)
                    for (int ival = first; ival <= last; ival += inc) k++;
133
                  else
Uwe Schulzweida's avatar
Uwe Schulzweida committed
134
135
136
137
                    for (int ival = first; ival >= last; ival += inc) k++;

                  e.nvalues += k - 1;
                  if (e.nvalues)
138
                    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
139
140
                      e.cvalues = Realloc(e.cvalues, e.nvalues * sizeof(int));

141
                      if (inc >= 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
142
143
144
                        {
                          for (int ival = first; ival <= last; ival += inc) ((int *) e.cvalues)[j++] = ival;
                        }
145
146
                      else
                        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
147
                          for (int ival = first; ival >= last; ival += inc) ((int *) e.cvalues)[j++] = ival;
148
149
150
151
                        }
                    }
                }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
152
153
154
155
156
157
158
              break;
            }
          case SELLIST_FLT: ((double *) e.cvalues)[i] = parameter2double(e.values[i].c_str()); break;
          case SELLIST_WORD: ((const char **) e.cvalues)[i] = parameter2word(e.values[i].c_str()); break;
          }

      if (e.nvalues) e.flag = (bool *) Calloc(e.nvalues, sizeof(bool));
159
#ifdef SELDEBUG
Uwe Schulzweida's avatar
Uwe Schulzweida committed
160
      printf("%s =", e.key.c_str());
Uwe Schulzweida's avatar
Uwe Schulzweida committed
161
      for (int i = 0; i < e.nvalues; ++i) switch (type)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
162
163
164
165
166
167
          {
          case SELLIST_INT: printf(" %d", ((int *) e.cvalues)[i]); break;
          case SELLIST_FLT: printf(" %g", ((double *) e.cvalues)[i]); break;
          case SELLIST_WORD: printf(" %s", ((char **) e.cvalues)[i]); break;
          }
      printf("\n");
168
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
169
170
    }

171
  return idx;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
172
173
}

174
int
Uwe Schulzweida's avatar
Uwe Schulzweida committed
175
sellist_nvalues(const SelectList &sellist, const int idx)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
176
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
  return (idx >= 0 && idx < (int) sellist.size()) ? sellist[idx].nvalues : 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
178
}
179

180
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
181
sellist_check_flag(const SelectList &sellist, const int idx)
182
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
183
  if (idx < 0 || idx >= (int) sellist.size()) return;
184

185
  const auto nvalues = sellist_nvalues(sellist, idx);
186
  if (nvalues)
187
    {
188
      const auto &e = sellist[idx];
189
      for (int i = 0; i < nvalues; ++i)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
190
        if (!e.flag[i]) switch (e.type)
191
            {
192
193
194
            case SELLIST_INT: cdoWarning("%s >%d< not found!", e.txt, ((int *) e.cvalues)[i]); break;
            case SELLIST_FLT: cdoWarning("%s >%g< not found!", e.txt, ((double *) e.cvalues)[i]); break;
            case SELLIST_WORD: cdoWarning("%s >%s< not found!", e.txt, ((char **) e.cvalues)[i]); break;
195
            }
196
197
198
    }
}

199
bool
Uwe Schulzweida's avatar
Uwe Schulzweida committed
200
sellist_check(SelectList &sellist, int idx, void *par)
201
202
203
{
  bool found = false;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
204
  if (idx < 0 || idx >= (int) sellist.size()) return found;
205

206
  const auto nvalues = sellist_nvalues(sellist, idx);
207
  if (nvalues)
208
    {
209
      auto &e = sellist[idx];
210
      for (int i = 0; i < nvalues; ++i)
211
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
212
          switch (e.type)
213
            {
214
            case SELLIST_INT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
215
              if (*(int *) par == ((int *) e.cvalues)[i])
216
217
                {
                  found = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
218
                  e.flag[i] = true;
219
220
221
                }
              break;
            case SELLIST_FLT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
222
              if (std::fabs(*(double *) par - ((double *) e.cvalues)[i]) < 1.e-4)
223
224
                {
                  found = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
225
                  e.flag[i] = true;
226
227
228
                }
              break;
            case SELLIST_WORD:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
229
              if (wildcardmatch(((char **) e.cvalues)[i], *(char **) par) == 0)
230
231
                {
                  found = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
232
                  e.flag[i] = true;
233
234
                }
              break;
235
            }
236
237
238
239
240
        }
    }

  return found;
}
241

242
bool
Uwe Schulzweida's avatar
Uwe Schulzweida committed
243
sellist_check_date(SelectList &sellist, int idx, const char *par)
244
245
246
{
  bool found = false;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
247
  if (idx < 0 || idx >= (int) sellist.size()) return found;
248

249
  const auto nvalues = sellist_nvalues(sellist, idx);
250
  if (nvalues)
251
252
    {
      char wcdate[512];
253
      auto &e = sellist[idx];
254

255
      if (*par == ' ') ++par;
256

257
      for (int i = 0; i < nvalues; ++i)
258
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
259
          strcpy(wcdate, e.values[i].c_str());
260
          strcat(wcdate, "*");
261
262
263
          if (wildcardmatch(wcdate, par) == 0)
            {
              found = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
264
              e.flag[i] = true;
265
            }
266
267
268
269
270
271
        }
    }

  return found;
}

272
void season_to_months(const char *season, int *imonths);
273

274
bool
Uwe Schulzweida's avatar
Uwe Schulzweida committed
275
sellist_check_season(SelectList &sellist, int idx, int month)
276
{
277
  assert(month >= 1 && month <= 12);
278
279
  bool found = false;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
280
  if (idx < 0 || idx >= (int) sellist.size()) return found;
281

282
  const auto nvalues = sellist_nvalues(sellist, idx);
283
  if (nvalues)
284
    {
285
      int imon[13]; /* 1-12 ! */
286
      const SelectEntry &e = sellist[idx];
287

288
      for (int i = 0; i < nvalues; ++i)
289
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
290
          for (int m = 0; m < 13; ++m) imon[m] = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
291
          season_to_months(e.values[i].c_str(), imon);
292
293
294
          if (imon[month])
            {
              found = true;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
295
              e.flag[i] = true;
296
            }
297
298
299
300
301
302
        }
    }

  return found;
}

303
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
304
sellist_def_flag(SelectList &sellist, int idx, int vindex, bool flag)
305
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
306
  if (idx < 0 || idx >= (int) sellist.size()) return;
307

308
  const auto nvalues = sellist_nvalues(sellist, idx);
309
  if (nvalues)
310
    {
311
      auto &e = sellist[idx];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
312
      if (vindex >= 0 && vindex < nvalues) e.flag[vindex] = flag;
313
    }
314
315
}

316
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
317
sellist_get_val(const SelectList &sellist, int idx, int vindex, void *val)
318
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
319
  if (idx < 0 || idx >= (int) sellist.size()) return;
320

321
  const auto nvalues = sellist_nvalues(sellist, idx);
322
  if (nvalues)
323
    {
324
      const auto &e = sellist[idx];
325
      if (vindex >= 0 && vindex < nvalues)
326
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
327
          switch (e.type)
328
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
329
330
331
            case SELLIST_INT: *(int *) val = ((int *) e.cvalues)[vindex]; break;
            case SELLIST_FLT: *(double *) val = ((double *) e.cvalues)[vindex]; break;
            case SELLIST_WORD: *(const char **) val = ((const char **) e.cvalues)[vindex]; break;
332
333
            }
        }
334
335
336
    }
}

337
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
338
sellist_def_val(SelectList &sellist, int idx, int vindex, void *val)
339
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
340
  if (idx < 0 || idx >= (int) sellist.size()) return;
341

342
  const auto nvalues = sellist_nvalues(sellist, idx);
343
  if (nvalues)
344
    {
345
      auto &e = sellist[idx];
346
      if (vindex >= 0 && vindex < nvalues)
347
        {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
348
          switch (e.type)
349
            {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
350
351
352
            case SELLIST_INT: ((int *) e.cvalues)[vindex] = *(int *) val; break;
            case SELLIST_FLT: ((double *) e.cvalues)[vindex] = *(double *) val; break;
            case SELLIST_WORD: ((const char **) e.cvalues)[vindex] = *(const char **) val; break;
353
354
355
356
            }
        }
    }
}
357

358
static void
359
sellist_print_val(const int type, CValues *cvalues, const int i)
360
361
362
{
  switch (type)
    {
363
364
365
    case SELLIST_INT: printf(" %d", ((int *) cvalues)[i]); break;
    case SELLIST_FLT: printf(" %g", ((double *) cvalues)[i]); break;
    case SELLIST_WORD: printf(" %s", ((char **) cvalues)[i]); break;
366
367
368
    }
}

369
void
Uwe Schulzweida's avatar
Uwe Schulzweida committed
370
sellist_print(const SelectList &sellist)
371
{
Uwe Schulzweida's avatar
Uwe Schulzweida committed
372
  if (sellist.size() > 0)
373
374
375
    {
      // printf("Parameter list: %s\n", sellist->
      printf("Num  Name             Type  Size  Entries\n");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
376
      for (int idx = 0; idx < (int) sellist.size(); ++idx)
377
        {
378
          const auto &e = sellist[idx];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
379
          printf("%3d  %-16s %4d  %4d ", idx + 1, e.key.c_str(), e.type, e.nvalues);
380
          auto nvalues = e.nvalues;
381
          if (nvalues > 12) nvalues = 11;
382
          for (int i = 0; i < nvalues; ++i) sellist_print_val(e.type, (CValues *) e.cvalues, i);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
383
          if (nvalues < e.nvalues)
384
385
            {
              printf(" ...");
386
              sellist_print_val(e.type, (CValues *) e.cvalues, e.nvalues - 1);
387
            }
388
389
390
391
          printf("\n");
        }
    }
}