OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
HDFCFUtil.cc
Go to the documentation of this file.
1 #include "HDFCFUtil.h"
2 #include <BESDebug.h>
3 #include <BESLog.h>
4 #include <math.h>
5 
6 #define SIGNED_BYTE_TO_INT32 1
7 using namespace std;
8 using namespace libdap;
9 
10 // Check the BES key.
11 // This function will check a BES key specified at the file h4.conf.in.
12 // If the key's value is either true or yes. The handler claims to find
13 // a key and will do some operations. Otherwise, will do different operations.
14 // For example, One may find a line H4.EnableCF=true at h4.conf.in.
15 // That means, the HDF4 handler will handle the HDF4 files by following CF conventions.
16 bool
17 HDFCFUtil::check_beskeys(const string& key) {
18 
19  bool found = false;
20  string doset ="";
21  const string dosettrue ="true";
22  const string dosetyes = "yes";
23 
24  TheBESKeys::TheKeys()->get_value( key, doset, found ) ;
25  if( true == found ) {
26  doset = BESUtil::lowercase( doset ) ;
27  if( dosettrue == doset || dosetyes == doset )
28  return true;
29  }
30  return false;
31 
32 }
33 
34 
35 // From a string separated by a separator to a list of string,
36 // for example, split "ab,c" to {"ab","c"}
37 void
38 HDFCFUtil::Split(const char *s, int len, char sep, std::vector<std::string> &names)
39 {
40  names.clear();
41  for (int i = 0, j = 0; j <= len; ++j) {
42  if ((j == len && len) || s[j] == sep) {
43  string elem(s + i, j - i);
44  names.push_back(elem);
45  i = j + 1;
46  continue;
47  }
48  }
49 }
50 
51 // Assume sz is Null terminated string.
52 void
53 HDFCFUtil::Split(const char *sz, char sep, std::vector<std::string> &names)
54 {
55  Split(sz, (int)strlen(sz), sep, names);
56 }
57 
58 // This is a safer way to insert and update a c++ map value.
59 // Otherwise, the local testsuite at The HDF Group will fail for HDF-EOS2 data
60 // under iMac machine platform.
61 // The implementation replaces the element even if the key exists.
62 // This function is equivalent to map[key]=value
63 bool
64 HDFCFUtil::insert_map(std::map<std::string,std::string>& m, string key, string val)
65 {
66  pair<map<string,string>::iterator, bool> ret;
67  ret = m.insert(make_pair(key, val));
68  if(ret.second == false){
69  m.erase(key);
70  ret = m.insert(make_pair(key, val));
71  if(ret.second == false){
72  BESDEBUG("h4","insert_map():insertion failed on Key=" << key << " Val=" << val << endl);
73  }
74  }
75  return ret.second;
76 }
77 
78 // Obtain CF string
79 string
81 {
82 
83  if(""==s)
84  return s;
85  string insertString(1,'_');
86 
87  // Always start with _ if the first character is not a letter
88  if (true == isdigit(s[0]))
89  s.insert(0,insertString);
90 
91  // New name conventions drop the first '/' from the path.
92  if ('/' ==s[0])
93  s.erase(0,1);
94 
95  for(unsigned int i=0; i < s.length(); i++)
96  if((false == isalnum(s[i])) && (s[i]!='_'))
97  s[i]='_';
98 
99  return s;
100 
101 }
102 
103 // Obtain the unique name for the clashed names and save it to set namelist.
104 // This is a recursive call. A unique name list is represented as a set.
105 // If we find that a name already exists in the nameset, we will add a number
106 // at the end of the name to form a new name. If the new name still exists
107 // in the nameset, we will increase the index number and check again until
108 // a unique name is generated.
109 void
110 HDFCFUtil::gen_unique_name(string &str,set<string>& namelist, int&clash_index) {
111 
112  pair<set<string>::iterator,bool> ret;
113  string newstr = "";
114  stringstream sclash_index;
115  sclash_index << clash_index;
116  newstr = str + sclash_index.str();
117 
118  ret = namelist.insert(newstr);
119  if (false == ret.second) {
120  clash_index++;
121  gen_unique_name(str,namelist,clash_index);
122  }
123  else
124  str = newstr;
125 }
126 
127 // General routine to handle the name clashing
128 // The input parameters include:
129 // name vector -> newobjnamelist(The name vector is changed to a unique name list
130 // a pre-allocated object name set ->objnameset(can be used to determine if a name exists)
131 void
132 HDFCFUtil::Handle_NameClashing(vector<string>&newobjnamelist,set<string>&objnameset) {
133 
134  pair<set<string>::iterator,bool> setret;
135  set<string>::iterator iss;
136 
137  vector<string> clashnamelist;
138  vector<string>::iterator ivs;
139 
140  // clash index to original index mapping
141  map<int,int> cl_to_ol;
142  int ol_index = 0;
143  int cl_index = 0;
144 
145  vector<string>::const_iterator irv;
146 
147  for (irv = newobjnamelist.begin(); irv != newobjnamelist.end(); ++irv) {
148  setret = objnameset.insert((*irv));
149  if (false == setret.second ) {
150  clashnamelist.insert(clashnamelist.end(),(*irv));
151  cl_to_ol[cl_index] = ol_index;
152  cl_index++;
153  }
154  ol_index++;
155  }
156 
157  // Now change the clashed elements to unique elements;
158  // Generate the set which has the same size as the original vector.
159  for (ivs=clashnamelist.begin(); ivs!=clashnamelist.end(); ivs++) {
160  int clash_index = 1;
161  string temp_clashname = *ivs +'_';
162  HDFCFUtil::gen_unique_name(temp_clashname,objnameset,clash_index);
163  *ivs = temp_clashname;
164  }
165 
166  // Now go back to the original vector, make it unique.
167  for (unsigned int i =0; i <clashnamelist.size(); i++)
168  newobjnamelist[cl_to_ol[i]] = clashnamelist[i];
169 
170 }
171 
172 // General routine to handle the name clashing
173 // The input parameter just includes:
174 // name vector -> newobjnamelist(The name vector is changed to a unique name list
175 void
176 HDFCFUtil::Handle_NameClashing(vector<string>&newobjnamelist) {
177 
178  set<string> objnameset;
179  Handle_NameClashing(newobjnamelist,objnameset);
180 }
181 
182 // Borrowed codes from ncdas.cc in netcdf_handle4 module.
183 string
184 HDFCFUtil::print_attr(int32 type, int loc, void *vals)
185 {
186  ostringstream rep;
187 
188  union {
189  char *cp;
190  unsigned char *ucp;
191  short *sp;
192  unsigned short *usp;
193  int32 /*nclong*/ *lp;
194  unsigned int *ui;
195  float *fp;
196  double *dp;
197  } gp;
198 
199  switch (type) {
200 
201  // Mapping both DFNT_UINT8 and DFNT_INT8 to unsigned char
202  // may cause overflow. Documented at jira ticket HFRHANDLER-169.
203  case DFNT_UINT8:
204  {
205  unsigned char uc;
206  gp.ucp = (unsigned char *) vals;
207 
208  uc = *(gp.ucp+loc);
209  rep << (int)uc;
210  return rep.str();
211  }
212 
213  case DFNT_INT8:
214  {
215  char c;
216  gp.cp = (char *) vals;
217 
218  c = *(gp.cp+loc);
219  rep << (int)c;
220  return rep.str();
221  }
222 
223  case DFNT_UCHAR:
224  case DFNT_CHAR:
225  {
226  // Use the customized escattr function. Don't escape \n,\t and \r. KY 2013-10-14
227  return escattr(static_cast<const char*>(vals));
228  }
229 
230  case DFNT_INT16:
231  {
232  gp.sp = (short *) vals;
233  rep << *(gp.sp+loc);
234  return rep.str();
235  }
236 
237  case DFNT_UINT16:
238  {
239  gp.usp = (unsigned short *) vals;
240  rep << *(gp.usp+loc);
241  return rep.str();
242  }
243 
244  case DFNT_INT32:
245  {
246  gp.lp = (int32 *) vals;
247  rep << *(gp.lp+loc);
248  return rep.str();
249  }
250 
251  case DFNT_UINT32:
252  {
253  gp.ui = (unsigned int *) vals;
254  rep << *(gp.ui+loc);
255  return rep.str();
256  }
257 
258  case DFNT_FLOAT:
259  {
260  gp.fp = (float *) vals;
261  rep << showpoint;
262  rep << setprecision(10);
263  rep << *(gp.fp+loc);
264  if (rep.str().find('.') == string::npos
265  && rep.str().find('e') == string::npos)
266  rep << ".";
267  return rep.str();
268  }
269 
270  case DFNT_DOUBLE:
271  {
272  gp.dp = (double *) vals;
273  rep << std::showpoint;
274  rep << std::setprecision(17);
275  rep << *(gp.dp+loc);
276  if (rep.str().find('.') == string::npos
277  && rep.str().find('e') == string::npos)
278  rep << ".";
279  return rep.str();
280  break;
281  }
282  default:
283  return string("UNKNOWN");
284  }
285 
286 }
287 
288 // Print datatype in string. This is used to generate DAS.
289 string
291 {
292 
293  // I expanded the list based on libdap/AttrTable.h.
294  static const char UNKNOWN[]="Unknown";
295  static const char BYTE[]="Byte";
296  static const char INT16[]="Int16";
297  static const char UINT16[]="UInt16";
298  static const char INT32[]="Int32";
299  static const char UINT32[]="UInt32";
300  static const char FLOAT32[]="Float32";
301  static const char FLOAT64[]="Float64";
302  static const char STRING[]="String";
303 
304  // I got different cases from hntdefs.h.
305  switch (type) {
306 
307  case DFNT_CHAR:
308  return STRING;
309 
310  case DFNT_UCHAR8:
311  return STRING;
312 
313  case DFNT_UINT8:
314  return BYTE;
315 
316  case DFNT_INT8:
317 // ADD the macro
318  {
319 #ifndef SIGNED_BYTE_TO_INT32
320  return BYTE;
321 #else
322  return INT32;
323 #endif
324  }
325  case DFNT_UINT16:
326  return UINT16;
327 
328  case DFNT_INT16:
329  return INT16;
330 
331  case DFNT_INT32:
332  return INT32;
333 
334  case DFNT_UINT32:
335  return UINT32;
336 
337  case DFNT_FLOAT:
338  return FLOAT32;
339 
340  case DFNT_DOUBLE:
341  return FLOAT64;
342 
343  default:
344  return UNKNOWN;
345  }
346 
347 }
348 
349 
350 // Subset of latitude and longitude to follow the parameters from the DAP expression constraint
351 // Somehow this function doesn't work. Now it is not used. Still keep it here for the future investigation.
352 template < typename T >
353 void HDFCFUtil::LatLon2DSubset (T * outlatlon,
354  int majordim,
355  int minordim,
356  T * latlon,
357  int32 * offset,
358  int32 * count,
359  int32 * step)
360 {
361 
362  // float64 templatlon[majordim][minordim];
363  T (*templatlonptr)[majordim][minordim] = (typeof templatlonptr) latlon;
364  int i, j, k;
365 
366  // do subsetting
367  // Find the correct index
368  int dim0count = count[0];
369  int dim1count = count[1];
370  int dim0index[dim0count], dim1index[dim1count];
371 
372  for (i = 0; i < count[0]; i++) // count[0] is the least changing dimension
373  dim0index[i] = offset[0] + i * step[0];
374 
375 
376  for (j = 0; j < count[1]; j++)
377  dim1index[j] = offset[1] + j * step[1];
378 
379  // Now assign the subsetting data
380  k = 0;
381 
382  for (i = 0; i < count[0]; i++) {
383  for (j = 0; j < count[1]; j++) {
384  outlatlon[k] = (*templatlonptr)[dim0index[i]][dim1index[j]];
385  k++;
386 
387  }
388  }
389 }
390 
391 // CF requires the _FillValue attribute datatype is the same as the corresponding field datatype.
392 // For some NASA files, this is not true.
393 // So we need to check if the _FillValue's datatype is the same as the attribute's.
394 // If not, we need to correct them.
395 void HDFCFUtil::correct_fvalue_type(AttrTable *at,int32 dtype) {
396 
397  AttrTable::Attr_iter it = at->attr_begin();
398  bool find_fvalue = false;
399  while (it!=at->attr_end() && false==find_fvalue) {
400  if (at->get_name(it) =="_FillValue")
401  {
402  find_fvalue = true;
403  string fillvalue ="";
404  string fillvalue_type ="";
405  if((*at->get_attr_vector(it)).size() !=1)
406  throw InternalErr(__FILE__,__LINE__,"The number of _FillValue must be 1.");
407  fillvalue = (*at->get_attr_vector(it)->begin());
408  fillvalue_type = at->get_type(it);
409  string var_type = HDFCFUtil::print_type(dtype);
410 
411  if(fillvalue_type != var_type){
412 
413  at->del_attr("_FillValue");
414 
415  if (fillvalue_type == "String") {
416 
417  // String fillvalue is always represented as /+octal numbers when its type is forced to
418  // change to string(check HFRHANDLER-223). So we have to retrieve it back.
419  if(fillvalue.size() >1) {
420 
421  long int fillvalue_int = 0;
422  vector<char> fillvalue_temp(fillvalue.size());
423  char *pEnd;
424  fillvalue_int = strtol((fillvalue.substr(1)).c_str(),&pEnd,8);
425  stringstream convert_str;
426  convert_str << fillvalue_int;
427  at->append_attr("_FillValue",var_type,convert_str.str());
428  }
429  else {
430 
431  // If somehow the fillvalue type is DFNT_CHAR or DFNT_UCHAR, and the size is 1,
432  // that means the fillvalue type is wrongly defined, we treat as a 8-bit integer number.
433  // Note, the code will only assume the value ranges from 0 to 128.(JIRA HFRHANDLER-248).
434  // KY 2014-04-24
435 
436  short fillvalue_int = fillvalue.at(0);
437 
438  stringstream convert_str;
439  convert_str << fillvalue_int;
440  if(fillvalue_int <0 || fillvalue_int >128)
441  throw InternalErr(__FILE__,__LINE__,
442  "If the fillvalue is a char type, the value must be between 0 and 128.");
443 
444 
445  at->append_attr("_FillValue",var_type,convert_str.str());
446  }
447  }
448 
449  else
450  at->append_attr("_FillValue",var_type,fillvalue);
451  }
452  }
453  it++;
454  }
455 
456 }
457 
458 // CF requires the scale_factor and add_offset attribute datatypes must be the same as the corresponding field datatype.
459 // For some NASA files, this is not true.
460 // So we need to check if the _FillValue's datatype is the same as the attribute's.
461 // If not, we need to correct them.
463 
464  AttrTable::Attr_iter it = at->attr_begin();
465  bool find_scale = false;
466  bool find_offset = false;
467 
468  // Declare scale_factor,add_offset, fillvalue and valid_range type in string format.
469  string scale_factor_type;
470  string add_offset_type;
471  string scale_factor_value;
472  string add_offset_value;
473 
474  while (it!=at->attr_end() &&((find_scale!=true) ||(find_offset!=true))) {
475  if (at->get_name(it) =="scale_factor")
476  {
477  find_scale = true;
478  scale_factor_value = (*at->get_attr_vector(it)->begin());
479  scale_factor_type = at->get_type(it);
480  }
481 
482  if(at->get_name(it)=="add_offset")
483  {
484  find_offset = true;
485  add_offset_value = (*at->get_attr_vector(it)->begin());
486  add_offset_type = at->get_type(it);
487  }
488 
489  it++;
490  }
491 
492  // Change offset type to the scale type
493  if((true==find_scale) && (true==find_offset)) {
494  if(scale_factor_type != add_offset_type) {
495  at->del_attr("add_offset");
496  at->append_attr("add_offset",scale_factor_type,add_offset_value);
497  }
498  }
499 }
500 
501 
502 #ifdef USE_HDFEOS2_LIB
503 
504 // For MODIS (confirmed by level 1B) products, values between 65500(MIN_NON_SCALE_SPECIAL_VALUE)
505 // and 65535(MAX_NON_SCALE_SPECIAL_VALUE) are treated as
506 // special values. These values represent non-physical data values caused by various failures.
507 // For example, 65533 represents "when Detector is saturated".
508 bool HDFCFUtil::is_special_value(int32 dtype, float fillvalue, float realvalue) {
509 
510  bool ret_value = false;
511 
512  if (DFNT_UINT16 == dtype) {
513 
514  int fillvalue_int = (int)fillvalue;
515  if (MAX_NON_SCALE_SPECIAL_VALUE == fillvalue_int) {
516  int realvalue_int = (int)realvalue;
517  if (realvalue_int <= MAX_NON_SCALE_SPECIAL_VALUE && realvalue_int >=MIN_NON_SCALE_SPECIAL_VALUE)
518  ret_value = true;
519  }
520  }
521 
522  return ret_value;
523 
524 }
525 
526 // Check if the MODIS file has dimension map and return the number of dimension maps
527 // Note: This routine is only applied to a MODIS geo-location file when the corresponding
528 // MODIS swath uses dimension maps and has the MODIS geo-location file under the same
529 // file directory. This is also restricted by turning on H4.EnableCheckMODISGeoFile to be true(file h4.conf.in).
530 // By default, this key is turned off. Also this function is only used once in one service. So it won't
531 // affect performance. KY 2014-02-18
532 int HDFCFUtil::check_geofile_dimmap(const string & geofilename) {
533 
534  int32 fileid = SWopen(const_cast<char*>(geofilename.c_str()),DFACC_READ);
535  if (fileid < 0)
536  return -1;
537  string swathname = "MODIS_Swath_Type_GEO";
538  int32 datasetid = SWattach(fileid,const_cast<char*>(swathname.c_str()));
539  if (datasetid < 0) {
540  SWclose(fileid);
541  return -1;
542  }
543 
544  int32 nummaps = 0;
545  int32 bufsize;
546 
547  // Obtain number of dimension maps and the buffer size.
548  if ((nummaps = SWnentries(datasetid, HDFE_NENTMAP, &bufsize)) == -1) {
549  SWdetach(datasetid);
550  SWclose(fileid);
551  return -1;
552  }
553 
554  SWdetach(datasetid);
555  SWclose(fileid);
556  return nummaps;
557 
558 }
559 
560 // Check if we need to change the datatype for MODIS fields. The datatype needs to be changed
561 // mainly because of non-CF scale and offset rules. To avoid violating CF conventions, we apply
562 // the non-CF MODIS scale and offset rule to MODIS data. So the final data type may be different
563 // than the original one due to this operation. For example, the original datatype may be int16.
564 // After applying the scale/offset rule, the datatype may become float32.
565 // The following are useful notes about MODIS SCALE OFFSET HANDLING
566 // Note: MODIS Scale and offset handling needs to re-organized. But it may take big efforts.
567 // Instead, I remove the global variable mtype, and _das; move the old calculate_dtype code
568 // back to HDFEOS2.cc. The code is a little better organized. If possible, we may think to overhaul
569 // the handling of MODIS scale-offset part. KY 2012-6-19
570 //
571 bool HDFCFUtil::change_data_type(DAS & das, SOType scaletype, const string &new_field_name)
572 {
573 
574  AttrTable *at = das.get_table(new_field_name);
575 
576  // The following codes do these:
577  // For MODIS level 1B(using the swath name), check radiance,reflectance etc.
578  // If the DISABLESCALE key is true, no need to check scale and offset for other types.
579  // Otherwise, continue checking the scale and offset names.
580  // KY 2013-12-13
581 
582  if(scaletype!=DEFAULT_CF_EQU && at!=NULL)
583  {
584  AttrTable::Attr_iter it = at->attr_begin();
585  string scale_factor_value="";
586  string add_offset_value="0";
587  string radiance_scales_value="";
588  string radiance_offsets_value="";
589  string reflectance_scales_value="";
590  string reflectance_offsets_value="";
591  string scale_factor_type, add_offset_type;
592  while (it!=at->attr_end())
593  {
594  if(at->get_name(it)=="radiance_scales")
595  radiance_scales_value = *(at->get_attr_vector(it)->begin());
596  if(at->get_name(it)=="radiance_offsets")
597  radiance_offsets_value = *(at->get_attr_vector(it)->begin());
598  if(at->get_name(it)=="reflectance_scales")
599  reflectance_scales_value = *(at->get_attr_vector(it)->begin());
600  if(at->get_name(it)=="reflectance_offsets")
601  reflectance_offsets_value = *(at->get_attr_vector(it)->begin());
602 
603  // Ideally may just check if the attribute name is scale_factor.
604  // But don't know if some products use attribut name like "scale_factor "
605  // So now just filter out the attribute scale_factor_err. KY 2012-09-20
606  if(at->get_name(it).find("scale_factor")!=string::npos){
607  string temp_attr_name = at->get_name(it);
608  if (temp_attr_name != "scale_factor_err") {
609  scale_factor_value = *(at->get_attr_vector(it)->begin());
610  scale_factor_type = at->get_type(it);
611  }
612  }
613  if(at->get_name(it).find("add_offset")!=string::npos)
614  {
615  string temp_attr_name = at->get_name(it);
616  if (temp_attr_name !="add_offset_err") {
617  add_offset_value = *(at->get_attr_vector(it)->begin());
618  add_offset_type = at->get_type(it);
619  }
620  }
621  it++;
622  }
623 
624  if((radiance_scales_value.length()!=0 && radiance_offsets_value.length()!=0)
625  || (reflectance_scales_value.length()!=0 && reflectance_offsets_value.length()!=0))
626  return true;
627 
628  if(scale_factor_value.length()!=0)
629  {
630  if(!(atof(scale_factor_value.c_str())==1 && atof(add_offset_value.c_str())==0))
631  return true;
632  }
633  }
634 
635  return false;
636 }
637 
638 // Obtain the MODIS swath dimension map info.
639 void HDFCFUtil::obtain_dimmap_info(const string& filename,HDFEOS2::Dataset*dataset,
640  vector<struct dimmap_entry> & dimmaps,
641  string & modis_geofilename, bool& geofile_has_dimmap) {
642 
643 
644  HDFEOS2::SwathDataset *sw = static_cast<HDFEOS2::SwathDataset *>(dataset);
645  const vector<HDFEOS2::SwathDataset::DimensionMap*>& origdimmaps = sw->getDimensionMaps();
646  vector<HDFEOS2::SwathDataset::DimensionMap*>::const_iterator it_dmap;
647  struct dimmap_entry tempdimmap;
648 
649  // if having dimension maps, we need to retrieve the dimension map info.
650  for(size_t i=0;i<origdimmaps.size();i++){
651  tempdimmap.geodim = origdimmaps[i]->getGeoDimension();
652  tempdimmap.datadim = origdimmaps[i]->getDataDimension();
653  tempdimmap.offset = origdimmaps[i]->getOffset();
654  tempdimmap.inc = origdimmaps[i]->getIncrement();
655  dimmaps.push_back(tempdimmap);
656  }
657 
658  string check_modis_geofile_key ="H4.EnableCheckMODISGeoFile";
659  bool check_geofile_key = false;
660  check_geofile_key = HDFCFUtil::check_beskeys(check_modis_geofile_key);
661 
662  // Only when there is dimension map, we need to consider the additional MODIS geolocation files.
663  // Will check if the check modis_geo_location file key is turned on.
664  if((origdimmaps.size() != 0) && (true == check_geofile_key) ) {
665 
666  // Has to use C-style since basename and dirname are not C++ routines.
667  char*tempcstr;
668  tempcstr = new char [filename.size()+1];
669  strncpy (tempcstr,filename.c_str(),filename.size());
670  string basefilename = basename(tempcstr);
671  string dirfilename = dirname(tempcstr);
672  delete [] tempcstr;
673 
674  // If the current file is a MOD03 or a MYD03 file, we don't need to check the extra MODIS geolocation file at all.
675  bool is_modis_geofile = false;
676  if(basefilename.size() >5) {
677  if((0 == basefilename.compare(0,5,"MOD03")) || (0 == basefilename.compare(0,5,"MYD03")))
678  is_modis_geofile = true;
679  }
680 
681  // This part is implemented specifically for supporting MODIS dimension map data.
682  // MODIS Aqua Swath dimension map geolocation file always starts with MYD03
683  // MODIS Terra Swath dimension map geolocation file always starts with MOD03
684  // We will check the first three characters to see if the dimension map geolocation file exists.
685  // An example MODIS swath filename is MOD05_L2.A2008120.0000.005.2008121182723.hdf
686  // An example MODIS geo-location file name is MOD03.A2008120.0000.005.2010003235220.hdf
687  // Notice that the "A2008120.0000" in the middle of the name is the "Acquistion Date" of the data
688  // So the geo-location file name should have exactly the same string. We will use this
689  // string to identify if a MODIS geo-location file exists or not.
690  // Note the string size is 14(.A2008120.0000).
691  // More information of naming convention, check http://modis-atmos.gsfc.nasa.gov/products_filename.html
692  // KY 2010-5-10
693 
694 
695  // Obtain string "MYD" or "MOD"
696  // Here we need to consider when MOD03 or MYD03 use the dimension map.
697  if ((false == is_modis_geofile) && (basefilename.size() >3)) {
698 
699  string fnameprefix = basefilename.substr(0,3);
700 
701  if(fnameprefix == "MYD" || fnameprefix =="MOD") {
702  size_t fnamemidpos = basefilename.find(".A");
703  if(fnamemidpos != string::npos) {
704  string fnamemiddle = basefilename.substr(fnamemidpos,14);
705  if(fnamemiddle.size()==14) {
706  string geofnameprefix = fnameprefix+"03";
707  // geofnamefp will be something like "MOD03.A2008120.0000"
708  string geofnamefp = geofnameprefix + fnamemiddle;
709  DIR *dirp;
710  struct dirent* dirs;
711 
712  // Go through the directory to see if we have the corresponding MODIS geolocation file
713  dirp = opendir(dirfilename.c_str());
714  if (NULL == dirp)
715  throw InternalErr(__FILE__,__LINE__,"opendir fails.");
716 
717  while ((dirs = readdir(dirp))!= NULL){
718  if(strncmp(dirs->d_name,geofnamefp.c_str(),geofnamefp.size())==0){
719  modis_geofilename = dirfilename + "/"+ dirs->d_name;
720  int num_dimmap = HDFCFUtil::check_geofile_dimmap(modis_geofilename);
721  if (num_dimmap < 0) {
722  closedir(dirp);
723  throw InternalErr(__FILE__,__LINE__,"this file is not a MODIS geolocation file.");
724  }
725  geofile_has_dimmap = (num_dimmap >0)?true:false;
726  break;
727  }
728  }
729  closedir(dirp);
730  }
731  }
732  }
733  }
734  }
735 }
736 
737 // This is for the case that the separate MODIS geo-location file is used.
738 // Some geolocation names at the MODIS data file are not consistent with
739 // the names in the MODIS geo-location file. So need to correct them.
740 bool HDFCFUtil::is_modis_dimmap_nonll_field(string & fieldname) {
741 
742  bool modis_dimmap_nonll_field = false;
743  vector<string> modis_dimmap_nonll_fieldlist;
744 
745  modis_dimmap_nonll_fieldlist.push_back("Height");
746  modis_dimmap_nonll_fieldlist.push_back("SensorZenith");
747  modis_dimmap_nonll_fieldlist.push_back("SensorAzimuth");
748  modis_dimmap_nonll_fieldlist.push_back("Range");
749  modis_dimmap_nonll_fieldlist.push_back("SolarZenith");
750  modis_dimmap_nonll_fieldlist.push_back("SolarAzimuth");
751  modis_dimmap_nonll_fieldlist.push_back("Land/SeaMask");
752  modis_dimmap_nonll_fieldlist.push_back("gflags");
753  modis_dimmap_nonll_fieldlist.push_back("Solar_Zenith");
754  modis_dimmap_nonll_fieldlist.push_back("Solar_Azimuth");
755  modis_dimmap_nonll_fieldlist.push_back("Sensor_Azimuth");
756  modis_dimmap_nonll_fieldlist.push_back("Sensor_Zenith");
757 
758  map<string,string>modis_field_to_geofile_field;
759  map<string,string>::iterator itmap;
760  modis_field_to_geofile_field["Solar_Zenith"] = "SolarZenith";
761  modis_field_to_geofile_field["Solar_Azimuth"] = "SolarAzimuth";
762  modis_field_to_geofile_field["Sensor_Zenith"] = "SensorZenith";
763  modis_field_to_geofile_field["Solar_Azimuth"] = "SolarAzimuth";
764 
765  for (unsigned int i = 0; i <modis_dimmap_nonll_fieldlist.size(); i++) {
766 
767  if (fieldname == modis_dimmap_nonll_fieldlist[i]) {
768  itmap = modis_field_to_geofile_field.find(fieldname);
769  if (itmap !=modis_field_to_geofile_field.end())
770  fieldname = itmap->second;
771  modis_dimmap_nonll_field = true;
772  break;
773  }
774  }
775 
776  return modis_dimmap_nonll_field;
777 }
778 
780 void HDFCFUtil::handle_modis_special_attrs_disable_scale_comp(AttrTable *at,
781  const string &filename,
782  bool is_grid,
783  const string & newfname,
784  SOType sotype){
785 
786  // Declare scale_factor,add_offset, fillvalue and valid_range type in string format.
787  string scale_factor_type;
788  string add_offset_type;
789 
790  // Scale and offset values
791  string scale_factor_value="";
792  float orig_scale_value = 1;
793  string add_offset_value="0";
794  float orig_offset_value = 0;
795  bool add_offset_found = false;
796 
797 
798  // Go through all attributes to find scale_factor,add_offset,_FillValue,valid_range
799  // Number_Type information
800  AttrTable::Attr_iter it = at->attr_begin();
801  while (it!=at->attr_end())
802  {
803  if(at->get_name(it)=="scale_factor")
804  {
805  scale_factor_value = (*at->get_attr_vector(it)->begin());
806  orig_scale_value = atof(scale_factor_value.c_str());
807  scale_factor_type = at->get_type(it);
808  }
809 
810  if(at->get_name(it)=="add_offset")
811  {
812  add_offset_value = (*at->get_attr_vector(it)->begin());
813  orig_offset_value = atof(add_offset_value.c_str());
814  add_offset_type = at->get_type(it);
815  add_offset_found = true;
816  }
817 
818  it++;
819  }
820 
821  // According to our observations, it seems that MODIS products ALWAYS use the "scale" factor to
822  // make bigger values smaller.
823  // So for MODIS_MUL_SCALE products, if the scale of some variable is greater than 1,
824  // it means that for this variable, the MODIS type for this variable may be MODIS_DIV_SCALE.
825  // For the similar logic, we may need to change MODIS_DIV_SCALE to MODIS_MUL_SCALE and MODIS_EQ_SCALE
826  // to MODIS_DIV_SCALE.
827  // We indeed find such a case. HDF-EOS2 Grid MODIS_Grid_1km_2D of MOD(or MYD)09GA is a MODIS_EQ_SCALE.
828  // However,
829  // the scale_factor of the variable Range_1 in the MOD09GA product is 25. According to our observation,
830  // this variable should be MODIS_DIV_SCALE.We verify this is true according to MODIS 09 product document
831  // http://modis-sr.ltdri.org/products/MOD09_UserGuide_v1_3.pdf.
832  // Since this conclusion is based on our observation, we would like to add a BESlog to detect if we find
833  // the similar cases so that we can verify with the corresponding product documents to see if this is true.
834  // More information,
835  // We just verified with the data producer, the scale_factor for Range_1 and Range_c is 25 but the
836  // equation is still multiplication instead of division. So we have to make this as a special case that
837  // we don't want to change the scale and offset settings.
838  // KY 2014-01-13
839 
840 
841  if(scale_factor_value.length()!=0) {
842  if (MODIS_EQ_SCALE == sotype || MODIS_MUL_SCALE == sotype) {
843  if (orig_scale_value > 1) {
844 
845  bool need_change_scale = true;
846  if(true == is_grid) {
847  if ((filename.size() >5) && ((filename.compare(0,5,"MOD09") == 0)|| (filename.compare(0,5,"MYD09")==0))) {
848  if ((newfname.size() >5) && newfname.find("Range") != string::npos)
849  need_change_scale = false;
850  }
851  }
852  if(true == need_change_scale) {
853  sotype = MODIS_DIV_SCALE;
854  (*BESLog::TheLog())<< "The field " << newfname << " scale factor is "<< scale_factor_value << endl
855  << " But the original scale factor type is MODIS_MUL_SCALE or MODIS_EQ_SCALE. " << endl
856  << " Now change it to MODIS_DIV_SCALE. "<<endl;
857  }
858  }
859  }
860 
861  if (MODIS_DIV_SCALE == sotype) {
862  if (orig_scale_value < 1) {
863  sotype = MODIS_MUL_SCALE;
864  (*BESLog::TheLog())<< "The field " << newfname << " scale factor is "<< scale_factor_value << endl
865  << " But the original scale factor type is MODIS_DIV_SCALE. " << endl
866  << " Now change it to MODIS_MUL_SCALE. "<<endl;
867  }
868  }
869 
870 
871  if ((MODIS_MUL_SCALE == sotype) &&(true == add_offset_found)) {
872 
873  //string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&orig_scale_value));
874  at->del_attr("scale_factor");
875  //at->append_attr("scale_factor", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
876  // Since scale_factor should always be smaller than 1, so this is fine. We just need to
877  // change the type.
878  at->append_attr("scale_factor", HDFCFUtil::print_type(DFNT_FLOAT32), scale_factor_value);
879 
880  if (true == add_offset_found) {
881  float new_offset_value = (orig_offset_value ==0)?0:(-1 * orig_offset_value *orig_scale_value);
882  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&new_offset_value));
883  at->del_attr("add_offset");
884  at->append_attr("add_offset", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
885  }
886  }
887 
888  if ((MODIS_DIV_SCALE == sotype)) {
889 
890  float new_scale_value = 1.0/orig_scale_value;
891  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&new_scale_value));
892  at->del_attr("scale_factor");
893  //at->append_attr("scale_factor", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
894  // Since scale_factor should always be smaller than 1, so this is fine. We just need to
895  // change the type.
896  at->append_attr("scale_factor", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
897 
898  if (true == add_offset_found) {
899  float new_offset_value = (orig_offset_value==0)?0:(-1 * orig_offset_value *new_scale_value);
900  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&new_offset_value));
901  at->del_attr("add_offset");
902  at->append_attr("add_offset", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
903  }
904 
905  }
906  }
907 
908 }
909 
910 // These routines will handle scale_factor,add_offset,valid_min,valid_max and other attributes
911 // such as Number_Type to make sure the CF is followed.
912 // For example, For the case that the scale and offset rule doesn't follow CF, the scale_factor and add_offset attributes are renamed
913 // to orig_scale_factor and orig_add_offset to keep the original field info.
914 // Note: This routine should only be called when MODIS Scale and offset rules don't follow CF.
915 // Input parameters:
916 // AttrTable at - DAS attribute table
917 // string newfname - field name: this is used to identify special MODIS level 1B emissive and refSB fields
918 // SOType sotype - MODIS scale and offset type
919 // bool gridname_change_valid_range - Flag to check if this is the special MODIS VIP product
920 // bool changedtype - Flag to check if the datatype of this field needs to be changed
921 // bool change_fvtype - Flag to check if the attribute _FillValue needs to change to data type
922 
924 // Divide this function into smaller functions:
925 //
926 void HDFCFUtil::handle_modis_special_attrs(AttrTable *at, const string & filename,
927  bool is_grid,const string & newfname,
928  SOType sotype, bool gridname_change_valid_range,
929  bool changedtype, bool & change_fvtype){
930 
931  // Declare scale_factor,add_offset, fillvalue and valid_range type in string format.
932  string scale_factor_type;
933  string add_offset_type;
934  string fillvalue_type;
935  string valid_range_type;
936 
937 
938  // Scale and offset values
939  string scale_factor_value="";
940  float orig_scale_value = 1;
941  string add_offset_value="0";
942  float orig_offset_value = 0;
943  bool add_offset_found = false;
944 
945  // Fillvalue
946  string fillvalue="";
947 
948  // Valid range value
949  string valid_range_value="";
950 
951  bool has_valid_range = false;
952 
953  // We may need to change valid_range to valid_min and valid_max. Initialize them here.
954  float orig_valid_min = 0;
955  float orig_valid_max = 0;
956 
957  // Number_Type also needs to be adjusted when datatype is changed
958  string number_type_value="";
959  string number_type_dap_type="";
960 
961  // Go through all attributes to find scale_factor,add_offset,_FillValue,valid_range
962  // Number_Type information
963  AttrTable::Attr_iter it = at->attr_begin();
964  while (it!=at->attr_end())
965  {
966  if(at->get_name(it)=="scale_factor")
967  {
968  scale_factor_value = (*at->get_attr_vector(it)->begin());
969  orig_scale_value = atof(scale_factor_value.c_str());
970  scale_factor_type = at->get_type(it);
971  }
972 
973  if(at->get_name(it)=="add_offset")
974  {
975  add_offset_value = (*at->get_attr_vector(it)->begin());
976  orig_offset_value = atof(add_offset_value.c_str());
977  add_offset_type = at->get_type(it);
978  add_offset_found = true;
979  }
980 
981  if(at->get_name(it)=="_FillValue")
982  {
983  fillvalue = (*at->get_attr_vector(it)->begin());
984  fillvalue_type = at->get_type(it);
985  }
986 
987  if(at->get_name(it)=="valid_range")
988  {
989  vector<string> *avalue = at->get_attr_vector(it);
990  vector<string>::iterator ait = avalue->begin();
991  while(ait!=avalue->end())
992  {
993  valid_range_value += *ait;
994  ait++;
995  if(ait!=avalue->end())
996  valid_range_value += ", ";
997  }
998  valid_range_type = at->get_type(it);
999  if (false == gridname_change_valid_range) {
1000  orig_valid_min = (float)(atof((avalue->at(0)).c_str()));
1001  orig_valid_max = (float)(atof((avalue->at(1)).c_str()));
1002  }
1003  has_valid_range = true;
1004  }
1005 
1006  if(true == changedtype && (at->get_name(it)=="Number_Type"))
1007  {
1008  number_type_value = (*at->get_attr_vector(it)->begin());
1009  number_type_dap_type= at->get_type(it);
1010  }
1011 
1012  it++;
1013  }
1014 
1015  // Rename scale_factor and add_offset attribute names. Otherwise, they will be
1016  // misused by CF tools to generate wrong data values based on the CF scale and offset rule.
1017  if(scale_factor_value.length()!=0)
1018  {
1019  if(!(atof(scale_factor_value.c_str())==1 && atof(add_offset_value.c_str())==0)) //Rename them.
1020  {
1021  at->del_attr("scale_factor");
1022  at->append_attr("orig_scale_factor", scale_factor_type, scale_factor_value);
1023  if(add_offset_found)
1024  {
1025  at->del_attr("add_offset");
1026  at->append_attr("orig_add_offset", add_offset_type, add_offset_value);
1027  }
1028  }
1029  }
1030 
1031  // Change _FillValue datatype
1032  if(true == changedtype && fillvalue.length()!=0 && fillvalue_type!="Float32" && fillvalue_type!="Float64")
1033  {
1034  change_fvtype = true;
1035  at->del_attr("_FillValue");
1036  at->append_attr("_FillValue", "Float32", fillvalue);
1037  }
1038 
1039  float valid_max = 0;
1040  float valid_min = 0;
1041 
1042  it = at->attr_begin();
1043  bool handle_modis_l1b = false;
1044 
1045  // MODIS level 1B's Emissive and RefSB fields' scale_factor and add_offset
1046  // get changed according to different vertical levels.
1047  // So we need to handle them specifically.
1048  if (sotype == MODIS_MUL_SCALE && true ==changedtype) {
1049 
1050  // Emissive should be at the end of the field name such as "..._Emissive"
1051  string emissive_str = "Emissive";
1052  string RefSB_str = "RefSB";
1053  bool is_emissive_field = false;
1054  bool is_refsb_field = false;
1055  if(newfname.find(emissive_str)!=string::npos) {
1056  if(0 == newfname.compare(newfname.size()-emissive_str.size(),emissive_str.size(),emissive_str))
1057  is_emissive_field = true;
1058  }
1059 
1060  if(newfname.find(RefSB_str)!=string::npos) {
1061  if(0 == newfname.compare(newfname.size()-RefSB_str.size(),RefSB_str.size(),RefSB_str))
1062  is_refsb_field = true;
1063  }
1064 
1065  // We will calculate the maximum and minimum scales and offsets within all the vertical levels.
1066  if ((true == is_emissive_field) || (true== is_refsb_field)){
1067 
1068  float scale_max = 0;
1069  float scale_min = 100000;
1070 
1071  float offset_max = 0;
1072  float offset_min = 0;
1073 
1074  float temp_var_val = 0;
1075 
1076  string orig_long_name_value;
1077  string modify_long_name_value;
1078  string str_removed_from_long_name=" Scaled Integers";
1079  string radiance_units_value;
1080 
1081  while (it!=at->attr_end())
1082  {
1083  // Radiance field(Emissive field)
1084  if(true == is_emissive_field) {
1085 
1086  if ("radiance_scales" == (at->get_name(it))) {
1087  vector<string> *avalue = at->get_attr_vector(it);
1088  for (vector<string>::const_iterator ait = avalue->begin();ait !=avalue->end();++ait) {
1089  temp_var_val = (float)(atof((*ait).c_str()));
1090  if (temp_var_val > scale_max)
1091  scale_max = temp_var_val;
1092  if (temp_var_val < scale_min)
1093  scale_min = temp_var_val;
1094  }
1095  }
1096 
1097  if ("radiance_offsets" == (at->get_name(it))) {
1098  vector<string> *avalue = at->get_attr_vector(it);
1099  for (vector<string>::const_iterator ait = avalue->begin();ait !=avalue->end();++ait) {
1100  temp_var_val = (float)(atof((*ait).c_str()));
1101  if (temp_var_val > offset_max)
1102  offset_max = temp_var_val;
1103  if (temp_var_val < scale_min)
1104  offset_min = temp_var_val;
1105  }
1106  }
1107 
1108  if ("long_name" == (at->get_name(it))) {
1109  orig_long_name_value = (*at->get_attr_vector(it)->begin());
1110  if (orig_long_name_value.find(str_removed_from_long_name)!=string::npos) {
1111  if(0 == orig_long_name_value.compare(orig_long_name_value.size()-str_removed_from_long_name.size(),
1112  str_removed_from_long_name.size(),str_removed_from_long_name)) {
1113 
1114  modify_long_name_value =
1115  orig_long_name_value.substr(0,orig_long_name_value.size()-str_removed_from_long_name.size());
1116  at->del_attr("long_name");
1117  at->append_attr("long_name","String",modify_long_name_value);
1118  at->append_attr("orig_long_name","String",orig_long_name_value);
1119  }
1120  }
1121  }
1122 
1123  if ("radiance_units" == (at->get_name(it)))
1124  radiance_units_value = (*at->get_attr_vector(it)->begin());
1125  }
1126 
1127  if (true == is_refsb_field) {
1128  if ("reflectance_scales" == (at->get_name(it))) {
1129  vector<string> *avalue = at->get_attr_vector(it);
1130  for (vector<string>::const_iterator ait = avalue->begin();ait !=avalue->end();++ait) {
1131  temp_var_val = (float)(atof((*ait).c_str()));
1132  if (temp_var_val > scale_max)
1133  scale_max = temp_var_val;
1134  if (temp_var_val < scale_min)
1135  scale_min = temp_var_val;
1136  }
1137  }
1138 
1139  if ("reflectance_offsets" == (at->get_name(it))) {
1140 
1141  vector<string> *avalue = at->get_attr_vector(it);
1142  for (vector<string>::const_iterator ait = avalue->begin();ait !=avalue->end();++ait) {
1143  temp_var_val = (float)(atof((*ait).c_str()));
1144  if (temp_var_val > offset_max)
1145  offset_max = temp_var_val;
1146  if (temp_var_val < scale_min)
1147  offset_min = temp_var_val;
1148  }
1149  }
1150 
1151  if ("long_name" == (at->get_name(it))) {
1152  orig_long_name_value = (*at->get_attr_vector(it)->begin());
1153  if (orig_long_name_value.find(str_removed_from_long_name)!=string::npos) {
1154  if(0 == orig_long_name_value.compare(orig_long_name_value.size()-str_removed_from_long_name.size(),
1155  str_removed_from_long_name.size(),str_removed_from_long_name)) {
1156 
1157  modify_long_name_value =
1158  orig_long_name_value.substr(0,orig_long_name_value.size()-str_removed_from_long_name.size());
1159  at->del_attr("long_name");
1160  at->append_attr("long_name","String",modify_long_name_value);
1161  at->append_attr("orig_long_name","String",orig_long_name_value);
1162  }
1163  }
1164  }
1165  }
1166  it++;
1167  }
1168 
1169  // Calculate the final valid_max and valid_min.
1170  if (scale_min <= 0)
1171  throw InternalErr(__FILE__,__LINE__,"the scale factor should always be greater than 0.");
1172 
1173  if (orig_valid_max > offset_min)
1174  valid_max = (orig_valid_max-offset_min)*scale_max;
1175  else
1176  valid_max = (orig_valid_max-offset_min)*scale_min;
1177 
1178  if (orig_valid_min > offset_max)
1179  valid_min = (orig_valid_min-offset_max)*scale_min;
1180  else
1181  valid_min = (orig_valid_min -offset_max)*scale_max;
1182 
1183  // These physical variables should be greater than 0
1184  if (valid_min < 0)
1185  valid_min = 0;
1186 
1187  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&valid_min));
1188  at->append_attr("valid_min","Float32",print_rep);
1189  print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&valid_max));
1190  at->append_attr("valid_max","Float32",print_rep);
1191  at->del_attr("valid_range");
1192  handle_modis_l1b = true;
1193 
1194  // Change the units for the emissive field
1195  if (true == is_emissive_field && radiance_units_value.size() >0) {
1196  at->del_attr("units");
1197  at->append_attr("units","String",radiance_units_value);
1198  }
1199  }
1200  }
1201 
1202  // Handle other valid_range attributes
1203  if(true == changedtype && true == has_valid_range && false == handle_modis_l1b) {
1204 
1205  // If the gridname_change_valid_range is true, call a special function to handle this.
1206  if (true == gridname_change_valid_range)
1207  HDFCFUtil::handle_modis_vip_special_attrs(valid_range_value,scale_factor_value,valid_min,valid_max);
1208  else if(scale_factor_value.length()!=0) {
1209 
1210  // We found MODIS products always scale to a smaller value. If somehow the original scale factor
1211  // is smaller than 1, the scale/offset should be the multiplication rule.(new_data =scale*(old_data-offset))
1212  // If the original scale factor is greater than 1, the scale/offset rule should be division rule.
1213  // New_data = (old_data-offset)/scale.
1214  // We indeed find such a case. HDF-EOS2 Grid MODIS_Grid_1km_2D of MOD(or MYD)09GA is a MODIS_EQ_SCALE.
1215  // However,
1216  // the scale_factor of the variable Range_1 in the MOD09GA product is 25. According to our observation,
1217  // this variable should be MODIS_DIV_SCALE.We verify this is true according to MODIS 09 product document
1218  // http://modis-sr.ltdri.org/products/MOD09_UserGuide_v1_3.pdf.
1219  // Since this conclusion is based on our observation, we would like to add a BESlog to detect if we find
1220  // the similar cases so that we can verify with the corresponding product documents to see if this is true.
1221  // More information,
1222  // We just verified with the data producer, the scale_factor for Range_1 and Range_c is 25 but the
1223  // equation is still multiplication instead of division. So we have to make this as a special case that
1224  // we don't want to change the scale and offset settings.
1225  // KY 2014-01-13
1226 
1227  if (MODIS_EQ_SCALE == sotype || MODIS_MUL_SCALE == sotype) {
1228  if (orig_scale_value > 1) {
1229 
1230  bool need_change_scale = true;
1231  if(true == is_grid) {
1232  if ((filename.size() >5) && ((filename.compare(0,5,"MOD09") == 0)|| (filename.compare(0,5,"MYD09")==0))) {
1233  if ((newfname.size() >5) && newfname.find("Range") != string::npos)
1234  need_change_scale = false;
1235  }
1236  }
1237  if(true == need_change_scale) {
1238  sotype = MODIS_DIV_SCALE;
1239  (*BESLog::TheLog())<< "The field " << newfname << " scale factor is "<< orig_scale_value << endl
1240  << " But the original scale factor type is MODIS_MUL_SCALE or MODIS_EQ_SCALE. " << endl
1241  << " Now change it to MODIS_DIV_SCALE. "<<endl;
1242  }
1243  }
1244  }
1245 
1246  if (MODIS_DIV_SCALE == sotype) {
1247  if (orig_scale_value < 1) {
1248  sotype = MODIS_MUL_SCALE;
1249  (*BESLog::TheLog())<< "The field " << newfname << " scale factor is "<< orig_scale_value << endl
1250  << " But the original scale factor type is MODIS_DIV_SCALE. " << endl
1251  << " Now change it to MODIS_MUL_SCALE. "<<endl;
1252  }
1253  }
1254 
1255  if(sotype == MODIS_MUL_SCALE) {
1256  valid_min = (orig_valid_min - orig_offset_value)*orig_scale_value;
1257  valid_max = (orig_valid_max - orig_offset_value)*orig_scale_value;
1258  }
1259  else if (sotype == MODIS_DIV_SCALE) {
1260  valid_min = (orig_valid_min - orig_offset_value)/orig_scale_value;
1261  valid_max = (orig_valid_max - orig_offset_value)/orig_scale_value;
1262  }
1263  else if (sotype == MODIS_EQ_SCALE) {
1264  valid_min = orig_valid_min * orig_scale_value + orig_offset_value;
1265  valid_max = orig_valid_max * orig_scale_value + orig_offset_value;
1266  }
1267  }
1268  else {// This is our current assumption.
1269  if (MODIS_MUL_SCALE == sotype || MODIS_DIV_SCALE == sotype) {
1270  valid_min = orig_valid_min - orig_offset_value;
1271  valid_max = orig_valid_max - orig_offset_value;
1272  }
1273  else if (MODIS_EQ_SCALE == sotype) {
1274  valid_min = orig_valid_min + orig_offset_value;
1275  valid_max = orig_valid_max + orig_offset_value;
1276  }
1277  }
1278 
1279  // Append the corrected valid_min and valid_max. (valid_min,valid_max) is equivalent to valid_range.
1280  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&valid_min));
1281  at->append_attr("valid_min","Float32",print_rep);
1282  print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&valid_max));
1283  at->append_attr("valid_max","Float32",print_rep);
1284  at->del_attr("valid_range");
1285  }
1286 
1287  // We also find that there is an attribute called "Number_Type" that will stores the original attribute
1288  // datatype. If the datatype gets changed, the attribute is confusion. here we can change the attribute
1289  // name to "Number_Type_Orig"
1290  if(true == changedtype && number_type_dap_type !="" ) {
1291  at->del_attr("Number_Type");
1292  at->append_attr("Number_Type_Orig",number_type_dap_type,number_type_value);
1293  }
1294 }
1295 
1296  // This routine makes the MeaSUREs VIP attributes follow CF.
1297 // valid_range attribute uses char type instead of the raw data's datatype.
1298 void HDFCFUtil::handle_modis_vip_special_attrs(const std::string& valid_range_value,
1299  const std::string& scale_factor_value,
1300  float& valid_min, float &valid_max) {
1301 
1302  int16 vip_orig_valid_min = 0;
1303  int16 vip_orig_valid_max = 0;
1304 
1305  size_t found = valid_range_value.find_first_of(",");
1306  size_t found_from_end = valid_range_value.find_last_of(",");
1307  if (string::npos == found)
1308  throw InternalErr(__FILE__,__LINE__,"should find the separator ,");
1309  if (found != found_from_end)
1310  throw InternalErr(__FILE__,__LINE__,"There should be only one separator.");
1311 
1312  //istringstream(valid_range_value.substr(0,found))>>orig_valid_min;
1313  //istringstream(valid_range_value.substr(found+1))>>orig_valid_max;
1314 
1315  vip_orig_valid_min = atoi((valid_range_value.substr(0,found)).c_str());
1316  vip_orig_valid_max = atoi((valid_range_value.substr(found+1)).c_str());
1317 
1318  int16 scale_factor_number = 1;
1319 
1320  //istringstream(scale_factor_value)>>scale_factor_number;
1321  scale_factor_number = atoi(scale_factor_value.c_str());
1322 
1323  valid_min = (float)(vip_orig_valid_min/scale_factor_number);
1324  valid_max = (float)(vip_orig_valid_max/scale_factor_number);
1325 }
1326 
1327 // Make AMSR-E attributes follow CF.
1328 // Change SCALE_FACTOR and OFFSET to CF names: scale_factor and add_offset.
1329 void HDFCFUtil::handle_amsr_attrs(AttrTable *at) {
1330 
1331  AttrTable::Attr_iter it = at->attr_begin();
1332  string scale_factor_value="", add_offset_value="0";
1333  string scale_factor_type, add_offset_type;
1334  bool OFFSET_found = false;
1335  bool Scale_found = false;
1336  bool SCALE_FACTOR_found = false;
1337 
1338  while (it!=at->attr_end())
1339  {
1340  if(at->get_name(it)=="SCALE_FACTOR")
1341  {
1342  scale_factor_value = (*at->get_attr_vector(it)->begin());
1343  scale_factor_type = at->get_type(it);
1344  SCALE_FACTOR_found = true;
1345  }
1346 
1347  if(at->get_name(it)=="Scale")
1348  {
1349  scale_factor_value = (*at->get_attr_vector(it)->begin());
1350  scale_factor_type = at->get_type(it);
1351  Scale_found = true;
1352  }
1353 
1354  if(at->get_name(it)=="OFFSET")
1355  {
1356  add_offset_value = (*at->get_attr_vector(it)->begin());
1357  add_offset_type = at->get_type(it);
1358  OFFSET_found = true;
1359  }
1360  it++;
1361  }
1362 
1363  if (true == SCALE_FACTOR_found) {
1364  at->del_attr("SCALE_FACTOR");
1365  at->append_attr("scale_factor",scale_factor_type,scale_factor_value);
1366  }
1367 
1368  if (true == Scale_found) {
1369  at->del_attr("Scale");
1370  at->append_attr("scale_factor",scale_factor_type,scale_factor_value);
1371  }
1372 
1373  if (true == OFFSET_found) {
1374  at->del_attr("OFFSET");
1375  at->append_attr("add_offset",add_offset_type,add_offset_value);
1376  }
1377 
1378 }
1379 
1380 #endif
1381 
1382  // Check OBPG attributes. Specifically, check if slope and intercept can be obtained from the file level.
1383  // If having global slope and intercept, obtain OBPG scaling, slope and intercept values.
1384 void HDFCFUtil::check_obpg_global_attrs(HDFSP::File *f, std::string & scaling,
1385  float & slope,bool &global_slope_flag,
1386  float & intercept, bool & global_intercept_flag){
1387 
1388  HDFSP::SD* spsd = f->getSD();
1389 
1390  for(vector<HDFSP::Attribute *>::const_iterator i=spsd->getAttributes().begin();i!=spsd->getAttributes().end();i++) {
1391 
1392  //We want to add two new attributes, "scale_factor" and "add_offset" to data fields if the scaling equation is linear.
1393  // OBPG products use "Slope" instead of "scale_factor", "intercept" instead of "add_offset". "Scaling" describes if the equation is linear.
1394  // Their values will be copied directly from File attributes. This addition is for OBPG L3 only.
1395  // We also add OBPG L2 support since all OBPG level 2 products(CZCS,MODISA,MODIST,OCTS,SeaWiFS) we evaluate use Slope,intercept and linear equation
1396  // for the final data. KY 2012-09-06
1397  if(f->getSPType()==OBPGL3 || f->getSPType() == OBPGL2)
1398  {
1399  if((*i)->getName()=="Scaling")
1400  {
1401  string tmpstring((*i)->getValue().begin(), (*i)->getValue().end());
1402  scaling = tmpstring;
1403  }
1404  if((*i)->getName()=="Slope" || (*i)->getName()=="slope")
1405  {
1406  global_slope_flag = true;
1407 
1408  switch((*i)->getType())
1409  {
1410 #define GET_SLOPE(TYPE, CAST) \
1411  case DFNT_##TYPE: \
1412  { \
1413  CAST tmpvalue = *(CAST*)&((*i)->getValue()[0]); \
1414  slope = (float)tmpvalue; \
1415  } \
1416  break;
1417  GET_SLOPE(INT16, int16);
1418  GET_SLOPE(INT32, int32);
1419  GET_SLOPE(FLOAT32, float);
1420  GET_SLOPE(FLOAT64, double);
1421 #undef GET_SLOPE
1422  } ;
1423  //slope = *(float*)&((*i)->getValue()[0]);
1424  }
1425  if((*i)->getName()=="Intercept" || (*i)->getName()=="intercept")
1426  {
1427  global_intercept_flag = true;
1428  switch((*i)->getType())
1429  {
1430 #define GET_INTERCEPT(TYPE, CAST) \
1431  case DFNT_##TYPE: \
1432  { \
1433  CAST tmpvalue = *(CAST*)&((*i)->getValue()[0]); \
1434  intercept = (float)tmpvalue; \
1435  } \
1436  break;
1437  GET_INTERCEPT(INT16, int16);
1438  GET_INTERCEPT(INT32, int32);
1439  GET_INTERCEPT(FLOAT32, float);
1440  GET_INTERCEPT(FLOAT64, double);
1441 #undef GET_INTERCEPT
1442  } ;
1443  //intercept = *(float*)&((*i)->getValue()[0]);
1444  }
1445  }
1446  }
1447 }
1448 
1449 // For some OBPG files that only provide slope and intercept at the file level,
1450 // global slope and intercept are needed to add to all fields and their names are needed to be changed to scale_factor and add_offset.
1451 // For OBPG files that provide slope and intercept at the field level, slope and intercept are needed to rename to scale_factor and add_offset.
1453  HDFSP::SDField *onespsds,
1454  string& scaling, float& slope,
1455  bool& global_slope_flag,
1456  float& intercept,
1457  bool & global_intercept_flag) {
1458 
1459  AttrTable *at = das.get_table(onespsds->getNewName());
1460  if (!at)
1461  at = das.add_table(onespsds->getNewName(), new AttrTable);
1462 
1463  //For OBPG L2 and L3 only.Some OBPG products put "slope" and "Intercept" etc. in the field attributes
1464  // We still need to handle the scale and offset here.
1465  bool scale_factor_flag = false;
1466  bool add_offset_flag = false;
1467  bool slope_flag = false;
1468  bool intercept_flag = false;
1469 
1470  if(f->getSPType()==OBPGL3 || f->getSPType() == OBPGL2) {// Begin OPBG CF attribute handling(Checking "slope" and "intercept")
1471  for(vector<HDFSP::Attribute *>::const_iterator i=onespsds->getAttributes().begin();
1472  i!=onespsds->getAttributes().end();i++) {
1473  if(global_slope_flag != true && ((*i)->getName()=="Slope" || (*i)->getName()=="slope"))
1474  {
1475  slope_flag = true;
1476 
1477  switch((*i)->getType())
1478  {
1479 #define GET_SLOPE(TYPE, CAST) \
1480  case DFNT_##TYPE: \
1481  { \
1482  CAST tmpvalue = *(CAST*)&((*i)->getValue()[0]); \
1483  slope = (float)tmpvalue; \
1484  } \
1485  break;
1486 
1487  GET_SLOPE(INT16, int16);
1488  GET_SLOPE(INT32, int32);
1489  GET_SLOPE(FLOAT32, float);
1490  GET_SLOPE(FLOAT64, double);
1491 #undef GET_SLOPE
1492  } ;
1493  //slope = *(float*)&((*i)->getValue()[0]);
1494  }
1495  if(global_intercept_flag != true && ((*i)->getName()=="Intercept" || (*i)->getName()=="intercept"))
1496  {
1497  intercept_flag = true;
1498  switch((*i)->getType())
1499  {
1500 #define GET_INTERCEPT(TYPE, CAST) \
1501  case DFNT_##TYPE: \
1502  { \
1503  CAST tmpvalue = *(CAST*)&((*i)->getValue()[0]); \
1504  intercept = (float)tmpvalue; \
1505  } \
1506  break;
1507  GET_INTERCEPT(INT16, int16);
1508  GET_INTERCEPT(INT32, int32);
1509  GET_INTERCEPT(FLOAT32, float);
1510  GET_INTERCEPT(FLOAT64, double);
1511 #undef GET_INTERCEPT
1512  } ;
1513  //intercept = *(float*)&((*i)->getValue()[0]);
1514  }
1515  }
1516  } // End of checking "slope" and "intercept"
1517 
1518  // Checking if OBPG has "scale_factor" ,"add_offset", generally checking for "long_name" attributes.
1519  for(vector<HDFSP::Attribute *>::const_iterator i=onespsds->getAttributes().begin();i!=onespsds->getAttributes().end();i++) {
1520 
1521  if((f->getSPType()==OBPGL3 || f->getSPType() == OBPGL2) && (*i)->getName()=="scale_factor")
1522  scale_factor_flag = true;
1523 
1524  if((f->getSPType()==OBPGL3 || f->getSPType() == OBPGL2) && (*i)->getName()=="add_offset")
1525  add_offset_flag = true;
1526  }
1527 
1528  // Checking if the scale and offset equation is linear, this is only for OBPG level 3.
1529  // Also checking if having the fill value and adding fill value if not having one for some OBPG data type
1530  if((f->getSPType() == OBPGL2 || f->getSPType()==OBPGL3 )&& onespsds->getFieldType()==0)
1531  {
1532 
1533  if((OBPGL3 == f->getSPType() && (scaling.find("linear")!=string::npos)) || OBPGL2 == f->getSPType() ) {
1534 
1535  if(false == scale_factor_flag && (true == slope_flag || true == global_slope_flag))
1536  {
1537  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32, 0, (void*)&(slope));
1538  at->append_attr("scale_factor", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
1539  }
1540 
1541  if(false == add_offset_flag && (true == intercept_flag || true == global_intercept_flag))
1542  {
1543  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32, 0, (void*)&(intercept));
1544  at->append_attr("add_offset", HDFCFUtil::print_type(DFNT_FLOAT32), print_rep);
1545  }
1546  }
1547 
1548  bool has_fill_value = false;
1549  for(vector<HDFSP::Attribute *>::const_iterator i=onespsds->getAttributes().begin();i!=onespsds->getAttributes().end();i++) {
1550  if ("_FillValue" == (*i)->getNewName()){
1551  has_fill_value = true;
1552  break;
1553  }
1554  }
1555 
1556 
1557  // Add fill value to some type of OBPG data. 16-bit integer, fill value = -32767, unsigned 16-bit integer fill value = 65535
1558  // This is based on the evaluation of the example files. KY 2012-09-06
1559  if ((false == has_fill_value) &&(DFNT_INT16 == onespsds->getType())) {
1560  short fill_value = -32767;
1561  string print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)&(fill_value));
1562  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_INT16),print_rep);
1563  }
1564 
1565  if ((false == has_fill_value) &&(DFNT_UINT16 == onespsds->getType())) {
1566  unsigned short fill_value = 65535;
1567  string print_rep = HDFCFUtil::print_attr(DFNT_UINT16,0,(void*)&(fill_value));
1568  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_UINT16),print_rep);
1569  }
1570 
1571  }// Finish OBPG handling
1572 
1573 }
1574 
1575 // Handle HDF4 OTHERHDF products that follow SDS dimension scale model.
1576 // The special handling of AVHRR data is also included.
1578 
1579  // For some HDF4 files that follow HDF4 dimension scales, P.O. DAAC's AVHRR files.
1580  // The "otherHDF" category can almost make AVHRR files work, except
1581  // that AVHRR uses the attribute name "unit" instead of "units" for latitude and longitude,
1582  // I have to correct the name to follow CF conventions(using "units"). I won't check
1583  // the latitude and longitude values since latitude and longitude values for some files(LISO files)
1584  // are not in the standard range(0-360 for lon and 0-180 for lat). KY 2011-3-3
1585  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
1586  vector<HDFSP::SDField *>::const_iterator it_g;
1587 
1588  if(f->getSPType() == OTHERHDF) {
1589 
1590  bool latflag = false;
1591  bool latunitsflag = false; //CF conventions use "units" instead of "unit"
1592  bool lonflag = false;
1593  bool lonunitsflag = false; // CF conventions use "units" instead of "unit"
1594  int llcheckoverflag = 0;
1595 
1596  // Here I try to condense the code within just two for loops
1597  // The outer loop: Loop through all SDS objects
1598  // The inner loop: Loop through all attributes of this SDS
1599  // Inside two inner loops(since "units" are common for other fields),
1600  // inner loop 1: when an attribute's long name value is L(l)atitude,mark it.
1601  // inner loop 2: when an attribute's name is units, mark it.
1602  // Outside the inner loop, when latflag is true, and latunitsflag is false,
1603  // adding a new attribute called units and the value should be "degrees_north".
1604  // doing the same thing for longitude.
1605 
1606  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1607 
1608  // Ignore ALL coordinate variables if this is "OTHERHDF" case and some dimensions
1609  // don't have dimension scale data.
1610  if ( true == f->Has_Dim_NoScale_Field() && ((*it_g)->getFieldType() !=0) && ((*it_g)->IsDimScale() == false))
1611  continue;
1612 
1613  // Ignore the empty(no data) dimension variable.
1614  if (OTHERHDF == f->getSPType() && true == (*it_g)->IsDimNoScale())
1615  continue;
1616 
1617  AttrTable *at = das.get_table((*it_g)->getNewName());
1618  if (!at)
1619  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1620 
1621  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
1622  if((*i)->getType()==DFNT_UCHAR || (*i)->getType() == DFNT_CHAR){
1623 
1624  if((*i)->getName() == "long_name") {
1625  string tempstring2((*i)->getValue().begin(),(*i)->getValue().end());
1626  string tempfinalstr= string(tempstring2.c_str());// This may remove some garbage characters
1627  if(tempfinalstr=="latitude" || tempfinalstr == "Latitude") // Find long_name latitude
1628  latflag = true;
1629  if(tempfinalstr=="longitude" || tempfinalstr == "Longitude") // Find long_name latitude
1630  lonflag = true;
1631  }
1632  }
1633  }
1634 
1635  if(latflag) {
1636  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
1637  if((*i)->getName() == "units")
1638  latunitsflag = true;
1639  }
1640  }
1641 
1642  if(lonflag) {
1643  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
1644  if((*i)->getName() == "units")
1645  lonunitsflag = true;
1646  }
1647  }
1648  if(latflag && !latunitsflag){ // No "units" for latitude, add "units"
1649  at->append_attr("units","String","degrees_north");
1650  latflag = false;
1651  latunitsflag = false;
1652  llcheckoverflag++;
1653  }
1654 
1655  if(lonflag && !lonunitsflag){ // No "units" for latitude, add "units"
1656  at->append_attr("units","String","degrees_east");
1657  lonflag = false;
1658  latunitsflag = false;
1659  llcheckoverflag++;
1660  }
1661  if(llcheckoverflag ==2) break;
1662 
1663  }
1664 
1665  }
1666 
1667 }
1668 
1669 // Add missing CF attributes for non-CV varibles
1670 void
1672 
1673 
1674  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
1675  vector<HDFSP::SDField *>::const_iterator it_g;
1676 
1677 
1678  // TRMM level 3 grid
1679  if(TRMML3A_V6== f->getSPType() || TRMML3C_V6==f->getSPType() || TRMML3S_V7 == f->getSPType() || TRMML3M_V7 == f->getSPType()) {
1680 
1681  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1682  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_FLOAT32) {
1683 
1684  AttrTable *at = das.get_table((*it_g)->getNewName());
1685  if (!at)
1686  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1687  string print_rep = "-9999.9";
1688  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_FLOAT32),print_rep);
1689 
1690  }
1691  }
1692 
1693  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1694  if((*it_g)->getFieldType() == 0 && (((*it_g)->getType()==DFNT_INT32) || ((*it_g)->getType()==DFNT_INT16))) {
1695 
1696  AttrTable *at = das.get_table((*it_g)->getNewName());
1697  if (!at)
1698  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1699  string print_rep = "-9999";
1700  if((*it_g)->getType()==DFNT_INT32)
1701  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_INT32),print_rep);
1702  else
1703  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_INT16),print_rep);
1704 
1705  }
1706  }
1707 
1708  // nlayer for TRMM single grid version 7, the units should be "km"
1709  if(TRMML3S_V7 == f->getSPType()) {
1710  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1711  if((*it_g)->getFieldType() == 6 && (*it_g)->getNewName()=="nlayer") {
1712 
1713  AttrTable *at = das.get_table((*it_g)->getNewName());
1714  if (!at)
1715  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1716  at->append_attr("units","String","km");
1717 
1718  }
1719  else if((*it_g)->getFieldType() == 4) {
1720 
1721  if ((*it_g)->getNewName()=="nh3" ||
1722  (*it_g)->getNewName()=="ncat3" ||
1723  (*it_g)->getNewName()=="nthrshZO" ||
1724  (*it_g)->getNewName()=="nthrshHB" ||
1725  (*it_g)->getNewName()=="nthrshSRT")
1726  {
1727 
1728  string references =
1729  "http://pps.gsfc.nasa.gov/Documents/filespec.TRMM.V7.pdf";
1730  string comment;
1731 
1732  AttrTable *at = das.get_table((*it_g)->getNewName());
1733  if (!at)
1734  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1735 
1736  if((*it_g)->getNewName()=="nh3") {
1737  comment="Index number to represent the fixed heights above the earth ellipsoid,";
1738  comment= comment + " at 2, 4, 6 km plus one for path-average.";
1739  }
1740 
1741  else if((*it_g)->getNewName()=="ncat3") {
1742  comment="Index number to represent catgories for probability distribution functions.";
1743  comment=comment + "Check more information from the references.";
1744  }
1745 
1746  else if((*it_g)->getNewName()=="nthrshZO")
1747  comment="Q-thresholds for Zero order used for probability distribution functions.";
1748 
1749  else if((*it_g)->getNewName()=="nthrshHB")
1750  comment="Q-thresholds for HB used for probability distribution functions.";
1751 
1752  else if((*it_g)->getNewName()=="nthrshSRT")
1753  comment="Q-thresholds for SRT used for probability distribution functions.";
1754 
1755  at->append_attr("comment","String",comment);
1756  at->append_attr("references","String",references);
1757 
1758  }
1759 
1760  }
1761 
1762  }
1763 
1764 
1765  // 3A26 use special values such as -666, -777,-999 in their fields.
1766  // Although the document doesn't provide range for some fields, the meaning of those fields should be greater than 0.
1767  // So add valid_min = 0 and fill_value = -999 .
1768  string base_filename;
1769  size_t last_slash_pos = f->getPath().find_last_of("/");
1770  if(last_slash_pos != string::npos)
1771  base_filename = f->getPath().substr(last_slash_pos+1);
1772  if(""==base_filename)
1773  base_filename = f->getPath();
1774  bool t3a26_flag = ((base_filename.find("3A26")!=string::npos)?true:false);
1775 
1776  if(true == t3a26_flag) {
1777 
1778  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1779 
1780  if((*it_g)->getFieldType() == 0 && ((*it_g)->getType()==DFNT_FLOAT32)) {
1781  AttrTable *at = das.get_table((*it_g)->getNewName());
1782  if (!at)
1783  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1784  at->del_attr("_FillValue");
1785  at->append_attr("_FillValue","Float32","-999");
1786  at->append_attr("valid_min","Float32","0");
1787 
1788  }
1789  }
1790  }
1791 
1792  }
1793 
1794  // nlayer for TRMM single grid version 7, the units should be "km"
1795  if(TRMML3M_V7 == f->getSPType()) {
1796  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1797 
1798  if((*it_g)->getFieldType() == 4 ) {
1799 
1800  string references ="http://pps.gsfc.nasa.gov/Documents/filespec.TRMM.V7.pdf";
1801  if ((*it_g)->getNewName()=="nh1") {
1802 
1803  AttrTable *at = das.get_table((*it_g)->getNewName());
1804  if (!at)
1805  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1806 
1807  string comment="Number of fixed heights above the earth ellipsoid,";
1808  comment= comment + " at 2, 4, 6, 10, and 15 km plus one for path-average.";
1809 
1810  at->append_attr("comment","String",comment);
1811  at->append_attr("references","String",references);
1812 
1813  }
1814  if ((*it_g)->getNewName()=="nh3") {
1815 
1816  AttrTable *at = das.get_table((*it_g)->getNewName());
1817  if (!at)
1818  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1819 
1820  string comment="Number of fixed heights above the earth ellipsoid,";
1821  comment= comment + " at 2, 4, 6 km plus one for path-average.";
1822 
1823  at->append_attr("comment","String",comment);
1824  at->append_attr("references","String",references);
1825 
1826  }
1827 
1828  if ((*it_g)->getNewName()=="nang") {
1829 
1830  AttrTable *at = das.get_table((*it_g)->getNewName());
1831  if (!at)
1832  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1833 
1834  string comment="Number of fixed incidence angles, at 0, 5, 10 and 15 degree and all angles.";
1835  references = "http://pps.gsfc.nasa.gov/Documents/ICSVol4.pdf";
1836 
1837  at->append_attr("comment","String",comment);
1838  at->append_attr("references","String",references);
1839 
1840  }
1841 
1842  if ((*it_g)->getNewName()=="ncat2") {
1843 
1844  AttrTable *at = das.get_table((*it_g)->getNewName());
1845  if (!at)
1846  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1847 
1848  string comment="Second number of categories for histograms (30). ";
1849  comment=comment + "Check more information from the references.";
1850 
1851  at->append_attr("comment","String",comment);
1852  at->append_attr("references","String",references);
1853 
1854  }
1855 
1856  }
1857  }
1858 
1859  }
1860 
1861  }
1862 
1863  // TRMM level 2 swath
1864  else if(TRMML2_V7== f->getSPType()) {
1865 
1866  string base_filename;
1867  size_t last_slash_pos = f->getPath().find_last_of("/");
1868  if(last_slash_pos != string::npos)
1869  base_filename = f->getPath().substr(last_slash_pos+1);
1870  if(""==base_filename)
1871  base_filename = f->getPath();
1872  bool t2b31_flag = ((base_filename.find("2B31")!=string::npos)?true:false);
1873  bool t2a21_flag = ((base_filename.find("2A21")!=string::npos)?true:false);
1874  bool t2a12_flag = ((base_filename.find("2A12")!=string::npos)?true:false);
1875  // 2A23 is temporarily not supported perhaps due to special fill values
1876  //bool t2a23_flag = ((base_filename.find("2A23")!=string::npos)?true:false);
1877  bool t2a25_flag = ((base_filename.find("2A25")!=string::npos)?true:false);
1878  bool t1c21_flag = ((base_filename.find("1C21")!=string::npos)?true:false);
1879  bool t1b21_flag = ((base_filename.find("1B21")!=string::npos)?true:false);
1880  bool t1b11_flag = ((base_filename.find("1B11")!=string::npos)?true:false);
1881  bool t1b01_flag = ((base_filename.find("1B01")!=string::npos)?true:false);
1882 
1883  // Handle scale and offset
1884 
1885  // group 1: 2B31,2A12,2A21
1886  if(t2b31_flag || t2a12_flag || t2a21_flag) {
1887 
1888  // special for 2B31
1889  if(t2b31_flag) {
1890 
1891  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1892 
1893 
1894  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_INT16) {
1895 
1896  AttrTable *at = das.get_table((*it_g)->getNewName());
1897  if (!at)
1898  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1899 
1900  AttrTable::Attr_iter it = at->attr_begin();
1901  while (it!=at->attr_end()) {
1902  if(at->get_name(it)=="scale_factor")
1903  {
1904  // Scale type and value
1905  string scale_factor_value="";
1906  string scale_factor_type;
1907 
1908  scale_factor_value = (*at->get_attr_vector(it)->begin());
1909  scale_factor_type = at->get_type(it);
1910 
1911  if(scale_factor_type == "Float64") {
1912  double new_scale = 1.0/strtod(scale_factor_value.c_str(),NULL);
1913  at->del_attr("scale_factor");
1914  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT64,0,(void*)(&new_scale));
1915  at->append_attr("scale_factor", scale_factor_type,print_rep);
1916 
1917  }
1918 
1919  if(scale_factor_type == "Float32") {
1920  float new_scale = 1.0/strtof(scale_factor_value.c_str(),NULL);
1921  at->del_attr("scale_factor");
1922  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&new_scale));
1923  at->append_attr("scale_factor", scale_factor_type,print_rep);
1924 
1925  }
1926 
1927  break;
1928  }
1929  ++it;
1930  }
1931  }
1932  }
1933  }
1934 
1935  // Special for 2A12
1936  if(t2a12_flag==true) {
1937 
1938  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1939 
1940  if((*it_g)->getFieldType() == 6 && (*it_g)->getNewName()=="nlayer") {
1941 
1942  AttrTable *at = das.get_table((*it_g)->getNewName());
1943  if (!at)
1944  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1945  at->append_attr("units","String","km");
1946 
1947  }
1948 
1949  // signed char maps to int32, so use int32 for the fillvalue.
1950  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_INT8) {
1951 
1952  AttrTable *at = das.get_table((*it_g)->getNewName());
1953  if (!at)
1954  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1955  at->append_attr("_FillValue","Int32","-99");
1956 
1957  }
1958 
1959  }
1960  }
1961 
1962 
1963  // for all 2A12,2A21 and 2B31
1964  // Add fillvalues for float32 and int32.
1965  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1966  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_FLOAT32) {
1967 
1968  AttrTable *at = das.get_table((*it_g)->getNewName());
1969  if (!at)
1970  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1971  string print_rep = "-9999.9";
1972  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_FLOAT32),print_rep);
1973 
1974  }
1975  }
1976 
1977  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1978 
1979 
1980  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_INT16) {
1981 
1982  AttrTable *at = das.get_table((*it_g)->getNewName());
1983  if (!at)
1984  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1985 
1986  string print_rep = "-9999";
1987  at->append_attr("_FillValue",HDFCFUtil::print_type(DFNT_INT32),print_rep);
1988 
1989  }
1990  }
1991 
1992  }
1993 
1994  // group 2: 2A21 and 2A25.
1995  else if(t2a21_flag == true || t2a25_flag == true) {
1996 
1997  // 2A25: handle reflectivity and rain rate scales
1998  if(t2a25_flag == true) {
1999 
2000  unsigned char handle_scale = 0;
2001  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2002 
2003  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_INT16) {
2004  bool has_dBZ = false;
2005  bool has_rainrate = false;
2006  bool has_scale = false;
2007  string scale_factor_value;
2008  string scale_factor_type;
2009 
2010  AttrTable *at = das.get_table((*it_g)->getNewName());
2011  if (!at)
2012  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2013  AttrTable::Attr_iter it = at->attr_begin();
2014  while (it!=at->attr_end()) {
2015  if(at->get_name(it)=="units"){
2016  string units_value = (*at->get_attr_vector(it)->begin());
2017  if("dBZ" == units_value) {
2018  has_dBZ = true;
2019  }
2020 
2021  else if("mm/hr" == units_value){
2022  has_rainrate = true;
2023  }
2024  }
2025  if(at->get_name(it)=="scale_factor")
2026  {
2027  scale_factor_value = (*at->get_attr_vector(it)->begin());
2028  scale_factor_type = at->get_type(it);
2029  has_scale = true;
2030  }
2031  ++it;
2032 
2033  }
2034 
2035  if((true == has_rainrate || true == has_dBZ) && true == has_scale) {
2036 
2037  handle_scale++;
2038  short valid_min = 0;
2039  short valid_max = 0;
2040 
2041  // Here just use 32-bit floating-point for the scale_factor, should be okay.
2042  if(true == has_rainrate)
2043  valid_max = (short)(300*strtof(scale_factor_value.c_str(),NULL));
2044  else if(true == has_dBZ)
2045  valid_max = (short)(80*strtof(scale_factor_value.c_str(),NULL));
2046 
2047  string print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)(&valid_min));
2048  at->append_attr("valid_min","Int16",print_rep);
2049  print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)(&valid_max));
2050  at->append_attr("valid_max","Int16",print_rep);
2051 
2052  at->del_attr("scale_factor");
2053  if(scale_factor_type == "Float64") {
2054  double new_scale = 1.0/strtod(scale_factor_value.c_str(),NULL);
2055  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT64,0,(void*)(&new_scale));
2056  at->append_attr("scale_factor", scale_factor_type,print_rep);
2057 
2058  }
2059 
2060  if(scale_factor_type == "Float32") {
2061  float new_scale = 1.0/strtof(scale_factor_value.c_str(),NULL);
2062  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&new_scale));
2063  at->append_attr("scale_factor", scale_factor_type,print_rep);
2064 
2065  }
2066 
2067 
2068  }
2069 
2070  if(2 == handle_scale)
2071  break;
2072 
2073  }
2074  }
2075  }
2076  }
2077 
2078  // 1B21,1C21 and 1B11
2079  else if(t1b21_flag || t1c21_flag || t1b11_flag) {
2080 
2081  // 1B21,1C21 scale_factor to CF and valid_range for dBm and dBZ.
2082  if(t1b21_flag || t1c21_flag) {
2083 
2084  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2085 
2086  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_INT16) {
2087 
2088  bool has_dBm = false;
2089  bool has_dBZ = false;
2090 
2091  AttrTable *at = das.get_table((*it_g)->getNewName());
2092  if (!at)
2093  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2094  AttrTable::Attr_iter it = at->attr_begin();
2095 
2096  while (it!=at->attr_end()) {
2097  if(at->get_name(it)=="units"){
2098 
2099  string units_value = (*at->get_attr_vector(it)->begin());
2100  if("dBm" == units_value) {
2101  has_dBm = true;
2102  break;
2103  }
2104 
2105  else if("dBZ" == units_value){
2106  has_dBZ = true;
2107  break;
2108  }
2109  }
2110  ++it;
2111  }
2112 
2113  if(has_dBm == true || has_dBZ == true) {
2114  it = at->attr_begin();
2115  while (it!=at->attr_end()) {
2116  if(at->get_name(it)=="scale_factor")
2117  {
2118 
2119  string scale_value = (*at->get_attr_vector(it)->begin());
2120 
2121  if(true == has_dBm) {
2122  short valid_min = (short)(-120 *strtof(scale_value.c_str(),NULL));
2123  short valid_max = (short)(-20 *strtof(scale_value.c_str(),NULL));
2124  string print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)(&valid_min));
2125  at->append_attr("valid_min","Int16",print_rep);
2126  print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)(&valid_max));
2127  at->append_attr("valid_max","Int16",print_rep);
2128  break;
2129 
2130  }
2131 
2132  else if(true == has_dBZ){
2133  short valid_min = (short)(-20 *strtof(scale_value.c_str(),NULL));
2134  short valid_max = (short)(80 *strtof(scale_value.c_str(),NULL));
2135  string print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)(&valid_min));
2136  at->append_attr("valid_min","Int16",print_rep);
2137  print_rep = HDFCFUtil::print_attr(DFNT_INT16,0,(void*)(&valid_max));
2138  at->append_attr("valid_max","Int16",print_rep);
2139  break;
2140 
2141  }
2142  }
2143  ++it;
2144  }
2145 
2146  }
2147  }
2148  }
2149  }
2150 
2151  // For all 1B21,1C21 and 1B11 int16-bit products,change scale to follow CF
2152  // I find that one 1B21 variable binStormHeight has fillvalue -9999,
2153  // so add _FillValue -9999 for int16-bit variables.
2154  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2155 
2156  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_INT16) {
2157 
2158  AttrTable *at = das.get_table((*it_g)->getNewName());
2159  if (!at)
2160  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2161  AttrTable::Attr_iter it = at->attr_begin();
2162 
2163 
2164  while (it!=at->attr_end()) {
2165 
2166  if(at->get_name(it)=="scale_factor")
2167  {
2168  // Scale type and value
2169  string scale_factor_value="";
2170  string scale_factor_type;
2171 
2172  scale_factor_value = (*at->get_attr_vector(it)->begin());
2173  scale_factor_type = at->get_type(it);
2174 
2175  if(scale_factor_type == "Float64") {
2176  double new_scale = 1.0/strtod(scale_factor_value.c_str(),NULL);
2177  at->del_attr("scale_factor");
2178  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT64,0,(void*)(&new_scale));
2179  at->append_attr("scale_factor", scale_factor_type,print_rep);
2180 
2181  }
2182 
2183  if(scale_factor_type == "Float32") {
2184  float new_scale = 1.0/strtof(scale_factor_value.c_str(),NULL);
2185  at->del_attr("scale_factor");
2186  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT32,0,(void*)(&new_scale));
2187  at->append_attr("scale_factor", scale_factor_type,print_rep);
2188 
2189  }
2190 
2191  break;
2192 
2193  }
2194  ++it;
2195 
2196  }
2197 
2198  at->append_attr("_FillValue","Int16","-9999");
2199 
2200  }
2201  }
2202  }
2203 
2204  // For 1B01 product, just add the fillvalue.
2205  else if(t1b01_flag == true) {
2206  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2207 
2208  if((*it_g)->getFieldType() == 0 && (*it_g)->getType()==DFNT_FLOAT32) {
2209  AttrTable *at = das.get_table((*it_g)->getNewName());
2210  if (!at)
2211  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2212 
2213  at->append_attr("_FillValue","Float32","-9999.9");
2214 
2215  }
2216  }
2217 
2218  }
2219 
2220  AttrTable *at = das.get_table("HDF_GLOBAL");
2221  if (!at)
2222  at = das.add_table("HDF_GLOBAL", new AttrTable);
2223  string references ="http://pps.gsfc.nasa.gov/Documents/filespec.TRMM.V7.pdf";
2224  string comment="The HDF4 OPeNDAP handler adds _FillValue, valid_min and valid_max for some TRMM level 1 and level 2 products.";
2225  comment= comment + " It also changes scale_factor to follow CF conventions. ";
2226 
2227  at->append_attr("comment","String",comment);
2228  at->append_attr("references","String",references);
2229 
2230  }
2231 
2232 }
2233 
2234 
2235 
2236 //
2237 // Many CERES products compose of multiple groups
2238 // There are many fields in CERES data(a few hundred) and the full name(with the additional path)
2239 // is very long. It causes Java clients choken since Java clients append names in the URL
2240 // To improve the performance and to make Java clients access the data, we will ignore
2241 // the path of these fields. Users can turn off this feature by commenting out the line: H4.EnableCERESMERRAShortName=true
2242 // or can set the H4.EnableCERESMERRAShortName=false
2243 // We still preserve the full path as an attribute in case users need to check them.
2244 // Kent 2012-6-29
2245 
2246 void HDFCFUtil::handle_merra_ceres_attrs_with_bes_keys(HDFSP::File *f, DAS &das,const string& filename) {
2247 
2248 
2249  string check_ceres_merra_short_name_key="H4.EnableCERESMERRAShortName";
2250  bool turn_on_ceres_merra_short_name_key= false;
2251  string base_filename = filename.substr(filename.find_last_of("/")+1);
2252 
2253  turn_on_ceres_merra_short_name_key = HDFCFUtil::check_beskeys(check_ceres_merra_short_name_key);
2254 
2255  bool merra_is_eos2 = false;
2256  if(0== (base_filename.compare(0,5,"MERRA"))) {
2257 
2258  for (vector < HDFSP::Attribute * >::const_iterator i =
2259  f->getSD()->getAttributes ().begin ();
2260  i != f->getSD()->getAttributes ().end (); ++i) {
2261 
2262  // CHeck if this MERRA file is an HDF-EOS2 or not.
2263  if(((*i)->getName().compare(0, 14, "StructMetadata" )== 0) ||
2264  ((*i)->getName().compare(0, 14, "structmetadata" )== 0)) {
2265  merra_is_eos2 = true;
2266  break;
2267  }
2268 
2269  }
2270  }
2271 
2272  if (true == turn_on_ceres_merra_short_name_key && (CER_ES4 == f->getSPType() || CER_SRB == f->getSPType()
2273  || CER_CDAY == f->getSPType() || CER_CGEO == f->getSPType()
2274  || CER_SYN == f->getSPType() || CER_ZAVG == f->getSPType()
2275  || CER_AVG == f->getSPType() || (true == merra_is_eos2))) {
2276 
2277  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
2278  vector<HDFSP::SDField *>::const_iterator it_g;
2279  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2280 
2281  AttrTable *at = das.get_table((*it_g)->getNewName());
2282  if (!at)
2283  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2284 
2285  at->append_attr("fullpath","String",(*it_g)->getSpecFullPath());
2286 
2287  }
2288 
2289  }
2290 
2291 }
2292 
2293 
2294 // Handle the attributes when the BES key EnableVdataDescAttr is enabled..
2296 
2297  // Check the EnableVdataDescAttr key. If this key is turned on, the handler-added attribute VDdescname and
2298  // the attributes of vdata and vdata fields will be outputed to DAS. Otherwise, these attributes will
2299  // not outputed to DAS. The key will be turned off by default to shorten the DAP output. KY 2012-09-18
2300 
2301  string check_vdata_desc_key="H4.EnableVdataDescAttr";
2302  bool turn_on_vdata_desc_key= false;
2303 
2304  turn_on_vdata_desc_key = HDFCFUtil::check_beskeys(check_vdata_desc_key);
2305 
2306  string VDdescname = "hdf4_vd_desc";
2307  string VDdescvalue = "This is an HDF4 Vdata.";
2308  string VDfieldprefix = "Vdata_field_";
2309  string VDattrprefix = "Vdata_attr_";
2310  string VDfieldattrprefix ="Vdata_field_attr_";
2311 
2312  // To speed up the performance for handling CERES data, we turn off some CERES vdata fields, this should be resumed in the future version with BESKeys.
2313  string check_ceres_vdata_key="H4.EnableCERESVdata";
2314  bool turn_on_ceres_vdata_key= false;
2315  turn_on_ceres_vdata_key = HDFCFUtil::check_beskeys(check_ceres_vdata_key);
2316 
2317  bool output_vdata_flag = true;
2318  if (false == turn_on_ceres_vdata_key &&
2319  (CER_AVG == f->getSPType() ||
2320  CER_ES4 == f->getSPType() ||
2321  CER_SRB == f->getSPType() ||
2322  CER_ZAVG == f->getSPType()))
2323  output_vdata_flag = false;
2324 
2325  //if(f->getSPType() != CER_AVG && f->getSPType() != CER_ES4 && f->getSPType() !=CER_SRB && f->getSPType() != CER_ZAVG) {
2326  if (true == output_vdata_flag) {
2327 
2328  for(vector<HDFSP::VDATA *>::const_iterator i=f->getVDATAs().begin(); i!=f->getVDATAs().end();i++) {
2329 
2330  AttrTable *at = das.get_table((*i)->getNewName());
2331  if(!at)
2332  at = das.add_table((*i)->getNewName(),new AttrTable);
2333 
2334  if (true == turn_on_vdata_desc_key) {
2335  // Add special vdata attributes
2336  bool emptyvddasflag = true;
2337  if(!((*i)->getAttributes().empty())) emptyvddasflag = false;
2338  if(((*i)->getTreatAsAttrFlag()))
2339  emptyvddasflag = false;
2340  else {
2341  for(vector<HDFSP::VDField *>::const_iterator j=(*i)->getFields().begin();j!=(*i)->getFields().end();j++) {
2342  if(!((*j)->getAttributes().empty())) {
2343  emptyvddasflag = false;
2344  break;
2345  }
2346  }
2347  }
2348 
2349  if(emptyvddasflag)
2350  continue;
2351  at->append_attr(VDdescname, "String" , VDdescvalue);
2352 
2353  for(vector<HDFSP::Attribute *>::const_iterator it_va = (*i)->getAttributes().begin();it_va!=(*i)->getAttributes().end();it_va++) {
2354 
2355  if((*it_va)->getType()==DFNT_UCHAR || (*it_va)->getType() == DFNT_CHAR){
2356 
2357  string tempstring2((*it_va)->getValue().begin(),(*it_va)->getValue().end());
2358  string tempfinalstr= string(tempstring2.c_str());
2359  at->append_attr(VDattrprefix+(*it_va)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2360  }
2361  else {
2362  for (int loc=0; loc < (*it_va)->getCount() ; loc++) {
2363  string print_rep = HDFCFUtil::print_attr((*it_va)->getType(), loc, (void*) &((*it_va)->getValue()[0]));
2364  at->append_attr(VDattrprefix+(*it_va)->getNewName(), HDFCFUtil::print_type((*it_va)->getType()), print_rep);
2365  }
2366  }
2367 
2368  }
2369  }
2370 
2371  if(false == ((*i)->getTreatAsAttrFlag())){
2372 
2373  if (true == turn_on_vdata_desc_key) {
2374 
2375  //NOTE: for vdata field, we assume that no special characters are found. We need to escape the special characters when the data type is char.
2376  // We need to create a DAS container for each field so that the attributes can be put inside.
2377  for(vector<HDFSP::VDField *>::const_iterator j=(*i)->getFields().begin();j!=(*i)->getFields().end();j++) {
2378 
2379  // This vdata field will NOT be treated as attributes, only save the field attribute as the attribute
2380  // First check if the field has attributes, if it doesn't have attributes, no need to create a container.
2381 
2382  if((*j)->getAttributes().size() !=0) {
2383 
2384  AttrTable *at_v = das.get_table((*j)->getNewName());
2385  if(!at_v)
2386  at_v = das.add_table((*j)->getNewName(),new AttrTable);
2387 
2388  for(vector<HDFSP::Attribute *>::const_iterator it_va = (*j)->getAttributes().begin();it_va!=(*j)->getAttributes().end();it_va++) {
2389 
2390  if((*it_va)->getType()==DFNT_UCHAR || (*it_va)->getType() == DFNT_CHAR){
2391 
2392  string tempstring2((*it_va)->getValue().begin(),(*it_va)->getValue().end());
2393  string tempfinalstr= string(tempstring2.c_str());
2394  at_v->append_attr((*it_va)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2395  }
2396  else {
2397  for (int loc=0; loc < (*it_va)->getCount() ; loc++) {
2398  string print_rep = HDFCFUtil::print_attr((*it_va)->getType(), loc, (void*) &((*it_va)->getValue()[0]));
2399  at_v->append_attr((*it_va)->getNewName(), HDFCFUtil::print_type((*it_va)->getType()), print_rep);
2400  }
2401  }
2402 
2403  }
2404  }
2405  }
2406  }
2407 
2408  }
2409 
2410  else {
2411 
2412  for(vector<HDFSP::VDField *>::const_iterator j=(*i)->getFields().begin();j!=(*i)->getFields().end();j++) {
2413 
2414  if((*j)->getFieldOrder() == 1) {
2415  if((*j)->getType()==DFNT_UCHAR || (*j)->getType() == DFNT_CHAR){
2416  string tempfinalstr;
2417  tempfinalstr.resize((*j)->getValue().size());
2418  copy((*j)->getValue().begin(),(*j)->getValue().end(),tempfinalstr.begin());
2419  at->append_attr(VDfieldprefix+(*j)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2420  }
2421  else {
2422  for ( int loc=0; loc < (*j)->getNumRec(); loc++) {
2423  string print_rep = HDFCFUtil::print_attr((*j)->getType(), loc, (void*) &((*j)->getValue()[0]));
2424  at->append_attr(VDfieldprefix+(*j)->getNewName(), HDFCFUtil::print_type((*j)->getType()), print_rep);
2425  }
2426  }
2427  }
2428  else {//When field order is greater than 1,we want to print each record in group with single quote,'0 1 2','3 4 5', etc.
2429 
2430  if((*j)->getValue().size() != (unsigned int)(DFKNTsize((*j)->getType())*((*j)->getFieldOrder())*((*j)->getNumRec()))){
2431  throw InternalErr(__FILE__,__LINE__,"the vdata field size doesn't match the vector value");
2432  }
2433 
2434  if((*j)->getNumRec()==1){
2435  if((*j)->getType()==DFNT_UCHAR || (*j)->getType() == DFNT_CHAR){
2436  string tempstring2((*j)->getValue().begin(),(*j)->getValue().end());
2437  string tempfinalstr= string(tempstring2.c_str());
2438  at->append_attr(VDfieldprefix+(*j)->getNewName(),"String",HDFCFUtil::escattr(tempfinalstr));
2439  }
2440  else {
2441  for (int loc=0; loc < (*j)->getFieldOrder(); loc++) {
2442  string print_rep = HDFCFUtil::print_attr((*j)->getType(), loc, (void*) &((*j)->getValue()[0]));
2443  at->append_attr(VDfieldprefix+(*j)->getNewName(), HDFCFUtil::print_type((*j)->getType()), print_rep);
2444  }
2445  }
2446 
2447  }
2448 
2449  else {
2450  if((*j)->getType()==DFNT_UCHAR || (*j)->getType() == DFNT_CHAR){
2451 
2452  for(int tempcount = 0; tempcount < (*j)->getNumRec()*DFKNTsize((*j)->getType());tempcount ++) {
2453  vector<char>::const_iterator tempit;
2454  tempit = (*j)->getValue().begin()+tempcount*((*j)->getFieldOrder());
2455  string tempstring2(tempit,tempit+(*j)->getFieldOrder());
2456  string tempfinalstr= string(tempstring2.c_str());
2457  string tempoutstring = "'"+tempfinalstr+"'";
2458  at->append_attr(VDfieldprefix+(*j)->getNewName(),"String",HDFCFUtil::escattr(tempoutstring));
2459  }
2460  }
2461 
2462  else {
2463  for(int tempcount = 0; tempcount < (*j)->getNumRec();tempcount ++) {
2464  at->append_attr(VDfieldprefix+(*j)->getNewName(),HDFCFUtil::print_type((*j)->getType()),"'");
2465  for (int loc=0; loc < (*j)->getFieldOrder(); loc++) {
2466  string print_rep = HDFCFUtil::print_attr((*j)->getType(), loc, (void*) &((*j)->getValue()[tempcount*((*j)->getFieldOrder())]));
2467  at->append_attr(VDfieldprefix+(*j)->getNewName(), HDFCFUtil::print_type((*j)->getType()), print_rep);
2468  }
2469  at->append_attr(VDfieldprefix+(*j)->getNewName(),HDFCFUtil::print_type((*j)->getType()),"'");
2470  }
2471  }
2472  }
2473  }
2474 
2475 
2476  if (true == turn_on_vdata_desc_key) {
2477  for(vector<HDFSP::Attribute *>::const_iterator it_va = (*j)->getAttributes().begin();it_va!=(*j)->getAttributes().end();it_va++) {
2478 
2479  if((*it_va)->getType()==DFNT_UCHAR || (*it_va)->getType() == DFNT_CHAR){
2480 
2481  string tempstring2((*it_va)->getValue().begin(),(*it_va)->getValue().end());
2482  string tempfinalstr= string(tempstring2.c_str());
2483  at->append_attr(VDfieldattrprefix+(*it_va)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2484  }
2485  else {
2486  for (int loc=0; loc < (*it_va)->getCount() ; loc++) {
2487  string print_rep = HDFCFUtil::print_attr((*it_va)->getType(), loc, (void*) &((*it_va)->getValue()[0]));
2488  at->append_attr(VDfieldattrprefix+(*it_va)->getNewName(), HDFCFUtil::print_type((*it_va)->getType()), print_rep);
2489  }
2490  }
2491  }
2492  }
2493  }
2494  }
2495 
2496  }
2497  }
2498 
2499 }
2500 
2501 
2502 string HDFCFUtil::escattr(string s)
2503 {
2504  const string printable = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()_-+={[}]|\\:;<,>.?/'\"\n\t\r";
2505  const string ESC = "\\";
2506  const string DOUBLE_ESC = ESC + ESC;
2507  const string QUOTE = "\"";
2508  const string ESCQUOTE = ESC + QUOTE;
2509 
2510 
2511  // escape \ with a second backslash
2512  string::size_type ind = 0;
2513  while ((ind = s.find(ESC, ind)) != s.npos) {
2514  s.replace(ind, 1, DOUBLE_ESC);
2515  ind += DOUBLE_ESC.length();
2516  }
2517 
2518  // escape non-printing characters with octal escape
2519  ind = 0;
2520  while ((ind = s.find_first_not_of(printable, ind)) != s.npos)
2521  s.replace(ind, 1, ESC + octstring(s[ind]));
2522 
2523  // escape " with backslash
2524  ind = 0;
2525  while ((ind = s.find(QUOTE, ind)) != s.npos) {
2526  s.replace(ind, 1, ESCQUOTE);
2527  ind += ESCQUOTE.length();
2528  }
2529 
2530  return s;
2531 }
2532 
2533 
2534 void HDFCFUtil::parser_trmm_v7_gridheader(const vector<char>& value,
2535  int& latsize, int&lonsize,
2536  float& lat_start, float& lon_start,
2537  float& lat_res, float& lon_res,
2538  bool check_reg_orig ){
2539 
2540  //bool cr_reg = false;
2541  //bool sw_origin = true;
2542  //float lat_res = 1.;
2543  //float lon_res = 1.;
2544  float lat_north = 0.;
2545  float lat_south = 0.;
2546  float lon_east = 0.;
2547  float lon_west = 0.;
2548 
2549  vector<string> ind_elems;
2550  char sep='\n';
2551  HDFCFUtil::Split(&value[0],sep,ind_elems);
2552 
2553  /* The number of elements in the GridHeader is 9. The string vector will add a leftover. So the size should be 10.*/
2554  if(ind_elems.size()!=10)
2555  throw InternalErr(__FILE__,__LINE__,"The number of elements in the TRMM level 3 GridHeader is not right.");
2556 
2557  if(false == check_reg_orig) {
2558  if (0 != ind_elems[1].find("Registration=CENTER"))
2559  throw InternalErr(__FILE__,__LINE__,"The TRMM grid registration is not center.");
2560  }
2561 
2562  if (0 == ind_elems[2].find("LatitudeResolution")){
2563 
2564  size_t equal_pos = ind_elems[2].find_first_of('=');
2565  if(string::npos == equal_pos)
2566  throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for TRMM level 3 products");
2567 
2568  size_t scolon_pos = ind_elems[2].find_first_of(';');
2569  if(string::npos == scolon_pos)
2570  throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for TRMM level 3 products");
2571  if (equal_pos < scolon_pos){
2572 
2573  string latres_str = ind_elems[2].substr(equal_pos+1,scolon_pos-equal_pos-1);
2574  lat_res = strtof(latres_str.c_str(),NULL);
2575  }
2576  else
2577  throw InternalErr(__FILE__,__LINE__,"latitude resolution is not right for TRMM level 3 products");
2578  }
2579  else
2580  throw InternalErr(__FILE__,__LINE__,"The TRMM grid LatitudeResolution doesn't exist.");
2581 
2582  if (0 == ind_elems[3].find("LongitudeResolution")){
2583 
2584  size_t equal_pos = ind_elems[3].find_first_of('=');
2585  if(string::npos == equal_pos)
2586  throw InternalErr(__FILE__,__LINE__,"Cannot find longitude resolution for TRMM level 3 products");
2587 
2588  size_t scolon_pos = ind_elems[3].find_first_of(';');
2589  if(string::npos == scolon_pos)
2590  throw InternalErr(__FILE__,__LINE__,"Cannot find longitude resolution for TRMM level 3 products");
2591  if (equal_pos < scolon_pos){
2592  string lonres_str = ind_elems[3].substr(equal_pos+1,scolon_pos-equal_pos-1);
2593  lon_res = strtof(lonres_str.c_str(),NULL);
2594  }
2595  else
2596  throw InternalErr(__FILE__,__LINE__,"longitude resolution is not right for TRMM level 3 products");
2597  }
2598  else
2599  throw InternalErr(__FILE__,__LINE__,"The TRMM grid LongitudeResolution doesn't exist.");
2600 
2601  if (0 == ind_elems[4].find("NorthBoundingCoordinate")){
2602 
2603  size_t equal_pos = ind_elems[4].find_first_of('=');
2604  if(string::npos == equal_pos)
2605  throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for TRMM level 3 products");
2606 
2607  size_t scolon_pos = ind_elems[4].find_first_of(';');
2608  if(string::npos == scolon_pos)
2609  throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for TRMM level 3 products");
2610  if (equal_pos < scolon_pos){
2611  string north_bounding_str = ind_elems[4].substr(equal_pos+1,scolon_pos-equal_pos-1);
2612  lat_north = strtof(north_bounding_str.c_str(),NULL);
2613  }
2614  else
2615  throw InternalErr(__FILE__,__LINE__,"NorthBoundingCoordinate is not right for TRMM level 3 products");
2616 
2617  }
2618  else
2619  throw InternalErr(__FILE__,__LINE__,"The TRMM grid NorthBoundingCoordinate doesn't exist.");
2620 
2621  if (0 == ind_elems[5].find("SouthBoundingCoordinate")){
2622 
2623  size_t equal_pos = ind_elems[5].find_first_of('=');
2624  if(string::npos == equal_pos)
2625  throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for TRMM level 3 products");
2626 
2627  size_t scolon_pos = ind_elems[5].find_first_of(';');
2628  if(string::npos == scolon_pos)
2629  throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for TRMM level 3 products");
2630  if (equal_pos < scolon_pos){
2631  string lat_south_str = ind_elems[5].substr(equal_pos+1,scolon_pos-equal_pos-1);
2632  lat_south = strtof(lat_south_str.c_str(),NULL);
2633  }
2634  else
2635  throw InternalErr(__FILE__,__LINE__,"south bound coordinate is not right for TRMM level 3 products");
2636 
2637  }
2638  else
2639  throw InternalErr(__FILE__,__LINE__,"The TRMM grid SouthBoundingCoordinate doesn't exist.");
2640 
2641  if (0 == ind_elems[6].find("EastBoundingCoordinate")){
2642 
2643  size_t equal_pos = ind_elems[6].find_first_of('=');
2644  if(string::npos == equal_pos)
2645  throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for TRMM level 3 products");
2646 
2647  size_t scolon_pos = ind_elems[6].find_first_of(';');
2648  if(string::npos == scolon_pos)
2649  throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for TRMM level 3 products");
2650  if (equal_pos < scolon_pos){
2651  string lon_east_str = ind_elems[6].substr(equal_pos+1,scolon_pos-equal_pos-1);
2652  lon_east = strtof(lon_east_str.c_str(),NULL);
2653  }
2654  else
2655  throw InternalErr(__FILE__,__LINE__,"south bound coordinate is not right for TRMM level 3 products");
2656 
2657  }
2658  else
2659  throw InternalErr(__FILE__,__LINE__,"The TRMM grid EastBoundingCoordinate doesn't exist.");
2660 
2661  if (0 == ind_elems[7].find("WestBoundingCoordinate")){
2662 
2663  size_t equal_pos = ind_elems[7].find_first_of('=');
2664  if(string::npos == equal_pos)
2665  throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for TRMM level 3 products");
2666 
2667  size_t scolon_pos = ind_elems[7].find_first_of(';');
2668  if(string::npos == scolon_pos)
2669  throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for TRMM level 3 products");
2670  if (equal_pos < scolon_pos){
2671  string lon_west_str = ind_elems[7].substr(equal_pos+1,scolon_pos-equal_pos-1);
2672  lon_west = strtof(lon_west_str.c_str(),NULL);
2673 //cerr<<"latres str is "<<lon_west_str <<endl;
2674 //cerr<<"latres is "<<lon_west <<endl;
2675  }
2676  else
2677  throw InternalErr(__FILE__,__LINE__,"south bound coordinate is not right for TRMM level 3 products");
2678 
2679  }
2680  else
2681  throw InternalErr(__FILE__,__LINE__,"The TRMM grid WestBoundingCoordinate doesn't exist.");
2682 
2683  if (false == check_reg_orig) {
2684  if (0 != ind_elems[8].find("Origin=SOUTHWEST"))
2685  throw InternalErr(__FILE__,__LINE__,"The TRMM grid origin is not SOUTHWEST.");
2686  }
2687 
2688  // Since we only treat the case when the Registration is center, so the size should be the
2689  // regular number size - 1.
2690  latsize =(int)((lat_north-lat_south)/lat_res);
2691  lonsize =(int)((lon_east-lon_west)/lon_res);
2692  lat_start = lat_south;
2693  lon_start = lon_west;
2694 }
2695 
2696 // Somehow the conversion of double to c++ string with sprintf causes the memory error in
2697 // the testing code. I used the following code to do the conversion. Most part of the code
2698 // in reverse, int_to_str and dtoa are adapted from geeksforgeeks.org
2699 
2700 // reverses a string 'str' of length 'len'
2701 void HDFCFUtil::rev_str(char *str, int len)
2702 {
2703  int i=0;
2704  int j=len-1;
2705  int temp = 0;
2706  while (i<j)
2707  {
2708  temp = str[i];
2709  str[i] = str[j];
2710  str[j] = temp;
2711  i++;
2712  j--;
2713  }
2714 }
2715 
2716 // Converts a given integer x to string str[]. d is the number
2717 // of digits required in output. If d is more than the number
2718 // of digits in x, then 0s are added at the beginning.
2719 int HDFCFUtil::int_to_str(int x, char str[], int d)
2720 {
2721  int i = 0;
2722  while (x)
2723  {
2724  str[i++] = (x%10) + '0';
2725  x = x/10;
2726  }
2727 
2728  // If number of digits required is more, then
2729  // add 0s at the beginning
2730  while (i < d)
2731  str[i++] = '0';
2732 
2733  rev_str(str, i);
2734  str[i] = '\0';
2735  return i;
2736 }
2737 
2738 // Converts a double floating point number to string.
2739 void HDFCFUtil::dtoa(double n, char *res, int afterpoint)
2740 {
2741  // Extract integer part
2742  int ipart = (int)n;
2743 
2744  // Extract the double part
2745  double fpart = n - (double)ipart;
2746 
2747  // convert integer part to string
2748  int i = int_to_str(ipart, res, 0);
2749 
2750  // check for display option after point
2751  if (afterpoint != 0)
2752  {
2753  res[i] = '.'; // add dot
2754 
2755  // Get the value of fraction part upto given no.
2756  // of points after dot. The third parameter is needed
2757  // to handle cases like 233.007
2758  fpart = fpart * pow(10, afterpoint);
2759 
2760  // A round-error of 1 is found when casting to the integer for some numbers.
2761  // We need to correct it.
2762  int final_fpart = (int)fpart;
2763  if(fpart -(int)fpart >0.5)
2764  final_fpart = (int)fpart +1;
2765  int_to_str(final_fpart, res + i + 1, afterpoint);
2766  }
2767 }
2768 
2769 
2770 string HDFCFUtil::get_double_str(double x,int total_digit,int after_point) {
2771 
2772  string str;
2773  if(x!=0) {
2774  char res[total_digit];
2775  for(int i = 0; i<total_digit;i++)
2776  res[i] = '\0';
2777  if (x<0) {
2778  str.push_back('-');
2779  dtoa(-x,res,after_point);
2780  for(int i = 0; i<total_digit;i++) {
2781  if(res[i] != '\0')
2782  str.push_back(res[i]);
2783  }
2784  }
2785  else {
2786  dtoa(x, res, after_point);
2787  for(int i = 0; i<total_digit;i++) {
2788  if(res[i] != '\0')
2789  str.push_back(res[i]);
2790  }
2791  }
2792 
2793  }
2794  else
2795  str.push_back('0');
2796 
2797 //std::cerr<<"str length is "<<str.size() <<std::endl;
2798 //std::cerr<<"str is "<<str <<std::endl;
2799  return str;
2800 
2801 }
2802 
2803 string HDFCFUtil::get_int_str(int x) {
2804 
2805  string str;
2806  if(x > 0 && x <10)
2807  str.push_back(x+'0');
2808 
2809  else if (x >10 && x<100) {
2810  str.push_back(x/10+'0');
2811  str.push_back(x%10+'0');
2812  }
2813  else {
2814  int num_digit = 0;
2815  int abs_x = (x<0)?-x:x;
2816  while(abs_x/=10)
2817  num_digit++;
2818  if(x<=0)
2819  num_digit++;
2820  char buf[num_digit];
2821  sprintf(buf,"%d",x);
2822  str.assign(buf);
2823 
2824  }
2825 
2826 //cerr<<"int str is "<<str<<endl;
2827  return str;
2828 
2829 }
2830 
2831 #if 0
2832 template<typename T>
2833 size_t HDFCFUtil::write_vector_to_file(const string & fname, const vector<T> &val, size_t dtypesize) {
2834 #endif
2835 #if 0
2836 size_t HDFCFUtil::write_vector_to_file(const string & fname, const vector<double> &val, size_t dtypesize) {
2837 
2838  size_t ret_val;
2839  FILE* pFile;
2840 cerr<<"Open a file with the name "<<fname<<endl;
2841  pFile = fopen(fname.c_str(),"wb");
2842  ret_val = fwrite(&val[0],dtypesize,val.size(),pFile);
2843 cerr<<"ret_val for write is "<<ret_val <<endl;
2844 //for (int i=0;i<val.size();i++)
2845 //cerr<<"val["<<i<<"] is "<<val[i]<<endl;
2846  fclose(pFile);
2847  return ret_val;
2848 }
2849 ssize_t HDFCFUtil::write_vector_to_file2(const string & fname, const vector<double> &val, size_t dtypesize) {
2850 
2851  ssize_t ret_val;
2852  //int fd = open(fname.c_str(),O_RDWR|O_CREAT|O_TRUNC,0666);
2853  int fd = open(fname.c_str(),O_RDWR|O_CREAT|O_EXCL,0666);
2854 cerr<<"The first val is "<<val[0] <<endl;
2855  ret_val = write(fd,&val[0],dtypesize*val.size());
2856  close(fd);
2857 cerr<<"ret_val for write is "<<ret_val <<endl;
2858 //for (int i=0;i<val.size();i++)
2859 //cerr<<"val["<<i<<"] is "<<val[i]<<endl;
2860  return ret_val;
2861 }
2862 #endif
2863 ssize_t HDFCFUtil::read_vector_from_file(int fd, vector<double> &val, size_t dtypesize) {
2864 
2865  ssize_t ret_val;
2866  //FILE* pFile;
2867  ret_val = read(fd,&val[0],val.size()*dtypesize);
2868 
2869 #if 0
2870 cerr<<"Open a file with the name "<<fname<<endl;
2871  pFile = fopen(fname.c_str(),"wb");
2872  ret_val = fwrite(&val[0],dtypesize,val.size(),pFile);
2873 cerr<<"ret_val for write is "<<ret_val <<endl;
2874 //for (int i=0;i<val.size();i++)
2875 //cerr<<"val["<<i<<"] is "<<val[i]<<endl;
2876  fclose(pFile);
2877 #endif
2878  return ret_val;
2879 }
2880 
2881 void HDFCFUtil::close_fileid(int32 sdfd, int32 fileid,int32 gridfd, int32 swathfd,bool pass_fileid) {
2882 
2883  if(false == pass_fileid) {
2884  if(sdfd != -1)
2885  SDend(sdfd);
2886  if(fileid != -1)
2887  Hclose(fileid);
2888 #ifdef USE_HDFEOS2_LIB
2889  if(gridfd != -1)
2890  GDclose(gridfd);
2891  if(swathfd != -1)
2892  SWclose(swathfd);
2893 
2894 #endif
2895  }
2896 
2897 }
2898 #if 0
2899 void HDFCFUtil::close_fileid(int32 sdfd, int32 fileid,int32 gridfd, int32 swathfd) {
2900 
2901  if(sdfd != -1)
2902  SDend(sdfd);
2903  if(fileid != -1)
2904  Hclose(fileid);
2905  if(gridfd != -1)
2906  GDclose(gridfd);
2907  if(swathfd != -1)
2908  SWclose(swathfd);
2909 
2910 }
2911 
2912 void HDFCFUtil::reset_fileid(int& sdfd, int& fileid,int& gridfd, int& swathfd) {
2913 
2914  sdfd = -1;
2915  fileid = -1;
2916  gridfd = -1;
2917  swathfd = -1;
2918 
2919 }
2920 #endif
SOType
const std::vector< VDATA * > & getVDATAs() const
Public interface to Obtain Vdata.
Definition: HDFSP.h:778
static void add_missing_cf_attrs(HDFSP::File *f, libdap::DAS &das)
Definition: HDFCFUtil.cc:1671
#define comment
Definition: lex.hdfeos.cc:606
static void parser_trmm_v7_gridheader(const std::vector< char > &value, int &latsize, int &lonsize, float &lat_start, float &lon_start, float &lat_res, float &lon_res, bool check_reg_orig)
Definition: HDFCFUtil.cc:2534
static bool insert_map(std::map< std::string, std::string > &m, std::string key, std::string val)
This is a safer way to insert and update a c++ map value. Otherwise, the local testsuite at The HDF G...
Definition: HDFCFUtil.cc:64
Definition: HDFCFUtil.h:49
string basename(const string &path)
Definition: dodsutil.h:133
static string lowercase(const string &s)
Convert a string to all lower case.
Definition: BESUtil.cc:182
static void check_obpg_global_attrs(HDFSP::File *f, std::string &scaling, float &slope, bool &global_slope_flag, float &intercept, bool &global_intercept_flag)
Definition: HDFCFUtil.cc:1384
This class retrieves all information from an HDF4 file. It is a container for SDS and Vdata...
Definition: HDFSP.h:727
const std::string & getNewName() const
Get the CF name(special characters replaced by underscores) of this field.
Definition: HDFSP.h:296
STL namespace.
This class retrieves all SDS objects and SD file attributes.
Definition: HDFSP.h:556
static void close_fileid(int32 sdfd, int32 file_id, int32 gridfd, int32 swathfd, bool pass_fileid_key)
Close HDF4 and HDF-EOS2 file IDs. For performance reasons, we want to keep HDF-EOS2/HDF4 IDs open for...
Definition: HDFCFUtil.cc:2881
static void handle_otherhdf_special_attrs(HDFSP::File *f, libdap::DAS &das)
Definition: HDFCFUtil.cc:1577
static class NCMLUtil overview
SD * getSD() const
Public interface to Obtain SD.
Definition: HDFSP.h:772
static void handle_merra_ceres_attrs_with_bes_keys(HDFSP::File *f, libdap::DAS &das, const std::string &filename)
Definition: HDFCFUtil.cc:2246
static void handle_vdata_attrs_with_desc_key(HDFSP::File *f, libdap::DAS &das)
Definition: HDFCFUtil.cc:2295
static void Handle_NameClashing(std::vector< std::string > &newobjnamelist)
General routines to handle name clashings.
Definition: HDFCFUtil.cc:176
static void correct_fvalue_type(libdap::AttrTable *at, int32 dtype)
CF requires the _FillValue attribute datatype is the same as the corresponding field datatype...
Definition: HDFCFUtil.cc:395
const int getFieldType() const
Definition: HDFSP.h:399
static std::string get_int_str(int)
Definition: HDFCFUtil.cc:2803
static std::string get_double_str(double, int, int)
Definition: HDFCFUtil.cc:2770
#define NULL
Definition: wcsUtil.h:65
One instance of this class represents one SDS object.
Definition: HDFSP.h:344
#define MAX_NON_SCALE_SPECIAL_VALUE
Definition: HDFCFUtil.h:41
static void gen_unique_name(std::string &str, std::set< std::string > &namelist, int &clash_index)
Obtain the unique name for the clashed names and save it to set namelist.
Definition: HDFCFUtil.cc:110
static void dtoa(double, char *, int)
Definition: HDFCFUtil.cc:2739
#define GET_INTERCEPT(TYPE, CAST)
static std::string print_type(int32)
Print datatype in string.
Definition: HDFCFUtil.cc:290
static int int_to_str(int, char str[], int)
Definition: HDFCFUtil.cc:2719
const std::string & getPath() const
Obtain the path of the file.
Definition: HDFSP.h:766
static void add_obpg_special_attrs(HDFSP::File *f, libdap::DAS &das, HDFSP::SDField *spsds, std::string &scaling, float &slope, bool &global_slope_flag, float &intercept, bool &global_intercept_flag)
Definition: HDFCFUtil.cc:1452
static void Split(const char *s, int len, char sep, std::vector< std::string > &names)
From a string separated by a separator to a list of string, for example, split "ab,c" to {"ab","c"}.
Definition: HDFCFUtil.cc:38
std::string geodim
Definition: HDFCFUtil.h:52
static std::string escattr(std::string s)
A customized escaping function to escape special characters following OPeNDAP's escattr function that...
Definition: HDFCFUtil.cc:2502
static std::string print_attr(int32, int, void *)
Print attribute values in string.
Definition: HDFCFUtil.cc:184
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:453
const std::vector< Attribute * > & getAttributes() const
Get the attributes of this field.
Definition: HDFSP.h:314
const std::vector< Attribute * > & getAttributes() const
Public interface to obtain the SD(file) attributes.
Definition: HDFSP.h:579
static BESLog * TheLog()
Definition: BESLog.cc:347
static void rev_str(char *str, int len)
Definition: HDFCFUtil.cc:2701
static ssize_t read_vector_from_file(int fd, vector< double > &, size_t)
Definition: HDFCFUtil.cc:2863
static std::string get_CF_string(std::string s)
Change special characters to "_".
Definition: HDFCFUtil.cc:80
static bool check_beskeys(const std::string &key)
Check the BES key. This function will check a BES key specified at the file h4.conf.in. If the key's value is either true or yes. The handler claims to find a key and will do some operations. Otherwise, will do different operations. For example, One may find a line H4.EnableCF=true at h4.conf.in. That means, the HDF4 handler will handle the HDF4 files by following CF conventions.
Definition: HDFCFUtil.cc:17
static void LatLon2DSubset(T *outlatlon, int ydim, int xdim, T *latlon, int32 *offset, int32 *count, int32 *step)
Definition: HDFCFUtil.cc:353
SPType getSPType() const
Obtain special HDF4 product type.
Definition: HDFSP.h:750
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
int32 getType() const
Get the data type of this field.
Definition: HDFSP.h:308
#define GET_SLOPE(TYPE, CAST)
static void correct_scale_offset_type(libdap::AttrTable *at)
CF requires the scale_factor and add_offset attribute datatypes hold the same datatype. So far we haven't found that scale_factor and add_offset attributes hold different datatypes in NASA files. But just in case, we implement a BES key to give users a chance to check this. By default, the key is always off.
Definition: HDFCFUtil.cc:462
bool Has_Dim_NoScale_Field() const
This file has a field that is a SDS dimension but no dimension scale.
Definition: HDFSP.h:757
const std::vector< SDField * > & getFields() const
Public interface to obtain information of all SDS vectors(objects).
Definition: HDFSP.h:573
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:48
#define MIN_NON_SCALE_SPECIAL_VALUE
Definition: HDFCFUtil.h:44