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