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 #ifndef DATARANGELIST_H
8 #define DATARANGELIST_H
9 
10 #include <cdi.h>
11 #include <cstddef>
12 #include "cdo_output.h"
13 #include "varray.h"
14 
15 struct Datarange
16 {
17   bool check_datarange;
18   size_t gridsize;
19   int datatype;
20   double missval;
21   double addoffset;
22   double scalefactor;
23 
DatarangeDatarange24   Datarange() : check_datarange(false), gridsize(0), datatype(0), missval(0), addoffset(0), scalefactor(1){};
25 
26   template <typename T>
27   void
checkDatarangeDatarange28   checkDatarange(T *array, size_t nmiss)
29   {
30     const auto mm = nmiss ? varray_min_max_mv(gridsize, array, (T)missval) : varray_min_max(gridsize, array);
31     const auto numberOfValues = nmiss ? mm.n : gridsize;
32 
33     if (numberOfValues > 0)
34       {
35         auto smin = (mm.min - addoffset) / scalefactor;
36         auto smax = (mm.max - addoffset) / scalefactor;
37 
38         if (datatype == CDI_DATATYPE_INT8 || datatype == CDI_DATATYPE_UINT8 || datatype == CDI_DATATYPE_INT16
39             || datatype == CDI_DATATYPE_UINT16)
40           {
41             smin = (int) std::lround(smin);
42             smax = (int) std::lround(smax);
43           }
44 
45         double vmin = 0.0, vmax = 0.0;
46         // clang-format off
47         if      (datatype == CDI_DATATYPE_INT8  ) { vmin =        -128.0; vmax =        127.0; }
48         else if (datatype == CDI_DATATYPE_UINT8 ) { vmin =           0.0; vmax =        255.0; }
49         else if (datatype == CDI_DATATYPE_INT16 ) { vmin =      -32768.0; vmax =      32767.0; }
50         else if (datatype == CDI_DATATYPE_UINT16) { vmin =           0.0; vmax =      65535.0; }
51         else if (datatype == CDI_DATATYPE_INT32 ) { vmin = -2147483648.0; vmax = 2147483647.0; }
52         else if (datatype == CDI_DATATYPE_UINT32) { vmin =           0.0; vmax = 4294967295.0; }
53         else if (datatype == CDI_DATATYPE_FLT32 ) { vmin =  -3.40282e+38; vmax =  3.40282e+38; }
54         else                                      { vmin =      -1.e+300; vmax =      1.e+300; }
55         // clang-format on
56 
57         if (smin < vmin || smax > vmax)
58           cdo_warning("Some data values (min=%g max=%g) are outside the\n"
59                       "    valid range (%g - %g) of the used output precision!\n"
60                       "    Use the CDO option%s -b F64 to increase the output precision.",
61                       smin, smax, vmin, vmax, (datatype == CDI_DATATYPE_FLT32) ? "" : " -b F32 or");
62       }
63   }
64 };
65 
66 #endif
67