NASA Logo
Ocean Color Science Software

ocssw V2022
scaledNcVar.cpp
Go to the documentation of this file.
1 
10 #include "scaledNcVar.hpp"
11 #include <ncVarAtt.h>
12 #include <math.h>
13 #include <limits>
14 
15 using namespace netCDF;
16 using namespace netCDF::exceptions;
17 using namespace std;
18 
19 ScaledNcVar::ScaledNcVar(const NcVar &copied) : netCDF::NcVar(copied) {
20 }
21 
23  if (prodInfo) {
24  freeProductInfo(prodInfo);
25  }
26 }
27 
28 bool ScaledNcVar::floatingPoint() {
29  return thisVarType == NcType::nc_DOUBLE || thisVarType == NcType::nc_FLOAT;
30 }
31 
32 double ScaledNcVar::initFillValue() {
33  switch (thisVarType) { // nc_type
34  case (NC_BYTE):
36  case (NC_UBYTE):
38  case (NC_USHORT):
40  case (NC_UINT):
42  default:
44  }
45 }
46 
47 void ScaledNcVar::assignBadValue(double newValue) {
48  this->badValue = newValue;
49 }
50 
51 void ScaledNcVar::assignFillValue(double newValue) {
52  switch (thisVarType) { // nc_type
53  case (NC_BYTE): {
54  int8_t fill;
55  if (newValue >= numeric_limits<int8_t>::max() || newValue <= numeric_limits<int8_t>::lowest()) {
56  throw out_of_range("Given fill value is outside the range of this variable");
57  } else {
58  fill = static_cast<int8_t>(newValue);
59  }
60  setFill(true, fill);
61  break;
62  }
63 
64  case (NC_UBYTE): {
65  uint8_t fill;
66  if (newValue >= numeric_limits<uint8_t>::max() || newValue <= numeric_limits<uint8_t>::lowest()) {
67  throw out_of_range("Given fill value is outside the range of this variable");
68  } else {
69  fill = static_cast<uint8_t>(newValue);
70  }
71  setFill(true, fill);
72  break;
73  }
74 
75  case (NC_SHORT): {
76  short fill;
77  if (newValue >= numeric_limits<short>::max() || newValue <= numeric_limits<short>::lowest()) {
78  throw out_of_range("Given fill value is outside the range of this variable");
79  } else {
80  fill = static_cast<short>(newValue);
81  }
82  setFill(true, fill);
83  break;
84  }
85 
86  case (NC_USHORT): {
87  uint16_t fill;
88  if (newValue >= numeric_limits<uint16_t>::max() ||
89  newValue <= numeric_limits<uint16_t>::lowest()) {
90  throw out_of_range("Given fill value is outside the range of this variable");
91  } else {
92  fill = static_cast<uint16_t>(newValue);
93  }
94  setFill(true, fill);
95  break;
96  }
97 
98  case (NC_INT): {
99  int fill;
100  if (newValue >= numeric_limits<int>::max() || newValue <= numeric_limits<int>::lowest()) {
101  throw out_of_range("Given fill value is outside the range of this variable");
102  } else {
103  fill = static_cast<int>(newValue);
104  }
105  setFill(true, fill);
106  break;
107  }
108 
109  case (NC_UINT): {
110  uint32_t fill;
111  if (newValue >= numeric_limits<uint32_t>::max() ||
112  newValue <= numeric_limits<uint32_t>::lowest()) {
113  throw out_of_range("Given fill value is outside the range of this variable");
114  } else {
115  fill = static_cast<uint32_t>(newValue);
116  }
117  setFill(true, fill);
118  break;
119  }
120 
121  case (NC_FLOAT): {
122  float fill;
123  if (newValue >= numeric_limits<float>::max() || newValue <= numeric_limits<float>::lowest()) {
124  throw out_of_range("Given fill value is outside the range of this variable");
125  } else {
126  fill = static_cast<float>(newValue);
127  }
128  setFill(true, fill);
129  break;
130  }
131 
132  default:
133  setFill(true, newValue);
134  }
135  this->fillValue = newValue;
136 }
137 
138 size_t getDimsSize(std::vector<NcDim> dims) {
139  size_t size = 1;
140  for (const auto &dim : dims)
141  size *= dim.getSize();
142  return size;
143 }
144 
145 void ScaledNcVar::getScaleFactorsFromFile() {
146  try {
147  getAtt("scale_factor").getValues(&scaleFactor);
148  } catch (NcException const &e) {
149  scaleFactor = 1.0;
150  }
151  try {
152  getAtt("add_offset").getValues(&addOffset);
153  } catch (NcException const &e) {
154  addOffset = 0.0;
155  }
156  try {
157  bool _;
158  NcVar::getFillModeParameters(_, &fillValue);
159  } catch (NcException const &e) {
160  fillValue = BAD_FLT;
161  }
162  scaleFactorsSet = true;
163 }
164 
165 void ScaledNcVar::getVar(float *dataValues) {
166  NcVar::getVar(dataValues);
167 
168  if (!scaleFactorsSet)
169  getScaleFactorsFromFile();
170 
171  if (thisVarType != NcType::nc_FLOAT && thisVarType != NcType::nc_DOUBLE)
172  ScaledNcVar::uncompress(dataValues, getDimsSize(getDims()));
173  else
174  fillToBad(dataValues, getDimsSize(getDims())); // since uncompress already does this
175 }
176 
177 void ScaledNcVar::getVar(double *dataValues) {
178  NcVar::getVar(dataValues);
179 
180  if (!scaleFactorsSet)
181  getScaleFactorsFromFile();
182 
183  if (thisVarType != NcType::nc_FLOAT && thisVarType != NcType::nc_DOUBLE)
184  ScaledNcVar::uncompress(dataValues, getDimsSize(getDims()));
185  else
186  fillToBad(dataValues, getDimsSize(getDims())); // since uncompress already does this
187 }
188 
189 void ScaledNcVar::getVar(vector<size_t> start, vector<size_t> count, float *dataValues) {
190  size_t sizeToGet = 1;
191  for (size_t stop : count)
192  sizeToGet *= stop;
193 
194  NcVar::getVar(start, count, dataValues);
195 
196  if (!scaleFactorsSet)
197  getScaleFactorsFromFile();
198 
199  if (thisVarType != NcType::nc_FLOAT && thisVarType != NcType::nc_DOUBLE)
200  ScaledNcVar::uncompress(dataValues, sizeToGet);
201  else
202  fillToBad(dataValues, sizeToGet); // since uncompress already does this
203 }
204 
205 void ScaledNcVar::getVar(vector<size_t> start, vector<size_t> count, double *dataValues) {
206  size_t sizeToGet = 1;
207  for (size_t stop : count)
208  sizeToGet *= stop;
209 
210  NcVar::getVar(start, count, dataValues);
211 
212  if (!scaleFactorsSet)
213  getScaleFactorsFromFile();
214 
215  if (thisVarType != NcType::nc_FLOAT && thisVarType != NcType::nc_DOUBLE)
216  ScaledNcVar::uncompress(dataValues, sizeToGet);
217  else
218  fillToBad(dataValues, sizeToGet); // since uncompress already does this
219 }
220 
221 void ScaledNcVar::putVar(const float *dataValues) {
222  size_t sizeToWrite = getDimsSize(getDims());
223 
224  if (floatingPoint() || !scaleFactorsSet) {
225  if (fillValue != badValue) {
226  vector<double> buf(sizeToWrite);
227  badToFill(dataValues, sizeToWrite, buf);
228  NcVar::putVar(buf.data());
229  } else {
230  NcVar::putVar(dataValues);
231  }
232  return;
233  }
234 
235  // scale factors are set and this is not a float
236  vector<int32_t> buf(dataValues, dataValues + sizeToWrite);
237  compress(dataValues, buf, sizeToWrite);
238  NcVar::putVar(buf.data());
239 }
240 
241 void ScaledNcVar::putVar(const double *dataValues) {
242  size_t sizeToWrite = getDimsSize(getDims());
243 
244  if (floatingPoint() || !scaleFactorsSet) {
245  if (fillValue != badValue) {
246  vector<double> buf(sizeToWrite);
247  badToFill(dataValues, sizeToWrite, buf);
248  NcVar::putVar(buf.data());
249  } else {
250  NcVar::putVar(dataValues);
251  }
252  return;
253  }
254 
255  // scale factors are set and this is not a float
256  vector<int32_t> buf(dataValues, dataValues + sizeToWrite);
257  compress(dataValues, buf, sizeToWrite);
258  NcVar::putVar(buf.data());
259 }
260 
261 void ScaledNcVar::putVar(vector<size_t> start, vector<size_t> count, const float *dataValues) {
262  size_t sizeToWrite = 1;
263  for (size_t stop : count) {
264  sizeToWrite *= stop;
265  }
266 
267  if (floatingPoint() || !scaleFactorsSet) {
268  if (fillValue != badValue) {
269  vector<double> buf(sizeToWrite);
270  badToFill(dataValues, sizeToWrite, buf);
271  NcVar::putVar(start, count, buf.data());
272  } else {
273  NcVar::putVar(start, count, dataValues);
274  }
275  return;
276  }
277 
278  // scale factors are set and this is not a float
279  vector<int32_t> buf(dataValues, dataValues + sizeToWrite);
280  compress(dataValues, buf, sizeToWrite);
281  NcVar::putVar(start, count, buf.data());
282 }
283 
284 void ScaledNcVar::putVar(vector<size_t> start, vector<size_t> count, const double *dataValues) {
285  size_t sizeToWrite = 1;
286  for (size_t stop : count) {
287  sizeToWrite *= stop;
288  }
289 
290  if (floatingPoint() || !scaleFactorsSet) {
291  if (fillValue != badValue) {
292  vector<double> buf(sizeToWrite);
293  badToFill(dataValues, sizeToWrite, buf);
294  NcVar::putVar(start, count, buf.data());
295  } else {
296  NcVar::putVar(start, count, dataValues);
297  }
298  return;
299  }
300 
301  // scale factors are set and this is not a float
302  vector<int32_t> buf(dataValues, dataValues + sizeToWrite);
303  compress(dataValues, buf, sizeToWrite);
304  NcVar::putVar(start, count, buf.data());
305 }
306 
307 void ScaledNcVar::getFillValue(double *fillValue) {
308  *fillValue = this->fillValue;
309 }
310 void ScaledNcVar::getFillValue(float *fillValue) {
311  *fillValue = this->fillValue;
312 }
313 
314 void ScaledNcVar::compress(const double *toCompress, std::vector<int32_t> &compressed, size_t count) {
315  compressed.resize(count);
316  pair<double, double> thisVarRange = range(); // [lowerBound, upperBound]
317 
318  for (size_t i = 0; i < count; i++) {
319  if (toCompress[i] == badValue) {
320  compressed[i] = fillValue;
321  } else {
322  double value = (toCompress[i] - this->addOffset) / this->scaleFactor;
323 
324  if (value < thisVarRange.first || thisVarRange.second < value) {
325  compressed[i] = fillValue;
326  } else {
327  compressed[i] = value;
328  }
329  }
330  }
331 }
332 
333 void ScaledNcVar::compress(const float *toCompress, std::vector<int32_t> &compressed, size_t count) {
334  compressed.resize(count);
335  pair<double, double> thisVarRange = range(); // [lowerBound, upperBound]
336 
337  for (size_t i = 0; i < count; i++) {
338  if (toCompress[i] == badValue) {
339  compressed[i] = fillValue;
340  } else {
341  double value = (toCompress[i] - this->addOffset) / this->scaleFactor;
342 
343  if (value < thisVarRange.first || thisVarRange.second < value) {
344  compressed[i] = fillValue;
345  } else {
346  compressed[i] = value;
347  }
348  }
349  }
350 }
351 
352 void ScaledNcVar::uncompress(double *toUncompress, size_t count) {
353  for (size_t i = 0; i < count; i++) {
354  if (toUncompress[i] == fillValue)
355  toUncompress[i] = badValue;
356  else if (scaleFactor != 1.0 || addOffset != 0.0)
357  toUncompress[i] = (toUncompress[i] * scaleFactor) + addOffset;
358  }
359 }
360 
361 void ScaledNcVar::uncompress(float *toUncompress, size_t count) {
362  for (size_t i = 0; i < count; i++) {
363  if (toUncompress[i] == fillValue)
364  toUncompress[i] = badValue;
365  else if (scaleFactor != 1.0 || addOffset != 0.0)
366  toUncompress[i] = (toUncompress[i] * scaleFactor) + addOffset;
367  }
368 }
369 
370 template <typename T>
371 void ScaledNcVar::fillToBad(T *data, size_t count) {
372  if (fillValue != badValue) {
373  for (size_t i = 0; i < count; i++) {
374  if (data[i] == fillValue)
375  data[i] = badValue;
376  }
377  }
378 }
379 
380 template <typename T, typename E>
381 void ScaledNcVar::badToFill(const T *data, const size_t &count, vector<E> &out) {
382  out.resize(count);
383  for (size_t i = 0; i < count; i++) {
384  if (data[i] == badValue)
385  out[i] = fillValue;
386  else
387  out[i] = data[i];
388  }
389 }
390 
392  if (!prodInfo) {
393  prodInfo = allocateProductInfo();
394 
395  if (findProductInfo(this->NcVar::getName().c_str(), sensorID, prodInfo) != 1) {
396  freeProductInfo(prodInfo);
397  prodInfo = nullptr;
398  return false;
399  }
400  }
401 
402  if (prodInfo->description && strcmp(prodInfo->description, PRODUCT_DEFAULT_description))
403  putAtt("long_name", prodInfo->description);
404 
405  if (prodInfo->units && strcmp(prodInfo->units, PRODUCT_DEFAULT_units) &&
406  strcmp(prodInfo->units, "dimensionless"))
407  putAtt("units", prodInfo->units);
408 
409  if (prodInfo->standardName)
410  putAtt("standard_name", prodInfo->standardName);
411 
412  assignFillValue(prodInfo->fillValue);
413 
414  if (prodInfo->validMin != PRODUCT_DEFAULT_validMin)
415  putAtt("valid_min", thisVarType, prodInfo->validMin);
416 
417  if (prodInfo->validMax != PRODUCT_DEFAULT_validMax)
418  putAtt("valid_max", thisVarType, prodInfo->validMax);
419 
420  // If either scaleFactor or addOffset are set, they both will be.
421  if ((prodInfo->scaleFactor != PRODUCT_DEFAULT_scaleFactor) ||
422  (prodInfo->addOffset != PRODUCT_DEFAULT_addOffset)) {
423  putAtt("scale_factor", NC_DOUBLE, prodInfo->scaleFactor);
424  putAtt("add_offset", NC_DOUBLE, prodInfo->addOffset);
425  scaleFactor = prodInfo->scaleFactor;
426  addOffset = prodInfo->addOffset;
427  }
428 
429  if (prodInfo->reference != PRODUCT_DEFAULT_reference)
430  putAtt("reference", prodInfo->reference);
431 
432  if (prodInfo->comment != PRODUCT_DEFAULT_comment)
433  putAtt("comment", prodInfo->comment);
434 
435  scaleFactorsSet = true;
436 
437  return true;
438 }
439 
440 void ScaledNcVar::setScaleFactors(double scale, double offset, double fillValue) {
441  scaleFactorsSet = true;
442  assignFillValue(fillValue);
443 
444  // need to set scale factors
445  if (scale != 1.0 || offset != 0.0) {
446  // not allowed to set scale and offset if not unity for floats
447  if (thisVarType == NC_DOUBLE || thisVarType == NC_FLOAT) {
448  throw invalid_argument("Setting scale/offset for a float/double is not allowed\n");
449  }
450 
451  this->scaleFactor = scale;
452  this->addOffset = offset;
453 
454  putAtt("scale_factor", NC_DOUBLE, scale);
455  putAtt("add_offset", NC_DOUBLE, offset);
456  }
457 }
458 
459 pair<double, double> ScaledNcVar::range() {
460  switch (thisVarType) {
461  case (NC_FLOAT):
462  return pair<double, double>(NC_MIN_FLOAT, NC_MAX_FLOAT);
463  case (NC_DOUBLE):
464  return pair<double, double>(NC_MIN_DOUBLE, NC_MAX_DOUBLE);
465  case (NC_BYTE):
466  return pair<double, double>(NC_MIN_BYTE, NC_MAX_BYTE);
467  case (NC_UBYTE):
468  return pair<double, double>(0, NC_MAX_UBYTE);
469  case (NC_SHORT):
470  return pair<double, double>(NC_MIN_SHORT, NC_MAX_SHORT);
471  case (NC_USHORT):
472  return pair<double, double>(0, NC_MAX_USHORT);
473  case (NC_INT):
474  return pair<double, double>(NC_MIN_INT, NC_MAX_INT);
475  case (NC_UINT):
476  return pair<double, double>(0, NC_MAX_UINT);
477  default:
478  return pair<double, double>(1, -1); // Dumb value
479  }
480 }
481 
482 netCDF::NcType::ncType productInfoType2ncType(string typeStr) {
483  if (typeStr == "byte")
484  return NcType::nc_BYTE;
485  else if (typeStr == "ubyte")
486  return NcType::nc_UBYTE;
487  else if (typeStr == "short")
488  return NcType::nc_SHORT;
489  else if (typeStr == "ushort")
490  return NcType::nc_USHORT;
491  else if (typeStr == "int")
492  return NcType::nc_INT;
493  else if (typeStr == "uint")
494  return NcType::nc_UINT;
495  else if (typeStr == "float")
496  return NcType::nc_FLOAT;
497  else if (typeStr == "double")
498  return NcType::nc_DOUBLE;
499  else
500  throw runtime_error("productInfoType2ncType could not lookup typeStr = " + typeStr);
501  return NcType::nc_FLOAT;
502 }
503 
504 ScaledNcVar newScaledNcVar(const netCDF::NcGroup &group, const std::string &name,
505  const std::vector<netCDF::NcDim> &dims, int sensorID) {
506  productInfo_t *prodInfo = allocateProductInfo();
507 
508  if (!findProductInfo(name.c_str(), sensorID, prodInfo)) {
509  freeProductInfo(prodInfo);
510  throw runtime_error("newScaledNcVar could not find product = " + name);
511  }
512 
513  ScaledNcVar var = group.addVar(name, productInfoType2ncType(prodInfo->dataType), dims);
514  var.setProdInfo(prodInfo);
515  var.populateScaleFactors();
516  return var;
517 }
int32 value
Definition: Granule.c:1235
void freeProductInfo(productInfo_t *info)
netCDF::NcType::ncType thisVarType
netCDF::NcType::ncType productInfoType2ncType(string typeStr)
#define PRODUCT_DEFAULT_validMax
Definition: productInfo.h:35
#define PRODUCT_DEFAULT_addOffset
Definition: productInfo.h:40
void getFillValue(double *fillValue)
Get the fill value of this NcVar.
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in out
Definition: HISTORY.txt:422
#define PRODUCT_DEFAULT_comment
Definition: productInfo.h:42
#define PRODUCT_DEFAULT_scaleFactor
Definition: productInfo.h:39
ScaledNcVar(const NcVar &copied)
Definition: scaledNcVar.cpp:19
#define PRODUCT_DEFAULT_description
Definition: productInfo.h:13
@ string
ScaledNcVar newScaledNcVar(const netCDF::NcGroup &group, const std::string &name, const std::vector< netCDF::NcDim > &dims, int sensorID)
Create a ScaledNcVar using the product.xml for definition.
void getVar(float *dataValues)
Takes in a pointer whose memory will be modified. Assumes values found there are integers and perform...
size_t getDimsSize(std::vector< NcDim > dims)
void assignFillValue(double newValue)
Reassign the fill value.
Definition: scaledNcVar.cpp:51
#define PRODUCT_DEFAULT_fillValue
Definition: productInfo.h:29
int getDims(int32_t fileID, const char sdsname[], int32_t dims[])
#define PRODUCT_DEFAULT_fillValue_byte
Definition: productInfo.h:30
#define PRODUCT_DEFAULT_reference
Definition: productInfo.h:41
productInfo_t * allocateProductInfo()
#define PRODUCT_DEFAULT_units
Definition: productInfo.h:14
void setScaleFactors(double scale, double offset, double fillValue=BAD_FLT)
Populate scale factor and add offset manually. Throws an invalid_argument
#define PRODUCT_DEFAULT_fillValue_uint
Definition: productInfo.h:33
void putVar(const float *dataValues)
put an entire variable
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
#define PRODUCT_DEFAULT_fillValue_ubyte
Definition: productInfo.h:31
int findProductInfo(const char *productName, int sensorId, productInfo_t *info)
void assignBadValue(double newValue)
Reassign the value of badValue.
Definition: scaledNcVar.cpp:47
#define BAD_FLT
Definition: jplaeriallib.h:19
bool populateScaleFactors(int sensorID=DEFAULT_SENSOR)
Populate scale factor and add offset from product.xml. Assumes default sensor (30 == OCI)
#define PRODUCT_DEFAULT_validMin
Definition: productInfo.h:34
void setProdInfo(productInfo_t *prodInfo)
l2prod offset
int i
Definition: decode_rs.h:71
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:91
#define PRODUCT_DEFAULT_fillValue_ushort
Definition: productInfo.h:32
l2prod max
int count
Definition: decode_rs.h:79