OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
L3FileSMI.cpp
Go to the documentation of this file.
1 #include <L3FileSMI.h>
2 #include <L3ShapeSMI.h>
3 #include <genutils.h>
4 #include <boost/algorithm/string.hpp>
5 
6 #include <hdf.h>
7 #include <mfhdf.h>
8 
9 using namespace std;
10 using namespace netCDF;
11 using namespace netCDF::exceptions;
12 
13 namespace l3 {
14 
15 //----------------------------------------------------------------------------
16 // L3FileSMI
17 //----------------------------------------------------------------------------
18 
19 L3FileSMI::L3FileSMI() {
20  ncFile = NULL;
21  bzero(&metaData, sizeof (meta_l3bType));
22  metaData.north = metaData.south = metaData.east = metaData.west = -999.0;
23 }
24 
25 L3FileSMI::~L3FileSMI() {
26  close();
27 }
28 
29 bool L3FileSMI::readVarCF(NcVar &var, const std::vector<size_t> &start,
30  const std::vector<size_t> &count, float* data) {
31  if (var.isNull()) {
32  return false;
33  }
34  size_t num = 1;
35  for (size_t i = 0; i < count.size(); i++)
36  num *= count[i];
37 
38  // get scale and offset if not float
39  float scale = 1;
40  float offset = 0;
41  bool needScale = false;
42  if ((var.getType().getId() != NC_FLOAT)
43  && (var.getType().getId() != NC_DOUBLE)) {
44  if (readAttribute(var, "scale_factor", &scale))
45  needScale = true;
46  if (readAttribute(var, "add_offset", &offset))
47  needScale = true;
48  }
49 
50  switch (var.getType().getId()) {
51  case NC_FLOAT:
52  {
53  float badVal = missingPixelValue;
54  readAttribute(var, "_FillValue", &badVal);
55  var.getVar(start, count, data);
56  for (size_t i = 0; i < num; i++)
57  if (data[i] == badVal)
59  break;
60  }
61  case NC_DOUBLE:
62  {
63  double badVal = missingPixelValue;
64  readAttribute(var, "_FillValue", &badVal);
65  double* tmp = new double[num];
66  var.getVar(start, count, tmp);
67  for (size_t i = 0; i < num; i++)
68  if (tmp[i] == badVal)
70  else
71  data[i] = tmp[i];
72  delete[] tmp;
73  break;
74  }
75  case NC_BYTE:
76  {
77  int8_t badVal = -128;
78  readAttribute(var, "_FillValue", &badVal);
79  int8_t* tmp = new int8_t[num];
80  var.getVar(start, count, tmp);
81  if (needScale) {
82  for (size_t i = 0; i < num; i++)
83  if (tmp[i] == badVal)
85  else
86  data[i] = tmp[i] * scale + offset;
87  } else {
88  for (size_t i = 0; i < num; i++)
89  if (tmp[i] == badVal)
91  else
92  data[i] = tmp[i];
93  }
94  delete[] tmp;
95  break;
96  }
97  case NC_UBYTE:
98  {
99  uint8_t badVal = 255;
100  readAttribute(var, "_FillValue", &badVal);
101  uint8_t* tmp = new uint8_t[num];
102  var.getVar(start, count, tmp);
103  if (needScale) {
104  for (size_t i = 0; i < num; i++)
105  if (tmp[i] == badVal)
107  else
108  data[i] = tmp[i] * scale + offset;
109  } else {
110  for (size_t i = 0; i < num; i++)
111  if (tmp[i] == badVal)
113  else
114  data[i] = tmp[i];
115  }
116  delete[] tmp;
117  break;
118  }
119  case NC_SHORT:
120  {
121  short badVal = -32767;
122  readAttribute(var, "_FillValue", &badVal);
123  short* tmp = new short[num];
124  var.getVar(start, count, tmp);
125  if (needScale) {
126  for (size_t i = 0; i < num; i++)
127  if (tmp[i] == badVal)
129  else
130  data[i] = tmp[i] * scale + offset;
131  } else {
132  for (size_t i = 0; i < num; i++)
133  if (tmp[i] == badVal)
135  else
136  data[i] = tmp[i];
137  }
138  delete[] tmp;
139  break;
140  }
141  case NC_USHORT:
142  {
143  uint16_t badVal = 65535;
144  readAttribute(var, "_FillValue", &badVal);
145  uint16_t* tmp = new uint16_t[num];
146  var.getVar(start, count, tmp);
147  if (needScale) {
148  for (size_t i = 0; i < num; i++)
149  if (tmp[i] == badVal)
151  else
152  data[i] = tmp[i] * scale + offset;
153  } else {
154  for (size_t i = 0; i < num; i++)
155  if (tmp[i] == badVal)
157  else
158  data[i] = tmp[i];
159  }
160  delete[] tmp;
161  break;
162  }
163  case NC_INT:
164  {
165  int badVal = -32767;
166  readAttribute(var, "_FillValue", &badVal);
167  int* tmp = new int[num];
168  var.getVar(start, count, tmp);
169  if (needScale) {
170  for (size_t i = 0; i < num; i++)
171  if (tmp[i] == badVal)
173  else
174  data[i] = tmp[i] * scale + offset;
175  } else {
176  for (size_t i = 0; i < num; i++)
177  if (tmp[i] == badVal)
179  else
180  data[i] = tmp[i];
181  }
182  delete[] tmp;
183  break;
184  }
185  case NC_UINT:
186  {
187  uint32_t badVal = 4294967295;
188  readAttribute(var, "_FillValue", &badVal);
189  uint32_t* tmp = new uint32_t[num];
190  var.getVar(start, count, tmp);
191  if (needScale) {
192  for (size_t i = 0; i < num; i++)
193  if (tmp[i] == badVal)
195  else
196  data[i] = tmp[i] * scale + offset;
197  } else {
198  for (size_t i = 0; i < num; i++)
199  if (tmp[i] == badVal)
201  else
202  data[i] = tmp[i];
203  }
204  delete[] tmp;
205  break;
206  }
207  case NC_UINT64:
208  {
209  uint64_t badVal = 1.844674407 * pow(10, 19);
210  readAttribute(var, "_FillValue", &badVal);
211  uint64_t* tmp = new uint64_t[num];
212  var.getVar(start, count, tmp);
213  if (needScale) {
214  for (size_t i = 0; i < num; i++)
215  if (tmp[i] == badVal)
217  else
218  data[i] = tmp[i] * scale + offset;
219  } else {
220  for (size_t i = 0; i < num; i++)
221  if (tmp[i] == badVal)
223  else
224  data[i] = tmp[i];
225  }
226  delete[] tmp;
227  break;
228  }
229  default:
230  if (want_verbose)
231  printf("Error - L3FileSMI::readVarCF - data type %s not supported",
232  var.getType().getName().c_str());
233  return false;
234  }
235  return true;
236 }
237 
238 bool L3FileSMI::open(const char* fileName) {
239  close();
240 
241  // bail if this is an hdf file
242  if (Hishdf(fileName))
243  return false;
244 
245  try {
246  ncFile = new NcFile(fileName, NcFile::read);
247  } catch (NcException& e) {
248  e.what();
249  if (want_verbose)
250  printf("Error - %s is not a valid netCDF file\n", fileName);
251  ncFile = NULL;
252  return false;
253  }
254 
255  if (ncFile->isNull()) {
256  if (want_verbose)
257  printf("Error - %s is not a valid netCDF file\n", fileName);
258  close();
259  return false;
260  }
261 
262  string tmpStr = "";
263  readAttribute("title", tmpStr);
264  if (tmpStr.find("Level-3 Standard Mapped Image") == string::npos) {
265  if (want_verbose)
266  printf("Error - %s is not a Level-3 SMI file\n", fileName);
267  close();
268  return false;
269  }
270 
271  NcDim latDim = ncFile->getDim("lat");
272  if (latDim.isNull()) {
273  if (want_verbose)
274  printf("Error - Could not find lat dimension\n");
275  close();
276  return false;
277  }
278  size_t numRows = latDim.getSize();
279 
280  NcDim lonDim = ncFile->getDim("lon");
281  if (latDim.isNull()) {
282  if (want_verbose)
283  printf("Error - Could not find lon dimension\n");
284  close();
285  return false;
286  }
287  size_t numCols = lonDim.getSize();
288 
289  read_l3b_meta_netcdf4(ncFile->getId(), &metaData);
290 
291  shape = new L3ShapeSMI(numRows, numCols, metaData.north, metaData.south,
292  metaData.east, metaData.west);
293 
294  initRecordLookup();
295 
296  // fill up the name list
297  prodNameList.clear();
298  multimap<string, NcVar> varMap = ncFile->getVars();
299  multimap<string, NcVar>::iterator iter = varMap.begin();
300  while (iter != varMap.end()) {
301  string varName = iter->first;
302  if (iter->second.getDimCount() == 2) {
303  size_t varRows = iter->second.getDim(0).getSize();
304  size_t varCols = iter->second.getDim(1).getSize();
305  size_t fileRows = shape->getNumRows();
306  size_t fileCols = shape->getNumCols(0);
307  if (varRows == fileRows && varCols == fileCols)
308  prodNameList.push_back(varName);
309  }
310  iter++;
311  }
312 
313  return true;
314 }
315 
316 void L3FileSMI::close() {
317  if (ncFile) {
318  delete ncFile;
319  ncFile = NULL;
320  }
321  metaData.north = metaData.south = metaData.east = metaData.west = -999.0;
322  prodNameList.clear();
323  activeProdNameList.clear();
324  prodVarList.clear();
325  L3File::close();
326 }
327 
328 meta_l3bType* L3FileSMI::getMetaData() {
329  return &metaData;
330 }
331 
336 int L3FileSMI::initRecordLookup() {
337 
338  if (shape->getNumRows() == 0) {
339  fprintf(stderr,
340  "-E- %s %d: initRecordLookup: Number of rows needs to be set and bin grid must be initialized first.\n",
341  __FILE__, __LINE__);
342  exit(EXIT_FAILURE);
343  }
344 
345  // remove memory if it exists
346  if (baseRecord) {
347  free(baseRecord);
348  }
349  baseRecord = (int64_t*) allocateMemory(
350  shape->getNumRows() * sizeof (int64_t), "baseRecord");
351  if (extentbin) {
352  free(extentbin);
353  }
354  extentbin = (int32_t*) allocateMemory(
355  shape->getNumRows() * sizeof (int32_t), "extbin");
356 
357  int32_t index = 0;
358  for (int row = 0; row < shape->getNumRows(); row++) {
359  extentbin[row] = shape->getNumCols(row);
360  baseRecord[row] = index;
361  index += shape->getNumCols(row);
362  }
363  return 0;
364 }
365 
366 int32_t L3FileSMI::getNumProducts() {
367  return prodNameList.size();
368 }
369 
371  return prodNameList[index];
372 }
373 
374 bool L3FileSMI::setActiveProductList(const char* prodStr) {
375  //free the sum buffer since it depends on the number of products
376  if (sumBuffer) {
377  free(sumBuffer);
378  sumBuffer = NULL;
379  }
380  clearCache();
381  outBin.clear();
382 
383  activeProdNameList.clear();
384  prodVarList.clear();
385 
386  if (ncFile == NULL || ncFile->isNull()) {
387  return false;
388  }
389 
390  boost::split(activeProdNameList, prodStr, boost::is_any_of(","));
391  for (size_t i = 0; i < activeProdNameList.size(); i++) {
392  boost::trim(activeProdNameList[i]);
393  NcVar tmpVar = ncFile->getVar(activeProdNameList[i]);
394  if (tmpVar.isNull()) {
395  activeProdNameList.clear();
396  prodVarList.clear();
397  if (want_verbose)
398  printf("Error - product %s not found in file\n",
399  activeProdNameList[i].c_str());
400  return false;
401  }
402  prodVarList.push_back(tmpVar);
403  }
404  return true;
405 }
406 
407 L3Row* L3FileSMI::readRow(int32_t row) {
408  L3Row* l3Row;
409 
410  if (row < 0 || row >= shape->getNumRows())
411  return NULL;
412 
413  if (rowList.size() < (uint32_t) numCacheRows) {
414  l3Row = new L3Row(row, shape->getNumCols(row),
415  activeProdNameList.size());
416  } else {
417  l3Row = rowList.back();
418  rowList.pop_back();
419  l3Row->row = row;
420  }
421  rowList.push_front(l3Row);
422 
423  // allocate the sum buffer if necessary
424  if (sumBuffer == NULL)
425  sumBuffer = (float*) allocateMemory(
426  shape->getNumCols(row) * sizeof (float), "L3FileSMI::sumBuffer");
427 
428  vector<size_t> start, count;
429  start.push_back(shape->getNumRows() - row - 1);
430  start.push_back(0);
431  count.push_back(1);
432  count.push_back(shape->getNumCols(row));
433 
434  for (size_t prodIndex = 0; prodIndex < prodVarList.size(); prodIndex++) {
435  readVarCF(prodVarList[prodIndex], start, count, sumBuffer);
436 
437  L3Bin* l3Bin;
438  for (int32_t i = 0; i < shape->getNumCols(row); i++) {
439  l3Bin = l3Row->binArray[i];
440  l3Bin->binNum = shape->rowcol2bin(row, i);
441  l3Bin->recordNum = l3Bin->binNum;
442  l3Bin->quality = L3Bin::qualityUnused;
443 
444  if (sumBuffer[i] == missingPixelValue) {
445  l3Bin->nobs = 0;
446  l3Bin->nscenes = 0;
447  l3Bin->weights = 0;
448  l3Bin->sums[prodIndex] = missingPixelValue;
449  l3Bin->sumSquares[prodIndex] = missingPixelValue;
450  } else {
451  l3Bin->nobs = 1;
452  l3Bin->nscenes = 1;
453  l3Bin->weights = 1;
454  l3Bin->sums[prodIndex] = sumBuffer[i];
455  l3Bin->sumSquares[prodIndex] = sumBuffer[i] * sumBuffer[i];
456  }
457  }
458  }
459  return l3Row;
460 }
461 
462 bool L3FileSMI::hasQuality() {
463  return false;
464 }
465 
466 } // namespace l3
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame index(0-based) was previously being used the frame number(1-based) should have been used. There were only a few minor changes to the uncertainty index(maximum of 1 digit). 3. Some inefficient arrays(Sigma_RVS_norm_sq) were eliminated and some code lines in Preprocess_L1A_Data were moved into Process_OBCEng_Emiss. There were no changes to the product. Required RAM was reduced by 20 MB. Now
float * sumSquares
Definition: L3File.h:74
void * allocateMemory(size_t numBytes, const char *name)
Definition: allocateMemory.c:7
#define NULL
Definition: decode_rs.h:63
int32_t nscenes
Definition: L3File.h:69
std::vector< L3Bin * > binArray
Definition: L3File.h:125
vector< string > prodNameList
Definition: l3mapgen.cpp:56
int32_t row
Definition: L3File.h:122
int32_t nobs
Definition: L3File.h:68
void bzero()
data_t tmp
Definition: decode_rs.h:74
uint8_t quality
Definition: L3File.h:70
NcFile * ncFile
float weights
Definition: L3File.h:72
const float missingPixelValue
Definition: L3File.h:19
int want_verbose
string & trim(string &s, const string &delimiters)
Definition: EnvsatUtil.cpp:29
int64_t binNum
Definition: L3File.h:66
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
void getProductName(char *name, l2prodstr *product)
int32_t read_l3b_meta_netcdf4(int ncid, meta_l3bType *meta_l3b)
Definition: L3File.cpp:10
l2prod offset
int64_t recordNum
Definition: L3File.h:67
float * sums
Definition: L3File.h:73
int i
Definition: decode_rs.h:71
int count
Definition: decode_rs.h:79