1 /*
2 This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.
3
4 Author: Uwe Schulzweida
5
6 */
7
8 #include <cdi.h>
9
10 #include <cassert>
11 #include <algorithm>
12
13 #include "percentiles.h"
14 #include "varray.h"
15 #include "field.h"
16 #include "cdo_output.h"
17
18 void
init(const CdoVar & var)19 Field::init(const CdoVar &var)
20 {
21 grid = var.gridID;
22 gridsize = var.gridsize;
23 missval = var.missval;
24 memType = var.memType;
25 size = var.gridsize * var.nwpv;
26 m_count = size;
27 if (memType == MemType::Float)
28 varrayResize(vec_f, size);
29 else
30 varrayResize(vec_d, size);
31 }
32
33 void
resize(const size_t count)34 Field::resize(const size_t count)
35 {
36 memType = MemType::Double;
37 m_count = count;
38 varrayResize(vec_d, m_count);
39 if (!size) size = m_count;
40 }
41
42 void
resize(const size_t count,const double value)43 Field::resize(const size_t count, const double value)
44 {
45 memType = MemType::Double;
46 m_count = count;
47 varrayResizeInit(vec_d, m_count, value);
48 if (!size) size = m_count;
49 }
50
51 void
resizef(const size_t count)52 Field::resizef(const size_t count)
53 {
54 memType = MemType::Float;
55 m_count = count;
56 varrayResize(vec_f, m_count);
57 if (!size) size = m_count;
58 }
59
60 void
resizef(const size_t count,const float value)61 Field::resizef(const size_t count, const float value)
62 {
63 memType = MemType::Float;
64 m_count = count;
65 varrayResizeInit(vec_f, m_count, value);
66 if (!size) size = m_count;
67 }
68
69 bool
empty() const70 Field::empty() const
71 {
72 return m_count == 0;
73 }
74
75 void
check_gridsize() const76 Field::check_gridsize() const
77 {
78 if (size == 0) fprintf(stderr, "Internal problem, size of field not set!\n");
79 if (size > m_count) fprintf(stderr, "Internal problem, size of field is greater than allocated size of field!\n");
80 }
81
82 void
init(const CdoVar & var)83 Field3D::init(const CdoVar &var)
84 {
85 nlevels = var.nlevels;
86 grid = var.gridID;
87 gridsize = var.gridsize;
88 missval = var.missval;
89 memType = var.memType;
90 size = var.nlevels * var.gridsize * var.nwpv;
91 if (memType == MemType::Float)
92 varrayResize(vec_f, size);
93 else
94 varrayResize(vec_d, size);
95 }
96
97 void
field_fill(Field & field,double value)98 field_fill(Field &field, double value)
99 {
100 field.check_gridsize();
101
102 if (field.memType == MemType::Float)
103 std::fill(field.vec_f.begin(), field.vec_f.begin() + field.size, value);
104 else
105 std::fill(field.vec_d.begin(), field.vec_d.begin() + field.size, value);
106 }
107
108 void
field_copy(const Field & field_src,Field & field_tgt)109 field_copy(const Field &field_src, Field &field_tgt)
110 {
111 field_tgt.nmiss = field_src.nmiss;
112
113 if (field_src.memType == MemType::Float)
114 field_tgt.vec_f = field_src.vec_f;
115 else
116 field_tgt.vec_d = field_src.vec_d;
117 }
118
119 void
field_copy(const Field3D & field_src,Field3D & field_tgt)120 field_copy(const Field3D &field_src, Field3D &field_tgt)
121 {
122 field_tgt.nmiss = field_src.nmiss;
123
124 if (field_src.memType == MemType::Float)
125 field_tgt.vec_f = field_src.vec_f;
126 else
127 field_tgt.vec_d = field_src.vec_d;
128 }
129
130 void
field_copy(const Field3D & field_src,const int levelID,Field & field_tgt)131 field_copy(const Field3D &field_src, const int levelID, Field &field_tgt)
132 {
133 const auto size = field_src.gridsize * field_src.nwpv;
134 const auto offset = levelID * size;
135 if (field_src.memType == MemType::Float)
136 std::copy(field_src.vec_f.begin() + offset, field_src.vec_f.begin() + offset + size, field_tgt.vec_f.begin());
137 else
138 std::copy(field_src.vec_d.begin() + offset, field_src.vec_d.begin() + offset + size, field_tgt.vec_d.begin());
139 }
140
141 void
field_add(Field & field1,const Field3D & field2,const int levelID)142 field_add(Field &field1, const Field3D &field2, const int levelID)
143 {
144 const auto size = field1.gridsize * field1.nwpv;
145 const auto offset = levelID * size;
146 if (field1.memType == MemType::Float)
147 for (size_t i = 0; i < size; i++) field1.vec_f[i] += field2.vec_f[offset + i];
148 else
149 for (size_t i = 0; i < size; i++) field1.vec_d[i] += field2.vec_d[offset + i];
150 }
151
152 // functor that returns true if value is equal to the value of the constructor parameter provided
153 class valueDblIsEqual
154 {
155 double _missval;
156
157 public:
valueDblIsEqual(double missval)158 valueDblIsEqual(double missval) : _missval(missval) {}
159 bool
operator ()(const double value) const160 operator()(const double value) const
161 {
162 return DBL_IS_EQUAL(value, _missval);
163 }
164 };
165
166 // functor that returns true if value is equal to the value of the constructor parameter provided
167 class valueIsEqual
168 {
169 double _missval;
170
171 public:
valueIsEqual(double missval)172 valueIsEqual(double missval) : _missval(missval) {}
173 bool
operator ()(const double value) const174 operator()(const double value) const
175 {
176 return IS_EQUAL(value, _missval);
177 }
178 };
179
180 size_t
field_num_miss(const Field & field)181 field_num_miss(const Field &field)
182 {
183 field.check_gridsize();
184
185 if (std::isnan(field.missval))
186 return std::count_if(field.vec_d.begin(), field.vec_d.begin() + field.size, valueDblIsEqual(field.missval));
187 else
188 return std::count_if(field.vec_d.begin(), field.vec_d.begin() + field.size, valueIsEqual(field.missval));
189 }
190
191 size_t
field_num_mv(Field & field)192 field_num_mv(Field &field)
193 {
194 if (field.memType == MemType::Float)
195 field.nmiss = varray_num_mv(field.size, field.vec_f, (float) field.missval);
196 else
197 field.nmiss = varray_num_mv(field.size, field.vec_d, field.missval);
198
199 return field.nmiss;
200 }
201
202 MinMax
field_min_max(const Field & field)203 field_min_max(const Field &field)
204 {
205 if (field.memType == MemType::Float)
206 return field.nmiss ? varray_min_max_mv(field.size, field.vec_f, (float) field.missval) : varray_min_max(field.vec_f);
207 else
208 return field.nmiss ? varray_min_max_mv(field.size, field.vec_d, field.missval) : varray_min_max(field.vec_d);
209 }
210
211 double
field_min(const Field & field)212 field_min(const Field &field)
213 {
214 if (field.memType == MemType::Float)
215 return field.nmiss ? varray_min_mv(field.size, field.vec_f, (float) field.missval) : varray_min(field.size, field.vec_f);
216 else
217 return field.nmiss ? varray_min_mv(field.size, field.vec_d, field.missval) : varray_min(field.size, field.vec_d);
218 }
219
220 double
field_max(const Field & field)221 field_max(const Field &field)
222 {
223 if (field.memType == MemType::Float)
224 return field.nmiss ? varray_max_mv(field.size, field.vec_f, (float) field.missval) : varray_max(field.size, field.vec_f);
225 else
226 return field.nmiss ? varray_max_mv(field.size, field.vec_d, field.missval) : varray_max(field.size, field.vec_d);
227 }
228
229 static double
field_range(const Field & field)230 field_range(const Field &field)
231 {
232 if (field.memType == MemType::Float)
233 return field.nmiss ? varray_range_mv(field.size, field.vec_f, (float) field.missval) : varray_range(field.size, field.vec_f);
234 else
235 return field.nmiss ? varray_range_mv(field.size, field.vec_d, field.missval) : varray_range(field.size, field.vec_d);
236 }
237
238 double
field_sum(const Field & field)239 field_sum(const Field &field)
240 {
241 if (field.memType == MemType::Float)
242 return field.nmiss ? varray_sum_mv(field.size, field.vec_f, (float) field.missval) : varray_sum(field.size, field.vec_f);
243 else
244 return field.nmiss ? varray_sum_mv(field.size, field.vec_d, field.missval) : varray_sum(field.size, field.vec_d);
245 }
246
247 double
field_mean(const Field & field)248 field_mean(const Field &field)
249 {
250 if (field.memType == MemType::Float)
251 return field.nmiss ? varray_mean_mv(field.size, field.vec_f, (float) field.missval) : varray_mean(field.size, field.vec_f);
252 else
253 return field.nmiss ? varray_mean_mv(field.size, field.vec_d, field.missval) : varray_mean(field.size, field.vec_d);
254 }
255
256 double
field_meanw(const Field & field)257 field_meanw(const Field &field)
258 {
259 if (field.memType == MemType::Float)
260 return field.nmiss ? varray_weighted_mean_mv(field.size, field.vec_f, field.weightv, (float) field.missval)
261 : varray_weighted_mean(field.size, field.vec_f, field.weightv, (float) field.missval);
262 else
263 return field.nmiss ? varray_weighted_mean_mv(field.size, field.vec_d, field.weightv, field.missval)
264 : varray_weighted_mean(field.size, field.vec_d, field.weightv, field.missval);
265 }
266
267 double
field_avg(const Field & field)268 field_avg(const Field &field)
269 {
270 if (field.memType == MemType::Float)
271 return field.nmiss ? varray_avg_mv(field.size, field.vec_f, (float) field.missval) : varray_mean(field.size, field.vec_f);
272 else
273 return field.nmiss ? varray_avg_mv(field.size, field.vec_d, field.missval) : varray_mean(field.size, field.vec_d);
274 }
275
276 double
field_avgw(const Field & field)277 field_avgw(const Field &field)
278 {
279 if (field.memType == MemType::Float)
280 return field.nmiss ? varray_weighted_avg_mv(field.size, field.vec_f, field.weightv, (float) field.missval)
281 : varray_weighted_mean(field.size, field.vec_f, field.weightv, (float) field.missval);
282 else
283 return field.nmiss ? varray_weighted_avg_mv(field.size, field.vec_d, field.weightv, field.missval)
284 : varray_weighted_mean(field.size, field.vec_d, field.weightv, field.missval);
285 }
286
287 double
field_var(const Field & field)288 field_var(const Field &field)
289 {
290 if (field.memType == MemType::Float)
291 return varray_var(field.size, field.vec_f, field.nmiss, (float) field.missval);
292 else
293 return varray_var(field.size, field.vec_d, field.nmiss, field.missval);
294 }
295
296 double
field_var1(const Field & field)297 field_var1(const Field &field)
298 {
299 if (field.memType == MemType::Float)
300 return varray_var_1(field.size, field.vec_f, field.nmiss, (float) field.missval);
301 else
302 return varray_var_1(field.size, field.vec_d, field.nmiss, field.missval);
303 }
304
305 static double
field_skew(const Field & field)306 field_skew(const Field &field)
307 {
308 if (field.memType == MemType::Float)
309 return varray_skew(field.size, field.vec_f, field.nmiss, (float) field.missval);
310 else
311 return varray_skew(field.size, field.vec_d, field.nmiss, field.missval);
312 }
313
314 static double
field_kurt(const Field & field)315 field_kurt(const Field &field)
316 {
317 if (field.memType == MemType::Float)
318 return varray_kurt(field.size, field.vec_f, field.nmiss, (float) field.missval);
319 else
320 return varray_kurt(field.size, field.vec_d, field.nmiss, field.missval);
321 }
322
323 static double
field_median(const Field & field)324 field_median(const Field &field)
325 {
326 if (field.memType == MemType::Float)
327 return varray_median(field.size, field.vec_f, field.nmiss, (float) field.missval);
328 else
329 return varray_median(field.size, field.vec_d, field.nmiss, field.missval);
330 }
331
332 double
field_varw(const Field & field)333 field_varw(const Field &field)
334 {
335 if (field.memType == MemType::Float)
336 return varray_weighted_var(field.size, field.vec_f, field.weightv, field.nmiss, (float) field.missval);
337 else
338 return varray_weighted_var(field.size, field.vec_d, field.weightv, field.nmiss, field.missval);
339 }
340
341 double
field_var1w(const Field & field)342 field_var1w(const Field &field)
343 {
344 if (field.memType == MemType::Float)
345 return varray_weighted_var_1(field.size, field.vec_f, field.weightv, field.nmiss, (float) field.missval);
346 else
347 return varray_weighted_var_1(field.size, field.vec_d, field.weightv, field.nmiss, field.missval);
348 }
349
350 double
var_to_std(double rvar,double missval)351 var_to_std(double rvar, double missval)
352 {
353 if (DBL_IS_EQUAL(rvar, missval) || rvar < 0) return missval;
354
355 return IS_NOT_EQUAL(rvar, 0) ? std::sqrt(rvar) : 0;
356 }
357
358 double
field_std(const Field & field)359 field_std(const Field &field)
360 {
361 return var_to_std(field_var(field), field.missval);
362 }
363
364 double
field_std1(const Field & field)365 field_std1(const Field &field)
366 {
367 return var_to_std(field_var1(field), field.missval);
368 }
369
370 double
field_stdw(const Field & field)371 field_stdw(const Field &field)
372 {
373 return var_to_std(field_varw(field), field.missval);
374 }
375
376 double
field_std1w(const Field & field)377 field_std1w(const Field &field)
378 {
379 return var_to_std(field_var1w(field), field.missval);
380 }
381
382 void
field_rms(const Field & field,const Field & field2,Field & field3)383 field_rms(const Field &field, const Field &field2, Field &field3)
384 {
385 size_t rnmiss = 0;
386 const auto grid1 = field.grid;
387 // size_t nmiss1 = field.nmiss;
388 const auto array1 = field.vec_d.data();
389 const auto grid2 = field2.grid;
390 // size_t nmiss2 = field2.nmiss;
391 const auto array2 = field2.vec_d.data();
392 const auto missval1 = field.missval;
393 const auto missval2 = field2.missval;
394 const auto &w = field.weightv;
395 auto rsum = 0.0, rsumw = 0.0;
396
397 const auto len = gridInqSize(grid1);
398 if (len != gridInqSize(grid2)) cdo_abort("fields have different size!");
399
400 // if ( nmiss1 )
401 {
402 for (size_t i = 0; i < len; i++)
403 if (!DBL_IS_EQUAL(w[i], missval1))
404 {
405 rsum = ADDMN(rsum, MULMN(w[i], MULMN(SUBMN(array2[i], array1[i]), SUBMN(array2[i], array1[i]))));
406 rsumw = ADDMN(rsumw, w[i]);
407 }
408 }
409 /*
410 else
411 {
412 for ( i = 0; i < len; i++ )
413 {
414 rsum += w[i] * array1[i];
415 rsumw += w[i];
416 }
417 }
418 */
419
420 const auto ravg = SQRTMN(DIVMN(rsum, rsumw));
421
422 if (DBL_IS_EQUAL(ravg, missval1)) rnmiss++;
423
424 field3.vec_d[0] = ravg;
425 field3.nmiss = rnmiss;
426 }
427
428 template <typename T>
429 double
array_pctl(size_t len,T * array,size_t nmiss,T missval,const double pn)430 array_pctl(size_t len, T *array, size_t nmiss, T missval, const double pn)
431 {
432 double pctl = missval;
433
434 if ((len - nmiss) > 0)
435 {
436 if (nmiss)
437 {
438 Varray<T> v(len - nmiss);
439
440 size_t j = 0;
441 for (size_t i = 0; i < len; i++)
442 if (!DBL_IS_EQUAL(array[i], missval)) v[j++] = array[i];
443
444 pctl = percentile(v.data(), j, pn);
445 }
446 else
447 {
448 pctl = percentile(array, len, pn);
449 }
450 }
451
452 return pctl;
453 }
454
455 double
field_pctl(Field & field,const double pn)456 field_pctl(Field &field, const double pn)
457 {
458 if (field.memType == MemType::Float)
459 return array_pctl(field.size, field.vec_f.data(), field.nmiss, (float) field.missval, pn);
460 else
461 return array_pctl(field.size, field.vec_d.data(), field.nmiss, field.missval, pn);
462 }
463
464 static int
compare_double(const void * const a,const void * const b)465 compare_double(const void *const a, const void *const b)
466 {
467 const double *const x = (const double *) a;
468 const double *const y = (const double *) b;
469 return ((*x > *y) - (*x < *y)) * 2 + (*x > *y) - (*x < *y);
470 }
471
472 double
field_rank(Field & field)473 field_rank(Field &field)
474 {
475 auto res = 0.0;
476 // Using first value as reference (observation)
477 const auto val = field.vec_d[0];
478 const auto array = &field.vec_d[1];
479 const auto len = field.size - 1;
480
481 if (field.nmiss) return field.missval;
482
483 std::qsort(array, len, sizeof(double), compare_double);
484
485 if (val > array[len - 1])
486 res = (double) len;
487 else
488 for (size_t j = 0; j < len; j++)
489 if (array[j] >= val)
490 {
491 res = (double) j;
492 break;
493 }
494
495 return res;
496 }
497
498 double
field_function(const Field & field,int function)499 field_function(const Field &field, int function)
500 {
501 // clang-format off
502 switch (function)
503 {
504 case FieldFunc_Min: return field_min(field);
505 case FieldFunc_Max: return field_max(field);
506 case FieldFunc_Range: return field_range(field);
507 case FieldFunc_Sum: return field_sum(field);
508 case FieldFunc_Mean: return field_mean(field);
509 case FieldFunc_Avg: return field_avg(field);
510 case FieldFunc_Std: return field_std(field);
511 case FieldFunc_Std1: return field_std1(field);
512 case FieldFunc_Var: return field_var(field);
513 case FieldFunc_Var1: return field_var1(field);
514 case FieldFunc_Meanw: return field_meanw(field);
515 case FieldFunc_Avgw: return field_avgw(field);
516 case FieldFunc_Stdw: return field_stdw(field);
517 case FieldFunc_Std1w: return field_std1w(field);
518 case FieldFunc_Varw: return field_varw(field);
519 case FieldFunc_Var1w: return field_var1w(field);
520 case FieldFunc_Skew: return field_skew(field);
521 case FieldFunc_Kurt: return field_kurt(field);
522 case FieldFunc_Median: return field_median(field);
523 default: cdo_abort("%s: function %d not implemented!", __func__, function);
524 }
525 // clang-format on
526 return 0.0;
527 }
528