OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
HDFSP.cc
Go to the documentation of this file.
1 // This file is part of the hdf4 data handler for the OPeNDAP data server.
19 
28 
30 #include <sstream>
31 #include <algorithm>
32 #include <functional>
33 #include <vector>
34 #include <map>
35 #include <set>
36 #include<libgen.h>
37 #include "HDFCFUtil.h"
38 #include "HDFSP.h"
39 #include "dodsutil.h"
40 
41 const char *_BACK_SLASH= "/";
42 
43 using namespace HDFSP;
44 using namespace std;
45 
46 // Convenient function to handle exceptions
47 template < typename T, typename U, typename V, typename W, typename X > static void
48 _throw5 (const char *fname, int line, int numarg,
49  const T & a1, const U & a2, const V & a3, const W & a4, const X & a5)
50 {
51  std::ostringstream ss;
52  ss << fname << ":" << line << ":";
53  for (int i = 0; i < numarg; ++i) {
54  ss << " ";
55  switch (i) {
56 
57  case 0:
58  ss << a1;
59  break;
60  case 1:
61  ss << a2;
62  break;
63  case 2:
64  ss << a3;
65  break;
66  case 3:
67  ss << a4;
68  break;
69  case 4:
70  ss << a5;
71  break;
72  }
73  }
74  throw Exception (ss.str ());
75 }
76 
78 // number of arguments.
80 #define throw1(a1) _throw5(__FILE__, __LINE__, 1, a1, 0, 0, 0, 0)
81 #define throw2(a1, a2) _throw5(__FILE__, __LINE__, 2, a1, a2, 0, 0, 0)
82 #define throw3(a1, a2, a3) _throw5(__FILE__, __LINE__, 3, a1, a2, a3, 0, 0)
83 #define throw4(a1, a2, a3, a4) _throw5(__FILE__, __LINE__, 4, a1, a2, a3, a4, 0)
84 #define throw5(a1, a2, a3, a4, a5) _throw5(__FILE__, __LINE__, 5, a1, a2, a3, a4, a5)
85 
86 #define assert_throw0(e) do { if (!(e)) throw1("assertion failure"); } while (false)
87 #define assert_range_throw0(e, ge, l) assert_throw0((ge) <= (e) && (e) < (l))
88 
89 
90 // Convenient function to release resources.
91 struct delete_elem
92 {
93  template < typename T > void operator () (T * ptr)
94  {
95  delete ptr;
96  }
97 };
98 
99 
100 // Class File destructor
102 {
103 
104  // Release SD resources
105  if (this->sdfd != -1) {
106  if (sd != NULL)
107  delete sd;
108  // No need to close SD interface since for performance reasons
109  // it is handled(opened/closed) at the top level(HDF4RequestHandler.cc)
110  // KY 2014-02-18
111  //SDend (this->sdfd);
112  }
113 
114  // Close V interface IDs and release vdata resources
115  if (this->fileid != -1) {
116 
117  for (vector < VDATA * >::const_iterator i = this->vds.begin ();
118  i != this->vds.end (); ++i) {
119  delete *i;
120  }
121 
122  for (vector < AttrContainer * >::const_iterator i = this->vg_attrs.begin ();
123  i != this->vg_attrs.end (); ++i) {
124  delete *i;
125  }
126 
127  Vend (this->fileid);
128  // No need to close H interface since for performance reasons
129  // it is handled(opened/closed) at the top level(HDF4RequestHandler.cc)
130  //Hclose (this->fileid);
131  }
132 }
133 
134 // Destructor to release vdata resources
136 {
137  // Release vdata field pointers
138  std::for_each (this->vdfields.begin (), this->vdfields.end (),
139  delete_elem ());
140 
141  // Release vdata attributes
142  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
143 }
144 
145 // Destructor to release SD resources
147 {
148  // Release vdata attributes
149  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
150 
151  // Release SD field pointers
152  std::for_each (this->sdfields.begin (), this->sdfields.end (),
153  delete_elem ());
154 
155 }
156 
157 // Destructor to release SD field resources
159 {
160  // Release dimension resources
161  std::for_each (this->dims.begin (), this->dims.end (), delete_elem ());
162 
163  // Release corrected dimension resources
164  std::for_each (this->correcteddims.begin (), this->correcteddims.end (),
165  delete_elem ());
166 
167  // Release attribute container dims_info resources(Only apply for the OTHERHDF case)
168  std::for_each (this->dims_info.begin (), this->dims_info.end (), delete_elem ());
169 }
170 
171 // Vdata field constructors, nothing needs to do here. We don't provide vdata dimensions.
172 // Only when mapping to DDS (at hdfdesc.cc,search VDFDim0), we add the dimension info. to DDS. The addition
173 // may not be in a good place, however, the good part is that we don't need to allocate dimension resources
174 // for vdata.
175 
177 {
178 }
179 
180 // We only need to release attributes since that's shared for both Vdata fields and SDS fields.
182 {
183  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
184 }
185 
186 // Release attribute container resources. This should only apply to the OTHERHDF case.
188 {
189  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
190 }
191 
192 
193 // Retrieve all the information from an HDF file; this is the same approach
194 // as the way to handle HDF-EOS2 files.
195 File *
196 File::Read (const char *path, int32 mysdid, int32 myfileid)
197 throw (Exception)
198 {
199 
200  // Allocate a new file object.
201  File *file = new File (path);
202 //cerr<<"FIle is opened for HDF4 "<<endl;
203 
204 #if 0
205  int32 mysdid = -1;
206 
207  // Obtain the SD ID.
208  if ((mysdid =
209  SDstart (const_cast < char *>(file->path.c_str ()),
210  DFACC_READ)) == -1) {
211  delete file;
212  throw2 ("SDstart", path);
213  }
214 #endif
215 
216  // Old comments just for reminders(KY 2014-02-18)
217  // A strange compiling bug was found if we don't pass the file id to this fuction.
218  // It will always give 0 number as the ID and the HDF4 library doesn't complain!!
219  // Will try dumplicating the problem and submit a bug report. KY 2010-7-14
220  file->sdfd = mysdid;
221  file->fileid = myfileid;
222 
223  // Start V interface
224  int32 status = Vstart (file->fileid);
225  if (status == FAIL) {
226  delete file;
227  throw2 ("Cannot start vdata/vgroup interface", path);
228  }
229 
230  try {
231  // Read SDS info.
232  file->sd = SD::Read (file->sdfd, file->fileid);
233 
234  // Handle lone vdatas, non-lone vdatas will be handled in Prepare().
235  // Read lone vdata.
236  file->ReadLoneVdatas(file);
237  }
238  catch(...) {
239  delete file;
240  throw;
241  }
242 
243  return file;
244 }
245 
246 // Retrieve all the information from the additional SDS objects of an HDF file; this is the same approach
247 // as the way to handle other HDF4 files.
248 File *
249 File::Read_Hybrid (const char *path, int32 mysdid, int32 myfileid)
250 throw (Exception)
251 {
252  // New File
253  File *file = new File (path);
254 //cerr<<"File is opened for HDF4 "<<endl;
255 
256 #if 0
257  // Obtain SD interface
258  int32 mysdid = -1;
259  if ((mysdid =
260  SDstart (const_cast < char *>(file->path.c_str ()),
261  DFACC_READ)) == -1) {
262  delete file;
263  throw2 ("SDstart", path);
264  }
265 #endif
266 
267  // Old comments just for reminders. The HDF4 issue may still exist. KY 2014-02-18
268  // A strange compiling bug was found if we don't pass the file id to this fuction.
269  // It will always give 0 number as the ID and the HDF4 library doesn't complain!!
270  // Will try dumplicating the problem and submit a bug report. KY 2010-7-14
271  file->sdfd = mysdid;
272  file->fileid = myfileid;
273 
274  // Start V interface
275  int status = Vstart (file->fileid);
276  if (status == FAIL) {
277  delete file;
278  throw2 ("Cannot start vdata/vgroup interface", path);
279  }
280 
281  try {
282 
283  // Retrieve extra SDS info.
284  file->sd = SD::Read_Hybrid(file->sdfd, file->fileid);
285 
286  // Retrieve lone vdata info.(HDF-EOS2 doesn't support any lone vdata)
287  file->ReadLoneVdatas(file);
288 
289  // Retrieve extra non-lone vdata in the hybrid HDF-EOS2 file
290  file->ReadHybridNonLoneVdatas(file);
291  }
292  catch(...) {
293  delete file;
294  throw;
295  }
296 
297  return file;
298 }
299 
300 // Retrieve lone vdata info.
301 void
303 
304  int status = -1;
305  // No need to start V interface again
306 #if 0
307  // Start V interface
308  int status = Vstart (file->fileid);
309  if (status == FAIL)
310  throw2 ("Cannot start vdata/vgroup interface", path);
311 #endif
312 
313  // Obtain number of lone vdata.
314  int num_lone_vdata = VSlone (file->fileid, NULL, 0);
315 
316  if (num_lone_vdata == FAIL)
317  throw2 ("Fail to obtain lone vdata number", path);
318 
319  // Currently the vdata name buffer has to be static allocated according to HDF4 reference manual. KY 2010-7-14
320  // Now HDF4 provides a dynamic way to allocate the length of vdata_class, should update to use that in the future.
321  // Documented in a jira ticket HFRHANDLER-168.
322  // KY 2013-07-11
323  char vdata_class[VSNAMELENMAX], vdata_name[VSNAMELENMAX];
324 
325  if (num_lone_vdata > 0) {
326 
327  vector<int32>ref_array;
328  ref_array.resize(num_lone_vdata);
329 
330  if (VSlone (file->fileid, &ref_array[0], num_lone_vdata) == FAIL) {
331  throw2 ("cannot obtain lone vdata reference arrays", path);
332  }
333 
334  for (int i = 0; i < num_lone_vdata; i++) {
335 
336  int32 vdata_id = -1;
337 
338  vdata_id = VSattach (file->fileid, ref_array[i], "r");
339  if (vdata_id == FAIL) {
340  throw2 ("Fail to attach Vdata", path);
341  }
342  status = VSgetclass (vdata_id, vdata_class);
343  if (status == FAIL) {
344  VSdetach (vdata_id);
345  throw2 ("Fail to obtain Vdata class", path);
346  }
347 
348  if (VSgetname (vdata_id, vdata_name) == FAIL) {
349  VSdetach (vdata_id);
350  throw3 ("Fail to obtain Vdata name", path, vdata_name);
351  }
352 
353  // Ignore any vdata that is either an HDF4 attribute or is used
354  // to store internal data structures.
355  if (VSisattr (vdata_id) == TRUE
356  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
357  strlen (_HDF_CHK_TBL_CLASS))
358  || !strncmp (vdata_class, _HDF_SDSVAR, strlen (_HDF_SDSVAR))
359  || !strncmp (vdata_class, _HDF_CRDVAR, strlen (_HDF_CRDVAR))
360  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
361  || !strncmp (vdata_class, DIM_VALS01, strlen (DIM_VALS01))
362  || !strncmp (vdata_class, RIGATTRCLASS, strlen (RIGATTRCLASS))
363  || !strncmp (vdata_name, RIGATTRNAME, strlen (RIGATTRNAME))) {
364 
365  status = VSdetach (vdata_id);
366  if (status == FAIL) {
367  throw3 ("VSdetach failed ", "Vdata name ", vdata_name);
368  }
369  }
370 
371  else {
372  VDATA*vdataobj = NULL;
373 
374  try {
375  // Read vdata information
376  vdataobj = VDATA::Read (vdata_id, ref_array[i]);
377  }
378  catch (...) {
379  VSdetach(vdata_id);
380  throw;
381  }
382 
383  // We want to map fields of vdata with more than 10 records to DAP variables
384  // and we need to add the path and vdata name to the new vdata field name
385  if (!vdataobj->getTreatAsAttrFlag ()) {
386  for (std::vector < VDField * >::const_iterator it_vdf =
387  vdataobj->getFields ().begin ();
388  it_vdf != vdataobj->getFields ().end (); it_vdf++) {
389 
390  // vdata name conventions.
391  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
392  (*it_vdf)->newname =
393  "vdata_" + vdataobj->newname + "_vdf_" +
394  (*it_vdf)->name;
395 
396  //Make sure the name is following CF, KY 2012-6-26
397  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
398  }
399  }
400 
401  // Save this vdata info. in the file instance.
402  file->vds.push_back (vdataobj);
403 
404  // THe following code should be replaced by using the VDField member functions in the future
405  // The code has largely overlapped with VDField member functions, but not for this release.
406  // KY 2010-8-11
407 
408  // To know if the data product is CERES, we need to check Vdata CERE_metadata(CERE_META_NAME).
409  // One field name LOCALGRANULEID(CERE_META_FIELD_NAME) includes the product name.
410  // We want to assign the filetype of this CERES file based on the LOCALGRANULEID.
411  // Please note that CERES products we support to follow CF are pure HDF4 files.
412  // For hybrid HDF-EOS2 files, this if loop is simply skipped.
413 
414  // When the vdata name indicates this is a CERES product, we need to do the following:
415  if (false == strncmp
416  (vdata_name, CERE_META_NAME, strlen (CERE_META_NAME))) {
417 
418  char *fieldname = NULL;
419 
420  // Obtain number of vdata fields
421  int num_field = VFnfields (vdata_id);
422  if (num_field == FAIL) {
423  VSdetach (vdata_id);
424  throw3 ("number of fields at Vdata ", vdata_name," is -1");
425  }
426 
427  // Search through the number of vdata fields
428  for (int j = 0; j < num_field; j++) {
429 
430  fieldname = VFfieldname (vdata_id, j);
431  if (fieldname == NULL) {
432  VSdetach (vdata_id);
433  throw5 ("vdata ", vdata_name, " field index ", j,
434  " field name is NULL.");
435  }
436 
437  // If the field name matches CERES's specific field name"LOCALGRANULEID"
438  if (!strcmp (fieldname, CERE_META_FIELD_NAME)) {
439 
440  int32 fieldsize = -1;
441  int32 nelms = -1;
442 
443  // Obtain field size
444  fieldsize = VFfieldesize (vdata_id, j);
445  if (fieldsize == FAIL) {
446  VSdetach (vdata_id);
447  throw5 ("vdata ", vdata_name, " field ",fieldname, " size is wrong.");
448  }
449 
450  // Obtain number of elements
451  nelms = VSelts (vdata_id);
452  if (nelms == FAIL) {
453  VSdetach (vdata_id);
454  throw5 ("vdata ", vdata_name,
455  " number of field record ", nelms," is wrong.");
456  }
457 
458  // Allocate data buf
459  char *databuf = (char *) malloc (fieldsize * nelms);
460  if (databuf == NULL) {
461  VSdetach (vdata_id);
462  throw1("no enough memory to allocate buffer.");
463  }
464 
465  // Initialize the seeking process
466  if (VSseek (vdata_id, 0) == FAIL) {
467  VSdetach (vdata_id);
468  free (databuf);
469  throw5 ("vdata ", vdata_name, "field ",
470  CERE_META_FIELD_NAME," VSseek failed.");
471  }
472 
473  // The field to seek is CERE_META_FIELD_NAME
474  if (VSsetfields (vdata_id, CERE_META_FIELD_NAME) == FAIL) {
475  VSdetach (vdata_id);
476  free (databuf);
477  throw5 ("vdata ", vdata_name, "field ",
478  CERE_META_FIELD_NAME," VSsetfields failed.");
479  }
480 
481  // Read this vdata field value
482  if (VSread(vdata_id, (uint8 *) databuf, 1,FULL_INTERLACE)
483  == FAIL) {
484  VSdetach (vdata_id);
485  free (databuf);
486  throw5 ("vdata ", vdata_name, "field ",
487  CERE_META_FIELD_NAME," VSread failed.");
488  }
489 
490  // Assign the corresponding special product indicator we supported for CF
491  if (!strncmp(databuf, CER_AVG_NAME,strlen (CER_AVG_NAME)))
492  file->sptype = CER_AVG;
493  else if (!strncmp
494  (databuf, CER_ES4_NAME,strlen(CER_ES4_NAME)))
495  file->sptype = CER_ES4;
496  else if (!strncmp
497  (databuf, CER_CDAY_NAME,strlen (CER_CDAY_NAME)))
498  file->sptype = CER_CDAY;
499  else if (!strncmp
500  (databuf, CER_CGEO_NAME,strlen (CER_CGEO_NAME)))
501  file->sptype = CER_CGEO;
502  else if (!strncmp
503  (databuf, CER_SRB_NAME,strlen (CER_SRB_NAME)))
504  file->sptype = CER_SRB;
505  else if (!strncmp
506  (databuf, CER_SYN_NAME,strlen (CER_SYN_NAME)))
507  file->sptype = CER_SYN;
508  else if (!strncmp
509  (databuf, CER_ZAVG_NAME,
510  strlen (CER_ZAVG_NAME)))
511  file->sptype = CER_ZAVG;
512  else;
513 
514  free (databuf);
515  }
516  }
517  }
518  }
519 
520  VSdetach (vdata_id);
521  }
522  }
523 }
524 
525 // Handle non-attribute non-lone vdata for Hybrid HDF-EOS2 files.
526 void
528 
529 
530  int32 status = -1;
531  int32 file_id = -1;
532  int32 vgroup_id = -1;
533  int32 vdata_id = -1;
534  //int32 vgroup_ref = -1;
535  //int32 obj_index = -1;
536  //int32 num_of_vg_objs = -1;
537  int32 obj_tag = -1;
538  int32 obj_ref = -1;
539 
540  int32 lone_vg_number = 0;
541  int32 num_of_lones = -1;
542  int32 num_gobjects = 0;
543 
544  // This can be updated in the future with new HDF4 APIs that can provide the actual length of an object name.
545  // Documented in a jira ticket HFRHANDLER-168.
546  // KY 2013-07-11
547  char vdata_name[VSNAMELENMAX];
548  char vdata_class[VSNAMELENMAX];
549  char vgroup_name[VGNAMELENMAX*4];
550  char vgroup_class[VGNAMELENMAX*4];
551 
552  // Full path of this vgroup
553  char *full_path = NULL;
554 
555  // Copy of a full path of this vgroup
556  char *cfull_path = NULL;
557 
558  // Obtain H interface ID
559  file_id = file->fileid;
560 
561  // No need to start V interface again.
562 #if 0
563  // Start V interface
564  status = Vstart (file_id);
565  if (status == FAIL)
566  throw2 ("Cannot start vdata/vgroup interface", path);
567 #endif
568 
569  // No NASA HDF4 files have the vgroup that forms a ring; so ignore this case.
570  // First, call Vlone with num_of_lones set to 0 to get the number of
571  // lone vgroups in the file, but not to get their reference numbers.
572  num_of_lones = Vlone (file_id, NULL, 0);
573  if (num_of_lones == FAIL)
574  throw3 ("Fail to obtain lone vgroup number", "file id is", file_id);
575 
576  // if there are any lone vgroups,
577  if (num_of_lones > 0) {
578 
579  // Use the num_of_lones returned to allocate sufficient space for the
580  // buffer ref_array to hold the reference numbers of all lone vgroups,
581 
582  // Use vectors to avoid the clean-up of the memory
583  vector<int32>ref_array;
584  ref_array.resize(num_of_lones);
585 
586  // Call Vlone again to retrieve the reference numbers into
587  // the buffer ref_array.
588  num_of_lones = Vlone (file_id, &ref_array[0], num_of_lones);
589  if (num_of_lones == FAIL) {
590  throw3 ("Cannot obtain lone vgroup reference arrays ",
591  "file id is ", file_id);
592  }
593 
594  // Loop the lone vgroups.
595  for (lone_vg_number = 0; lone_vg_number < num_of_lones;
596  lone_vg_number++) {
597 
598  // Attach to the current vgroup
599  vgroup_id = Vattach (file_id, ref_array[lone_vg_number], "r");
600  if (vgroup_id == FAIL) {
601  throw3 ("Vattach failed ", "Reference number is ",
602  ref_array[lone_vg_number]);
603  }
604 
605  // Obtain the vgroup name.
606  status = Vgetname (vgroup_id, vgroup_name);
607  if (status == FAIL) {
608  Vdetach (vgroup_id);
609  throw3 ("Vgetname failed ", "vgroup_id is ", vgroup_id);
610  }
611 
612  // Obtain the vgroup_class name.
613  status = Vgetclass (vgroup_id, vgroup_class);
614  if (status == FAIL) {
615  Vdetach (vgroup_id);
616  throw3 ("Vgetclass failed ", "vgroup_name is ", vgroup_name);
617  }
618 
619  //Ignore internal HDF groups
620  if (strcmp (vgroup_class, _HDF_ATTRIBUTE) == 0
621  || strcmp (vgroup_class, _HDF_VARIABLE) == 0
622  || strcmp (vgroup_class, _HDF_DIMENSION) == 0
623  || strcmp (vgroup_class, _HDF_UDIMENSION) == 0
624  || strcmp (vgroup_class, _HDF_CDF) == 0
625  || strcmp (vgroup_class, GR_NAME) == 0
626  || strcmp (vgroup_class, RI_NAME) == 0) {
627  Vdetach(vgroup_id);
628  continue;
629  }
630 
631  // Obtain number of objects under this vgroup
632  num_gobjects = Vntagrefs (vgroup_id);
633  if (num_gobjects < 0) {
634  Vdetach (vgroup_id);
635  throw3 ("Vntagrefs failed ", "vgroup_name is ", vgroup_name);
636  }
637 
638  // Allocate enough buffer for the full path
639  // MAX_FULL_PATH_LEN(1024) is long enough
640  // to cover any HDF4 object path for all NASA HDF4 products.
641  // We replace strcpy and strcat with strncpy and strncat as suggested. KY 2013-08-29
642  full_path = (char *) malloc (MAX_FULL_PATH_LEN);
643  if (full_path == NULL) {
644  Vdetach (vgroup_id);
645  throw1 ("No enough memory to allocate the buffer.");
646  }
647  memset(full_path,'\0',MAX_FULL_PATH_LEN);
648 
649  // Obtain the full path of this vgroup
650  strncpy (full_path,_BACK_SLASH,strlen(_BACK_SLASH));
651  strncat(full_path,vgroup_name,strlen(vgroup_name));
652  strncat(full_path,_BACK_SLASH,strlen(_BACK_SLASH));
653 
654  // Make a copy the current vgroup full path since full path may be passed to a recursive routine
655  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
656  if (cfull_path == NULL) {
657  Vdetach (vgroup_id);
658  free (full_path);
659  throw1 ("No enough memory to allocate the buffer.");
660  }
661  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
662  strncpy(cfull_path,full_path,strlen(full_path));
663 
664  // Loop all vgroup objects
665  for (int i = 0; i < num_gobjects; i++) {
666 
667  // Obtain the object tag/ref pair of an object
668  if (Vgettagref (vgroup_id, i, &obj_tag, &obj_ref) == FAIL) {
669  Vdetach (vgroup_id);
670  free (full_path);
671  free (cfull_path);
672  throw5 ("Vgettagref failed ", "vgroup_name is ",
673  vgroup_name, " reference number is ", obj_ref);
674  }
675 
676  // If the object is a vgroup,always pass the original full path to its decendant vgroup
677  // The reason to use a copy is because the full_path will be changed when it goes down to its descendant.
678  if (Visvg (vgroup_id, obj_ref) == TRUE) {
679  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
680  full_path[strlen(cfull_path)]='\0';
681  obtain_vdata_path (file_id, full_path, obj_ref);
682  }
683 
684  // If this object is vdata
685  else if (Visvs (vgroup_id, obj_ref)) {
686 
687  // Obtain vdata ID
688  vdata_id = VSattach (file_id, obj_ref, "r");
689  if (vdata_id == FAIL) {
690  Vdetach (vgroup_id);
691  free (full_path);
692  free (cfull_path);
693  throw5 ("VSattach failed ", "vgroup_name is ",
694  vgroup_name, " reference number is ",
695  obj_ref);
696  }
697 
698  // Obtain vdata name
699  status = VSgetname (vdata_id, vdata_name);
700  if (status == FAIL) {
701  Vdetach (vgroup_id);
702  free (full_path);
703  free (cfull_path);
704  throw5 ("VSgetclass failed ", "vgroup_name is ",
705  vgroup_name, " reference number is ",
706  obj_ref);
707  }
708 
709  // Obtain vdata class name
710  status = VSgetclass (vdata_id, vdata_class);
711  if (status == FAIL) {
712  Vdetach (vgroup_id);
713  free (full_path);
714  free (cfull_path);
715  throw5 ("VSgetclass failed ", "vgroup_name is ",
716  vgroup_name, " reference number is ",
717  obj_ref);
718  }
719 
720  // Ignore the vdata to store internal HDF structure and the vdata used as an attribute
721  if (VSisattr (vdata_id) == TRUE
722  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
723  strlen (_HDF_CHK_TBL_CLASS))
724  || !strncmp (vdata_class, _HDF_SDSVAR,
725  strlen (_HDF_SDSVAR))
726  || !strncmp (vdata_class, _HDF_CRDVAR,
727  strlen (_HDF_CRDVAR))
728  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
729  || !strncmp (vdata_class, DIM_VALS01,
730  strlen (DIM_VALS01))
731  || !strncmp (vdata_class, RIGATTRCLASS,
732  strlen (RIGATTRCLASS))
733  || !strncmp (vdata_name, RIGATTRNAME,
734  strlen (RIGATTRNAME))) {
735 
736  status = VSdetach (vdata_id);
737  if (status == FAIL) {
738  Vdetach (vgroup_id);
739  free (full_path);
740  free (cfull_path);
741  throw3 ("VSdetach failed ",
742  "Vdata is under vgroup ", vgroup_name);
743  }
744 
745  }
746  // Now user-defined vdata
747  else {
748 
749  VDATA *vdataobj = NULL;
750  try {
751  vdataobj = VDATA::Read (vdata_id, obj_ref);
752  }
753  catch(...) {
754  free (full_path);
755  free (cfull_path);
756  VSdetach(vdata_id);
757  Vdetach (vgroup_id);
758  throw;
759  }
760 
761  vdataobj->newname = full_path +vdataobj->name;
762 
763  //We want to map fields of vdata with more than 10 records to DAP variables
764  // and we need to add the path and vdata name to the new vdata field name
765  if (!vdataobj->getTreatAsAttrFlag ()) {
766  for (std::vector <VDField * >::const_iterator it_vdf =
767  vdataobj->getFields ().begin ();
768  it_vdf != vdataobj->getFields ().end ();
769  it_vdf++) {
770 
771  // Change vdata name conventions.
772  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
773 
774  (*it_vdf)->newname =
775  "vdata" + vdataobj->newname + "_vdf_" + (*it_vdf)->name;
776 
777  //Make sure the name is following CF, KY 2012-6-26
778  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
779  }
780 
781  }
782 
783  // Make sure the name is following CF
784  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
785 
786  // Save back this vdata
787  this->vds.push_back (vdataobj);
788 
789  status = VSdetach (vdata_id);
790  if (status == FAIL) {
791  Vdetach (vgroup_id);
792  free (full_path);
793  free (cfull_path);
794  throw3 ("VSdetach failed ",
795  "Vdata is under vgroup ", vgroup_name);
796  }
797  }
798  }
799 
800  //Ignore the handling of SDS objects. They are handled elsewhere.
801  else;
802  }
803  free (full_path);
804  free (cfull_path);
805 
806  status = Vdetach (vgroup_id);
807  if (status == FAIL) {
808  throw3 ("Vdetach failed ", "vgroup_name is ", vgroup_name);
809  }
810  }//end of the for loop
811 
812  }// end of the if loop
813 
814 }
815 
816 // Check if this is a special SDS(MOD08_M3) that needs the connection between CVs and dimension names.
817 // General algorithm:
818 // 1. Insert a set for fields' dimensions,
819 // 2. in the mean time, insert a set for 1-D field
820 // 3. For each dimension in the set, search if one can find the corresponding field that has the same dimension name in the set.
821 // Return false if non-found occurs.
822 // Else return true.
823 
824 bool
825 File::Check_update_special(const string& grid_name) throw(Exception) {
826 
827  set<string> dimnameset;
828  set<SDField*> fldset;
829 
830  // Build up a dimension set and a 1-D field set.
831  // We already know that XDim and YDim should be in the dimension set. so inserting them.
832  // Hopefully by doing this, we can save some time since many variables have dimensions
833  // "XDim" and "YDim" and excluding "XDim" and "YDim" may save some time if there are many
834  // dimensions in the dimnameset.
835 
836  string FullXDim,FullYDim;
837  FullXDim="XDim:" ;
838  FullYDim="YDim:";
839 
840  FullXDim= FullXDim+grid_name;
841  FullYDim =FullYDim+grid_name;
842 
843  for (vector < SDField * >::const_iterator i =
844  this->sd->getFields ().begin ();
845  i != this->sd->getFields ().end (); ++i) {
846 
847  for (vector < Dimension * >::const_iterator k =
848  (*i)->getDimensions ().begin ();
849  k != (*i)->getDimensions ().end (); ++k) {
850  if((*k)->getName() !=FullXDim && (*k)->getName()!=FullYDim)
851  dimnameset.insert((*k)->getName());
852  }
853 
854  if (1==(*i)->getRank())
855  fldset.insert((*i));
856 
857  }
858 
859 //cerr<<"field size is= "<<fldset.size() <<endl;
860 //cerr<<"dim. size is= "<<dimnameset.size() <<endl;
861 
862  // Check if all dimension names in the dimension set can be found in the 1-D variable sets. Moreover, the size of a dimension
863  // should be smaller or the same as the size of 1-D variable.
864  // Plus XDim and YDim for number of dimensions
865  if (fldset.size() < (dimnameset.size()+2))
866  return false;
867 
868  int total_num_dims = 0;
869  size_t grid_name_size = grid_name.size();
870  string reduced_dimname;
871 
872  for(set<SDField*>::const_iterator j =
873  fldset.begin(); j!=fldset.end(); ++ j) {
874 
875  size_t dim_size = ((*j)->getDimensions())[0]->getName().size();
876  if( dim_size > grid_name_size){
877  reduced_dimname = ((*j)->getDimensions())[0]->getName().substr(0,dim_size-grid_name_size-1);
878  if ((*j)->getName() == reduced_dimname)
879  total_num_dims++;
880  }
881  }
882 
883  if((size_t)total_num_dims != (dimnameset.size()+2))
884  return false;
885 
886  // Updated dimension names for all variables: removing the grid_name prefix.
887  for (vector < SDField * >::const_iterator i =
888  this->sd->getFields ().begin ();
889  i != this->sd->getFields ().end (); ++i) {
890 
891  for (vector < Dimension * >::const_iterator k =
892  (*i)->getDimensions ().begin ();
893  k != (*i)->getDimensions ().end (); ++k) {
894 
895  size_t dim_size = (*k)->getName().size();
896  if( dim_size > grid_name_size){
897  reduced_dimname = (*k)->getName().substr(0,dim_size-grid_name_size-1);
898  (*k)->name = reduced_dimname;
899  }
900  else // Here we enforce that the dimension name has the grid suffix. This can be lifted in the future. KY 2014-01-16
901  return false;
902  }
903 
904  }
905 
906  // Build up Dimensions for DDS and DAS.
907  for(std::set<SDField*>::const_iterator j =
908  fldset.begin(); j!=fldset.end(); ++ j) {
909 
910  if ((*j)->getName() == ((*j)->getDimensions())[0]->getName()) {
911 
912  if("XDim" == (*j)->getName()){
913  std::string tempunits = "degrees_east";
914  (*j)->setUnits (tempunits);
915  (*j)->fieldtype = 2;
916  }
917 
918  else if("YDim" == (*j)->getName()){
919  std::string tempunits = "degrees_north";
920  (*j)->setUnits (tempunits);
921  (*j)->fieldtype = 1;
922  }
923 
924  else if("Pressure_Level" == (*j)->getName()) {
925  std::string tempunits = "hPa";
926  (*j)->setUnits (tempunits);
927  (*j)->fieldtype = 3;
928  }
929  else {
930  std::string tempunits = "level";
931  (*j)->setUnits (tempunits);
932  (*j)->fieldtype = 3;
933  }
934  }
935  }
936 
937  return true;
938 
939 }
940 
941 #if 0
942 // This routine is used to check if this grid is a special MOD08M3-like grid in DDS-build.
943 // Check_if_special is used when building DAS. The reason to separate is that we pass the
944 // File pointer from DAS to DDS to reduce the building time.
945 // How to check:
946 // 1)
947 
948 bool
949 File::Check_if_special(const string& grid_name) throw(Exception) {
950 
951 
952  bool xdim_is_lon = false;
953  bool ydim_is_lat = false;
954  bool pre_unit_hpa = true;
955  for (vector < SDField * >::const_iterator i =
956  this->sd->getFields ().begin ();
957  i != this->sd->getFields ().end (); ++i) {
958  if (1==(*i)->getRank()) {
959  if(1 == ((*i)->fieldtype)) {
960  if("YDim" == (*j)->getName()
961 
962  }
963 
964  }
965  }
966 }
967 #endif
968 void
970 
971  File *file = this;
972 
973  bool airs_l3 = true;
974  if(basename(file->path).find(".L2.")!=string::npos)
975  airs_l3 = false;
976 
977  // set of names of dimensions that have dimension scales.
978  set<string> scaled_dname_set;
979 
980  // set of names of dimensions that don't have dimension scales.
981  set<string> non_scaled_dname_set;
982  pair<set<string>::iterator,bool> ret;
983 
984  // For dimensions that don't have dimension scales, a map between dimension name and size.
985  map<string,int> non_scaled_dname_to_size;
986 
987  // 1. Loop through SDS fields and remove suffixes(:???) of the dimension names and the variable names.
988  // Also create scaled dim. name set and non-scaled dim. name set.
989  for (std::vector < SDField * >::const_iterator i =
990  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
991 
992  string tempname = (*i)->name;
993  size_t found_colon = tempname.find_first_of(':');
994  if(found_colon!=string::npos)
995  (*i)->newname = tempname.substr(0,found_colon);
996 
997  for (vector < Dimension * >::const_iterator k =
998  (*i)->getDimensions ().begin ();
999  k != (*i)->getDimensions ().end (); ++k) {
1000 
1001  string tempname = (*k)->name;
1002  size_t found_colon = tempname.find_first_of(':');
1003  if(found_colon!=string::npos)
1004  (*k)->name = tempname.substr(0,found_colon);
1005 
1006  if(0==(*k)->getType()) {
1007  ret = non_scaled_dname_set.insert((*k)->name);
1008  if (true == ret.second)
1009  non_scaled_dname_to_size[(*k)->name] = (*k)->dimsize;
1010  }
1011  else{
1012  scaled_dname_set.insert((*k)->name);
1013  }
1014 
1015  }
1016 
1017  }
1018 #if 0
1019 for(set<string>::const_iterator sdim_it = scaled_dname_set.begin();
1020  sdim_it !=scaled_dname_set.end();
1021  ++sdim_it) {
1022 cerr<<"scaled dim. name "<<*sdim_it <<endl;
1023 
1024 }
1025 #endif
1026 
1027  // For AIRS level 3 only ****
1028  // 2. Remove potential redundant CVs
1029  // For AIRS level 3 version 6 products, many dimension scale variables shared the same value. Physically they are the same.
1030  // So to keep the performance optimal and reduce the non-necessary clutter, I remove the duplicate variables.
1031  // An Example: StdPressureLev:asecending is the same as the StdPressureLev:descending, reduce to StdPressureLev
1032 
1033  // Make a copy of the scaled-dim name set:scaled-dim-marker
1034  if(true == airs_l3) {
1035  set<string>scaled_dname_set_marker = scaled_dname_set;
1036 
1037  // Loop through all the SDS objects,
1038  // If finding a 1-D variable name
1039  // b1) in both the scaled-dim name set and the scaled-dim-marker set,
1040  // keep this variable but remove the variable name from the scaled-dim-marker.
1041  // Mark this variable as a CV.(XDim: 2, YDim:1 Others: 3).
1042  // b2) In the scaled-dim name set but not in the scaled-dim-marker set,
1043  // remove the variable from the variable vector.
1044  for (std::vector < SDField * >::iterator i =
1045  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
1046  if(1 == (*i)->getRank()) {
1047  if(scaled_dname_set.find((*i)->getNewName())!=scaled_dname_set.end()) {
1048  if(scaled_dname_set_marker.find((*i)->getNewName())!=scaled_dname_set_marker.end()) {
1049  scaled_dname_set_marker.erase((*i)->getNewName());
1050  }
1051 
1052  else {// Redundant variables
1053 //cerr<<"redundant variable names "<< (*i)->newname <<endl;
1054  delete(*i);
1055  file->sd->sdfields.erase(i);
1056  // when erasing the iterator, it always goes to the next elment, so move back.
1057  i--;
1058  }
1059  }
1060  }
1061  // Remove Latitude and Longitude
1062  else if( 2 == (*i)->getRank()) {
1063  if ("Latitude" == (*i)->getNewName() || "Longitude" == (*i)->getNewName()) {
1064  delete(*i);
1065  file->sd->sdfields.erase(i);
1066  i--;
1067  }
1068  }
1069  else
1070  ++i;
1071  }
1072  }
1073 
1074 #if 0
1075 for(set<string>::const_iterator sdim_it = scaled_dname_set.begin();
1076  sdim_it !=scaled_dname_set.end();
1077  ++sdim_it) {
1078 cerr<<"new scaled dim. name "<<*sdim_it <<endl;
1079 
1080 }
1081 #endif
1082 
1083  //3. Add potential missing CVs
1084 
1085  // 3.1 Find the true dimensions that don't have dimension scales.
1086  set<string>final_non_scaled_dname_set;
1087  for(set<string>::const_iterator non_sdim_it = non_scaled_dname_set.begin();
1088  non_sdim_it !=non_scaled_dname_set.end();
1089  ++non_sdim_it) {
1090 //cerr<<"non-scaled dim. name "<<*non_sdim_it <<endl;
1091  if(scaled_dname_set.find(*non_sdim_it)==scaled_dname_set.end())
1092  final_non_scaled_dname_set.insert(*non_sdim_it);
1093  }
1094 
1095  // 3.2 Create the missing CVs based on the non-scaled dimensions.
1096  for(set<string>::const_iterator non_sdim_it = final_non_scaled_dname_set.begin();
1097  non_sdim_it !=final_non_scaled_dname_set.end();
1098  ++non_sdim_it) {
1099 
1100  SDField *missingfield = new SDField ();
1101 
1102  // The name of the missingfield is not necessary.
1103  // We only keep here for consistency.
1104  missingfield->type = DFNT_INT32;
1105  missingfield->name = *non_sdim_it;
1106  missingfield->newname = *non_sdim_it;
1107  missingfield->rank = 1;
1108  missingfield->fieldtype = 4;
1109  missingfield->setUnits("level");
1110  Dimension *dim = new Dimension (*non_sdim_it,non_scaled_dname_to_size[*non_sdim_it] , 0);
1111 
1112  missingfield->dims.push_back (dim);
1113  file->sd->sdfields.push_back (missingfield);
1114  }
1115 
1116  // For AIRS level 3 only
1117  // Change XDim to Longitude and YDim to Latitude for field name and dimension names
1118 
1119  if(true == airs_l3) {
1120  for (std::vector < SDField * >::const_iterator i =
1121  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
1122 
1123  if(1 ==(*i)->getRank()){
1124  if ("XDim" == (*i)->newname)
1125  (*i)->newname = "Longitude";
1126  else if ("YDim" == (*i)->newname)
1127  (*i)->newname = "Latitude";
1128  }
1129 
1130  for (vector < Dimension * >::const_iterator k =
1131  (*i)->getDimensions ().begin ();
1132  k != (*i)->getDimensions ().end (); ++k) {
1133  if("XDim" == (*k)->name)
1134  (*k)->name = "Longitude";
1135  else if ("YDim" == (*k)->name)
1136  (*k)->name = "Latitude";
1137  }
1138 
1139  }
1140  }
1141 
1142  // For AIRS level 2 only
1143  if(false == airs_l3) {
1144 
1145  bool change_lat_unit = false;
1146  bool change_lon_unit = false;
1147  string ll_dimname1 = "";
1148  string ll_dimname2 = "";
1149 
1150  // 1. Assign the lat/lon units according to the CF conventions.
1151  // 2. Obtain dimension names of lat/lon.
1152  for (std::vector < SDField * >::const_iterator i =
1153  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
1154 
1155  if(2 == (*i)->getRank()) {
1156  if("Latitude" == (*i)->newname){
1157  (*i)->fieldtype = 1;
1158  change_lat_unit = true;
1159  string tempunits = "degrees_north";
1160  (*i)->setUnits(tempunits);
1161  ll_dimname1 = (*i)->getDimensions()[0]->getName();
1162  ll_dimname2 = (*i)->getDimensions()[1]->getName();
1163 
1164  }
1165  else if("Longitude" == (*i)->newname) {
1166  (*i)->fieldtype = 2;
1167  change_lon_unit = true;
1168  string tempunits = "degrees_east";
1169  (*i)->setUnits(tempunits);
1170  }
1171  if((true == change_lat_unit) && (true == change_lon_unit))
1172  break;
1173  }
1174  }
1175 
1176  // 2. Generate the coordinate attribute
1177  string tempcoordinates = "";
1178  string tempfieldname = "";
1179  int tempcount = 0;
1180 
1181  for (std::vector < SDField * >::const_iterator i =
1182  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
1183 
1184  // We don't want to add "coordinates" attributes to all dimension scale variables.
1185  bool dimscale_var = false;
1186  dimscale_var = ((*i)->rank == 1) & (((*i)->newname) == ((*i)->getDimensions()[0]->getName()));
1187 
1188  if((0 ==(*i)->fieldtype) && (false == dimscale_var)) {
1189 
1190  tempcount = 0;
1191  tempcoordinates = "";
1192  tempfieldname = "";
1193 
1194  // First check if the dimension names of this variable include both ll_dimname1 and ll_dimname2.
1195  bool has_lldim1 = false;
1196  bool has_lldim2 = false;
1197  for (std::vector < Dimension * >::const_iterator j =
1198  (*i)->getDimensions ().begin ();
1199  j != (*i)->getDimensions ().end (); ++j) {
1200  if((*j)->name == ll_dimname1)
1201  has_lldim1 = true;
1202  else if ((*j)->name == ll_dimname2)
1203  has_lldim2 = true;
1204  if((true == has_lldim1) && (true == has_lldim2))
1205  break;
1206 
1207  }
1208 
1209 
1210  if((true == has_lldim1) && (true == has_lldim2)) {
1211  for (std::vector < Dimension * >::const_iterator j =
1212  (*i)->getDimensions ().begin ();
1213  j != (*i)->getDimensions ().end (); ++j) {
1214  if((*j)->name == ll_dimname1)
1215  tempfieldname = "Latitude";
1216  else if ((*j)->name == ll_dimname2)
1217  tempfieldname = "Longitude";
1218  else
1219  tempfieldname = (*j)->name;
1220 
1221  if (0 == tempcount)
1222  tempcoordinates = tempfieldname;
1223  else
1224  tempcoordinates = tempcoordinates + " " + tempfieldname;
1225  tempcount++;
1226  }
1227  }
1228  else {
1229  for (std::vector < Dimension * >::const_iterator j =
1230  (*i)->getDimensions ().begin ();
1231  j != (*i)->getDimensions ().end (); ++j) {
1232  if (0 == tempcount)
1233  tempcoordinates = (*j)->name;
1234  else
1235  tempcoordinates = tempcoordinates + " " + (*j)->name;
1236  tempcount++;
1237  }
1238 
1239  }
1240  (*i)->setCoordinates (tempcoordinates);
1241 
1242  }
1243  }
1244  }
1245 }
1246 
1247 // This method will check if the HDF4 file is one of TRMM or OBPG products or MODISARNSS we supported.
1248 void
1250 throw (Exception)
1251 {
1252 
1253  // check the TRMM version 7 cases
1254  // The default sptype is OTHERHDF.
1255  // 2A,2B check attribute FileHeader, FileInfo and SwathHeader
1256  // 3A,3B check attribute FileHeader, FileInfo and GridHeader
1257  // 3A25 check attribute FileHeader, FileInfo and GridHeader1, GridHeader2
1258  if (this->sptype == OTHERHDF) {
1259 
1260  int trmm_multi_gridflag = 0;
1261  int trmm_single_gridflag = 0;
1262  int trmm_swathflag = 0;
1263 
1264  for (std::vector < Attribute * >::const_iterator i =
1265  this->sd->getAttributes ().begin ();
1266  i != this->sd->getAttributes ().end (); ++i) {
1267  if ((*i)->getName () == "FileHeader") {
1268  trmm_multi_gridflag++;
1269  trmm_single_gridflag++;
1270  trmm_swathflag++;
1271  }
1272  if ((*i)->getName () == "FileInfo") {
1273  trmm_multi_gridflag++;
1274  trmm_single_gridflag++;
1275  trmm_swathflag++;
1276  }
1277  if ((*i)->getName () == "SwathHeader")
1278  trmm_swathflag++;
1279 
1280  if ((*i)->getName () == "GridHeader")
1281  trmm_single_gridflag++;
1282 
1283  else if (((*i)->getName ().find ("GridHeader") == 0) &&
1284  (((*i)->getName()).size() >10))
1285  trmm_multi_gridflag++;
1286 
1287  }
1288 
1289 
1290  if(3 == trmm_single_gridflag)
1291  this->sptype = TRMML3S_V7;
1292  else if(3 == trmm_swathflag)
1293  this->sptype = TRMML2_V7;
1294  else if(trmm_multi_gridflag >3)
1295  this->sptype = TRMML3M_V7;
1296 
1297  }
1298 
1299  // check the TRMM and MODARNSS/MYDARNSS cases
1300  // The default sptype is OTHERHDF.
1301  if (this->sptype == OTHERHDF) {
1302 
1303  int metadataflag = 0;
1304 
1305  for (std::vector < Attribute * >::const_iterator i =
1306  this->sd->getAttributes ().begin ();
1307  i != this->sd->getAttributes ().end (); ++i) {
1308  if ((*i)->getName () == "CoreMetadata.0")
1309  metadataflag++;
1310  if ((*i)->getName () == "ArchiveMetadata.0")
1311  metadataflag++;
1312  if ((*i)->getName () == "StructMetadata.0")
1313  metadataflag++;
1314  if ((*i)->getName ().find ("SubsettingMethod") !=
1315  std::string::npos)
1316  metadataflag++;
1317  }
1318 
1319  // This is a very special MODIS product. It includes StructMetadata.0
1320  // but it is not an HDF-EOS2 file. We use metadata name "SubsettingMethod" as an indicator.
1321  // We find this metadata name is uniquely applied to this MODIS product.
1322  // We need to change the way if HDF-EOS MODIS files also use this metadata name.
1323  if (metadataflag == 4)
1324  this->sptype = MODISARNSS;
1325 
1326  // DATA_GRANULE is the TRMM "swath" name; geolocation
1327  // is the TRMM "geolocation" field.
1328  if (metadataflag == 2) {
1329 
1330  for (std::vector < SDField * >::const_iterator i =
1331  this->sd->getFields ().begin ();
1332  i != this->sd->getFields ().end (); ++i) {
1333  if (((*i)->getName () == "geolocation")
1334  && (*i)->getNewName ().find ("DATA_GRANULE") !=
1335  std::string::npos
1336  && (*i)->getNewName ().find ("SwathData") !=
1337  std::string::npos && (*i)->getRank () == 3) {
1338  this->sptype = TRMML2_V6;
1339  break;
1340  }
1341  }
1342 
1343  // For TRMM Level 3 3A46, CSH, 3B42 and 3B43 data.
1344  // The vgroup name is DATA_GRANULE.
1345  // For 3B42 and 3B43, at least one field is 1440*400 array.
1346  // For CSH and 3A46 the number of dimension should be >2.
1347  // CSH: 2 dimensions should be 720 and 148.
1348  // 3A46: 2 dimensions should be 180 and 360.
1349  // The information is obtained from
1350  // http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
1351  if (this->sptype == OTHERHDF) {
1352  for (std::vector < SDField * >::const_iterator i =
1353  this->sd->getFields ().begin ();
1354  i != this->sd->getFields ().end (); ++i) {
1355  if ((*i)->getNewName ().find ("DATA_GRANULE") !=
1356  std::string::npos) {
1357  bool l3b_v6_lonflag = false;
1358  bool l3b_v6_latflag = false;
1359  for (std::vector < Dimension * >::const_iterator k =
1360  (*i)->getDimensions ().begin ();
1361  k != (*i)->getDimensions ().end (); ++k) {
1362  if ((*k)->getSize () == 1440)
1363  l3b_v6_lonflag = true;
1364 
1365  if ((*k)->getSize () == 400)
1366  l3b_v6_latflag = true;
1367  }
1368  if (l3b_v6_lonflag == true && l3b_v6_latflag == true) {
1369  this->sptype = TRMML3B_V6;
1370  break;
1371  }
1372 
1373 
1374  bool l3a_v6_latflag = false;
1375  bool l3a_v6_lonflag = false;
1376 
1377  bool l3c_v6_lonflag = false;
1378  bool l3c_v6_latflag = false;
1379 
1380  if ((*i)->getRank()>2) {
1381  for (std::vector < Dimension * >::const_iterator k =
1382  (*i)->getDimensions ().begin ();
1383  k != (*i)->getDimensions ().end (); ++k) {
1384  if ((*k)->getSize () == 360)
1385  l3a_v6_lonflag = true;
1386 
1387  if ((*k)->getSize () == 180)
1388  l3a_v6_latflag = true;
1389 
1390  if ((*k)->getSize () == 720)
1391  l3c_v6_lonflag = true;
1392 
1393  if ((*k)->getSize () == 148)
1394  l3c_v6_latflag = true;
1395  }
1396 
1397  }
1398 
1399  if (true == l3a_v6_latflag && true == l3a_v6_lonflag) {
1400  this->sptype = TRMML3A_V6;
1401  break;
1402  }
1403 
1404  if (true == l3c_v6_latflag && true == l3c_v6_lonflag) {
1405  this->sptype = TRMML3C_V6;
1406  break;
1407  }
1408 
1409 
1410  }
1411  }
1412  }
1413  }
1414  }
1415 #if 0
1416 if(this->sptype == TRMML3A_V6)
1417 cerr<<"3A46 products "<<endl;
1418 if(this->sptype == TRMML3C_V6)
1419 cerr<<"CSH products "<<endl;
1420 #endif
1421 
1422 
1423 
1424  // Check the OBPG case
1425  // OBPG includes SeaWIFS,OCTS,CZCS,MODISA,MODIST
1426  // One attribute "Product Name" includes unique information for each product,
1427  // For example, SeaWIFS L2 data' "Product Name" is S2003006001857.L2_MLAC
1428  // Since we only support Level 2 and Level 3m data, we just check if those characters exist inside the attribute.
1429  // The reason we cannot support L1A data is that lat/lon consists of fill values.
1430 
1431  if (this->sptype == OTHERHDF) {
1432 
1433  // MODISA level 2 product flag
1434  int modisal2flag = 0;
1435 
1436  // MODIST level 2 product flag
1437  int modistl2flag = 0;
1438 
1439  // OCTS level 2 product flag
1440  int octsl2flag = 0;
1441 
1442  // SeaWiFS level 2 product flag
1443  int seawifsl2flag = 0;
1444 
1445  // CZCS level 2 product flag
1446  int czcsl2flag = 0;
1447 
1448  // MODISA level 3m product flag
1449  int modisal3mflag = 0;
1450 
1451  // MODIST level 3m product flag
1452  int modistl3mflag = 0;
1453 
1454  // OCTS level 3m product flag
1455  int octsl3mflag = 0;
1456 
1457  // SeaWIFS level 3m product flag
1458  int seawifsl3mflag = 0;
1459 
1460  // CZCS level 3m product flag
1461  int czcsl3mflag = 0;
1462 
1463  // Loop the global attributes and find the attribute called "Product Name"
1464  // and the attribute called "Sensor Name",
1465  // then identify different products.
1466  for (std::vector < Attribute * >::const_iterator i =
1467  this->sd->getAttributes ().begin ();
1468  i != this->sd->getAttributes ().end (); ++i) {
1469  if ((*i)->getName () == "Product Name") {
1470 
1471  std::string attrvalue ((*i)->getValue ().begin (),
1472  (*i)->getValue ().end ());
1473  if ((attrvalue.find_first_of ('A', 0) == 0)
1474  && (attrvalue.find (".L2", 0) != std::string::npos))
1475  modisal2flag++;
1476  else if ((attrvalue.find_first_of ('A', 0) == 0)
1477  && (attrvalue.find (".L3m", 0) != std::string::npos))
1478  modisal3mflag++;
1479  else if ((attrvalue.find_first_of ('T', 0) == 0)
1480  && (attrvalue.find (".L2", 0) != std::string::npos))
1481  modistl2flag++;
1482  else if ((attrvalue.find_first_of ('T', 0) == 0)
1483  && (attrvalue.find (".L3m", 0) != std::string::npos))
1484  modistl3mflag++;
1485  else if ((attrvalue.find_first_of ('O', 0) == 0)
1486  && (attrvalue.find (".L2", 0) != std::string::npos))
1487  octsl2flag++;
1488  else if ((attrvalue.find_first_of ('O', 0) == 0)
1489  && (attrvalue.find (".L3m", 0) != std::string::npos))
1490  octsl3mflag++;
1491  else if ((attrvalue.find_first_of ('S', 0) == 0)
1492  && (attrvalue.find (".L2", 0) != std::string::npos))
1493  seawifsl2flag++;
1494  else if ((attrvalue.find_first_of ('S', 0) == 0)
1495  && (attrvalue.find (".L3m", 0) != std::string::npos))
1496  seawifsl3mflag++;
1497  else if ((attrvalue.find_first_of ('C', 0) == 0)
1498  && ((attrvalue.find (".L2", 0) != std::string::npos)
1499  ||
1500  ((attrvalue.find (".L1A", 0) != std::string::npos))))
1501  czcsl2flag++;
1502  else if ((attrvalue.find_first_of ('C', 0) == 0)
1503  && (attrvalue.find (".L3m", 0) != std::string::npos))
1504  czcsl3mflag++;
1505  else;
1506  }
1507  if ((*i)->getName () == "Sensor Name") {
1508 
1509  std::string attrvalue ((*i)->getValue ().begin (),
1510  (*i)->getValue ().end ());
1511  if (attrvalue.find ("MODISA", 0) != std::string::npos) {
1512  modisal2flag++;
1513  modisal3mflag++;
1514  }
1515  else if (attrvalue.find ("MODIST", 0) != std::string::npos) {
1516  modistl2flag++;
1517  modistl3mflag++;
1518  }
1519  else if (attrvalue.find ("OCTS", 0) != std::string::npos) {
1520  octsl2flag++;
1521  octsl3mflag++;
1522  }
1523  else if (attrvalue.find ("SeaWiFS", 0) != std::string::npos) {
1524  seawifsl2flag++;
1525  seawifsl3mflag++;
1526  }
1527  else if (attrvalue.find ("CZCS", 0) != std::string::npos) {
1528  czcsl2flag++;
1529  czcsl3mflag++;
1530  }
1531  else;
1532  }
1533 
1534  if ((modisal2flag == 2) || (modisal3mflag == 2)
1535  || (modistl2flag == 2) || (modistl3mflag == 2)
1536  || (octsl2flag == 2) || (octsl3mflag == 2)
1537  || (seawifsl2flag == 2) || (seawifsl3mflag == 2)
1538  || (czcsl2flag == 2) || (czcsl3mflag == 2))
1539  break;
1540 
1541  }
1542  // Only when both the sensor name and the product name match, we can
1543  // be sure the products are OBPGL2 or OBPGL3m.
1544  if ((modisal2flag == 2) || (modistl2flag == 2) ||
1545  (octsl2flag == 2) || (seawifsl2flag == 2) || (czcsl2flag == 2))
1546  this->sptype = OBPGL2;
1547 
1548  if ((modisal3mflag == 2) ||
1549  (modistl3mflag == 2) || (octsl3mflag == 2) ||
1550  (seawifsl3mflag == 2) || (czcsl3mflag == 2))
1551  this->sptype = OBPGL3;
1552 
1553  }
1554 }
1555 
1556 // Read SDS information from the HDF4 file
1557 SD *
1558 SD::Read (int32 sdfd, int32 fileid)
1559 throw (Exception)
1560 {
1561 
1562  // Indicator of status
1563  int32 status = 0;
1564 
1565  // Number of SDS objects in this file
1566  int32 n_sds = 0;
1567 
1568  // Number of SDS attributes in this file
1569  int32 n_sd_attrs = 0;
1570 
1571  // Object index
1572  int sds_index = 0;
1573 
1574  // SDS ID
1575  int32 sds_id = 0;
1576 
1577  // Dimension sizes
1578  int32 dim_sizes[H4_MAX_VAR_DIMS];
1579 
1580  // number of SDS attributes
1581  int32 n_sds_attrs = 0;
1582 
1583  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
1584  // Documented in a jira ticket HFRHANDLER-168.
1585 
1586  // SDS name
1587  char sds_name[H4_MAX_NC_NAME];
1588 
1589  // SDS dimension names
1590  char dim_name[H4_MAX_NC_NAME];
1591 
1592  // SDS attribute names
1593  char attr_name[H4_MAX_NC_NAME];
1594 
1595  // Dimension size
1596  int32 dim_size = 0;
1597 
1598  // SDS reference number
1599  int32 sds_ref = 0;
1600 
1601  // Dimension type(if dimension type is 0, this dimension doesn't have dimension scales)
1602  // Otherwise, this dimension type is the datatype of this dimension scale.
1603  int32 dim_type = 0;
1604 
1605  // Number of dimension attributes(This is almost never used)
1606  //int32 num_dim_attrs = 0;
1607 
1608  // Attribute value count
1609  int32 attr_value_count = 0;
1610 
1611  // Obtain a SD instance
1612  SD* sd = new SD (sdfd, fileid);
1613 
1614  // Obtain number of SDS objects and number of SD(file) attributes
1615  if (SDfileinfo (sdfd, &n_sds, &n_sd_attrs) == FAIL) {
1616  delete sd;
1617  throw2 ("SDfileinfo failed ", sdfd);
1618  }
1619 
1620  // Go through the SDS object
1621  for (sds_index = 0; sds_index < n_sds; sds_index++) {
1622 
1623  // New SDField instance
1624  SDField *field = new SDField ();
1625 
1626  // Obtain SDS ID.
1627  sds_id = SDselect (sdfd, sds_index);
1628  if (sds_id == FAIL) {
1629  delete sd;
1630  delete field;
1631  // We only need to close SDS ID. SD ID will be closed when the destructor is called.
1632  SDendaccess (sds_id);
1633  throw3 ("SDselect Failed ", "SDS index ", sds_index);
1634  }
1635 
1636  // Obtain SDS reference number
1637  sds_ref = SDidtoref (sds_id);
1638  if (sds_ref == FAIL) {
1639  delete sd;
1640  delete field;
1641  SDendaccess (sds_id);
1642  throw3 ("Cannot obtain SDS reference number", " SDS ID is ",
1643  sds_id);
1644  }
1645 
1646  // Obtain object name, rank, size, field type and number of SDS attributes
1647  status = SDgetinfo (sds_id, sds_name, &field->rank, dim_sizes,
1648  &field->type, &n_sds_attrs);
1649  if (status == FAIL) {
1650  delete sd;
1651  delete field;
1652  SDendaccess (sds_id);
1653  throw2 ("SDgetinfo failed ", sds_name);
1654  }
1655 
1656  //Assign SDS field info. to class field instance.
1657  string tempname (sds_name);
1658  field->name = tempname;
1659  field->newname = field->name;
1660  field->fieldref = sds_ref;
1661  // This will be used to obtain the SDS full path later.
1662  sd->refindexlist[sds_ref] = sds_index;
1663 
1664  // Handle dimension scale
1665  bool dim_no_dimscale = false;
1666  vector <int> dimids;
1667  if (field->rank >0)
1668  dimids.assign(field->rank,0);
1669 
1670  // Assign number of dimension attribute vector
1671  vector <int>num_dim_attrs;
1672  if (field->rank >0)
1673  num_dim_attrs.assign(field->rank,0);
1674 
1675  // Handle dimensions with original dimension names
1676  for (int dimindex = 0; dimindex < field->rank; dimindex++) {
1677 
1678  // Obtain dimension ID.
1679  int dimid = SDgetdimid (sds_id, dimindex);
1680  if (dimid == FAIL) {
1681  delete sd;
1682  delete field;
1683  SDendaccess (sds_id);
1684  throw5 ("SDgetdimid failed ", "SDS name ", sds_name,
1685  "dim index= ", dimindex);
1686  }
1687 
1688  // Obtain dimension info.: dim_name, dim_size,dim_type and num of dim. attrs.
1689  int temp_num_dim_attrs = 0;
1690  status =
1691  SDdiminfo (dimid, dim_name, &dim_size, &dim_type,
1692  (int32*)&temp_num_dim_attrs);
1693  if (status == FAIL) {
1694  delete sd;
1695  delete field;
1696  SDendaccess (sds_id);
1697  throw5 ("SDdiminfo failed ", "SDS name ", sds_name,
1698  "dim index= ", dimindex);
1699  }
1700 
1701  num_dim_attrs[dimindex] = temp_num_dim_attrs;
1702 
1703  // No dimension attribute has been found in NASA files,
1704  // so don't handle it now. KY 2010-06-08
1705 
1706  // Dimension attributes are found in one JPL file(S2000415.HDF).
1707  // So handle it.
1708  // If the corresponding dimension scale exists, no need to
1709  // specially handle the attributes.
1710  // But when the dimension scale doesn't exist, we would like to
1711  // handle the attributes following
1712  // the default HDF4 handler. We will add attribute containers.
1713  // For example, variable name foo has
1714  // two dimensions, foo1, foo2. We just create two attribute names:
1715  // foo_dim0, foo_dim1,
1716  // foo_dim0 will include an attribute "name" with the value as
1717  // foo1 and other attributes.
1718  // KY 2012-09-11
1719 
1720  string dim_name_str (dim_name);
1721 
1722  // Since dim_size will be 0 if the dimension is
1723  // unlimited dimension, so use dim_sizes instead
1724  Dimension *dim =
1725  new Dimension (dim_name_str, dim_sizes[dimindex], dim_type);
1726 
1727  // Save this dimension
1728  field->dims.push_back (dim);
1729 
1730  // First check if there are dimensions in this field that
1731  // don't have dimension scales.
1732  dimids[dimindex] = dimid;
1733  if (0 == dim_type) {
1734  if (false == dim_no_dimscale)
1735  dim_no_dimscale = true;
1736  if ((dim_name_str == field->name) && (1 == field->rank))
1737  field->is_noscale_dim = true;
1738  }
1739  }
1740 
1741  // Find dimensions that have no dimension scales,
1742  // add attribute for this whole field ???_dim0, ???_dim1 etc.
1743 
1744  if( true == dim_no_dimscale) {
1745 
1746  for (int dimindex = 0; dimindex < field->rank; dimindex++) {
1747 
1748  string dim_name_str = (field->dims)[dimindex]->name;
1749  AttrContainer *dim_info = new AttrContainer ();
1750  string index_str;
1751  stringstream out_index;
1752  out_index << dimindex;
1753  index_str = out_index.str();
1754  dim_info->name = "_dim_" + index_str;
1755 
1756  // newname will be created at the final stage.
1757 
1758  bool dimname_flag = false;
1759 
1760  int32 dummy_type = 0;
1761  int32 dummy_value_count = 0;
1762 
1763  // Loop through to check if an attribute called "name" exists and set a flag.
1764  for (int attrindex = 0; attrindex < num_dim_attrs[dimindex]; attrindex++) {
1765 
1766  status = SDattrinfo(dimids[dimindex],attrindex,attr_name,
1767  &dummy_type,&dummy_value_count);
1768  if (status == FAIL) {
1769  delete sd;
1770  delete field;
1771  SDendaccess (sds_id);
1772  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
1773  }
1774 
1775  string tempname(attr_name);
1776  if ("name"==tempname) {
1777  dimname_flag = true;
1778  break;
1779  }
1780  }
1781 
1782  // Loop through to obtain the dimension attributes and save the corresponding attributes to dim_info.
1783  for (int attrindex = 0; attrindex < num_dim_attrs[dimindex]; attrindex++) {
1784 
1785  Attribute *attr = new Attribute();
1786  status = SDattrinfo(dimids[dimindex],attrindex,attr_name,
1787  &attr->type,&attr_value_count);
1788  if (status == FAIL) {
1789  delete sd;
1790  delete field;
1791  SDendaccess (sds_id);
1792  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
1793  }
1794  string tempname (attr_name);
1795  attr->name = tempname;
1796  tempname = HDFCFUtil::get_CF_string(tempname);
1797 
1798  attr->newname = tempname;
1799  attr->count = attr_value_count;
1800  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
1801  if (SDreadattr (dimids[dimindex], attrindex, &attr->value[0]) == -1) {
1802  delete sd;
1803  delete field;
1804  SDendaccess (sds_id);
1805  throw5 ("read SDS attribute failed ", "Field name ",
1806  field->name, " Attribute name ", attr->name);
1807  }
1808 
1809  dim_info->attrs.push_back (attr);
1810 
1811  }
1812 
1813  // If no attribute called "name", we create an attribute "name" and save the name of the attribute
1814  // as the attribute value.
1815  if (false == dimname_flag) {
1816 
1817  Attribute *attr = new Attribute();
1818  attr->name = "name";
1819  attr->newname = "name";
1820  attr->type = DFNT_CHAR;
1821  attr->count = dim_name_str.size();
1822  attr->value.resize(attr->count);
1823  copy(dim_name_str.begin(),dim_name_str.end(),attr->value.begin());
1824  dim_info->attrs.push_back(attr);
1825 
1826  }
1827  field->dims_info.push_back(dim_info);
1828  }
1829  }
1830 
1831  // Loop through all the SDS attributes and save them to the class field instance.
1832  for (int attrindex = 0; attrindex < n_sds_attrs; attrindex++) {
1833  Attribute *attr = new Attribute ();
1834  status =
1835  SDattrinfo (sds_id, attrindex, attr_name, &attr->type,
1836  &attr_value_count);
1837 
1838  if (status == FAIL) {
1839  delete attr;
1840  delete sd;
1841  delete field;
1842  SDendaccess (sds_id);
1843  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
1844  }
1845 
1846  string tempname (attr_name);
1847  attr->name = tempname;
1848  tempname = HDFCFUtil::get_CF_string(tempname);
1849 
1850  attr->newname = tempname;
1851  attr->count = attr_value_count;
1852  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
1853  if (SDreadattr (sds_id, attrindex, &attr->value[0]) == -1) {
1854  delete attr;
1855  delete sd;
1856  delete field;
1857  SDendaccess (sds_id);
1858  throw5 ("read SDS attribute failed ", "Field name ",
1859  field->name, " Attribute name ", attr->name);
1860  }
1861  field->attrs.push_back (attr);
1862  }
1863  SDendaccess (sds_id);
1864  sd->sdfields.push_back (field);
1865  }
1866 
1867  // Loop through all SD(file) attributes and save them to the class sd instance.
1868  for (int attrindex = 0; attrindex < n_sd_attrs; attrindex++) {
1869 
1870  Attribute *attr = new Attribute ();
1871  status = SDattrinfo (sdfd, attrindex, attr_name, &attr->type,
1872  &attr_value_count);
1873  if (status == FAIL) {
1874  delete attr;
1875  delete sd;
1876  throw3 ("SDattrinfo failed ", "SD id ", sdfd);
1877  }
1878  std::string tempname (attr_name);
1879  attr->name = tempname;
1880 
1881  // Checking and handling the special characters for the SDS attribute name.
1882  tempname = HDFCFUtil::get_CF_string(tempname);
1883  attr->newname = tempname;
1884  attr->count = attr_value_count;
1885  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
1886  if (SDreadattr (sdfd, attrindex, &attr->value[0]) == -1) {
1887  delete attr;
1888  delete sd;
1889  throw3 ("Cannot read SD attribute", " Attribute name ",
1890  attr->name);
1891  }
1892  sd->attrs.push_back (attr);
1893  }
1894 
1895  return sd;
1896 
1897 }
1898 
1899 // Retrieve the extra SDS object info. from a hybrid HDF-EOS2 file
1900 SD *
1901 SD::Read_Hybrid (int32 sdfd, int32 fileid)
1902 throw (Exception)
1903 {
1904  // Indicator of status
1905  int32 status = 0;
1906 
1907  // Number of SDS objects in this file
1908  int32 n_sds = 0;
1909 
1910  // Number of SDS attributes in this file
1911  int32 n_sd_attrs = 0;
1912 
1913  // SDS Object index
1914  int sds_index = 0;
1915 
1916  // Extra SDS object index
1917  int extra_sds_index = 0;
1918 
1919  // SDS ID
1920  int32 sds_id = 0;
1921 
1922  // Dimension sizes
1923  int32 dim_sizes[H4_MAX_VAR_DIMS];
1924 
1925  // number of SDS attributes
1926  int32 n_sds_attrs = 0;
1927 
1928  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
1929  // Documented in a jira ticket HFRHANDLER-168.
1930 
1931  // SDS name
1932  char sds_name[H4_MAX_NC_NAME];
1933 
1934  // SDS dimension names
1935  char dim_name[H4_MAX_NC_NAME];
1936 
1937  // SDS attribute names
1938  char attr_name[H4_MAX_NC_NAME];
1939 
1940  // Dimension size
1941  int32 dim_size = 0;
1942 
1943  // SDS reference number
1944  int32 sds_ref = 0;
1945 
1946  // Dimension type(if dimension type is 0, this dimension doesn't have dimension scales)
1947  // Otherwise, this dimension type is the datatype of this dimension scale.
1948  int32 dim_type = 0;
1949 
1950  // Number of dimension attributes(This is almost never used)
1951  int32 num_dim_attrs = 0;
1952 
1953  // Attribute value count
1954  int32 attr_value_count = 0;
1955 
1956 
1957  // TO OBTAIN the full path of the SDS objects
1958  int32 vgroup_id = 0;
1959 
1960  // lone vgroup index
1961  int32 lone_vg_number = 0;
1962 
1963  // number of lone vgroups
1964  int32 num_of_lones = -1;
1965 
1966  int32 num_gobjects;
1967 
1968  // Object reference and tag pair. Key to find an HDF4 object
1969  int32 obj_ref = 0;
1970  int32 obj_tag = 0;
1971 
1972  // Temporary index.
1973  int i;
1974 
1975  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
1976  // Documented in a jira ticket HFRHANDLER-168.
1977  char vgroup_name[VGNAMELENMAX*4];
1978  char vgroup_class[VGNAMELENMAX*4];
1979 
1980  //std::string full_path;
1981 
1982  // full path of an object
1983  char *full_path;
1984  // char full_path[MAX_FULL_PATH_LEN];
1985 
1986  // copy of the full path
1987  char *cfull_path;
1988 // char cfull_path[MAX_FULL_PATH_LEN];
1989 
1990  // Obtain a SD instance
1991  SD *sd = new SD (sdfd, fileid);
1992 
1993  // Obtain number of SDS objects and number of SD(file) attributes
1994  if (SDfileinfo (sdfd, &n_sds, &n_sd_attrs) == FAIL) {
1995  delete sd;
1996  throw2 ("SDfileinfo failed ", sdfd);
1997  }
1998 
1999  // Loop through all SDS objects to obtain the SDS reference numbers.
2000  // Then save the reference numbers into the SD instance sd.
2001  for (sds_index = 0; sds_index < n_sds; sds_index++) {
2002  sds_id = SDselect (sdfd, sds_index);
2003 
2004  if (sds_id == FAIL) {
2005  delete sd;
2006  // We only need to close SDS ID. SD ID will be closed when
2007  // the destructor is called.
2008  SDendaccess (sds_id);
2009  throw3 ("SDselect Failed ", "SDS index ", sds_index);
2010  }
2011 
2012  sds_ref = SDidtoref (sds_id);
2013  if (sds_ref == FAIL) {
2014  delete sd;
2015  SDendaccess (sds_id);
2016  throw3 ("Cannot obtain SDS reference number", " SDS ID is ",
2017  sds_id);
2018  }
2019  sd->sds_ref_list.push_back(sds_ref);
2020  SDendaccess(sds_id);
2021  }
2022 
2023  // Now we need to obtain the sds reference numbers
2024  // for SDS objects that are accessed as the HDF-EOS2 grid or swath.
2025  // No NASA HDF4 files have the vgroup that forms a ring; so ignore this case.
2026  // First, call Vlone with num_of_lones set to 0 to get the number of
2027  // lone vgroups in the file, but not to get their reference numbers.
2028 
2029  num_of_lones = Vlone (fileid, NULL, 0);
2030  if (num_of_lones == FAIL){
2031  delete sd;
2032  throw3 ("Fail to obtain lone vgroup number", "file id is", fileid);
2033  }
2034 
2035  // if there are any lone vgroups,
2036  if (num_of_lones > 0) {
2037 
2038  // use the num_of_lones returned to allocate sufficient space for the
2039  // buffer ref_array to hold the reference numbers of all lone vgroups,
2040  vector<int32>ref_array;
2041  ref_array.resize(num_of_lones);
2042 
2043  // and call Vlone again to retrieve the reference numbers into
2044  // the buffer ref_array.
2045  num_of_lones = Vlone (fileid, &ref_array[0], num_of_lones);
2046  if (num_of_lones == FAIL) {
2047  delete sd;
2048  throw3 ("Cannot obtain lone vgroup reference arrays ",
2049  "file id is ", fileid);
2050  }
2051 
2052  // loop through all the lone vgroup objects
2053  for (lone_vg_number = 0; lone_vg_number < num_of_lones;
2054  lone_vg_number++) {
2055 
2056  // Attach to the current vgroup
2057  vgroup_id = Vattach (fileid, ref_array[lone_vg_number], "r");
2058  if (vgroup_id == FAIL) {
2059  delete sd;
2060  throw3 ("Vattach failed ", "Reference number is ",
2061  ref_array[lone_vg_number]);
2062  }
2063 
2064  status = Vgetname (vgroup_id, vgroup_name);
2065  if (status == FAIL) {
2066  delete sd;
2067  Vdetach (vgroup_id);
2068  throw3 ("Vgetname failed ", "vgroup_id is ", vgroup_id);
2069  }
2070 
2071  status = Vgetclass (vgroup_id, vgroup_class);
2072  if (status == FAIL) {
2073  delete sd;
2074  Vdetach (vgroup_id);
2075  throw3 ("Vgetclass failed ", "vgroup_name is ", vgroup_name);
2076  }
2077 
2078  //Ignore internal HDF groups
2079  if (strcmp (vgroup_class, _HDF_ATTRIBUTE) == 0
2080  || strcmp (vgroup_class, _HDF_VARIABLE) == 0
2081  || strcmp (vgroup_class, _HDF_DIMENSION) == 0
2082  || strcmp (vgroup_class, _HDF_UDIMENSION) == 0
2083  || strcmp (vgroup_class, _HDF_CDF) == 0
2084  || strcmp (vgroup_class, GR_NAME) == 0
2085  || strcmp (vgroup_class, RI_NAME) == 0) {
2086  Vdetach (vgroup_id);
2087  continue;
2088  }
2089 
2090  // Obtain the number of objects of this vgroup
2091  num_gobjects = Vntagrefs (vgroup_id);
2092  if (num_gobjects < 0) {
2093  delete sd;
2094  Vdetach (vgroup_id);
2095  throw3 ("Vntagrefs failed ", "vgroup_name is ", vgroup_name);
2096  }
2097 
2098  // Obtain the vgroup full path and the copied vgroup full path
2099  // MAX_FULL_PATH_LEN(1024) is long enough
2100  // to cover any HDF4 object path for all NASA HDF4 products.
2101  // So using strcpy and strcat is safe in a practical sense.
2102  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
2103  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
2104  // Documented in a jira ticket HFRHANDLER-168.
2105  // KY 2013-07-12
2106  // We replace strcpy and strcat with strncpy and strncat as suggested. KY 2013-08-29
2107 
2108  full_path = (char *) malloc (MAX_FULL_PATH_LEN);
2109  if (full_path == NULL) {
2110  delete sd;
2111  Vdetach (vgroup_id);
2112  throw1 ("No enough memory to allocate the buffer.");
2113  }
2114 
2115  memset(full_path,'\0',MAX_FULL_PATH_LEN);
2116  strncpy(full_path,_BACK_SLASH,strlen(_BACK_SLASH));
2117  strncat(full_path, vgroup_name,strlen(vgroup_name));
2118 
2119  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
2120  if (cfull_path == NULL) {
2121  delete sd;
2122  Vdetach (vgroup_id);
2123  free (full_path);
2124  throw1 ("No enough memory to allocate the buffer.");
2125  }
2126  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
2127  strncpy (cfull_path, full_path,strlen(full_path));
2128 
2129  // Loop all objects in this vgroup
2130  for (i = 0; i < num_gobjects; i++) {
2131 
2132  // Obtain the object reference and tag of this object
2133  if (Vgettagref (vgroup_id, i, &obj_tag, &obj_ref) == FAIL) {
2134  delete sd;
2135  Vdetach (vgroup_id);
2136  free (full_path);
2137  free (cfull_path);
2138  throw5 ("Vgettagref failed ", "vgroup_name is ",
2139  vgroup_name, " reference number is ", obj_ref);
2140  }
2141 
2142  // If this object is a vgroup, will call recursively to obtain the SDS path.
2143  if (Visvg (vgroup_id, obj_ref) == TRUE) {
2144  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
2145  full_path[strlen(cfull_path)]='\0';
2146  sd->obtain_noneos2_sds_path (fileid, full_path, obj_ref);
2147  }
2148 
2149  // These are SDS objects
2150  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
2151  || obj_tag == DFTAG_SD) {
2152 
2153  // Here we need to check if the SDS is an EOS object by checking
2154  // if the the path includes "Data Fields" or "Geolocation Fields".
2155  // If the object is an EOS object, we will remove the sds
2156  // reference number from the list.
2157  string temp_str = string(full_path);
2158  if((temp_str.find("Data Fields") != std::string::npos)||
2159  (temp_str.find("Geolocation Fields") != std::string::npos))
2160  sd->sds_ref_list.remove(obj_ref);
2161 
2162  }
2163  // Do nothing for other objects
2164  else;
2165  }
2166  free (full_path);
2167  free (cfull_path);
2168 
2169  status = Vdetach (vgroup_id);
2170 
2171  if (status == FAIL) {
2172  delete sd;
2173  throw3 ("Vdetach failed ", "vgroup_name is ", vgroup_name);
2174  }
2175  }//end of the for loop
2176 
2177  }// end of the if loop
2178 
2179  // Loop through the sds reference list; now the list should only include non-EOS SDS objects.
2180  for(std::list<int32>::iterator sds_ref_it = sd->sds_ref_list.begin();
2181  sds_ref_it!=sd->sds_ref_list.end();++sds_ref_it) {
2182 
2183  extra_sds_index = SDreftoindex(sdfd,*sds_ref_it);
2184  if(extra_sds_index == FAIL) {
2185  delete sd;
2186  throw3("SDreftoindex Failed ","SDS reference number ", *sds_ref_it);
2187  }
2188 
2189  SDField *field = new SDField ();
2190  sds_id = SDselect (sdfd, extra_sds_index);
2191  if (sds_id == FAIL) {
2192  delete field;
2193  delete sd;
2194  // We only need to close SDS ID. SD ID will be closed when the destructor is called.
2195  SDendaccess (sds_id);
2196  throw3 ("SDselect Failed ", "SDS index ", extra_sds_index);
2197  }
2198 
2199  // Obtain object name, rank, size, field type and number of SDS attributes
2200  status = SDgetinfo (sds_id, sds_name, &field->rank, dim_sizes,
2201  &field->type, &n_sds_attrs);
2202  if (status == FAIL) {
2203  delete field;
2204  delete sd;
2205  SDendaccess (sds_id);
2206  throw2 ("SDgetinfo failed ", sds_name);
2207  }
2208 
2209  // new name for added SDS objects are renamed as original_name + "NONEOS".
2210  string tempname (sds_name);
2211  field->name = tempname;
2212  tempname = HDFCFUtil::get_CF_string(tempname);
2213  field->newname = tempname+"_"+"NONEOS";
2214  field->fieldref = *sds_ref_it;
2215  sd->refindexlist[*sds_ref_it] = extra_sds_index;
2216 
2217  // Handle dimensions with original dimension names
2218  for (int dimindex = 0; dimindex < field->rank; dimindex++) {
2219  int dimid = SDgetdimid (sds_id, dimindex);
2220  if (dimid == FAIL) {
2221  delete field;
2222  delete sd;
2223  SDendaccess (sds_id);
2224  throw5 ("SDgetdimid failed ", "SDS name ", sds_name,
2225  "dim index= ", dimindex);
2226  }
2227  status = SDdiminfo (dimid, dim_name, &dim_size, &dim_type,
2228  &num_dim_attrs);
2229 
2230  if (status == FAIL) {
2231  delete field;
2232  delete sd;
2233  SDendaccess (sds_id);
2234  throw5 ("SDdiminfo failed ", "SDS name ", sds_name,
2235  "dim index= ", dimindex);
2236  }
2237 
2238  string dim_name_str (dim_name);
2239 
2240  // Since dim_size will be 0 if the dimension is unlimited dimension,
2241  // so use dim_sizes instead
2242  Dimension *dim =
2243  new Dimension (dim_name_str, dim_sizes[dimindex], dim_type);
2244 
2245  field->dims.push_back (dim);
2246 
2247  // The corrected dims are added simply for the consistency in hdfdesc.cc,
2248  // it doesn't matter
2249  // for the added SDSes at least for now. KY 2011-2-13
2250 
2251  // However, some dimension names have special characters.
2252  // We need to remove special characters.
2253  // Since no coordinate attributes will be provided for
2254  // these extra SDSes, we don't need to
2255  // make the dimension names consistent with other dimension names.
2256  // But we need to keep an eye
2257  // on if the units of the extra SDSes are degrees_north or degrees_east.
2258  // This will make the tools
2259  // automatically treat them as latitude or longitude.
2260  // Need to double check. KY 2011-2-17
2261  // So far we don't meet the above case. KY 2013-07-12
2262 
2263  string cfdimname = HDFCFUtil::get_CF_string(dim_name_str);
2264  Dimension *correcteddim =
2265  new Dimension (cfdimname, dim_sizes[dimindex], dim_type);
2266 
2267  field->correcteddims.push_back (correcteddim);
2268 
2269  }
2270 
2271  // Loop through all SDS attributes and save them to field.
2272  for (int attrindex = 0; attrindex < n_sds_attrs; attrindex++) {
2273 
2274  Attribute *attr = new Attribute ();
2275 
2276  status = SDattrinfo (sds_id, attrindex, attr_name, &attr->type,
2277  &attr_value_count);
2278  if (status == FAIL) {
2279  delete attr;
2280  delete field;
2281  delete sd;
2282  SDendaccess (sds_id);
2283  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
2284  }
2285 
2286  string tempname (attr_name);
2287  attr->name = tempname;
2288 
2289  // Checking and handling the special characters for the SDS attribute name.
2290  tempname = HDFCFUtil::get_CF_string(tempname);
2291  attr->newname = tempname;
2292  attr->count = attr_value_count;
2293  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
2294  if (SDreadattr (sds_id, attrindex, &attr->value[0]) == -1) {
2295  delete attr;
2296  delete field;
2297  delete sd;
2298  SDendaccess (sds_id);
2299  throw5 ("read SDS attribute failed ", "Field name ",
2300  field->name, " Attribute name ", attr->name);
2301  }
2302  field->attrs.push_back (attr);
2303  }
2304  SDendaccess (sds_id);
2305  sd->sdfields.push_back (field);
2306  }
2307  return sd;
2308 }
2309 
2310 // Retrieve Vdata information from the HDF4 file
2311 VDATA *
2312 VDATA::Read (int32 vdata_id, int32 obj_ref)
2313 throw (Exception)
2314 {
2315 
2316  // Vdata field size
2317  int32 fieldsize = 0;
2318 
2319  // Vdata field datatype
2320  int32 fieldtype = 0;
2321 
2322  // Vdata field order
2323  int32 fieldorder = 0;
2324 
2325  // Vdata field name
2326  char *fieldname = NULL;
2327 
2328  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
2329  // Documented in a jira ticket HFRHANDLER-168.
2330  char vdata_name[VSNAMELENMAX];
2331 
2332  VDATA *vdata = new VDATA (vdata_id, obj_ref);
2333 
2334  vdata->vdref = obj_ref;
2335 
2336  if (VSQueryname (vdata_id, vdata_name) == FAIL){
2337  delete vdata;
2338  throw3 ("VSQueryname failed ", "vdata id is ", vdata_id);
2339  }
2340 
2341  string vdatanamestr (vdata_name);
2342 
2343  vdata->name = vdatanamestr;
2344  vdata->newname = HDFCFUtil::get_CF_string(vdata->name);
2345  int32 num_field = VFnfields (vdata_id);
2346 
2347  if (num_field == -1){
2348  delete vdata;
2349  throw3 ("For vdata, VFnfields failed. ", "vdata name is ",
2350  vdata->name);
2351  }
2352 
2353  int32 num_record = VSelts (vdata_id);
2354 
2355  if (num_record == -1) {
2356  delete vdata;
2357  throw3 ("For vdata, VSelts failed. ", "vdata name is ", vdata->name);
2358  }
2359 
2360 
2361  // Using the BES KEY for people to choose to map the vdata to attribute for a smaller number of record.
2362  // KY 2012-6-26
2363 
2364  string check_vdata_to_attr_key="H4.EnableVdata_to_Attr";
2365  bool turn_on_vdata_to_attr_key = false;
2366 
2367  turn_on_vdata_to_attr_key = HDFCFUtil::check_beskeys(check_vdata_to_attr_key);
2368 
2369  // The reason to add this flag is if the number of record is too big, the DAS table is too huge to allow some clients to work.
2370  // Currently if the number of record is >=10; one vdata field is mapped to a DAP variable.
2371  // Otherwise, it is mapped to a DAP attribute.
2372 
2373  if (num_record <= 10 && true == turn_on_vdata_to_attr_key)
2374  vdata->TreatAsAttrFlag = true;
2375  else
2376  vdata->TreatAsAttrFlag = false;
2377 
2378  // Loop through all fields and save information to a vector
2379  for (int i = 0; i < num_field; i++) {
2380 
2381  VDField *field = new VDField ();
2382  fieldsize = VFfieldesize (vdata_id, i);
2383  if (fieldsize == FAIL) {
2384  delete field;
2385  delete vdata;
2386  throw5 ("For vdata field, VFfieldsize failed. ", "vdata name is ",
2387  vdata->name, " index is ", i);
2388  }
2389 
2390  fieldname = VFfieldname (vdata_id, i);
2391  if (fieldname == NULL) {
2392  delete field;
2393  delete vdata;
2394  throw5 ("For vdata field, VFfieldname failed. ", "vdata name is ",
2395  vdata->name, " index is ", i);
2396  }
2397 
2398  fieldtype = VFfieldtype (vdata_id, i);
2399  if (fieldtype == FAIL) {
2400  delete field;
2401  delete vdata;
2402  throw5 ("For vdata field, VFfieldtype failed. ", "vdata name is ",
2403  vdata->name, " index is ", i);
2404  }
2405 
2406  fieldorder = VFfieldorder (vdata_id, i);
2407  if (fieldorder == FAIL) {
2408  delete field;
2409  delete vdata;
2410  throw5 ("For vdata field, VFfieldtype failed. ", "vdata name is ",
2411  vdata->name, " index is ", i);
2412  }
2413 
2414  field->name = fieldname;
2415  field->newname = HDFCFUtil::get_CF_string(field->name);
2416  field->type = fieldtype;
2417  field->order = fieldorder;
2418  field->size = fieldsize;
2419  field->rank = 1;
2420  field->numrec = num_record;
2421 //cerr<<"vdata field name is "<<field->name <<endl;
2422 //cerr<<"vdata field type is "<<field->type <<endl;
2423 
2424 
2425  if (vdata->getTreatAsAttrFlag () && num_record > 0) { // Currently we only save small size vdata to attributes
2426 
2427  field->value.resize (num_record * fieldsize);
2428  if (VSseek (vdata_id, 0) == FAIL) {
2429  delete field;
2430  delete vdata;
2431  throw5 ("vdata ", vdata_name, "field ", fieldname,
2432  " VSseek failed.");
2433  }
2434 
2435  if (VSsetfields (vdata_id, fieldname) == FAIL) {
2436  delete field;
2437  delete vdata;
2438  throw3 ("vdata field ", fieldname, " VSsetfields failed.");
2439  }
2440 
2441  if (VSread
2442  (vdata_id, (uint8 *) & field->value[0], num_record,
2443  FULL_INTERLACE) == FAIL){
2444  delete field;
2445  delete vdata;
2446  throw3 ("vdata field ", fieldname, " VSread failed.");
2447  }
2448 
2449  }
2450 
2451  try {
2452  // Read field attributes
2453  field->ReadAttributes (vdata_id, i);
2454  }
2455  catch(...) {
2456  delete field;
2457  delete vdata;
2458  throw;
2459  }
2460  vdata->vdfields.push_back (field);
2461  }
2462 
2463  try {
2464  // Read Vdata attributes
2465  vdata->ReadAttributes (vdata_id);
2466  }
2467  catch(...) {
2468  delete vdata;
2469  throw;
2470  }
2471  return vdata;
2472 
2473 }
2474 
2475 // Read Vdata attributes and save them into vectors
2476 void
2477 VDATA::ReadAttributes (int32 vdata_id)
2478 throw (Exception)
2479 {
2480  // Vdata attribute name
2481  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
2482  // Documented in a jira ticket HFRHANDLER-168.
2483  char attr_name[H4_MAX_NC_NAME];
2484 
2485  // Number of attributes
2486  int32 nattrs = 0;
2487 
2488  // Number of attribute size
2489  int32 attrsize = 0;
2490 
2491  // API status indicator
2492  int32 status = 0;
2493 
2494  // Number of vdata attributes
2495  nattrs = VSfnattrs (vdata_id, _HDF_VDATA);
2496 
2497 // This is just to check if the weird MacOS portability issue go away.KY 2011-3-31
2498 #if 0
2499  if (nattrs == FAIL)
2500  throw3 ("VSfnattrs failed ", "vdata id is ", vdata_id);
2501 #endif
2502 
2503  if (nattrs > 0) {
2504 
2505  // Obtain number of vdata attributes
2506  for (int i = 0; i < nattrs; i++) {
2507 
2508  Attribute *attr = new Attribute ();
2509 
2510  status = VSattrinfo (vdata_id, _HDF_VDATA, i, attr_name,
2511  &attr->type, &attr->count, &attrsize);
2512  if (status == FAIL) {
2513  delete attr;
2514  throw5 ("VSattrinfo failed ", "vdata id is ", vdata_id,
2515  " attr index is ", i);
2516  }
2517 
2518  // Checking and handling the special characters for the vdata attribute name.
2519  string tempname(attr_name);
2520  attr->name = tempname;
2521  attr->newname = HDFCFUtil::get_CF_string(attr->name);
2522  attr->value.resize (attrsize);
2523  if (VSgetattr (vdata_id, _HDF_VDATA, i, &attr->value[0]) == FAIL) {
2524  delete attr;
2525  throw5 ("VSgetattr failed ", "vdata id is ", vdata_id,
2526  " attr index is ", i);
2527  }
2528  attrs.push_back (attr);
2529  }
2530  }
2531 }
2532 
2533 
2534 // Retrieve VD field attributes from the HDF4 file.
2535 // Input parameters are vdata ID and vdata field index
2536 void
2537 VDField::ReadAttributes (int32 vdata_id, int32 fieldindex)
2538 throw (Exception)
2539 {
2540  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
2541  // Documented in a jira ticket HFRHANDLER-168.
2542  // vdata field attribute name
2543  char attr_name[H4_MAX_NC_NAME];
2544 
2545  // Number of vdata field attributes
2546  int32 nattrs = 0;
2547 
2548  // Vdata attribute size
2549  int32 attrsize = 0;
2550 
2551  // Indicator of vdata field APIs
2552  int32 status = 0;
2553 
2554  // Obtain
2555  nattrs = VSfnattrs (vdata_id, fieldindex);
2556 
2557 // This is just to check if the weird MacOS portability issue go away.KY 2011-3-9
2558 #if 0
2559  if (nattrs == FAIL)
2560  throw5 ("VSfnattrs failed ", "vdata id is ", vdata_id,
2561  "Field index is ", fieldindex);
2562 #endif
2563 
2564  if (nattrs > 0) {
2565 
2566  // Obtain vdata field attributes
2567  for (int i = 0; i < nattrs; i++) {
2568 
2569  Attribute *attr = new Attribute ();
2570 
2571  status = VSattrinfo (vdata_id, fieldindex, i, attr_name,
2572  &attr->type, &attr->count, &attrsize);
2573 
2574  if (status == FAIL) {
2575  delete attr;
2576  throw5 ("VSattrinfo failed ", "vdata field index ",
2577  fieldindex, " attr index is ", i);
2578  }
2579 
2580  string tempname(attr_name);
2581  attr->name = tempname;
2582 
2583  // Checking and handling the special characters for the vdata field attribute name.
2584  attr->newname = HDFCFUtil::get_CF_string(attr->name);
2585 
2586  attr->value.resize (attrsize);
2587  if (VSgetattr (vdata_id, fieldindex, i, &attr->value[0]) == FAIL) {
2588  delete attr;
2589  throw5 ("VSgetattr failed ", "vdata field index is ",
2590  fieldindex, " attr index is ", i);
2591  }
2592  attrs.push_back (attr);
2593  }
2594  }
2595 }
2596 
2597 void
2598 File::ReadVgattrs(int32 vgroup_id,char*fullpath) throw(Exception) {
2599 
2600  intn status_n;
2601  //int n_attr_value = 0;
2602  char attr_name[H4_MAX_NC_NAME];
2603  AttrContainer *vg_attr = NULL;
2604 
2605  intn n_attrs = Vnattrs(vgroup_id);
2606  if(n_attrs == FAIL)
2607  throw1("Vnattrs failed");
2608  if(n_attrs > 0) {
2609  vg_attr = new AttrContainer();
2610  string temp_container_name(fullpath);
2611  vg_attr->name = HDFCFUtil::get_CF_string(temp_container_name);
2612  }
2613 
2614  for(int attr_index = 0; attr_index <n_attrs; attr_index++) {
2615 
2616  Attribute *attr = new Attribute();
2617  int32 value_size_32 = 0;
2618  status_n = Vattrinfo(vgroup_id, (intn)attr_index, attr_name, &attr->type,
2619  &attr->count, &value_size_32);
2620  if(status_n == FAIL) {
2621  delete attr;
2622  throw1("Vattrinfo failed.");
2623  }
2624  int value_size = value_size_32;
2625 
2626  string tempname (attr_name);
2627  attr->name = tempname;
2628  tempname = HDFCFUtil::get_CF_string(tempname);
2629  attr->newname = tempname;
2630  attr->value.resize (value_size);
2631 
2632  status_n = Vgetattr(vgroup_id,(intn)attr_index,&attr->value[0]);
2633  if(status_n == FAIL) {
2634  delete attr;
2635  throw3("Vgetattr failed. ","The attribute name is ",attr->name);
2636  }
2637  vg_attr->attrs.push_back(attr);
2638  }
2639 
2640  if(vg_attr !=NULL)
2641  vg_attrs.push_back(vg_attr);
2642 
2643 
2644 }
2645 
2646 // This code is used to obtain the full path of SDS and vdata.
2647 // Since it uses HDF4 library a lot, we keep the C style. KY 2010-7-13
2648 void
2650 throw (Exception)
2651 {
2652  /************************* Variable declaration **************************/
2653 
2654  // Status indicator of HDF4 APIs
2655  int32 status = 0;
2656 
2657  // H interface ID
2658  int32 file_id = 0;
2659 
2660  // vgroup ID
2661  int32 vgroup_id = 0;
2662 
2663  // Vdata ID
2664  int32 vdata_id = 0;
2665 
2666  // Lone vgroup index
2667  int32 lone_vg_number = 0;
2668 
2669  // Number of lone vgroups
2670  int32 num_of_lones = -1;
2671 
2672  // Number of vgroup objects
2673  int32 num_gobjects = 0;
2674 
2675  // Object reference number and tag(The pair is a key to identify an HDF4 object)
2676  int32 obj_ref = 0;
2677  int32 obj_tag = 0;
2678 
2679  // We may use new HDF4 APIs to obtain the length of the following object names and then
2680  // allocate a buffer to store the names dynamically. Documented in a jira ticket HFRHANDLER-168.
2681 
2682  // Vdata name
2683  char vdata_name[VSNAMELENMAX];
2684 
2685  // Vdata class
2686  char vdata_class[VSNAMELENMAX];
2687 
2688  // Vgroup name
2689  char vgroup_name[VGNAMELENMAX*4];
2690 
2691  // Vgroup class
2692  char vgroup_class[VGNAMELENMAX*4];
2693 
2694  // Full path of an object
2695  char *full_path;
2696 
2697  // Copy of a full path of an object
2698  char *cfull_path;
2699 
2700  // SD interface ID
2701  int32 sd_id;
2702 
2703  file_id = this->fileid;
2704  sd_id = this->sdfd;
2705 
2706  // No NASA HDF4 files have the vgroup that forms a ring; so ignore this case.
2707  // First, call Vlone with num_of_lones set to 0 to get the number of
2708  // lone vgroups in the file, but not to get their reference numbers.
2709  num_of_lones = Vlone (file_id, NULL, 0);
2710  if (num_of_lones == FAIL)
2711  throw3 ("Fail to obtain lone vgroup number", "file id is", file_id);
2712 
2713  // if there are any lone vgroups,
2714  if (num_of_lones > 0) {
2715 
2716  // Use the num_of_lones returned to allocate sufficient space for the
2717  // buffer ref_array to hold the reference numbers of all lone vgroups,
2718  vector<int32>ref_array;
2719  ref_array.resize(num_of_lones);
2720 
2721  // And call Vlone again to retrieve the reference numbers into
2722  // the buffer ref_array.
2723  num_of_lones = Vlone (file_id, &ref_array[0], num_of_lones);
2724  if (num_of_lones == FAIL) {
2725  throw3 ("Cannot obtain lone vgroup reference arrays ",
2726  "file id is ", file_id);
2727  }
2728 
2729  // Loop through all lone vgroups
2730  for (lone_vg_number = 0; lone_vg_number < num_of_lones;
2731  lone_vg_number++) {
2732 
2733  // Attach to the current vgroup
2734  vgroup_id = Vattach (file_id, ref_array[lone_vg_number], "r");
2735  if (vgroup_id == FAIL) {
2736  throw3 ("Vattach failed ", "Reference number is ",
2737  ref_array[lone_vg_number]);
2738  }
2739 
2740  status = Vgetname (vgroup_id, vgroup_name);
2741  if (status == FAIL) {
2742  Vdetach (vgroup_id);
2743  throw3 ("Vgetname failed ", "vgroup_id is ", vgroup_id);
2744  }
2745 
2746  status = Vgetclass (vgroup_id, vgroup_class);
2747  if (status == FAIL) {
2748  Vdetach (vgroup_id);
2749  throw3 ("Vgetclass failed ", "vgroup_name is ", vgroup_name);
2750  }
2751 
2752  //Ignore internal HDF groups
2753  if (strcmp (vgroup_class, _HDF_ATTRIBUTE) == 0
2754  || strcmp (vgroup_class, _HDF_VARIABLE) == 0
2755  || strcmp (vgroup_class, _HDF_DIMENSION) == 0
2756  || strcmp (vgroup_class, _HDF_UDIMENSION) == 0
2757  || strcmp (vgroup_class, _HDF_CDF) == 0
2758  || strcmp (vgroup_class, GR_NAME) == 0
2759  || strcmp (vgroup_class, RI_NAME) == 0) {
2760  Vdetach(vgroup_id);
2761  continue;
2762  }
2763 
2764  num_gobjects = Vntagrefs (vgroup_id);
2765  if (num_gobjects < 0) {
2766  Vdetach (vgroup_id);
2767  throw3 ("Vntagrefs failed ", "vgroup_name is ", vgroup_name);
2768  }
2769 
2770  // Obtain full path and cfull_path.
2771  // MAX_FULL_PATH_LEN(1024) is long enough
2772  // to cover any HDF4 object path for all NASA HDF4 products.
2773  // KY 2013-07-12
2774  //
2775  full_path = (char *) malloc (MAX_FULL_PATH_LEN);
2776  if (full_path == NULL) {
2777  Vdetach (vgroup_id);
2778  throw1 ("No enough memory to allocate the buffer.");
2779  }
2780 
2781  memset(full_path,'\0',MAX_FULL_PATH_LEN);
2782  strncpy (full_path,_BACK_SLASH,strlen(_BACK_SLASH));
2783  strncat(full_path,vgroup_name,strlen(vgroup_name));
2784  try {
2785  ReadVgattrs(vgroup_id,full_path);
2786 
2787  }
2788  catch(...) {
2789  Vdetach (vgroup_id);
2790  free (full_path);
2791  throw1 ("ReadVgattrs failed ");
2792  }
2793  strncat(full_path,_BACK_SLASH,strlen(_BACK_SLASH));
2794 
2795  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
2796  if (cfull_path == NULL) {
2797  Vdetach (vgroup_id);
2798  free (full_path);
2799  throw1 ("No enough memory to allocate the buffer.");
2800  }
2801  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
2802  strncpy (cfull_path, full_path,strlen(full_path));
2803 
2804  // Loop all vgroup objects
2805  for (int i = 0; i < num_gobjects; i++) {
2806  if (Vgettagref (vgroup_id, i, &obj_tag, &obj_ref) == FAIL) {
2807  Vdetach (vgroup_id);
2808  free (full_path);
2809  free (cfull_path);
2810  throw5 ("Vgettagref failed ", "vgroup_name is ",
2811  vgroup_name, " reference number is ", obj_ref);
2812  }
2813 
2814  // If this is a vgroup, recursively obtain information
2815  if (Visvg (vgroup_id, obj_ref) == TRUE) {
2816  strncpy (full_path, cfull_path,strlen(cfull_path)+1);
2817  full_path[strlen(cfull_path)]='\0';
2818  obtain_path (file_id, sd_id, full_path, obj_ref);
2819  }
2820  // This is a vdata
2821  else if (Visvs (vgroup_id, obj_ref)) {
2822 
2823  vdata_id = VSattach (file_id, obj_ref, "r");
2824  if (vdata_id == FAIL) {
2825  Vdetach (vgroup_id);
2826  free (full_path);
2827  free (cfull_path);
2828  throw5 ("VSattach failed ", "vgroup_name is ",
2829  vgroup_name, " reference number is ",
2830  obj_ref);
2831  }
2832  status = VSgetname (vdata_id, vdata_name);
2833  if (status == FAIL) {
2834  Vdetach (vgroup_id);
2835  free (full_path);
2836  free (cfull_path);
2837  throw5 ("VSgetclass failed ", "vgroup_name is ",
2838  vgroup_name, " reference number is ",
2839  obj_ref);
2840  }
2841 
2842  status = VSgetclass (vdata_id, vdata_class);
2843  if (status == FAIL) {
2844  Vdetach (vgroup_id);
2845  free (full_path);
2846  free (cfull_path);
2847  throw5 ("VSgetclass failed ", "vgroup_name is ",
2848  vgroup_name, " reference number is ",
2849  obj_ref);
2850  }
2851 
2852  //NOTE: I found that for 1BTRMMdata(1B21...), there
2853  // is an attribute stored in vdata under vgroup SwathData that cannot
2854  // be retrieved by any attribute APIs. I suspect this is an HDF4 bug.
2855  // This attribute is supposed to be an attribute under vgroup SwathData.
2856  // Since currently the information has been preserved by the handler,
2857  // so we don't have to handle this. It needs to be reported to the
2858  // HDF4 developer. 2010-6-25 ky
2859 
2860  // Vdata that is either used to store attributes or internal HDF4 classes. ignore.
2861  if (VSisattr (vdata_id) == TRUE
2862  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
2863  strlen (_HDF_CHK_TBL_CLASS))
2864  || !strncmp (vdata_class, _HDF_SDSVAR,
2865  strlen (_HDF_SDSVAR))
2866  || !strncmp (vdata_class, _HDF_CRDVAR,
2867  strlen (_HDF_CRDVAR))
2868  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
2869  || !strncmp (vdata_class, DIM_VALS01,
2870  strlen (DIM_VALS01))
2871  || !strncmp (vdata_class, RIGATTRCLASS,
2872  strlen (RIGATTRCLASS))
2873  || !strncmp (vdata_name, RIGATTRNAME,
2874  strlen (RIGATTRNAME))) {
2875 
2876  status = VSdetach (vdata_id);
2877  if (status == FAIL) {
2878  Vdetach (vgroup_id);
2879  free (full_path);
2880  free (cfull_path);
2881  throw3 ("VSdetach failed ",
2882  "Vdata is under vgroup ", vgroup_name);
2883  }
2884 
2885  }
2886  else {
2887 
2888  VDATA*vdataobj = NULL;
2889  try {
2890  vdataobj = VDATA::Read (vdata_id, obj_ref);
2891  }
2892  catch(...) {
2893  free (full_path);
2894  free (cfull_path);
2895  VSdetach(vdata_id);
2896  Vdetach (vgroup_id);
2897  throw;
2898  }
2899 
2900 
2901  vdataobj->newname = full_path +vdataobj->name;
2902 
2903  //We want to map fields of vdata with more than 10 records to DAP variables
2904  // and we need to add the path and vdata name to the new vdata field name
2905  if (!vdataobj->getTreatAsAttrFlag ()) {
2906  for (std::vector <VDField * >::const_iterator it_vdf =
2907  vdataobj->getFields ().begin ();
2908  it_vdf != vdataobj->getFields ().end ();
2909  it_vdf++) {
2910 
2911  // Change vdata name conventions.
2912  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
2913 
2914  (*it_vdf)->newname =
2915  "vdata" + vdataobj->newname + "_vdf_" + (*it_vdf)->name;
2916 
2917  //Make sure the name is following CF, KY 2012-6-26
2918  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
2919  }
2920 
2921  }
2922 
2923  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
2924 
2925  this->vds.push_back (vdataobj);
2926 
2927  status = VSdetach (vdata_id);
2928  if (status == FAIL) {
2929  Vdetach (vgroup_id);
2930  free (full_path);
2931  free (cfull_path);
2932  throw3 ("VSdetach failed ",
2933  "Vdata is under vgroup ", vgroup_name);
2934  }
2935  }
2936  }
2937 
2938  // These are SDS objects
2939  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
2940  || obj_tag == DFTAG_SD) {
2941 
2942  // We need to obtain the SDS index; also need to store the new name(object name + full_path).
2943  if (this->sd->refindexlist.find (obj_ref) !=
2944  sd->refindexlist.end ())
2945  this->sd->sdfields[this->sd->refindexlist[obj_ref]]->newname =
2946  full_path +
2947  this->sd->sdfields[this->sd->refindexlist[obj_ref]]->name;
2948  else {
2949  Vdetach (vgroup_id);
2950  free (full_path);
2951  free (cfull_path);
2952  throw3 ("SDS with the reference number ", obj_ref,
2953  " is not found");
2954  }
2955  }
2956  else;
2957  }
2958  free (full_path);
2959  free (cfull_path);
2960 
2961  status = Vdetach (vgroup_id);
2962  if (status == FAIL) {
2963  throw3 ("Vdetach failed ", "vgroup_name is ", vgroup_name);
2964  }
2965  }//end of the for loop
2966  }// end of the if loop
2967 
2968 }
2969 
2970 // This fuction is called recursively to obtain the full path of an HDF4 object.
2971 // obtain_path, obtain_noneos2_sds_path,obtain_vdata_path are very similar.
2972 // We may combine them in the future. Documented at HFRHANDLER-166.
2973 void
2974 File::obtain_path (int32 file_id, int32 sd_id, char *full_path,
2975  int32 pobj_ref)
2976 throw (Exception)
2977 {
2978  // Vgroup parent ID
2979  int32 vgroup_pid = 0;
2980 
2981  // Indicator of status
2982  int32 status = 0;
2983 
2984  // Index i
2985  int i = 0;
2986 
2987  // Number of group objects
2988  int num_gobjects = 0;
2989 
2990  // The following names are statically allocated.
2991  // This can be updated in the future with new HDF4 APIs that can provide the actual length of an object name.
2992  // Documented in a jira ticket HFRHANDLER-168.
2993  // KY 2013-07-11
2994 
2995  // Child vgroup name
2996  char cvgroup_name[VGNAMELENMAX*4];
2997 
2998  // Vdata name
2999  char vdata_name[VSNAMELENMAX];
3000 
3001  // Vdata class name
3002  char vdata_class[VSNAMELENMAX];
3003 
3004  // Vdata ID
3005  int32 vdata_id = -1;
3006 
3007  // Object tag
3008  int32 obj_tag = 0;
3009 
3010  // Object reference
3011  int32 obj_ref = 0;
3012 
3013  // full path of the child group
3014  char *cfull_path;
3015 
3016  // MAX_FULL_PATH_LEN(1024) is long enough
3017  // to cover any HDF4 object path for all NASA HDF4 products.
3018  // So using strcpy and strcat is safe in a practical sense.
3019  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
3020  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
3021  // Documented in a jira ticket HFRHANDLER-168.
3022  // KY 2013-07-12
3023  // We use strncpy and strncat to replace strcpy and strcat. KY 2013-09-06
3024 
3025  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
3026  if (cfull_path == NULL)
3027  throw1 ("No enough memory to allocate the buffer");
3028 
3029  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
3030  vgroup_pid = Vattach (file_id, pobj_ref, "r");
3031  if (vgroup_pid == FAIL) {
3032  free (cfull_path);
3033  throw3 ("Vattach failed ", "Object reference number is ", pobj_ref);
3034  }
3035 
3036  if (Vgetname (vgroup_pid, cvgroup_name) == FAIL) {
3037  Vdetach (vgroup_pid);
3038  free (cfull_path);
3039  throw3 ("Vgetname failed ", "Object reference number is ", pobj_ref);
3040  }
3041  num_gobjects = Vntagrefs (vgroup_pid);
3042  if (num_gobjects < 0) {
3043  Vdetach (vgroup_pid);
3044  free (cfull_path);
3045  throw3 ("Vntagrefs failed ", "Object reference number is ", pobj_ref);
3046  }
3047 
3048  strncpy(cfull_path,full_path,strlen(full_path));
3049  strncat(cfull_path,cvgroup_name,strlen(cvgroup_name));
3050  try {
3051  ReadVgattrs(vgroup_pid,cfull_path);
3052 
3053  }
3054  catch(...) {
3055  Vdetach (vgroup_pid);
3056  free (cfull_path);
3057  throw1 ("ReadVgattrs failed ");
3058  }
3059 
3060  strncat(cfull_path,_BACK_SLASH,strlen(_BACK_SLASH));
3061 
3062 
3063 
3064  for (i = 0; i < num_gobjects; i++) {
3065 
3066  if (Vgettagref (vgroup_pid, i, &obj_tag, &obj_ref) == FAIL) {
3067  Vdetach (vgroup_pid);
3068  free (cfull_path);
3069  throw3 ("Vgettagref failed ", "object index is ", i);
3070  }
3071 
3072  if (Visvg (vgroup_pid, obj_ref) == TRUE) {
3073  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
3074  full_path[strlen(cfull_path)]='\0';
3075  obtain_path (file_id, sd_id, full_path, obj_ref);
3076  }
3077  else if (Visvs (vgroup_pid, obj_ref)) {
3078 
3079  vdata_id = VSattach (file_id, obj_ref, "r");
3080  if (vdata_id == FAIL) {
3081  Vdetach (vgroup_pid);
3082  free (cfull_path);
3083  throw3 ("VSattach failed ", "object index is ", i);
3084  }
3085 
3086 
3087  status = VSQueryname (vdata_id, vdata_name);
3088  if (status == FAIL) {
3089  Vdetach (vgroup_pid);
3090  free (cfull_path);
3091  throw3 ("VSgetclass failed ", "object index is ", i);
3092  }
3093 
3094  status = VSgetclass (vdata_id, vdata_class);
3095  if (status == FAIL) {
3096  Vdetach (vgroup_pid);
3097  free (cfull_path);
3098  throw3 ("VSgetclass failed ", "object index is ", i);
3099  }
3100 
3101  if (VSisattr (vdata_id) != TRUE) {
3102  if (strncmp
3103  (vdata_class, _HDF_CHK_TBL_CLASS,
3104  strlen (_HDF_CHK_TBL_CLASS))) {
3105 
3106  VDATA *vdataobj = NULL;
3107 
3108  try {
3109  vdataobj = VDATA::Read (vdata_id, obj_ref);
3110  }
3111  catch(...) {
3112  free (cfull_path);
3113  Vdetach (vgroup_pid);
3114  throw;
3115  }
3116 
3117 
3118  // The new name conventions require the path prefixed before the object name.
3119  vdataobj->newname = cfull_path + vdataobj->name;
3120  // We want to map fields of vdata with more than 10 records to DAP variables
3121  // and we need to add the path and vdata name to the new vdata field name
3122  if (!vdataobj->getTreatAsAttrFlag ()) {
3123  for (std::vector <VDField * >::const_iterator it_vdf =
3124  vdataobj->getFields ().begin ();
3125  it_vdf != vdataobj->getFields ().end ();
3126  it_vdf++) {
3127 
3128  // Change vdata name conventions.
3129  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
3130  (*it_vdf)->newname =
3131  "vdata" + vdataobj->newname + "_vdf_" +
3132  (*it_vdf)->name;
3133 
3134  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
3135  }
3136  }
3137 
3138  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
3139  this->vds.push_back (vdataobj);
3140  }
3141  }
3142  status = VSdetach (vdata_id);
3143  if (status == FAIL) {
3144  free(cfull_path);
3145  throw3 ("VSdetach failed ", "object index is ", i);
3146  }
3147  }
3148  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
3149  || obj_tag == DFTAG_SD) {
3150  if (this->sd->refindexlist.find (obj_ref) !=
3151  this->sd->refindexlist.end ())
3152  this->sd->sdfields[this->sd->refindexlist[obj_ref]]->newname =
3153  // New name conventions require the path to be prefixed before the object name
3154  cfull_path + this->sd->sdfields[this->sd->refindexlist[obj_ref]]->name;
3155  else {
3156  Vdetach (vgroup_pid);
3157  free (cfull_path);
3158  throw3 ("SDS with the reference number ", obj_ref,
3159  " is not found");;
3160  }
3161  }
3162  else;
3163  }
3164  status = Vdetach (vgroup_pid);
3165  if (status == FAIL) {
3166  free (cfull_path);
3167  throw3 ("Vdetach failed ", "vgroup name is ", cvgroup_name);
3168  }
3169  free (cfull_path);
3170 
3171 }
3172 
3173 // This fuction is called recursively to obtain the full path of an HDF4 SDS path for extra SDS objects
3174 // in a hybrid HDF-EOS2 file.
3175 // obtain_path, obtain_noneos2_sds_path,obtain_vdata_path are very similar.
3176 // We may combine them in the future. Documented at HFRHANDLER-166.
3177 // Also we only add minimum comments since this code may be removed in the future.
3178 void
3179 SD::obtain_noneos2_sds_path (int32 file_id, char *full_path, int32 pobj_ref)
3180 throw (Exception)
3181 {
3182 
3183  int32 vgroup_cid = 0;
3184  int32 status = 0;
3185  int i = 0;
3186  int num_gobjects = 0;
3187 
3188  // Now HDF4 provides a dynamic way to allocate the length of an HDF4 object name, should update to use that in the future.
3189  // Documented in a jira ticket HFRHANDLER-168.
3190  // KY 2013-07-11
3191  char cvgroup_name[VGNAMELENMAX*4];
3192 
3193  int32 obj_tag, obj_ref;
3194  char *cfull_path;
3195 
3196  // MAX_FULL_PATH_LEN(1024) is long enough
3197  // to cover any HDF4 object path for all NASA HDF4 products.
3198  // So using strcpy and strcat is safe in a practical sense.
3199  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
3200  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
3201  // Documented in a jira ticket HFRHANDLER-168.
3202  // KY 2013-07-12
3203  // We use strncpy and strncat to replace strcpy and strcat. KY 2013-09-06
3204 
3205  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
3206  if (cfull_path == NULL)
3207  throw1 ("No enough memory to allocate the buffer");
3208 
3209  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
3210 
3211  vgroup_cid = Vattach (file_id, pobj_ref, "r");
3212  if (vgroup_cid == FAIL) {
3213  free (cfull_path);
3214  throw3 ("Vattach failed ", "Object reference number is ", pobj_ref);
3215  }
3216 
3217  if (Vgetname (vgroup_cid, cvgroup_name) == FAIL) {
3218  Vdetach (vgroup_cid);
3219  free (cfull_path);
3220  throw3 ("Vgetname failed ", "Object reference number is ", pobj_ref);
3221  }
3222  num_gobjects = Vntagrefs (vgroup_cid);
3223  if (num_gobjects < 0) {
3224  Vdetach (vgroup_cid);
3225  free (cfull_path);
3226  throw3 ("Vntagrefs failed ", "Object reference number is ", pobj_ref);
3227  }
3228 
3229  // NOTE: The order of cat gets changed.
3230  strncpy(cfull_path,full_path,strlen(full_path));
3231  strncat(cfull_path,cvgroup_name,strlen(cvgroup_name));
3232  strncat(cfull_path,_BACK_SLASH,strlen(_BACK_SLASH));
3233 
3234  for (i = 0; i < num_gobjects; i++) {
3235 
3236  if (Vgettagref (vgroup_cid, i, &obj_tag, &obj_ref) == FAIL) {
3237  Vdetach (vgroup_cid);
3238  free (cfull_path);
3239  throw3 ("Vgettagref failed ", "object index is ", i);
3240  }
3241 
3242  if (Visvg (vgroup_cid, obj_ref) == TRUE) {
3243  strncpy (full_path, cfull_path,strlen(cfull_path)+1);
3244  full_path[strlen(cfull_path)]='\0';
3245  obtain_noneos2_sds_path (file_id, full_path, obj_ref);
3246  }
3247  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
3248  || obj_tag == DFTAG_SD) {
3249 
3250  // Here we need to check if the SDS is an EOS object by checking
3251  // if the the path includes "Data Fields" or "Geolocation Fields".
3252  // If the object is an EOS object, we will remove it from the list.
3253 
3254  string temp_str = string(cfull_path);
3255  if((temp_str.find("Data Fields") != std::string::npos)||
3256  (temp_str.find("Geolocation Fields") != std::string::npos))
3257  sds_ref_list.remove(obj_ref);
3258  }
3259  else;
3260  }
3261  status = Vdetach (vgroup_cid);
3262  if (status == FAIL) {
3263  free (cfull_path);
3264  throw3 ("Vdetach failed ", "vgroup name is ", cvgroup_name);
3265  }
3266  free (cfull_path);
3267 
3268 }
3269 
3270 
3271 // This fuction is called recursively to obtain the full path of the HDF4 vgroup.
3272 // This function is especially used when obtaining non-lone vdata objects for a hybrid file.
3273 // obtain_path, obtain_noneos2_sds_path,obtain_vdata_path are very similar.
3274 // We may combine them in the future. Documented at HFRHANDLER-166.
3275 
3276 void
3277 File::obtain_vdata_path (int32 file_id, char *full_path,
3278  int32 pobj_ref)
3279 throw (Exception)
3280 {
3281 
3282  int32 vgroup_cid = -1;
3283  int32 status = -1;
3284  int i = -1;
3285  int num_gobjects = -1;
3286 
3287  // Now HDF4 provides dynamic ways to allocate the length of object names, should update to use that in the future.
3288  // Documented in a jira ticket HFRHANDLER-168.
3289  // KY 2013-07-11
3290  char cvgroup_name[VGNAMELENMAX*4];
3291  char vdata_name[VSNAMELENMAX];
3292  char vdata_class[VSNAMELENMAX];
3293  int32 vdata_id = -1;
3294  int32 obj_tag = -1;
3295  int32 obj_ref = -1;
3296  char *cfull_path;
3297 
3298  // MAX_FULL_PATH_LEN(1024) is long enough
3299  // to cover any HDF4 object path for all NASA HDF4 products.
3300  // So using strcpy and strcat is safe in a practical sense.
3301  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
3302  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
3303  // Documented in a jira ticket HFRHANDLER-168.
3304  // KY 2013-07-12
3305  // We replace strcpy and strcat with strncpy and strncat as suggested. KY 2013-08-29
3306 
3307  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
3308  if (cfull_path == NULL)
3309  throw1 ("No enough memory to allocate the buffer");
3310  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
3311 
3312  vgroup_cid = Vattach (file_id, pobj_ref, "r");
3313  if (vgroup_cid == FAIL) {
3314  free (cfull_path);
3315  throw3 ("Vattach failed ", "Object reference number is ", pobj_ref);
3316  }
3317 
3318  if (Vgetname (vgroup_cid, cvgroup_name) == FAIL) {
3319  Vdetach (vgroup_cid);
3320  free (cfull_path);
3321  throw3 ("Vgetname failed ", "Object reference number is ", pobj_ref);
3322  }
3323  num_gobjects = Vntagrefs (vgroup_cid);
3324  if (num_gobjects < 0) {
3325  Vdetach (vgroup_cid);
3326  free (cfull_path);
3327  throw3 ("Vntagrefs failed ", "Object reference number is ", pobj_ref);
3328  }
3329 
3330  strncpy(cfull_path,full_path,strlen(full_path));
3331  strncat(cfull_path,cvgroup_name,strlen(cvgroup_name));
3332  strncat(cfull_path,_BACK_SLASH,strlen(_BACK_SLASH));
3333 
3334 
3335  // If having a vgroup "Geolocation Fields", we would like to set the EOS2Swath flag.
3336  std::string temp_str = std::string(cfull_path);
3337 
3338  if (temp_str.find("Geolocation Fields") != string::npos) {
3339  if(false == this->EOS2Swathflag)
3340  this->EOS2Swathflag = true;
3341  }
3342 
3343  for (i = 0; i < num_gobjects; i++) {
3344 
3345  if (Vgettagref (vgroup_cid, i, &obj_tag, &obj_ref) == FAIL) {
3346  Vdetach (vgroup_cid);
3347  free (cfull_path);
3348  throw3 ("Vgettagref failed ", "object index is ", i);
3349  }
3350 
3351  if (Visvg (vgroup_cid, obj_ref) == TRUE) {
3352  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
3353  full_path[strlen(cfull_path)] = '\0';
3354  obtain_vdata_path (file_id, full_path, obj_ref);
3355  }
3356  else if (Visvs (vgroup_cid, obj_ref)) {
3357 
3358  vdata_id = VSattach (file_id, obj_ref, "r");
3359  if (vdata_id == FAIL) {
3360  Vdetach (vgroup_cid);
3361  free (cfull_path);
3362  throw3 ("VSattach failed ", "object index is ", i);
3363  }
3364 
3365  status = VSQueryname (vdata_id, vdata_name);
3366  if (status == FAIL) {
3367  Vdetach (vgroup_cid);
3368  free (cfull_path);
3369  throw3 ("VSgetclass failed ", "object index is ", i);
3370  }
3371 
3372  status = VSgetclass (vdata_id, vdata_class);
3373  if (status == FAIL) {
3374  Vdetach (vgroup_cid);
3375  free (cfull_path);
3376  throw3 ("VSgetclass failed ", "object index is ", i);
3377  }
3378 
3379  // Obtain the C++ string format of the path.
3380  string temp_str = string(cfull_path);
3381 
3382  // Swath 1-D is mapped to Vdata, we need to ignore them.
3383  // But if vdata is added to a grid, we should not ignore.
3384  // Since "Geolocation Fields" will always appear before
3385  // the "Data Fields", we can use a flag to distinguish
3386  // the swath from the grid. Swath includes both "Geolocation Fields"
3387  // and "Data Fields". Grid only has "Data Fields".
3388  // KY 2013-01-03
3389 
3390  bool ignore_eos2_geo_vdata = false;
3391  bool ignore_eos2_data_vdata = false;
3392  if (temp_str.find("Geolocation Fields") != string::npos) {
3393  ignore_eos2_geo_vdata = true;
3394  }
3395 
3396  // Only ignore "Data Fields" vdata when "Geolocation Fields" appears.
3397  if (temp_str.find("Data Fields") != string::npos) {
3398  if (true == this->EOS2Swathflag)
3399  ignore_eos2_data_vdata = true;
3400  }
3401  if ((true == ignore_eos2_data_vdata)
3402  ||(true == ignore_eos2_geo_vdata)
3403  || VSisattr (vdata_id) == TRUE
3404  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
3405  strlen (_HDF_CHK_TBL_CLASS))
3406  || !strncmp (vdata_class, _HDF_SDSVAR,
3407  strlen (_HDF_SDSVAR))
3408  || !strncmp (vdata_class, _HDF_CRDVAR,
3409  strlen (_HDF_CRDVAR))
3410  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
3411  || !strncmp (vdata_class, DIM_VALS01,
3412  strlen (DIM_VALS01))
3413  || !strncmp (vdata_class, RIGATTRCLASS,
3414  strlen (RIGATTRCLASS))
3415  || !strncmp (vdata_name, RIGATTRNAME,
3416  strlen (RIGATTRNAME))) {
3417 
3418  status = VSdetach (vdata_id);
3419  if (status == FAIL) {
3420  Vdetach (vgroup_cid);
3421  free (cfull_path);
3422  throw3 ("VSdetach failed ",
3423  "Vdata is under vgroup ", cvgroup_name);
3424  }
3425  }
3426  else {
3427 
3428  VDATA *vdataobj = NULL;
3429  try {
3430  vdataobj = VDATA::Read (vdata_id, obj_ref);
3431  }
3432  catch(...) {
3433  free (cfull_path);
3434  VSdetach(vdata_id);
3435  Vdetach (vgroup_cid);
3436  throw;
3437  }
3438 
3439  // The new name conventions require the path prefixed before the object name.
3440  vdataobj->newname = cfull_path + vdataobj->name;
3441  // We want to map fields of vdata with more than 10 records to DAP variables
3442  // and we need to add the path and vdata name to the new vdata field name
3443  if (!vdataobj->getTreatAsAttrFlag ()) {
3444  for (std::vector <VDField * >::const_iterator it_vdf =
3445  vdataobj->getFields ().begin ();
3446  it_vdf != vdataobj->getFields ().end ();
3447  it_vdf++) {
3448 
3449  // Change vdata name conventions.
3450  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
3451  (*it_vdf)->newname =
3452  "vdata" + vdataobj->newname + "_vdf_" +
3453  (*it_vdf)->name;
3454 
3455  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
3456  }
3457  }
3458 
3459  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
3460  this->vds.push_back (vdataobj);
3461  status = VSdetach (vdata_id);
3462  if (status == FAIL) {
3463  free(cfull_path);
3464  Vdetach(vgroup_cid);
3465  throw3 ("VSdetach failed ", "object index is ", i);
3466  }
3467  }
3468  }
3469  else;
3470  }
3471  status = Vdetach (vgroup_cid);
3472  if (status == FAIL) {
3473  free (cfull_path);
3474  throw3 ("Vdetach failed ", "vgroup name is ", cvgroup_name);
3475  }
3476  free (cfull_path);
3477 
3478 }
3479 
3480 // Handle SDS fakedim names: make the dimensions with the same dimension size
3481 // share the same dimension name. In this way, we can reduce many fakedims.
3482 void
3483 File::handle_sds_fakedim_names() throw(Exception) {
3484 
3485  File *file = this;
3486 
3487  // Build Dimension name list
3488  // We have to assume that NASA HDF4 SDSs provide unique dimension names under each vgroup
3489  // Find unique dimension name list
3490  // Build a map from unique dimension name list to the original dimension name list
3491  // Don't count fakeDim ......
3492  // Based on the new dimension name list, we will build a coordinate field for each dimension
3493  // for each product we support. If dimension scale data are found, that dimension scale data will
3494  // be retrieved according to our knowledge to the data product.
3495  // The unique dimension name is the dimension name plus the full path
3496  // We should build a map to obtain the final coordinate fields of each field
3497 
3498  std::string tempdimname;
3499  std::pair < std::set < std::string >::iterator, bool > ret;
3500  std::string temppath;
3501  std::set < int32 > fakedimsizeset;
3502  std::pair < std::set < int32 >::iterator, bool > fakedimsizeit;
3503  std::map < int32, std::string > fakedimsizenamelist;
3504  std::map < int32, std::string >::iterator fakedimsizenamelistit;
3505 
3506  for (std::vector < SDField * >::const_iterator i =
3507  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3508 
3509  for (std::vector < Dimension * >::const_iterator j =
3510  (*i)->getDimensions ().begin ();
3511  j != (*i)->getDimensions ().end (); ++j) {
3512 
3513  //May treat corrected dimension names as the original dimension names the SAME, CORRECT it in the future.
3514  if (file->sptype != OTHERHDF)
3515  tempdimname = (*j)->getName ();
3516  else
3517  tempdimname = (*j)->getName () + temppath;
3518 
3519  Dimension *dim =
3520  new Dimension (tempdimname, (*j)->getSize (),
3521  (*j)->getType ());
3522  (*i)->correcteddims.push_back (dim);
3523  if (tempdimname.find ("fakeDim") != std::string::npos) {
3524  fakedimsizeit = fakedimsizeset.insert ((*j)->getSize ());
3525  if (fakedimsizeit.second == true) {
3526  fakedimsizenamelist[(*j)->getSize ()] = (*j)->getName (); //Here we just need the original name since fakeDim is globally generated.
3527  }
3528  }
3529  }
3530  }
3531 
3532  // The CF conventions have to be followed for products(TRMM etc.) that use fakeDims . KY 2012-6-26
3533  // Sequeeze "fakeDim" names according to fakeDim size. For example, if fakeDim1, fakeDim3, fakeDim5 all shares the same size,
3534  // we use one name(fakeDim1) to be the dimension name. This will reduce the number of fakeDim names.
3535 
3536  if (file->sptype != OTHERHDF) {
3537  for (std::vector < SDField * >::const_iterator i =
3538  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3539  for (std::vector < Dimension * >::const_iterator j =
3540  (*i)->getCorrectedDimensions ().begin ();
3541  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3542  if ((*j)->getName ().find ("fakeDim") != std::string::npos) {
3543  if (fakedimsizenamelist.find ((*j)->getSize ()) !=
3544  fakedimsizenamelist.end ()) {
3545  (*j)->name = fakedimsizenamelist[(*j)->getSize ()]; //sequeeze the redundant fakeDim with the same size
3546  }
3547  else
3548  throw5 ("The fakeDim name ", (*j)->getName (),
3549  "with the size", (*j)->getSize (),
3550  "does not in the fakedimsize list");
3551  }
3552  }
3553  }
3554  }
3555 }
3556 
3557 // Create the new dimension name set and the dimension name to size map.
3559 
3560  File *file = this;
3561 
3562  // Create the new dimension name set and the dimension name to size map.
3563  for (std::vector < SDField * >::const_iterator i =
3564  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3565  for (std::vector < Dimension * >::const_iterator j =
3566  (*i)->getCorrectedDimensions ().begin ();
3567  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3568  std::pair < std::set < std::string >::iterator, bool > ret;
3569  ret = file->sd->fulldimnamelist.insert ((*j)->getName ());
3570 
3571  // Map from the unique dimension name to its size
3572  if (ret.second == true) {
3573  file->sd->n1dimnamelist[(*j)->getName ()] = (*j)->getSize ();
3574  }
3575  }
3576  }
3577 
3578 }
3579 
3580 // Add the missing coordinate variables based on the corrected dimension name list
3582 
3583  File *file = this;
3584 
3585  // Adding the missing coordinate variables based on the corrected dimension name list
3586  // For some CERES products, there are so many vgroups, so there are potentially many missing fields.
3587  // Go through the n1dimnamelist and check the map dimcvarlist; if no dimcvarlist[dimname], then this dimension namelist must be a missing field
3588  // Create the missing field and insert the missing field to the SDField list.
3589 
3590  for (std::map < std::string, int32 >::const_iterator i =
3591  file->sd->n1dimnamelist.begin ();
3592  i != file->sd->n1dimnamelist.end (); ++i) {
3593 
3594  if (file->sd->nonmisscvdimnamelist.find ((*i).first) == file->sd->nonmisscvdimnamelist.end ()) {// Create a missing Z-dimension field
3595 
3596  SDField *missingfield = new SDField ();
3597 
3598  // The name of the missingfield is not necessary.
3599  // We only keep here for consistency.
3600 
3601  missingfield->type = DFNT_INT32;
3602  missingfield->name = (*i).first;
3603  missingfield->newname = (*i).first;
3604  missingfield->rank = 1;
3605  missingfield->fieldtype = 4;
3606  Dimension *dim = new Dimension ((*i).first, (*i).second, 0);
3607 
3608  missingfield->dims.push_back (dim);
3609  dim = new Dimension ((*i).first, (*i).second, 0);
3610  missingfield->correcteddims.push_back (dim);
3611  file->sd->sdfields.push_back (missingfield);
3612  }
3613  }
3614 }
3615 
3616 // Create the final CF-compliant dimension name list for each field
3618 
3619  File * file = this;
3620 
3622  // We will create the final unique dimension name list(erasing special characters etc.)
3623  // After erasing special characters, the nameclashing for dimension name is still possible.
3624  // So still handle the name clashings.
3625 
3626  vector<string>tempfulldimnamelist;
3627  for (std::set < std::string >::const_iterator i =
3628  file->sd->fulldimnamelist.begin ();
3629  i != file->sd->fulldimnamelist.end (); ++i)
3630  tempfulldimnamelist.push_back(HDFCFUtil::get_CF_string(*i));
3631 
3632  HDFCFUtil::Handle_NameClashing(tempfulldimnamelist);
3633 
3634  // Not the most efficient way, but to keep the original code structure,KY 2012-6-27
3635  int total_dcounter = 0;
3636  for (std::set < std::string >::const_iterator i =
3637  file->sd->fulldimnamelist.begin ();
3638  i != file->sd->fulldimnamelist.end (); ++i) {
3639  HDFCFUtil::insert_map(file->sd->n2dimnamelist, (*i), tempfulldimnamelist[total_dcounter]);
3640  total_dcounter++;
3641  }
3642 
3643  // change the corrected dimension name list for each SDS field
3644  std::map < std::string, std::string >::iterator tempmapit;
3645  for (std::vector < SDField * >::const_iterator i =
3646  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3647  for (std::vector < Dimension * >::const_iterator j =
3648  (*i)->getCorrectedDimensions ().begin ();
3649  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3650  tempmapit = file->sd->n2dimnamelist.find ((*j)->getName ());
3651  if (tempmapit != file->sd->n2dimnamelist.end ())
3652  (*j)->name = tempmapit->second;
3653  else { //When the dimension name is fakeDim***, we will ignore. this dimension will not have the corresponding coordinate variable.
3654  throw5 ("This dimension with the name ", (*j)->name,
3655  "and the field name ", (*i)->name,
3656  " is not found in the dimension list.");
3657  }
3658  }
3659  }
3660 
3661 }
3662 
3663 // Create the final CF-compliant field name list
3664 void
3665 File::handle_sds_names(bool & COARDFLAG, string & lldimname1, string&lldimname2) throw(Exception)
3666 {
3667 
3668  File * file = this;
3669 
3670  // Handle name clashings
3671 
3672  // There are many fields in CERES data(a few hundred) and the full name(with the additional path)
3673  // is very long. It causes Java clients choken since Java clients append names in the URL
3674  // To improve the performance and to make Java clients access the data, simply use the field names for
3675  // these fields. Users can turn off this feature by commenting out the line: H4.EnableCERESMERRAShortName=true
3676  // or set the H4.EnableCERESMERRAShortName=false
3677  // KY 2012-6-27
3678 
3679  string check_ceres_short_name_key="H4.EnableCERESMERRAShortName";
3680  bool turn_on_ceres_short_name_key= false;
3681 
3682  turn_on_ceres_short_name_key = HDFCFUtil::check_beskeys(check_ceres_short_name_key);
3683 
3684  if (true == turn_on_ceres_short_name_key && (file->sptype == CER_ES4 || file->sptype == CER_SRB
3685  || file->sptype == CER_CDAY || file->sptype == CER_CGEO
3686  || file->sptype == CER_SYN || file->sptype == CER_ZAVG
3687  || file->sptype == CER_AVG)) {
3688 
3689  for (unsigned int i = 0; i < file->sd->sdfields.size (); ++i) {
3690  file->sd->sdfields[i]->special_product_fullpath = file->sd->sdfields[i]->newname;
3691  file->sd->sdfields[i]->newname = file->sd->sdfields[i]->name;
3692  }
3693  }
3694 
3695 
3696  vector<string>sd_data_fieldnamelist;
3697  vector<string>sd_latlon_fieldnamelist;
3698  vector<string>sd_nollcv_fieldnamelist;
3699 
3700  set<string>sd_fieldnamelist;
3701 
3702  for (std::vector < SDField * >::const_iterator i =
3703  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3704  if ((*i)->fieldtype ==0)
3705  sd_data_fieldnamelist.push_back(HDFCFUtil::get_CF_string((*i)->newname));
3706  else if ((*i)->fieldtype == 1 || (*i)->fieldtype == 2)
3707  sd_latlon_fieldnamelist.push_back(HDFCFUtil::get_CF_string((*i)->newname));
3708  else
3709  sd_nollcv_fieldnamelist.push_back(HDFCFUtil::get_CF_string((*i)->newname));
3710  }
3711 
3712  HDFCFUtil::Handle_NameClashing(sd_data_fieldnamelist,sd_fieldnamelist);
3713  HDFCFUtil::Handle_NameClashing(sd_latlon_fieldnamelist,sd_fieldnamelist);
3714  HDFCFUtil::Handle_NameClashing(sd_nollcv_fieldnamelist,sd_fieldnamelist);
3715 
3716  // Check the special characters and change those characters to _ for field namelist
3717  // Also create dimension name to coordinate variable name list
3718 
3719  int total_data_counter = 0;
3720  int total_latlon_counter = 0;
3721  int total_nollcv_counter = 0;
3722 
3723  //bool COARDFLAG = false;
3724  //string lldimname1;
3725  //string lldimname2;
3726 
3727  // change the corrected dimension name list for each SDS field
3728  std::map < std::string, std::string >::iterator tempmapit;
3729 
3730 
3731  for (std::vector < SDField * >::const_iterator i =
3732  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3733 
3734  // Handle dimension name to coordinate variable map
3735  // Currently there is a backward compatibility issue in the CF conventions,
3736  // If a field temp[ydim = 10][xdim =5][zdim=2], the
3737  // coordinate variables are lat[ydim=10][xdim=5],
3738  // lon[ydim =10][xdim=5], zdim[zdim =2]. Panoply and IDV will
3739  // not display these properly because they think the field is
3740  // following COARD conventions based on zdim[zdim =2].
3741  // To make the IDV and Panoply work, we have to change zdim[zdim=2]
3742  // to something like zdim_v[zdim=2] to distinguish the dimension name
3743  // from the variable name.
3744  // KY 2010-7-21
3745  // set a flag
3746 
3747  if ((*i)->fieldtype != 0) {
3748  if ((*i)->fieldtype == 1 || (*i)->fieldtype == 2) {
3749 
3750  (*i)->newname = sd_latlon_fieldnamelist[total_latlon_counter];
3751  total_latlon_counter++;
3752 
3753  if ((*i)->getRank () > 2)
3754  throw3 ("the lat/lon rank should NOT be greater than 2",
3755  (*i)->name, (*i)->getRank ());
3756  else if ((*i)->getRank () == 2) {// Each lat/lon must be 2-D under the same group.
3757  for (std::vector < Dimension * >::const_iterator j =
3758  (*i)->getCorrectedDimensions ().begin ();
3759  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3760  tempmapit =
3761  file->sd->dimcvarlist.find ((*j)->getName ());
3762  if (tempmapit == file->sd->dimcvarlist.end ()) {
3763  HDFCFUtil::insert_map(file->sd->dimcvarlist, (*j)->name, (*i)->newname);
3764 
3765  // Save this dim. to lldims
3766  if (lldimname1 =="")
3767  lldimname1 =(*j)->name;
3768  else
3769  lldimname2 = (*j)->name;
3770  break;
3771  }
3772  }
3773  }
3774 
3775  else {
3776  // When rank = 1, must follow COARD conventions.
3777  // Here we don't check name clashing for the performance
3778  // reason, the chance of clashing is very,very rare.
3779  (*i)->newname =
3780  (*i)->getCorrectedDimensions ()[0]->getName ();
3781  HDFCFUtil::insert_map(file->sd->dimcvarlist, (*i)->getCorrectedDimensions()[0]->getName(), (*i)->newname);
3782  COARDFLAG = true;
3783 
3784  }
3785  }
3786  }
3787  else {
3788  (*i)->newname = sd_data_fieldnamelist[total_data_counter];
3789  total_data_counter++;
3790  }
3791  }
3792 
3793 
3794  for (std::vector < SDField * >::const_iterator i =
3795  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3796 
3797 
3798  // Handle dimension name to coordinate variable map
3799  // Currently there is a backward compatibility issue in the CF conventions,
3800  // If a field temp[ydim = 10][xdim =5][zdim=2], the
3801  // coordinate variables are lat[ydim=10][xdim=5],
3802  // lon[ydim =10][xdim=5], zdim[zdim =2]. Panoply and IDV will
3803  // not display these properly because they think the field is
3804  // following COARD conventions based on zdim[zdim =2].
3805  // To make the IDV and Panoply work, we have to change zdim[zdim=2]
3806  // to something like zdim_v[zdim=2] to distinguish the dimension name
3807  // from the variable name.
3808  // KY 2010-7-21
3809  // set a flag
3810 
3811  if ((*i)->fieldtype != 0) {
3812  if ((*i)->fieldtype != 1 && (*i)->fieldtype != 2) {
3813  // "Missing" coordinate variables or coordinate variables having dimensional scale data
3814 
3815  (*i)->newname = sd_nollcv_fieldnamelist[total_nollcv_counter];
3816  total_nollcv_counter++;
3817 
3818  if ((*i)->getRank () > 1)
3819  throw3 ("The lat/lon rank should be 1", (*i)->name,
3820  (*i)->getRank ());
3821 
3822  // The current OTHERHDF case we support(MERRA and SDS dimension scale)
3823  // follow COARDS conventions. Panoply fail to display the data,
3824  // if we just follow CF conventions. So following COARD. KY-2011-3-4
3825  if (COARDFLAG || file->sptype == OTHERHDF)// Follow COARD Conventions
3826  (*i)->newname =
3827  (*i)->getCorrectedDimensions ()[0]->getName ();
3828  else
3829  // It seems that netCDF Java stricts following COARDS conventions, so change the dimension name back. KY 2012-5-4
3830  (*i)->newname =
3831  (*i)->getCorrectedDimensions ()[0]->getName ();
3832 // (*i)->newname =
3833 // (*i)->getCorrectedDimensions ()[0]->getName () + "_d";
3834  HDFCFUtil::insert_map(file->sd->dimcvarlist, (*i)->getCorrectedDimensions()[0]->getName(), (*i)->newname);
3835 
3836  }
3837  }
3838  }
3839 }
3840 
3841 // Create "coordinates", "units" CF attributes
3842 void
3843 File::handle_sds_coords(bool & COARDFLAG,std::string & lldimname1, std::string & lldimname2) throw(Exception) {
3844 
3845  File *file = this;
3846 
3847  // 9. Generate "coordinates " attribute
3848 
3849  std::map < std::string, std::string >::iterator tempmapit;
3850  int tempcount;
3851 
3852  std::string tempcoordinates, tempfieldname;
3853  for (std::vector < SDField * >::const_iterator i =
3854  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3855  if ((*i)->fieldtype == 0) {
3856  tempcount = 0;
3857  tempcoordinates = "";
3858  tempfieldname = "";
3859 
3860  for (std::vector < Dimension * >::const_iterator j =
3861  (*i)->getCorrectedDimensions ().begin ();
3862  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3863  tempmapit = (file->sd->dimcvarlist).find ((*j)->getName ());
3864  if (tempmapit != (file->sd->dimcvarlist).end ())
3865  tempfieldname = tempmapit->second;
3866  else
3867  throw3 ("The dimension with the name ", (*j)->getName (),
3868  "must have corresponding coordinate variables.");
3869  if (tempcount == 0)
3870  tempcoordinates = tempfieldname;
3871  else
3872  tempcoordinates = tempcoordinates + " " + tempfieldname;
3873  tempcount++;
3874  }
3875  (*i)->setCoordinates (tempcoordinates);
3876  }
3877 
3878  // Add units for latitude and longitude
3879  if ((*i)->fieldtype == 1) { // latitude,adding the "units" attribute degrees_east.
3880  std::string tempunits = "degrees_north";
3881  (*i)->setUnits (tempunits);
3882  }
3883 
3884  if ((*i)->fieldtype == 2) { // longitude, adding the units of
3885  std::string tempunits = "degrees_east";
3886  (*i)->setUnits (tempunits);
3887  }
3888 
3889  // Add units for Z-dimension, now it is always "level"
3890  if (((*i)->fieldtype == 3) || ((*i)->fieldtype == 4)) {
3891  std::string tempunits = "level";
3892  (*i)->setUnits (tempunits);
3893  }
3894  }
3895 
3896  // Remove some coordinates attribute for some variables. This happens when a field just share one dimension name with
3897  // latitude/longitude that have 2 dimensions. For example, temp[latlondim1][otherdim] with lat[latlondim1][otherdim]; the
3898  // "coordinates" attribute may become "lat ???", which is not correct. Remove the coordinates for this case.
3899 
3900  if (false == COARDFLAG) {
3901  for (std::vector < SDField * >::const_iterator i =
3902  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3903  if ((*i)->fieldtype == 0) {
3904  bool has_lldim1 = false;
3905  bool has_lldim2 = false;
3906  for (std::vector < Dimension * >::const_iterator j =
3907  (*i)->getCorrectedDimensions ().begin ();
3908  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3909  if(lldimname1 == (*j)->name)
3910  has_lldim1 = true;
3911  else if(lldimname2 == (*j)->name)
3912  has_lldim2 = true;
3913  }
3914 
3915  // Currently we don't remove the "coordinates" attribute if no lat/lon dimension names are used.
3916  if (has_lldim1^has_lldim2)
3917  (*i)->coordinates = "";
3918  }
3919  }
3920  }
3921 }
3922 
3923 
3924 // Handle Vdata
3925 void
3927 
3928  // Define File
3929  File *file = this;
3930 
3931  // Handle vdata, only need to check name clashings and special characters for vdata field names
3932  //
3933  // Check name clashings, the chance for the nameclashing between SDS and Vdata fields are almost 0. Not
3934  // to add performance burden, I won't consider the nameclashing check between SDS and Vdata fields. KY 2012-6-28
3935  //
3936 
3937  string check_disable_vdata_nameclashing_key="H4.DisableVdataNameclashingCheck";
3938  bool turn_on_disable_vdata_nameclashing_key = false;
3939 
3940  turn_on_disable_vdata_nameclashing_key = HDFCFUtil::check_beskeys(check_disable_vdata_nameclashing_key);
3941 
3942  if (false == turn_on_disable_vdata_nameclashing_key) {
3943 
3944  vector<string> tempvdatafieldnamelist;
3945 
3946  for (std::vector < VDATA * >::const_iterator i = file->vds.begin ();
3947  i != file->vds.end (); ++i) {
3948  for (std::vector < VDField * >::const_iterator j =
3949  (*i)->getFields ().begin (); j != (*i)->getFields ().end ();
3950  ++j)
3951  tempvdatafieldnamelist.push_back((*j)->newname);
3952  }
3953 
3954  HDFCFUtil::Handle_NameClashing(tempvdatafieldnamelist);
3955 
3956  int total_vfd_counter = 0;
3957 
3958  for (std::vector < VDATA * >::const_iterator i = file->vds.begin ();
3959  i != file->vds.end (); ++i) {
3960  for (std::vector < VDField * >::const_iterator j =
3961  (*i)->getFields ().begin (); j != (*i)->getFields ().end ();
3962  ++j) {
3963  (*j)->newname = tempvdatafieldnamelist[total_vfd_counter];
3964  total_vfd_counter++;
3965  }
3966  }
3967  }
3968 
3969 
3970 }
3971 
3972 // This is the main function that make the HDF SDS objects follow the CF convention.
3973 void
3975 {
3976 
3977  File *file = this;
3978 
3979  // 1. Obtain the original SDS and Vdata path,
3980  // Start with the lone vgroup they belong to and add the path
3981  // This also add Vdata objects that belong to lone vgroup
3983 
3984  // 2. Check the SDS special type(CERES special type has been checked at the Read function)
3985  file->CheckSDType ();
3986 
3987  // 2.1 Remove AttrContainer from the Dimension list for non-OTHERHDF products
3988  if (file->sptype != OTHERHDF) {
3989 
3990  for (std::vector < SDField * >::const_iterator i =
3991  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3992  for (vector<AttrContainer *>::iterator j = (*i)->dims_info.begin();
3993  j!= (*i)->dims_info.end(); ++j) {
3994  delete (*j);
3995  (*i)->dims_info.erase(j);
3996  j--;
3997  }
3998  if ((*i)->dims_info.size() != 0)
3999  throw1("Not totally erase the dimension container ");
4000  }
4001  }
4002 
4003  // 3. Handle fake dimensions of HDF4 SDS objects. make the dimensions with the same dimension size
4004  // share the same dimension name. In this way, we can reduce many fakedims.
4005 
4007 
4008  // 4. Prepare the latitude/longitude "coordinate variable" list for each special NASA HDF product
4009  switch (file->sptype) {
4010  case TRMML2_V6:
4011  {
4012  file->PrepareTRMML2_V6 ();
4013  break;
4014  }
4015  case TRMML3B_V6:
4016  {
4017  file->PrepareTRMML3B_V6 ();
4018  break;
4019  }
4020  case TRMML3A_V6:
4021  {
4022  file->PrepareTRMML3A_V6 ();
4023  break;
4024  }
4025  case TRMML3C_V6:
4026  {
4027  file->PrepareTRMML3C_V6 ();
4028  break;
4029  }
4030  case TRMML2_V7:
4031  {
4032  file->PrepareTRMML2_V7 ();
4033  break;
4034  }
4035  case TRMML3S_V7:
4036  {
4037  file->PrepareTRMML3S_V7 ();
4038  break;
4039  }
4040  case TRMML3M_V7:
4041  {
4042  file->PrepareTRMML3M_V7 ();
4043  break;
4044  }
4045  case CER_AVG:
4046  {
4047  file->PrepareCERAVGSYN ();
4048  break;
4049  }
4050  case CER_ES4:
4051  {
4052  file->PrepareCERES4IG ();
4053  break;
4054  }
4055  case CER_CDAY:
4056  {
4057  file->PrepareCERSAVGID ();
4058  break;
4059  }
4060  case CER_CGEO:
4061  {
4062  file->PrepareCERES4IG ();
4063  break;
4064  }
4065  case CER_SRB:
4066  {
4067  file->PrepareCERSAVGID ();
4068  break;
4069  }
4070  case CER_SYN:
4071  {
4072  file->PrepareCERAVGSYN ();
4073  break;
4074  }
4075  case CER_ZAVG:
4076  {
4077  file->PrepareCERZAVG ();
4078  break;
4079  }
4080  case OBPGL2:
4081  {
4082  file->PrepareOBPGL2 ();
4083  break;
4084  }
4085  case OBPGL3:
4086  {
4087  file->PrepareOBPGL3 ();
4088  break;
4089  }
4090 
4091  case MODISARNSS:
4092  {
4093  file->PrepareMODISARNSS ();
4094  break;
4095  }
4096 
4097  case OTHERHDF:
4098  {
4099  file->PrepareOTHERHDF ();
4100  break;
4101  }
4102  default:
4103  {
4104  throw3 ("No such SP datatype ", "sptype is ", sptype);
4105  break;
4106  }
4107  }
4108 
4109 
4110  // 5. Create the new dimension name set and the dimension name to size map
4112 
4113  // 6. Add the missing coordinate variables based on the corrected dimension name list
4115 
4116  // 7. Create the final CF-compliant dimension name list for each field
4118 
4119  bool COARDFLAG = false;
4120  string lldimname1;
4121  string lldimname2;
4122 
4123  // 8. Create the final CF-compliant field name list, pass COARDFLAG as a reference
4124  // since COARDS may requires the names to change.
4125  handle_sds_names(COARDFLAG, lldimname1, lldimname2);
4126 
4127  // 9. Create "coordinates", "units" CF attributes
4128  handle_sds_coords(COARDFLAG, lldimname1,lldimname2);
4129 
4130  // 10. Handle Vdata
4131  handle_vdata();
4132 }
4133 
4134 void File:: Obtain_TRMML3S_V7_latlon_size(int &latsize, int&lonsize) throw(Exception) {
4135 
4136  // No need to check if "GridHeader" etc. exists since this has been checked in the CheckSDType routine.
4137  for (std::vector < Attribute * >::const_iterator i =
4138  this->sd->getAttributes ().begin ();
4139  i != this->sd->getAttributes ().end (); ++i) {
4140 
4141  if ((*i)->getName () == "GridHeader") {
4142  float lat_start = 0.;
4143  float lon_start = 0.;
4144  float lat_res = 1.;
4145  float lon_res = 1.;
4146  HDFCFUtil::parser_trmm_v7_gridheader((*i)->getValue(),latsize,lonsize,
4147  lat_start,lon_start,
4148  lat_res,lon_res,false);
4149  break;
4150  }
4151  }
4152 
4153 }
4154 
4155 bool File:: Obtain_TRMM_V7_latlon_name(const SDField* sdfield, const int latsize,
4156  const int lonsize, string& latname, string& lonname) throw(Exception) {
4157 
4158 // bool latflag = false;
4159 // bool lonflag = false;
4160 
4161  int latname_index = -1;
4162  int lonname_index = -1;
4163  for (int temp_index = 0; temp_index <sdfield->getRank(); ++temp_index) {
4164  if(-1==latname_index && sdfield->getCorrectedDimensions()[temp_index]->getSize() == latsize) {
4165  latname_index = temp_index;
4166 //cerr<<"lat name index = "<<latname_index <<endl;
4167  latname = sdfield->getCorrectedDimensions()[temp_index]->getName();
4168  }
4169  else if (-1 == lonname_index && sdfield->getCorrectedDimensions()[temp_index]->getSize() == lonsize) {
4170  lonname_index = temp_index;
4171 //cerr<<"lon name index = "<<lonname_index <<endl;
4172  lonname = sdfield->getCorrectedDimensions()[temp_index]->getName();
4173  }
4174  }
4175 
4176  return (latname_index + lonname_index == 1);
4177 
4178 }
4180 
4181  File *file = this;
4182 
4183  // 1. Obtain the geolocation field: type,dimension size and dimension name
4184  // 2. Create latitude and longtiude fields according to the geolocation field.
4185  std::string tempdimname1, tempdimname2;
4186  std::string tempnewdimname1, tempnewdimname2;
4187  std::string temppath;
4188 
4189  //int32 tempdimsize1, tempdimsize2;
4190  //SDField *longitude;
4191  //SDField *latitude;
4192 
4193  // Create a temporary map from the dimension size to the dimension name
4194  std::set < int32 > tempdimsizeset;
4195  std::map < int32, std::string > tempdimsizenamelist;
4196  std::map < int32, std::string >::iterator tempsizemapit;
4197  std::pair < std::set < int32 >::iterator, bool > tempsetit;
4198 
4199  // Reduce the fakeDim list. FakeDim is found to be used by TRMM team.
4200  for (std::vector < SDField * >::const_iterator i =
4201  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4202  for (std::vector < Dimension * >::const_iterator j =
4203  (*i)->getCorrectedDimensions ().begin ();
4204  j != (*i)->getCorrectedDimensions ().end (); ++j) {
4205  if (((*j)->getName ()).find ("fakeDim") == std::string::npos) { //No fakeDim in the string
4206  tempsetit = tempdimsizeset.insert ((*j)->getSize ());
4207  if (tempsetit.second == true)
4208  tempdimsizenamelist[(*j)->getSize ()] = (*j)->getName ();
4209  }
4210  }
4211  }
4212 
4213  // Reduce the fakeDim list. FakeDim is found to be used by TRMM team.
4214  for (std::vector < SDField * >::const_iterator i =
4215  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4216 
4217  string temp_name = (*i)->newname.substr(1) ;
4218  size_t temp_pos = temp_name.find_first_of('/');
4219  if (temp_pos !=string::npos)
4220  (*i)->newname = temp_name.substr(temp_pos+1);
4221 //cerr<<"temp_name is "<<temp_name<<endl;
4222 
4223  }
4224 
4225 
4226  for (std::vector < SDField * >::const_iterator i =
4227  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4228 
4229  if((*i)->getName() == "Latitude") {
4230  if((*i)->getRank() ==2) {
4231 
4232  tempnewdimname1 =
4233  ((*i)->getCorrectedDimensions ())[0]->getName ();
4234  tempnewdimname2 =
4235  ((*i)->getCorrectedDimensions ())[1]->getName ();
4236  }
4237 
4238  (*i)->fieldtype = 1;
4239 
4240  }
4241  else if ((*i)->getName() == "Longitude") {
4242  (*i)->fieldtype = 2;
4243 
4244  }
4245  else {
4246 
4247  // Use the temp. map (size to name) to replace the name of "fakeDim???" with the dimension name having the same dimension length
4248  // This is done only for TRMM. It should be evaluated if this can be applied to other products.
4249  for (std::vector < Dimension * >::const_iterator k =
4250  (*i)->getCorrectedDimensions ().begin ();
4251  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4252  size_t fakeDimpos = ((*k)->getName ()).find ("fakeDim");
4253 
4254  if (fakeDimpos != std::string::npos) {
4255  tempsizemapit =
4256  tempdimsizenamelist.find ((*k)->getSize ());
4257  if (tempsizemapit != tempdimsizenamelist.end ())
4258  (*k)->name = tempdimsizenamelist[(*k)->getSize ()];// Change the dimension name
4259  }
4260  }
4261 
4262  }
4263  }
4264 
4265  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4266  if(tempnewdimname1.empty()!=true)
4267  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
4268 
4269  if(tempnewdimname2.empty()!=true)
4270  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
4271 
4272  string base_filename;
4273  size_t last_slash_pos = file->getPath().find_last_of("/");
4274  if(last_slash_pos != string::npos)
4275  base_filename = file->getPath().substr(last_slash_pos+1);
4276  if(""==base_filename)
4277  base_filename = file->getPath();
4278 
4279 
4280  if(base_filename.find("2A12")!=string::npos) {
4281  SDField *nlayer = NULL;
4282  string nlayer_name ="nlayer";
4283 
4284  for (vector < SDField * >::iterator i =
4285  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4286 
4287  bool has_nlayer = false;
4288 
4289  for (vector < Dimension * >::const_iterator k =
4290  (*i)->getDimensions ().begin ();
4291  k != (*i)->getDimensions ().end (); ++k) {
4292 
4293  if((*k)->getSize() == 28 && (*k)->name == nlayer_name) {
4294 
4295  nlayer = new SDField();
4296  nlayer->name = nlayer_name;
4297  nlayer->rank = 1;
4298  nlayer->type = DFNT_FLOAT32;
4299  nlayer->fieldtype = 6;
4300 
4301  nlayer->newname = nlayer->name ;
4302  Dimension *dim =
4303  new Dimension (nlayer->name, (*k)->getSize (), 0);
4304  nlayer->dims.push_back(dim);
4305 
4306  dim = new Dimension(nlayer->name,(*k)->getSize(),0);
4307  nlayer->correcteddims.push_back(dim);
4308 
4309  has_nlayer = true;
4310  break;
4311  }
4312 
4313  }
4314 
4315  if(true == has_nlayer)
4316  break;
4317  }
4318 
4319  if(nlayer !=NULL) {
4320  file->sd->sdfields.push_back(nlayer);
4321  file->sd->nonmisscvdimnamelist.insert (nlayer_name);
4322  }
4323  }
4324 
4325 }
4326 
4327 void
4329 
4330  File *file = this;
4331  for (std::vector < SDField * >::iterator i =
4332  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4333 
4334  //According to GES DISC, the next three variables should be removed from the list.
4335  if((*i)->name == "InputFileNames") {
4336  delete (*i);
4337  file->sd->sdfields.erase(i);
4338  i--;
4339  }
4340  else if((*i)->name == "InputAlgorithmVersions") {
4341  delete (*i);
4342  file->sd->sdfields.erase(i);
4343  i--;
4344  }
4345  else if((*i)->name == "InputGenerationDateTimes") {
4346  delete (*i);
4347  file->sd->sdfields.erase(i);
4348  i--;
4349  }
4350  else // Just use SDS names and for performance reasons, change them here.
4351  (*i)->newname = (*i)->name;
4352  }
4353 
4354 
4355  SDField *nlayer = NULL;
4356  string nlayer_name ="nlayer";
4357 
4358  for (vector < SDField * >::iterator i =
4359  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4360 
4361  bool has_nlayer = false;
4362 
4363  for (vector < Dimension * >::const_iterator k =
4364  (*i)->getDimensions ().begin ();
4365  k != (*i)->getDimensions ().end (); ++k) {
4366 
4367  if((*k)->getSize() == 28 && (*k)->name == nlayer_name) {
4368 
4369  nlayer = new SDField();
4370  nlayer->name = nlayer_name;
4371  nlayer->rank = 1;
4372  nlayer->type = DFNT_FLOAT32;
4373  nlayer->fieldtype = 6;
4374 
4375  nlayer->newname = nlayer->name ;
4376  Dimension *dim =
4377  new Dimension (nlayer->name, (*k)->getSize (), 0);
4378  nlayer->dims.push_back(dim);
4379 
4380  dim = new Dimension(nlayer->name,(*k)->getSize(),0);
4381  nlayer->correcteddims.push_back(dim);
4382 
4383  has_nlayer = true;
4384  break;
4385  }
4386 
4387  }
4388 
4389  if(true == has_nlayer)
4390  break;
4391  }
4392 
4393  if(nlayer !=NULL) {
4394  file->sd->sdfields.push_back(nlayer);
4395  file->sd->nonmisscvdimnamelist.insert (nlayer_name);
4396  }
4397 
4398  int latsize = 0;
4399  int lonsize = 0;
4400 
4401  Obtain_TRMML3S_V7_latlon_size(latsize,lonsize);
4402 //cerr<<"latsize "<<latsize <<endl;
4403 //cerr<<"lonsize "<<lonsize <<endl;
4404 
4405  string latname;
4406  string lonname;
4407 
4408  bool llname_found = false;
4409  for (std::vector < SDField * >::iterator i =
4410  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4411 
4412  if(2 == (*i)->getRank()) {
4413 
4414  llname_found = Obtain_TRMM_V7_latlon_name((*i),latsize,lonsize,latname,lonname);
4415  if (true == llname_found)
4416  break;
4417 
4418  }
4419  }
4420 
4421 //cerr<<"latitude name "<<latname <<endl;
4422 //cerr<<"longitude name "<<lonname <<endl;
4423  // Create lat/lon SD fields.
4424  SDField* longitude = new SDField ();
4425  longitude->name = lonname;
4426  longitude->rank = 1;
4427  longitude->type = DFNT_FLOAT32;
4428  longitude->fieldtype = 2;
4429 
4430  longitude->newname = longitude->name;
4431  Dimension *dim =
4432  new Dimension (lonname, lonsize, 0);
4433  longitude->dims.push_back (dim);
4434 
4435  dim = new Dimension (lonname, lonsize, 0);
4436  longitude->correcteddims.push_back (dim);
4437  file->sd->sdfields.push_back(longitude);
4438 
4439  SDField* latitude = new SDField ();
4440  latitude->name = latname;
4441  latitude->rank = 1;
4442  latitude->type = DFNT_FLOAT32;
4443  latitude->fieldtype = 1;
4444 
4445  latitude->newname = latitude->name;
4446  dim = new Dimension (latname, latsize, 0);
4447  latitude->dims.push_back (dim);
4448 
4449  dim = new Dimension (latname, latsize, 0);
4450  latitude->correcteddims.push_back (dim);
4451  file->sd->sdfields.push_back(latitude);
4452 
4453  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4454  file->sd->nonmisscvdimnamelist.insert (latname);
4455  file->sd->nonmisscvdimnamelist.insert (lonname);
4456 
4457 
4458  // Now we want to handle the special CVs for 3A26 products. Since these special CVs only apply to the 3A26 products,
4459  // we don't want to find them from other products to reduce the performance cost. So here I simply check the filename
4460  string base_filename;
4461  if(path.find_last_of("/") != string::npos)
4462  base_filename = path.substr(path.find_last_of("/")+1);
4463  if(base_filename.find("3A26")!=string::npos) {
4464 
4465  bool ZOflag = false;
4466  bool SRTflag = false;
4467  bool HBflag = false;
4468  string nthrsh_base_name = "nthrsh";
4469  string nthrsh_zo_name ="nthrshZO";
4470  string nthrsh_hb_name ="nthrshHB";
4471  string nthrsh_srt_name ="nthrshSRT";
4472 
4473  SDField* nthrsh_zo = NULL;
4474  SDField* nthrsh_hb = NULL;
4475  SDField* nthrsh_srt = NULL;
4476 
4477  for (vector < SDField * >::iterator i =
4478  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4479 
4480  if(ZOflag != true) {
4481  if((*i)->name.find("Order")!=string::npos) {
4482  for (vector < Dimension * >::const_iterator k =
4483  (*i)->getDimensions ().begin ();
4484  k != (*i)->getDimensions ().end (); ++k) {
4485 
4486  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4487  nthrsh_zo = new SDField();
4488  nthrsh_zo->name = nthrsh_zo_name;
4489  nthrsh_zo->rank = 1;
4490  nthrsh_zo->type = DFNT_FLOAT32;
4491  nthrsh_zo->fieldtype = 6;
4492 
4493  nthrsh_zo->newname = nthrsh_zo->name ;
4494  Dimension *dim =
4495  new Dimension (nthrsh_zo->name, (*k)->getSize (), 0);
4496  nthrsh_zo->dims.push_back(dim);
4497 
4498  dim = new Dimension(nthrsh_zo->name,(*k)->getSize(),0);
4499  nthrsh_zo->correcteddims.push_back(dim);
4500 
4501  ZOflag = true;
4502 
4503  }
4504  }
4505  }
4506 
4507  }
4508 
4509  else if(SRTflag != true) {
4510  if((*i)->name.find("2A25")!=string::npos) {
4511 
4512  for (vector < Dimension * >::const_iterator k =
4513  (*i)->getDimensions ().begin ();
4514  k != (*i)->getDimensions ().end (); ++k) {
4515 
4516  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4517  nthrsh_srt = new SDField();
4518  nthrsh_srt->name = nthrsh_srt_name;
4519  nthrsh_srt->rank = 1;
4520  nthrsh_srt->type = DFNT_FLOAT32;
4521  nthrsh_srt->fieldtype = 6;
4522 
4523  nthrsh_srt->newname = nthrsh_srt->name ;
4524  Dimension *dim =
4525  new Dimension (nthrsh_srt->name, (*k)->getSize (), 0);
4526  nthrsh_srt->dims.push_back(dim);
4527 
4528  dim = new Dimension(nthrsh_srt->name,(*k)->getSize(),0);
4529  nthrsh_srt->correcteddims.push_back(dim);
4530 
4531  SRTflag = true;
4532 
4533  }
4534  }
4535  }
4536  }
4537  else if(HBflag != true) {
4538  if((*i)->name.find("hb")!=string::npos || (*i)->name.find("HB")!=string::npos) {
4539 
4540  for (vector < Dimension * >::const_iterator k =
4541  (*i)->getDimensions ().begin ();
4542  k != (*i)->getDimensions ().end (); ++k) {
4543 
4544  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4545 
4546  nthrsh_hb = new SDField();
4547  nthrsh_hb->name = nthrsh_hb_name;
4548  nthrsh_hb->rank = 1;
4549  nthrsh_hb->type = DFNT_FLOAT32;
4550  nthrsh_hb->fieldtype = 6;
4551 
4552  nthrsh_hb->newname = nthrsh_hb->name ;
4553  Dimension *dim =
4554  new Dimension (nthrsh_hb->name, (*k)->getSize (), 0);
4555  nthrsh_hb->dims.push_back(dim);
4556 
4557  dim = new Dimension(nthrsh_hb->name,(*k)->getSize(),0);
4558  nthrsh_hb->correcteddims.push_back(dim);
4559 
4560  HBflag = true;
4561 
4562  }
4563  }
4564  }
4565  }
4566  }
4567 
4568 
4569  for (vector < SDField * >::iterator i =
4570  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4571 
4572  if((*i)->name.find("Order")!=string::npos && ZOflag == true) {
4573  for (vector < Dimension * >::const_iterator k =
4574  (*i)->getDimensions ().begin ();
4575  k != (*i)->getDimensions ().end (); ++k) {
4576 
4577  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4578  (*k)->name = nthrsh_zo_name;
4579  break;
4580  }
4581  }
4582 
4583  for (std::vector < Dimension * >::const_iterator k =
4584  (*i)->getCorrectedDimensions ().begin ();
4585  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4586  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4587  (*k)->name = nthrsh_zo_name;
4588  break;
4589  }
4590  }
4591 
4592  }
4593 
4594  else if(((*i)->name.find("hb")!=string::npos || (*i)->name.find("HB")!=string::npos)&& HBflag == true) {
4595  for (vector < Dimension * >::const_iterator k =
4596  (*i)->getDimensions ().begin ();
4597  k != (*i)->getDimensions ().end (); ++k) {
4598 
4599  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4600  (*k)->name = nthrsh_hb_name;
4601  break;
4602  }
4603  }
4604 
4605  for (std::vector < Dimension * >::const_iterator k =
4606  (*i)->getCorrectedDimensions ().begin ();
4607  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4608  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4609  (*k)->name = nthrsh_hb_name;
4610  break;
4611  }
4612  }
4613 
4614  }
4615  else if(((*i)->name.find("2A25")!=string::npos) && SRTflag == true) {
4616  for (vector < Dimension * >::const_iterator k =
4617  (*i)->getDimensions ().begin ();
4618  k != (*i)->getDimensions ().end (); ++k) {
4619 
4620  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4621  (*k)->name = nthrsh_srt_name;
4622  break;
4623  }
4624  }
4625 
4626  for (std::vector < Dimension * >::const_iterator k =
4627  (*i)->getCorrectedDimensions ().begin ();
4628  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4629  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4630  (*k)->name = nthrsh_srt_name;
4631  break;
4632  }
4633  }
4634 
4635  }
4636 
4637 
4638  }
4639 
4640  if(nthrsh_zo !=NULL) {
4641  file->sd->sdfields.push_back(nthrsh_zo);
4642  file->sd->nonmisscvdimnamelist.insert (nthrsh_zo_name);
4643  }
4644 
4645  if(nthrsh_hb !=NULL) {
4646  file->sd->sdfields.push_back(nthrsh_hb);
4647  file->sd->nonmisscvdimnamelist.insert (nthrsh_hb_name);
4648  }
4649 
4650  if(nthrsh_srt !=NULL) {
4651  file->sd->sdfields.push_back(nthrsh_srt);
4652  file->sd->nonmisscvdimnamelist.insert (nthrsh_srt_name);
4653  }
4654 
4655  }
4656 
4657 }
4658 
4659 void
4661 
4662  File *file = this;
4663  for (std::vector < SDField * >::iterator i =
4664  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4665 
4666  if((*i)->name == "InputFileNames") {
4667  delete (*i);
4668  file->sd->sdfields.erase(i);
4669  i--;
4670  }
4671  else if((*i)->name == "InputAlgorithmVersions") {
4672  delete (*i);
4673  file->sd->sdfields.erase(i);
4674  i--;
4675  }
4676  else if((*i)->name == "InputGenerationDateTimes") {
4677  delete (*i);
4678  file->sd->sdfields.erase(i);
4679  i--;
4680  }
4681  }
4682 
4683 
4684 #if 0
4685  NOTE for programming:
4686  1. Outer loop: loop global attribute for GridHeader?. Retrieve ? as a number for index.
4687  1.5. Obtain the lat/lon sizes for this grid.
4688  The following steps are to retrieve lat/lon names for this grid.
4689  2. Inner loop: Then loop through the field
4690  3. Check the field rank,
4691  3.1 if the rank is not 2, (if the index is the first index, change the newname to name )
4692  continue.
4693  3.2 else {
4694  3.2.1 Retrieve the index from the field new name(retrieve last path Grid1 then retrieve 1)
4695  3.2.2 If the index from the field is the same as that from the GridHeader, continue checking
4696  the lat/lon name for this grid as the single grid.
4697  change the newname to name.
4698  }
4699 #endif
4700 
4701  // The following code tries to be performance-friendly by looping through the fields and handling the operations
4702  // as less as I can.
4703 
4704  int first_index = -1;
4705  for (vector < Attribute * >::const_iterator i =
4706  this->sd->getAttributes ().begin ();
4707  i != this->sd->getAttributes ().end (); ++i) {
4708 
4709  if ((*i)->getName ().find("GridHeader")==0) {
4710  string temp_name = (*i)->getName();
4711 
4712  // The size of "GridHeader" is 10, no need to calculate.
4713  string str_num = temp_name.substr(10);
4714  stringstream ss_num(str_num);
4715 
4716  int grid_index;
4717  ss_num >> grid_index;
4718 
4719  if ( -1 == first_index)
4720  first_index = grid_index;
4721 
4722  float lat_start = 0.;
4723  float lon_start = 0.;
4724  float lat_res = 1.;
4725  float lon_res = 1.;
4726  int latsize = 0;
4727  int lonsize = 0;
4728 
4729  HDFCFUtil::parser_trmm_v7_gridheader((*i)->getValue(),latsize,lonsize,
4730  lat_start,lon_start,
4731  lat_res, lon_res, false);
4732 
4733  string latname;
4734  string lonname;
4735 
4736  bool llname_found = false;
4737  for (std::vector < SDField * >::iterator i =
4738  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4739 
4740  // Just loop the 2-D fields to find the lat/lon size
4741  if(2 == (*i)->getRank()) {
4742 
4743  // If a grid has not been visited, we will check the fields attached to this grid.
4744  if ((*i)->newname !=(*i)->name) {
4745 
4746  string temp_field_full_path = (*i)->getNewName();
4747  size_t last_path_pos = temp_field_full_path.find_last_of('/');
4748  char str_index = temp_field_full_path[last_path_pos-1];
4749  if(grid_index ==(int)(str_index - '0')) {
4750  if(llname_found != true)
4751  llname_found = Obtain_TRMM_V7_latlon_name((*i),latsize,lonsize,latname,lonname);
4752  (*i)->newname = (*i)->name;
4753  }
4754  }
4755  }
4756  else if (first_index == grid_index)
4757  (*i)->newname = (*i)->name;
4758  }
4759 
4760  // Create lat/lon SD fields.
4761  SDField* longitude = new SDField ();
4762  longitude->name = lonname;
4763  longitude->rank = 1;
4764  longitude->type = DFNT_FLOAT32;
4765  longitude->fieldtype = 2;
4766  longitude->fieldref = grid_index;
4767 
4768  longitude->newname = longitude->name;
4769  Dimension *dim =
4770  new Dimension (lonname, lonsize, 0);
4771  longitude->dims.push_back (dim);
4772 
4773  dim = new Dimension (lonname, lonsize, 0);
4774  longitude->correcteddims.push_back (dim);
4775  file->sd->sdfields.push_back(longitude);
4776 
4777  SDField* latitude = new SDField ();
4778  latitude->name = latname;
4779  latitude->rank = 1;
4780  latitude->type = DFNT_FLOAT32;
4781  latitude->fieldtype = 1;
4782  latitude->fieldref = grid_index;
4783 
4784  latitude->newname = latitude->name;
4785  dim = new Dimension (latname, latsize, 0);
4786  latitude->dims.push_back (dim);
4787 
4788  dim = new Dimension (latname, latsize, 0);
4789  latitude->correcteddims.push_back (dim);
4790  file->sd->sdfields.push_back(latitude);
4791 
4792  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4793  file->sd->nonmisscvdimnamelist.insert (latname);
4794  file->sd->nonmisscvdimnamelist.insert (lonname);
4795 
4796  }
4797  }
4798 }
4799 
4802 void
4804 throw (Exception)
4805 {
4806 
4807  File *file = this;
4808 
4809  // 1. Obtain the geolocation field: type,dimension size and dimension name
4810  // 2. Create latitude and longtiude fields according to the geolocation field.
4811  std::string tempdimname1, tempdimname2;
4812  std::string tempnewdimname1, tempnewdimname2;
4813  std::string temppath;
4814 
4815  int32 tempdimsize1, tempdimsize2;
4816  SDField *longitude;
4817  SDField *latitude;
4818 
4819  // Create a temporary map from the dimension size to the dimension name
4820  std::set < int32 > tempdimsizeset;
4821  std::map < int32, std::string > tempdimsizenamelist;
4822  std::map < int32, std::string >::iterator tempsizemapit;
4823  std::pair < std::set < int32 >::iterator, bool > tempsetit;
4824 
4825  // Reduce the fakeDim list. FakeDim is found to be used by TRMM team.
4826  for (std::vector < SDField * >::const_iterator i =
4827  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4828  for (std::vector < Dimension * >::const_iterator j =
4829  (*i)->getCorrectedDimensions ().begin ();
4830  j != (*i)->getCorrectedDimensions ().end (); ++j) {
4831  if (((*j)->getName ()).find ("fakeDim") == std::string::npos) { //No fakeDim in the string
4832  tempsetit = tempdimsizeset.insert ((*j)->getSize ());
4833  if (tempsetit.second == true)
4834  tempdimsizenamelist[(*j)->getSize ()] = (*j)->getName ();
4835  }
4836  }
4837  }
4838 
4839  for (std::vector < SDField * >::const_iterator i =
4840  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4841 
4842  if ((*i)->getName () == "geolocation") {
4843 
4844  // Obtain the size and the name of the first two dimensions of the geolocation field;
4845  // make these two dimensions the dimensions of latitude and longtiude.
4846  tempdimname1 = ((*i)->getDimensions ())[0]->getName ();
4847  tempdimsize1 = ((*i)->getDimensions ())[0]->getSize ();
4848  tempdimname2 = ((*i)->getDimensions ())[1]->getName ();
4849  tempdimsize2 = ((*i)->getDimensions ())[1]->getSize ();
4850 
4851  tempnewdimname1 =
4852  ((*i)->getCorrectedDimensions ())[0]->getName ();
4853  tempnewdimname2 =
4854  ((*i)->getCorrectedDimensions ())[1]->getName ();
4855 
4856  latitude = new SDField ();
4857  latitude->name = "latitude";
4858  latitude->rank = 2;
4859  latitude->fieldref = (*i)->fieldref;
4860  latitude->type = (*i)->getType ();
4861  temppath = (*i)->newname.substr ((*i)->name.size ());
4862  latitude->newname = latitude->name + temppath;
4863  latitude->fieldtype = 1;
4864  latitude->rootfieldname = "geolocation";
4865 
4866  Dimension *dim = new Dimension (tempdimname1, tempdimsize1, 0);
4867 
4868  latitude->dims.push_back (dim);
4869 
4870  dim = new Dimension (tempdimname2, tempdimsize2, 0);
4871  latitude->dims.push_back (dim);
4872 
4873  dim = new Dimension (tempnewdimname1, tempdimsize1, 0);
4874  latitude->correcteddims.push_back (dim);
4875 
4876  dim = new Dimension (tempnewdimname2, tempdimsize2, 0);
4877  latitude->correcteddims.push_back (dim);
4878 
4879  longitude = new SDField ();
4880  longitude->name = "longitude";
4881  longitude->rank = 2;
4882  longitude->fieldref = (*i)->fieldref;
4883  longitude->type = (*i)->getType ();
4884  longitude->newname = longitude->name + temppath;
4885  longitude->fieldtype = 2;
4886  longitude->rootfieldname = "geolocation";
4887 
4888  dim = new Dimension (tempdimname1, tempdimsize1, 0);
4889  longitude->dims.push_back (dim);
4890  dim = new Dimension (tempdimname2, tempdimsize2, 0);
4891  longitude->dims.push_back (dim);
4892 
4893  dim = new Dimension (tempnewdimname1, tempdimsize1, 0);
4894  longitude->correcteddims.push_back (dim);
4895 
4896  dim = new Dimension (tempnewdimname2, tempdimsize2, 0);
4897  longitude->correcteddims.push_back (dim);
4898 
4899  }
4900  else {
4901 
4902  // Use the temp. map (size to name) to replace the name of "fakeDim???" with the dimension name having the same dimension length
4903  // This is done only for TRMM. It should be evaluated if this can be applied to other products.
4904  for (std::vector < Dimension * >::const_iterator k =
4905  (*i)->getCorrectedDimensions ().begin ();
4906  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4907  size_t fakeDimpos = ((*k)->getName ()).find ("fakeDim");
4908 
4909  if (fakeDimpos != std::string::npos) {
4910  tempsizemapit =
4911  tempdimsizenamelist.find ((*k)->getSize ());
4912  if (tempsizemapit != tempdimsizenamelist.end ())
4913  (*k)->name = tempdimsizenamelist[(*k)->getSize ()];// Change the dimension name
4914  }
4915  }
4916  }
4917  }
4918 
4919  file->sd->sdfields.push_back (latitude);
4920  file->sd->sdfields.push_back (longitude);
4921 
4922  // 3. Remove the geolocation field from the field list
4923  SDField *origeo = NULL;
4924 
4925  std::vector < SDField * >::iterator toeraseit;
4926  for (std::vector < SDField * >::iterator i = file->sd->sdfields.begin ();
4927  i != file->sd->sdfields.end (); ++i) {
4928  if ((*i)->getName () == "geolocation") { // Check the release of dimension and other resources
4929  toeraseit = i;
4930  origeo = *i;
4931  break;
4932  }
4933  }
4934 
4935  file->sd->sdfields.erase (toeraseit);
4936  if (origeo != NULL)
4937  delete (origeo);
4938 
4939  // 4. Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4940  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
4941  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
4942 
4943 }
4944 
4945 // Prepare TRMM Level 3, no lat/lon are in the original HDF4 file. Need to provide them.
4946 void
4948 throw (Exception)
4949 {
4950 
4951  std::string tempnewdimname1, tempnewdimname2;
4952  int latflag = 0;
4953  int lonflag = 0;
4954 
4955  std::string temppath;
4956  SDField *latitude = NULL;
4957  SDField *longitude = NULL;
4958  File *file = this;
4959 
4960  for (std::vector < SDField * >::const_iterator i =
4961  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4962 
4963  for (std::vector < Dimension * >::const_iterator k =
4964  (*i)->getDimensions ().begin ();
4965  k != (*i)->getDimensions ().end (); ++k) {
4966 
4967  // This dimension has the dimension name
4968  if ((((*k)->getName ()).find ("fakeDim")) == std::string::npos) {
4969 
4970  temppath = (*i)->newname.substr ((*i)->name.size ());
4971  // The lat/lon formula is from GES DISC web site. http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
4972  // KY 2010-7-13
4973  if ((*k)->getSize () == 1440 && (*k)->getType () == 0) {//No dimension scale
4974 
4975  longitude = new SDField ();
4976  longitude->name = "longitude";
4977  longitude->rank = 1;
4978  longitude->type = DFNT_FLOAT32;
4979  longitude->fieldtype = 2;
4980 
4981  longitude->newname = longitude->name + temppath;
4982  Dimension *dim =
4983  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
4984  longitude->dims.push_back (dim);
4985  tempnewdimname2 = (*k)->getName ();
4986 
4987  dim =
4988  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
4989  longitude->correcteddims.push_back (dim);
4990  lonflag++;
4991  }
4992 
4993  if ((*k)->getSize () == 400 && (*k)->getType () == 0) {
4994 
4995  latitude = new SDField ();
4996  latitude->name = "latitude";
4997  latitude->rank = 1;
4998  latitude->type = DFNT_FLOAT32;
4999  latitude->fieldtype = 1;
5000  latitude->newname = latitude->name + temppath;
5001  Dimension *dim =
5002  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
5003  latitude->dims.push_back (dim);
5004  tempnewdimname1 = (*k)->getName ();
5005 
5006  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5007  // Leave here just as a reference.
5008  // std::string uniquedimname = (*k)->getName() +temppath;
5009  // tempnewdimname1 = uniquedimname;
5010  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5011  dim =
5012  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
5013  latitude->correcteddims.push_back (dim);
5014  latflag++;
5015  }
5016  }
5017 
5018  if (latflag == 1 && lonflag == 1)
5019  break;
5020  }
5021 
5022  if (latflag == 1 && lonflag == 1)
5023  break; // For this case, a field that needs lon and lot must exist
5024 
5025  // Need to reset the flag to avoid false alarm. For TRMM L3 we can handle, a field that has dimension
5026  // which size is 400 and 1440 must exist in the file.
5027  latflag = 0;
5028  lonflag = 0;
5029  }
5030 
5031  if (latflag != 1 || lonflag != 1) {
5032  if(latitude != NULL)
5033  delete latitude;
5034  if(longitude != NULL)
5035  delete longitude;
5036  throw5 ("Either latitude or longitude doesn't exist.", "lat. flag= ",
5037  latflag, "lon. flag= ", lonflag);
5038  }
5039  file->sd->sdfields.push_back (latitude);
5040  file->sd->sdfields.push_back (longitude);
5041 
5042 
5043  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5044  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5045  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5046 
5047 }
5048 
5049 // Prepare TRMM Level 3, no lat/lon are in the original HDF4 file. Need to provide them.
5050 void
5052 throw (Exception)
5053 {
5054  std::string tempnewdimname1, tempnewdimname2;
5055  bool latflag = false;
5056  bool lonflag = false;
5057 
5058  SDField *latitude = NULL;
5059  SDField *longitude = NULL;
5060  File *file = this;
5061 
5062  for (std::vector < SDField * >::const_iterator i =
5063  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5064 
5065  for (std::vector < Dimension * >::const_iterator k =
5066  (*i)->getDimensions ().begin ();
5067  k != (*i)->getDimensions ().end (); ++k) {
5068  if ((((*k)->getName ()).find ("latitude")) == 0)
5069  (*k)->name = "fakeDim1";
5070  if ((((*k)->getName()).find ("longitude")) == 0)
5071  (*k)->name = "fakeDim2";
5072 
5073  }
5074 
5075  // Since we use correctedims, we also need to change them. We may
5076  // need to remove correctedims from HDFSP space in the future.
5077  for (std::vector < Dimension * >::const_iterator k =
5078  (*i)->getCorrectedDimensions ().begin ();
5079  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5080  if ((((*k)->getName ()).find ("latitude")) == 0)
5081  (*k)->name = "fakeDim1";
5082  if ((((*k)->getName()).find ("longitude")) == 0)
5083  (*k)->name = "fakeDim2";
5084 
5085  }
5086  }
5087 
5088  for (std::vector < SDField * >::const_iterator i =
5089  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5090 
5091 
5092  for (std::vector < Dimension * >::const_iterator k =
5093  (*i)->getDimensions ().begin ();
5094  k != (*i)->getDimensions ().end (); ++k) {
5095 
5096 
5097  // This dimension has the dimension name
5098  //if ((((*k)->getName ()).find ("fakeDim")) == std::string::npos)
5099 
5100  // The lat/lon formula is from GES DISC web site. http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
5101  // KY 2010-7-13
5102  if ((*k)->getSize () == 360 && (*k)->getType () == 0) {//No dimension scale
5103 
5104  longitude = new SDField ();
5105  longitude->name = "longitude";
5106  longitude->rank = 1;
5107  longitude->type = DFNT_FLOAT32;
5108  longitude->fieldtype = 2;
5109 
5110  longitude->newname = longitude->name ;
5111  Dimension *dim =
5112  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5113  longitude->dims.push_back (dim);
5114  tempnewdimname2 = longitude->name;
5115 
5116  dim =
5117  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5118  longitude->correcteddims.push_back (dim);
5119  lonflag = true;
5120  }
5121 
5122  if ((*k)->getSize () == 180 && (*k)->getType () == 0) {
5123 
5124  latitude = new SDField ();
5125  latitude->name = "latitude";
5126  latitude->rank = 1;
5127  latitude->type = DFNT_FLOAT32;
5128  latitude->fieldtype = 1;
5129  latitude->newname = latitude->name ;
5130  Dimension *dim =
5131  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5132 
5133  latitude->dims.push_back (dim);
5134  tempnewdimname1 = latitude->getName ();
5135 
5136  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5137  // Leave here just as a reference.
5138  // std::string uniquedimname = (*k)->getName() +temppath;
5139  // tempnewdimname1 = uniquedimname;
5140  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5141  dim =
5142  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5143  latitude->correcteddims.push_back (dim);
5144  latflag = true;
5145  }
5146 
5147 
5148  if (latflag == true && lonflag == true)
5149  break;
5150  }
5151 
5152  if (latflag == true && lonflag == true)
5153  break; // For this case, a field that needs lon and lot must exist
5154 
5155  // Need to reset the flag to avoid false alarm. For TRMM L3 we can handle, a field that has dimension
5156  // which size is 400 and 1440 must exist in the file.
5157  latflag = false;
5158  lonflag = false;
5159  }
5160 
5161  if (latflag !=true || lonflag != true) {
5162  if(latitude != NULL)
5163  delete latitude;
5164  if(longitude != NULL)
5165  delete longitude;
5166  throw5 ("Either latitude or longitude doesn't exist.", "lat. flag= ",
5167  latflag, "lon. flag= ", lonflag);
5168  }
5169 
5170  for (std::vector < SDField * >::const_iterator i =
5171  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5172 
5173 
5174  for (std::vector < Dimension * >::const_iterator k =
5175  (*i)->getDimensions ().begin ();
5176  k != (*i)->getDimensions ().end (); ++k) {
5177 
5178  if ((*k)->getSize () == 360 )
5179  (*k)->name = longitude->name;
5180 
5181  if ((*k)->getSize () == 180 )
5182  (*k)->name = latitude->name;
5183 
5184  }
5185 
5186  for (std::vector < Dimension * >::const_iterator k =
5187  (*i)->getCorrectedDimensions ().begin ();
5188  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5189 
5190  if ((*k)->getSize () == 360 )
5191  (*k)->name = longitude->name;
5192 
5193  if ((*k)->getSize () == 180 )
5194  (*k)->name = latitude->name;
5195 
5196  }
5197 
5198 
5199  }
5200 
5201 
5202  file->sd->sdfields.push_back (latitude);
5203  file->sd->sdfields.push_back (longitude);
5204 
5205 
5206  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5207  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5208  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5209 
5210 }
5211 
5212 // Prepare TRMM Level 3, no lat/lon are in the original HDF4 file. Need to provide them.
5213 void
5215 throw (Exception)
5216 {
5217 
5218  std::string tempnewdimname1, tempnewdimname2,tempnewdimname3;
5219  bool latflag = false;
5220  bool lonflag = false;
5221  bool heiflag = false;
5222 
5223  SDField *latitude = NULL;
5224  SDField *longitude = NULL;
5225  SDField *height = NULL;
5226 
5227  File *file = this;
5228 
5229  for (std::vector < SDField * >::const_iterator i =
5230  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5231 
5232 
5233  for (std::vector < Dimension * >::const_iterator k =
5234  (*i)->getDimensions ().begin ();
5235  k != (*i)->getDimensions ().end (); ++k) {
5236 
5237 
5238  // This dimension has the dimension name
5239  //if ((((*k)->getName ()).find ("fakeDim")) == std::string::npos)
5240 
5241  // The lat/lon formula is from GES DISC web site. http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
5242  // KY 2010-7-13
5243  if ((*k)->getSize () == 720 && (*k)->getType () == 0) {//No dimension scale
5244 
5245  longitude = new SDField ();
5246  longitude->name = "longitude";
5247  longitude->rank = 1;
5248  longitude->type = DFNT_FLOAT32;
5249  longitude->fieldtype = 2;
5250 
5251  longitude->newname = longitude->name ;
5252  Dimension *dim =
5253  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5254  longitude->dims.push_back (dim);
5255  tempnewdimname2 = longitude->name;
5256 
5257  dim =
5258  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5259  longitude->correcteddims.push_back (dim);
5260  lonflag = true;
5261  }
5262 
5263  if ((*k)->getSize () == 148 && (*k)->getType () == 0) {
5264 
5265  latitude = new SDField ();
5266  latitude->name = "latitude";
5267  latitude->rank = 1;
5268  latitude->type = DFNT_FLOAT32;
5269  latitude->fieldtype = 1;
5270  latitude->newname = latitude->name ;
5271  Dimension *dim =
5272  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5273 
5274  latitude->dims.push_back (dim);
5275  tempnewdimname1 = latitude->getName ();
5276 
5277  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5278  // Leave here just as a reference.
5279  // std::string uniquedimname = (*k)->getName() +temppath;
5280  // tempnewdimname1 = uniquedimname;
5281  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5282  dim =
5283  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5284  latitude->correcteddims.push_back (dim);
5285  latflag = true;
5286  }
5287 
5288  if ((*k)->getSize () == 19 && (*k)->getType () == 0) {
5289 
5290  height = new SDField ();
5291  height->name = "height";
5292  height->rank = 1;
5293  height->type = DFNT_FLOAT32;
5294  height->fieldtype = 6;
5295  height->newname = height->name ;
5296  Dimension *dim =
5297  new Dimension (height->getName (), (*k)->getSize (), 0);
5298 
5299  height->dims.push_back (dim);
5300  tempnewdimname3 = height->getName ();
5301 
5302  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5303  // Leave here just as a reference.
5304  // std::string uniquedimname = (*k)->getName() +temppath;
5305  // tempnewdimname1 = uniquedimname;
5306  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5307  dim =
5308  new Dimension (height->getName (), (*k)->getSize (), 0);
5309  height->correcteddims.push_back (dim);
5310  heiflag = true;
5311  }
5312 
5313 
5314  }
5315 
5316  if (latflag == true && lonflag == true)
5317  break; // For this case, a field that needs lon and lot must exist
5318 
5319  // Need to reset the flag to avoid false alarm. For TRMM L3 we can handle, a field that has dimension
5320  // which size is 400 and 1440 must exist in the file.
5321  latflag = false;
5322  lonflag = false;
5323  heiflag = false;
5324  }
5325 
5326  if (latflag != true || lonflag != true) {
5327  if(latitude != NULL)
5328  delete latitude;
5329  if(longitude != NULL)
5330  delete longitude;
5331  throw5 ("Either latitude or longitude doesn't exist.", "lat. flag= ",
5332  latflag, "lon. flag= ", lonflag);
5333  }
5334 
5335  if(height!=NULL && heiflag !=true) {
5336  delete height;
5337  throw1("Height is allocated but the flag is not true");
5338  }
5339 
5340 
5341  file->sd->sdfields.push_back (latitude);
5342  file->sd->sdfields.push_back (longitude);
5343 
5344  if(height!=NULL) {
5345 
5346  if(heiflag != true) {
5347  delete height;
5348  throw1("Height is allocated but the flag is not true");
5349  }
5350  else {
5351  file->sd->sdfields.push_back (height);
5352  file->sd->nonmisscvdimnamelist.insert (tempnewdimname3);
5353  }
5354  }
5355 
5356  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5357  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5358  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5359 
5360 }
5361 // This applies to all OBPG level 2 products include SeaWIFS, MODISA, MODIST,OCTS, CZCS
5362 // A formula similar to swath dimension map needs to apply to this file.
5363 void
5365 throw (Exception)
5366 {
5367  int pixels_per_scan_line = 0;
5368 
5369  std::string pixels_per_scan_line_name = "Pixels per Scan Line";
5370  std::string number_pixels_control_points = "Number of Pixel Control Points";
5371  std::string tempnewdimname1, tempnewdimname2;
5372 
5373  File *file = this;
5374 
5375  // 1. Obtain the expanded size of the latitude/longitude
5376  for (std::vector < Attribute * >::const_iterator i =
5377  file->sd->getAttributes ().begin ();
5378  i != file->sd->getAttributes ().end (); ++i) {
5379  if ((*i)->getName () == pixels_per_scan_line_name) {
5380  int *attrvalueptr = (int *) (&((*i)->getValue ()[0]));
5381  pixels_per_scan_line = *attrvalueptr;
5382  break;
5383  }
5384  }
5385 
5386  if ( 0 == pixels_per_scan_line)
5387  throw1("The attribute 'Pixels per Scan Line' doesn't exist");
5388 
5389  // 2. Obtain the latitude and longitude information
5390  // Assign the new dimension name and the dimension size
5391  // std::string temppath;
5392  int tempcountllflag = 0;
5393 
5394  for (std::vector < SDField * >::const_iterator i =
5395  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5396 
5397  if ((*i)->getName () == "longitude" || (*i)->getName () == "latitude") {
5398  if ((*i)->getName () == "longitude")
5399  (*i)->fieldtype = 2;
5400  if ((*i)->getName () == "latitude")
5401  (*i)->fieldtype = 1;
5402 
5403  tempcountllflag++;
5404  if ((*i)->getRank () != 2)
5405  throw3 ("The lat/lon rank must be 2", (*i)->getName (),
5406  (*i)->getRank ());
5407  for (std::vector < Dimension * >::const_iterator k =
5408  (*i)->getDimensions ().begin ();
5409  k != (*i)->getDimensions ().end (); ++k) {
5410  if ((*k)->getName () == number_pixels_control_points) {
5411  (*k)->name = pixels_per_scan_line_name;
5412  (*k)->dimsize = pixels_per_scan_line;
5413  break;
5414  }
5415  }
5416 
5417  for (std::vector < Dimension * >::const_iterator k =
5418  (*i)->getCorrectedDimensions ().begin ();
5419  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5420  if ((*k)->getName ().find (number_pixels_control_points) !=
5421  std::string::npos) {
5422  (*k)->name = pixels_per_scan_line_name;
5423  (*k)->dimsize = pixels_per_scan_line;
5424  if (tempcountllflag == 1)
5425  tempnewdimname2 = (*k)->name;
5426  }
5427  else {
5428  if (tempcountllflag == 1)
5429  tempnewdimname1 = (*k)->name;
5430  }
5431  }
5432  }
5433  if (tempcountllflag == 2)
5434  break;
5435  }
5436 
5437 
5438  // 3. Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5439  // Obtain the corrected dimension names for latitude and longitude
5440  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5441  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5442 
5443 }
5444 
5445 // This applies to all OBPG l3m products include SeaWIFS, MODISA, MODIST,OCTS, CZCS
5446 // Latitude and longitude need to be calculated based on attributes.
5447 //
5448 void
5450 throw (Exception)
5451 {
5452 
5453  std::string num_lat_name = "Number of Lines";
5454  std::string num_lon_name = "Number of Columns";
5455  int32 num_lat = 0;
5456  int32 num_lon = 0;
5457 
5458  File *file = this;
5459 
5460  int tempcountllflag = 0;
5461 
5462  for (std::vector < Attribute * >::const_iterator i =
5463  file->sd->getAttributes ().begin ();
5464  i != file->sd->getAttributes ().end (); ++i) {
5465 
5466  if ((*i)->getName () == num_lon_name) {
5467 
5468  // Check later if float can be changed to float32
5469  int *attrvalue = (int *) (&((*i)->getValue ()[0]));
5470 
5471  num_lon = *attrvalue;
5472  tempcountllflag++;
5473  }
5474 
5475  if ((*i)->getName () == num_lat_name) {
5476 
5477  int *attrvalue = (int *) (&((*i)->getValue ()[0]));
5478 
5479  num_lat = *attrvalue;
5480  tempcountllflag++;
5481  }
5482  if (tempcountllflag == 2)
5483  break;
5484  }
5485 
5486  // Longitude
5487  SDField *longitude = new SDField ();
5488 
5489  longitude->name = "longitude";
5490  longitude->rank = 1;
5491  longitude->type = DFNT_FLOAT32;
5492  longitude->fieldtype = 2;
5493 
5494  // No need to assign fullpath, in this case, only one SDS under one file. If finding other OBPGL3 data, will handle then.
5495  longitude->newname = longitude->name;
5496  if (0 == num_lon) {
5497  delete longitude;
5498  throw3("The size of the dimension of the longitude ",longitude->name," is 0.");
5499  }
5500 
5501  Dimension *dim = new Dimension (num_lon_name, num_lon, 0);
5502 
5503  longitude->dims.push_back (dim);
5504 
5505  // Add the corrected dimension name only to be consistent with general handling of other cases.
5506  dim = new Dimension (num_lon_name, num_lon, 0);
5507  longitude->correcteddims.push_back (dim);
5508 
5509  // Latitude
5510  SDField *latitude = new SDField ();
5511  latitude->name = "latitude";
5512  latitude->rank = 1;
5513  latitude->type = DFNT_FLOAT32;
5514  latitude->fieldtype = 1;
5515 
5516  // No need to assign fullpath, in this case, only one SDS under one file. If finding other OBPGL3 data, will handle then.
5517  latitude->newname = latitude->name;
5518  if (0 == num_lat) {
5519  delete longitude;
5520  delete latitude;
5521  throw3("The size of the dimension of the latitude ",latitude->name," is 0.");
5522  }
5523 
5524  dim = new Dimension (num_lat_name, num_lat, 0);
5525  latitude->dims.push_back (dim);
5526 
5527  // Add the corrected dimension name only to be consistent with general handling of other cases.
5528  dim = new Dimension (num_lat_name, num_lat, 0);
5529  latitude->correcteddims.push_back (dim);
5530 
5531  // The dimension names of the SDS are fakeDim, so need to change them to dimension names of latitude and longitude
5532  for (std::vector < SDField * >::const_iterator i =
5533  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5534  if ((*i)->getRank () != 2) {
5535  delete latitude;
5536  delete longitude;
5537  throw3 ("The lat/lon rank must be 2", (*i)->getName (),
5538  (*i)->getRank ());
5539  }
5540  for (std::vector < Dimension * >::const_iterator k =
5541  (*i)->getDimensions ().begin ();
5542  k != (*i)->getDimensions ().end (); ++k) {
5543  if ((((*k)->getName ()).find ("fakeDim")) != std::string::npos) {
5544  if ((*k)->getSize () == num_lon)
5545  (*k)->name = num_lon_name;
5546  if ((*k)->getSize () == num_lat)
5547  (*k)->name = num_lat_name;
5548  }
5549  }
5550  for (std::vector < Dimension * >::const_iterator k =
5551  (*i)->getCorrectedDimensions ().begin ();
5552  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5553  if ((((*k)->getName ()).find ("fakeDim")) != std::string::npos) {
5554  if ((*k)->getSize () == num_lon)
5555  (*k)->name = num_lon_name;
5556  if ((*k)->getSize () == num_lat)
5557  (*k)->name = num_lat_name;
5558  }
5559  }
5560  }
5561  file->sd->sdfields.push_back (latitude);
5562  file->sd->sdfields.push_back (longitude);
5563 
5564  // Set dimname,coordinate variable list
5565  file->sd->nonmisscvdimnamelist.insert (num_lat_name);
5566  file->sd->nonmisscvdimnamelist.insert (num_lon_name);
5567 
5568 }
5569 
5570 // This applies to CERES AVG and SYN(CER_AVG_??? and CER_SYN_??? cases)
5571 // Latitude and longitude are provided; some redundant CO-Latitude and longitude are removed from the final DDS.
5572 void
5574 throw (Exception)
5575 {
5576 
5577  bool colatflag = false;
5578  bool lonflag = false;
5579 
5580  std::string tempnewdimname1, tempnewdimname2;
5581  std::string tempcvarname1, tempcvarname2;
5582  File *file = this;
5583  // int eraseflag = 0; Unused jhrg 3/16/11
5584 
5585  std::vector < SDField * >::iterator beerasedit;
5586 
5587  // SDField *beerased; Unused jhrg 3/16/11
5588 
5589  for (std::vector < SDField * >::iterator i = file->sd->sdfields.begin ();
5590  i != file->sd->sdfields.end (); ++i) {
5591 
5592  // This product uses "Colatitude".
5593  if (((*i)->getName ()).find ("Colatitude") != std::string::npos) {
5594  if (!colatflag) {
5595  if ((*i)->getRank () != 2)
5596  throw3 ("The lat/lon rank must be 2", (*i)->getName (),
5597  (*i)->getRank ());
5598  int dimsize0 = (*i)->getDimensions ()[0]->getSize ();
5599  int dimsize1 = (*i)->getDimensions ()[1]->getSize ();
5600 
5601  // The following comparision may not be necessary.
5602  // For most cases, the C-order first dimension is cooresponding to lat(in 1-D),
5603  // which is mostly smaller than the dimension of lon(in 2-D). E.g. 90 for lat vs 180 for lon.
5604  if (dimsize0 < dimsize1) {
5605  tempnewdimname1 = (*i)->getDimensions ()[0]->getName ();
5606  tempnewdimname2 = (*i)->getDimensions ()[1]->getName ();
5607  }
5608  else {
5609  tempnewdimname1 = (*i)->getDimensions ()[1]->getName ();
5610  tempnewdimname2 = (*i)->getDimensions ()[0]->getName ();
5611 
5612  }
5613 
5614  colatflag = true;
5615  (*i)->fieldtype = 1;
5616  tempcvarname1 = (*i)->getName ();
5617  }
5618  else {//remove the redundant Colatitude field
5619  delete (*i);
5620  file->sd->sdfields.erase (i);
5621  // When erasing the iterator, the iterator will
5622  // automatically go to the next element,
5623  // so we need to go back 1 in order not to miss the next element.
5624  i--;
5625  }
5626  }
5627 
5628  else if (((*i)->getName ()).find ("Longitude") != std::string::npos) {
5629  if (!lonflag) {
5630  lonflag = true;
5631  (*i)->fieldtype = 2;
5632  tempcvarname2 = (*i)->getName ();
5633  }
5634  else {//remove the redundant Longitude field
5635  delete (*i);
5636  file->sd->sdfields.erase (i);
5637  // When erasing the iterator, the iterator will
5638  // automatically go to the next element, so we need to go back 1
5639  // in order not to miss the next element.
5640  i--;
5641  }
5642  }
5643  }
5644 
5645  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5646  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5647 
5648 }
5649 
5650 // Handle CERES ES4 and ISCCP-GEO cases. Essentially the lat/lon need to be condensed to 1-D for the geographic projection.
5651 void
5653 throw (Exception)
5654 {
5655 
5656  std::string tempdimname1, tempdimname2;
5657  int tempdimsize1 = 0;
5658  int tempdimsize2 = 0;
5659  std::string tempcvarname1, tempcvarname2;
5660  std::string temppath;
5661  std::set < std::string > tempdimnameset;
5662  std::pair < std::set < std::string >::iterator, bool > tempsetit;
5663 
5664  // bool eraseflag = false; Unused jhrg 3/16/11
5665  bool cvflag = false;
5666  File *file = this;
5667 
5668  // The original latitude is 3-D array; we have to use the dimension name to determine which dimension is the final dimension
5669  // for 1-D array. "regional colat" and "regional lon" are consistently used in these two CERES cases.
5670  for (std::vector < SDField * >::iterator i = file->sd->sdfields.begin ();
5671  i != file->sd->sdfields.end (); ++i) {
5672  std::string tempfieldname = (*i)->getName ();
5673  if (tempfieldname.find ("Colatitude") != std::string::npos) {
5674  // They may have more than 2 dimensions, so we have to adjust it.
5675  for (std::vector < Dimension * >::const_iterator j =
5676  (*i)->getDimensions ().begin ();
5677  j != (*i)->getDimensions ().end (); ++j) {
5678  if ((((*j)->getName ()).find ("regional colat") !=
5679  std::string::npos)) {
5680  tempsetit = tempdimnameset.insert ((*j)->getName ());
5681  if (tempsetit.second == true) {
5682  tempdimname1 = (*j)->getName ();
5683  tempdimsize1 = (*j)->getSize ();
5684  (*i)->fieldtype = 1;
5685  (*i)->rank = 1;
5686  cvflag = true;
5687  break;
5688  }
5689  }
5690  }
5691 
5692  if (cvflag) {// change the dimension from 3-D to 1-D.
5693  // Clean up the original dimension vector first
5694  for (std::vector < Dimension * >::const_iterator j =
5695  (*i)->getDimensions ().begin ();
5696  j != (*i)->getDimensions ().end (); ++j)
5697  delete (*j);
5698  for (std::vector < Dimension * >::const_iterator j =
5699  (*i)->getCorrectedDimensions ().begin ();
5700  j != (*i)->getCorrectedDimensions ().end (); ++j)
5701  delete (*j);
5702  (*i)->dims.clear ();
5703  (*i)->correcteddims.clear ();
5704 
5705  Dimension *dim =
5706  new Dimension (tempdimname1, tempdimsize1, 0);
5707  (*i)->dims.push_back (dim);
5708  dim = new Dimension (tempdimname1, tempdimsize1, 0);
5709  (*i)->correcteddims.push_back (dim);
5710  file->sd->nonmisscvdimnamelist.insert (tempdimname1);
5711  cvflag = false;
5712  }
5713  else {//delete this element from the vector and erase it.
5714  delete (*i);
5715  file->sd->sdfields.erase (i);
5716 
5717  // When erasing the iterator, the iterator will automatically
5718  // go to the next element, so we need to go back 1 in order not
5719  // to miss the next element.
5720  i--;
5721  }
5722  }
5723 
5724  else if (tempfieldname.find ("Longitude") != std::string::npos) {
5725  for (std::vector < Dimension * >::const_iterator j =
5726  (*i)->getDimensions ().begin ();
5727  j != (*i)->getDimensions ().end (); ++j) {
5728  if (((*j)->getName ()).find ("regional long") !=
5729  std::string::npos) {
5730  tempsetit = tempdimnameset.insert ((*j)->getName ());
5731  if (tempsetit.second == true) {
5732  tempdimname2 = (*j)->getName ();
5733  tempdimsize2 = (*j)->getSize ();
5734  (*i)->fieldtype = 2;
5735  (*i)->rank = 1;
5736  cvflag = true;
5737  break;
5738  }
5739  // Make this the only dimension name of this field
5740  }
5741  }
5742  if (cvflag) {
5743  for (std::vector < Dimension * >::const_iterator j =
5744  (*i)->getDimensions ().begin ();
5745  j != (*i)->getDimensions ().end (); ++j) {
5746  delete (*j);
5747  }
5748  for (std::vector < Dimension * >::const_iterator j =
5749  (*i)->getCorrectedDimensions ().begin ();
5750  j != (*i)->getCorrectedDimensions ().end (); ++j) {
5751  delete (*j);
5752  }
5753  (*i)->dims.clear ();
5754  (*i)->correcteddims.clear ();
5755 
5756  Dimension *dim =
5757  new Dimension (tempdimname2, tempdimsize2, 0);
5758  (*i)->dims.push_back (dim);
5759  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5760  (*i)->correcteddims.push_back (dim);
5761 
5762  file->sd->nonmisscvdimnamelist.insert (tempdimname2);
5763  cvflag = false;
5764  }
5765  else{//delete this element from the vector and erase it.
5766  delete (*i);
5767  file->sd->sdfields.erase (i);
5768  // When erasing the iterator, the iterator
5769  // will automatically go to the next element,
5770  // so we need to go back 1 in order not to miss the next element.
5771  i--;
5772  }
5773  }
5774  }
5775 }
5776 
5777 
5778 // CERES SAVG and CERES ISCCP-IDAY cases.
5779 // We need provide nested CERES grid 2-D lat/lon.
5780 // The lat and lon should be calculated following:
5781 // http://eosweb.larc.nasa.gov/PRODOCS/ceres/SRBAVG/Quality_Summaries/srbavg_ed2d/nestedgrid.html
5782 // or https://eosweb.larc.nasa.gov/sites/default/files/project/ceres/quality_summaries/srbavg_ed2d/nestedgrid.pdf
5783 // The dimension names and sizes are set according to the studies of these files.
5784 void
5786 throw (Exception)
5787 {
5788 
5789  // bool colatflag = false; unused jhrg 3/16/11
5790  // bool lonflag = false; Unused jhrg 3/16/11
5791 
5792  std::string tempdimname1 = "1.0 deg. regional colat. zones";
5793  std::string tempdimname2 = "1.0 deg. regional long. zones";
5794  std::string tempdimname3 = "1.0 deg. zonal colat. zones";
5795  std::string tempdimname4 = "1.0 deg. zonal long. zones";
5796  int tempdimsize1 = 180;
5797  int tempdimsize2 = 360;
5798  int tempdimsize3 = 180;
5799  int tempdimsize4 = 1;
5800 
5801  std::string tempnewdimname1, tempnewdimname2;
5802  std::string tempcvarname1, tempcvarname2;
5803  File *file;
5804 
5805  file = this;
5806 
5807  SDField *latitude = new SDField ();
5808 
5809  latitude->name = "latitude";
5810  latitude->rank = 2;
5811  latitude->type = DFNT_FLOAT32;
5812  latitude->fieldtype = 1;
5813 
5814  // No need to obtain the full path
5815  latitude->newname = latitude->name;
5816 
5817  Dimension *dim = new Dimension (tempdimname1, tempdimsize1, 0);
5818 
5819  latitude->dims.push_back (dim);
5820 
5821  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5822  latitude->dims.push_back (dim);
5823 
5824  dim = new Dimension (tempdimname1, tempdimsize1, 0);
5825  latitude->correcteddims.push_back (dim);
5826 
5827  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5828  latitude->correcteddims.push_back (dim);
5829  file->sd->sdfields.push_back (latitude);
5830 
5831  SDField *longitude = new SDField ();
5832 
5833  longitude->name = "longitude";
5834  longitude->rank = 2;
5835  longitude->type = DFNT_FLOAT32;
5836  longitude->fieldtype = 2;
5837 
5838  // No need to obtain the full path
5839  longitude->newname = longitude->name;
5840 
5841  dim = new Dimension (tempdimname1, tempdimsize1, 0);
5842  longitude->dims.push_back (dim);
5843 
5844  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5845  longitude->dims.push_back (dim);
5846 
5847  dim = new Dimension (tempdimname1, tempdimsize1, 0);
5848  longitude->correcteddims.push_back (dim);
5849 
5850  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5851  longitude->correcteddims.push_back (dim);
5852  file->sd->sdfields.push_back (longitude);
5853 
5854  // For the CER_SRB case, zonal average data is also included.
5855  // We need only provide the latitude.
5856  if (file->sptype == CER_SRB) {
5857 
5858  SDField *latitudez = new SDField ();
5859 
5860  latitudez->name = "latitudez";
5861  latitudez->rank = 1;
5862  latitudez->type = DFNT_FLOAT32;
5863  latitudez->fieldtype = 1;
5864  latitudez->newname = latitudez->name;
5865 
5866  dim = new Dimension (tempdimname3, tempdimsize3, 0);
5867  latitudez->dims.push_back (dim);
5868 
5869  dim = new Dimension (tempdimname3, tempdimsize3, 0);
5870  latitudez->correcteddims.push_back (dim);
5871  file->sd->sdfields.push_back (latitudez);
5872 
5873  SDField *longitudez = new SDField ();
5874  longitudez->name = "longitudez";
5875  longitudez->rank = 1;
5876  longitudez->type = DFNT_FLOAT32;
5877  longitudez->fieldtype = 2;
5878  longitudez->newname = longitudez->name;
5879 
5880  dim = new Dimension (tempdimname4, tempdimsize4, 0);
5881  longitudez->dims.push_back (dim);
5882 
5883  dim = new Dimension (tempdimname4, tempdimsize4, 0);
5884  longitudez->correcteddims.push_back (dim);
5885  file->sd->sdfields.push_back (longitudez);
5886  }
5887 
5888  if (file->sptype == CER_SRB) {
5889  file->sd->nonmisscvdimnamelist.insert (tempdimname3);
5890  file->sd->nonmisscvdimnamelist.insert (tempdimname4);
5891  }
5892 
5893  file->sd->nonmisscvdimnamelist.insert (tempdimname1);
5894  file->sd->nonmisscvdimnamelist.insert (tempdimname2);
5895 
5896  if(file->sptype == CER_CDAY) {
5897 
5898  string odddimname1= "1.0 deg. regional Colat. zones";
5899  string odddimname2 = "1.0 deg. regional Long. zones";
5900 
5901  // Add a loop to change the odddimnames to (normal)tempdimnames.
5902  for (std::vector < SDField * >::const_iterator i =
5903  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5904  for (std::vector < Dimension * >::const_iterator j =
5905  (*i)->getDimensions ().begin ();
5906  j != (*i)->getDimensions ().end (); ++j) {
5907  if (odddimname1 == (*j)->name)
5908  (*j)->name = tempdimname1;
5909  if (odddimname2 == (*j)->name)
5910  (*j)->name = tempdimname2;
5911  }
5912  for (std::vector < Dimension * >::const_iterator j =
5913  (*i)->getCorrectedDimensions ().begin ();
5914  j != (*i)->getCorrectedDimensions ().end (); ++j) {
5915  if (odddimname1 == (*j)->name)
5916  (*j)->name = tempdimname1;
5917  if (odddimname2 == (*j)->name)
5918  (*j)->name = tempdimname2;
5919 
5920  }
5921  }
5922  }
5923 }
5924 
5925 // Prepare the CER_ZAVG case. This is the zonal average case.
5926 // Only latitude is needed.
5927 void
5929 throw (Exception)
5930 {
5931 
5932  std::string tempdimname3 = "1.0 deg. zonal colat. zones";
5933  std::string tempdimname4 = "1.0 deg. zonal long. zones";
5934  int tempdimsize3 = 180;
5935  int tempdimsize4 = 1;
5936  File *file = this;
5937 
5938  SDField *latitudez = new SDField ();
5939 
5940  latitudez->name = "latitudez";
5941  latitudez->rank = 1;
5942  latitudez->type = DFNT_FLOAT32;
5943  latitudez->fieldtype = 1;
5944  latitudez->newname = latitudez->name;
5945 
5946 
5947  Dimension *dim = new Dimension (tempdimname3, tempdimsize3, 0);
5948  latitudez->dims.push_back (dim);
5949 
5950  dim = new Dimension (tempdimname3, tempdimsize3, 0);
5951  latitudez->correcteddims.push_back (dim);
5952 
5953  file->sd->sdfields.push_back (latitudez);
5954  SDField *longitudez = new SDField ();
5955 
5956  longitudez->name = "longitudez";
5957  longitudez->rank = 1;
5958  longitudez->type = DFNT_FLOAT32;
5959  longitudez->fieldtype = 2;
5960  longitudez->newname = longitudez->name;
5961 
5962  dim = new Dimension (tempdimname4, tempdimsize4, 0);
5963  longitudez->dims.push_back (dim);
5964 
5965  dim = new Dimension (tempdimname4, tempdimsize4, 0);
5966  longitudez->correcteddims.push_back (dim);
5967 
5968  file->sd->sdfields.push_back (longitudez);
5969  file->sd->nonmisscvdimnamelist.insert (tempdimname3);
5970  file->sd->nonmisscvdimnamelist.insert (tempdimname4);
5971 
5972 }
5973 
5974 // Prepare the "Latitude" and "Longitude" for the MODISARNSS case.
5975 // This file has Latitude and Longitude. The only thing it needs
5976 // to change is to assure the dimension names of the field names the same
5977 // as the lat and lon.
5978 void
5980 throw (Exception)
5981 {
5982 
5983  std::set < std::string > tempfulldimnamelist;
5984  std::pair < std::set < std::string >::iterator, bool > ret;
5985 
5986  std::map < int, std::string > tempsizedimnamelist;
5987 
5988  File *file = this;
5989 
5990  for (std::vector < SDField * >::const_iterator i =
5991  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5992  if ((*i)->getName () == "Latitude")
5993  (*i)->fieldtype = 1;
5994  if ((*i)->getName () == "Longitude") {
5995  (*i)->fieldtype = 2;
5996 
5997  // Fields associate with lat/lon use different dimension names;
5998  // To be consistent with other code, use size-dim map to change
5999  // fields that have the same size as lat/lon to hold the same dimension names.
6000  for (std::vector < Dimension * >::const_iterator j =
6001  (*i)->getCorrectedDimensions ().begin ();
6002  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6003  tempsizedimnamelist[(*j)->getSize ()] = (*j)->getName ();
6004  file->sd->nonmisscvdimnamelist.insert ((*j)->getName ());
6005  }
6006  }
6007  }
6008 
6009  for (std::vector < SDField * >::const_iterator i =
6010  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6011  for (std::vector < Dimension * >::const_iterator j =
6012  (*i)->getCorrectedDimensions ().begin ();
6013  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6014 
6015  // Need to change those dimension names to be the same as lat/lon
6016  // so that a coordinate variable dimension name map can be built.
6017  if ((*i)->fieldtype == 0) {
6018  if ((tempsizedimnamelist.find ((*j)->getSize ())) !=
6019  tempsizedimnamelist.end ())
6020  (*j)->name = tempsizedimnamelist[(*j)->getSize ()];
6021  }
6022  }
6023  }
6024 }
6025 
6026 
6027 // For all other cases not listed above. What we did here is very limited.
6028 // We only consider the field to be a "third-dimension" coordinate variable
6029 // when dimensional scale is applied.
6030 void
6032 throw (Exception)
6033 {
6034 
6035  std::set < std::string > tempfulldimnamelist;
6036  std::pair < std::set < std::string >::iterator, bool > ret;
6037  File *file = this;
6038 
6039  // I need to trimm MERRA data field and dim. names according to NASA's request.
6040  // Currently the field name includes the full path(/EOSGRID/Data Fields/PLE);
6041  // the dimension name is something
6042  // like XDim::EOSGRID, which are from the original HDF-EOS2 files.
6043  // I need to trim them. Field name PLE, Dimension name: XDim.
6044  // KY 2012-7-2
6045 
6046  bool merra_is_eos2 = false;
6047  size_t found_forward_slash = file->path.find_last_of("/");
6048  if ((found_forward_slash != string::npos) &&
6049  (((file->path).substr(found_forward_slash+1).compare(0,5,"MERRA"))==0)){
6050 
6051  for (std::vector < Attribute * >::const_iterator i =
6052  file->sd->getAttributes ().begin ();
6053  i != file->sd->getAttributes ().end (); ++i) {
6054 
6055  // CHeck if this MERRA file is an HDF-EOS2 or not.
6056  if(((*i)->getName().compare(0, 14, "StructMetadata" )== 0) ||
6057  ((*i)->getName().compare(0, 14, "structmetadata" )== 0)) {
6058  merra_is_eos2 = true;
6059  break;
6060  }
6061 
6062  }
6063  }
6064 
6065  if( true == merra_is_eos2) {
6066  vector <string> noneos_newnamelist;
6067 
6068  // 1. Remove EOSGRID from the added-non-EOS field names(XDim:EOSGRID to XDim)
6069  for (std::vector < SDField * >::const_iterator i =
6070  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6071  (*i)->special_product_fullpath = (*i)->newname;
6072  // "EOSGRID" inside variable and dim. names needs to be trimmed out. KY 7-2-2012
6073  string EOSGRIDstring=":EOSGRID";
6074  size_t found = ((*i)->name).rfind(EOSGRIDstring);
6075 
6076  if (found !=string::npos && (((*i)->name).size() == (found + EOSGRIDstring.size()))) {
6077 
6078  (*i)->newname = (*i)->name.substr(0,found);
6079  noneos_newnamelist.push_back((*i)->newname);
6080  }
6081  else
6082  (*i)->newname = (*i)->name;
6083  }
6084 
6085  // 2. Make the redundant and clashing CVs such as XDim to XDim_EOS etc.
6086  // I don't want to remove these fields since a variable like Time is different than TIME
6087  // So still keep it in case it is useful for some users.
6088 
6089  for (std::vector < SDField * >::const_iterator i =
6090  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6091 
6092  for(vector<string>::const_iterator j =
6093  noneos_newnamelist.begin(); j !=noneos_newnamelist.end();++j) {
6094 
6095  if ((*i)->newname == (*j) && (*i)->name == (*j)) {
6096  // Make XDim to XDim_EOS so that we don't have two "XDim".
6097  (*i)->newname = (*i)->newname +"_EOS";
6098  }
6099  }
6100  }
6101 
6102  // 3. Handle Dimension scales
6103  // 3.1 Change the dimension names for coordinate variables.
6104  map<string,string> dimname_to_newdimname;
6105  for (std::vector < SDField * >::const_iterator i =
6106  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6107  for (std::vector < Dimension * >::const_iterator j =
6108  (*i)->getCorrectedDimensions ().begin ();
6109  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6110  // Find the dimension scale
6111  if ((*j)->getType () != 0) {
6112  if ((*i)->name == (*j)->getName () && (*i)->getRank () == 1){
6113  (*i)->fieldtype = 3;
6114  (*i)->is_dim_scale = true;
6115  (*j)->name = (*i)->newname;
6116  // Build up the map from the original name to the new name, Note (*i)->name is the original
6117  // dimension name.
6118  HDFCFUtil::insert_map(dimname_to_newdimname,(*i)->name,(*j)->name);
6119  }
6120  file->sd->nonmisscvdimnamelist.insert ((*j)->name);
6121  }
6122  }
6123  }
6124 
6125  // 3.2 Change the dimension names for data variables.
6126  map<string,string>::iterator itmap;
6127  for (std::vector < SDField * >::const_iterator i =
6128  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6129 
6130  if (0 == (*i)->fieldtype) {
6131  for (std::vector < Dimension * >::const_iterator j =
6132  (*i)->getCorrectedDimensions ().begin ();
6133  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6134  itmap = dimname_to_newdimname.find((*j)->name);
6135  if (itmap == dimname_to_newdimname.end())
6136  throw2("Cannot find the corresponding new dim. name for dim. name ",(*j)->name);
6137  else
6138  (*j)->name = (*itmap).second;
6139 
6140  }
6141  }
6142  }
6143  }
6144  else {
6145 
6146  for (std::vector < SDField * >::const_iterator i =
6147  file->sd->sdfields.begin (); i != file->sd->sdfields.end () && (false == this->OTHERHDF_Has_Dim_NoScale_Field); ++i) {
6148  for (std::vector < Dimension * >::const_iterator j =
6149  (*i)->getCorrectedDimensions ().begin ();
6150  j != (*i)->getCorrectedDimensions ().end () && (false == this->OTHERHDF_Has_Dim_NoScale_Field); ++j) {
6151 
6152  if ((*j)->getType () != 0) {
6153  if ((*i)->name == (*j)->getName () && (*i)->getRank () == 1)
6154  (*i)->fieldtype = 3;
6155  file->sd->nonmisscvdimnamelist.insert ((*j)->getName ());
6156  }
6157  else {
6158  this->OTHERHDF_Has_Dim_NoScale_Field = true;
6159  }
6160  }
6161  }
6162 
6163  // For OTHERHDF cases, currently if we find that there are "no dimension scale" dimensions, we will NOT generate any "cooridnates" attributes.
6164  // That means "nonmisscvdimnamelist" should be cleared if OTHERHDF_Has_Dim_NoScale_Field is true.
6165 
6166  if (true == this->OTHERHDF_Has_Dim_NoScale_Field)
6167  file->sd->nonmisscvdimnamelist.clear();
6168  }
6169 }
#define CER_CGEO_NAME
Definition: HDFSP.h:62
std::vector< VDATA * > vds
Vdata objects in this file.
Definition: HDFSP.h:806
std::string name
Original vdata name.
Definition: HDFSP.h:703
void PrepareCERSAVGID()
Special method to prepare CERES SAVG (CER_SAVG_???) and CERES ISCCP DAYLIKE(CER_ISCCP__???DAYLIKE) latitude and longitude information. Essentially nested CERES 2-d lat/lon need to be provided. https://eosweb.larc.nasa.gov/sites/default/files/project/ceres/quality_summaries/srbavg_ed2d/nestedgrid.pdf.
Definition: HDFSP.cc:5785
void Handle_AIRS_L23()
Definition: HDFSP.cc:969
void free(void *)
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
#define throw5(a1, a2, a3, a4, a5)
Definition: HDFSP.cc:84
std::map< std::string, std::string > dimcvarlist
dimension name to coordinate variable name list: the key list to generate CF "coordinates" attributes...
Definition: HDFSP.h:630
int32 count
The number of elements.
Definition: HDFSP.h:221
void PrepareCERAVGSYN()
Special method to prepare CERES AVG (CER_AVG_???) and CERES SYN(CER_SYN_???) latitude and longitude i...
Definition: HDFSP.cc:5573
if(!(yy_init))
Definition: lex.gse.cc:752
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
#define _HDF_CHK_TBL_CLASS
Definition: HDFSP.h:54
void ReadHybridNonLoneVdatas(File *)
Handle non-attribute non-lone vdatas. Note: this function is only used for handling hybrid Vdata func...
Definition: HDFSP.cc:527
static SD * Read_Hybrid(int32 sdfileid, int32 hfileid)
Read the information of all hybrid SDS objects from the HDF4 file.
Definition: HDFSP.cc:1901
void handle_sds_coords(bool &COARDFLAG, std::string &lldimname1, std::string &lldimname2)
Create "coordinates", "units" CF attributes.
Definition: HDFSP.cc:3843
void handle_sds_final_dim_names()
Create the final CF-compliant dimension name list for each field.
Definition: HDFSP.cc:3617
string basename(const string &path)
Definition: dodsutil.h:133
void ReadAttributes(int32 vdata_id, int32 fieldindex)
Read vdata field attributes.
Definition: HDFSP.cc:2537
#define CER_AVG_NAME
Definition: HDFSP.h:59
void PrepareTRMML2_V6()
Latitude and longitude are stored in one array(geolocation). Need to separate.
Definition: HDFSP.cc:4803
void handle_vdata()
Handle Vdata.
Definition: HDFSP.cc:3926
bool TreatAsAttrFlag
Flag to map vdata fields to DAP variables or DAP attributes.
Definition: HDFSP.h:715
#define CER_ES4_NAME
Definition: HDFSP.h:60
This class retrieves all information from an HDF4 file. It is a container for SDS and Vdata...
Definition: HDFSP.h:727
STL namespace.
This class retrieves all SDS objects and SD file attributes.
Definition: HDFSP.h:556
void PrepareTRMML3S_V7()
Special method to prepare TRMM single grid Level 3 geolocation fields(latitude,longitude,etc) information.
Definition: HDFSP.cc:4328
void PrepareCERZAVG()
Special method to prepare CERES Zonal Average latitude and longitude information. ...
Definition: HDFSP.cc:5928
int32 type
Attribute type.
Definition: HDFSP.h:218
std::set< std::string > fulldimnamelist
Full dimension name list set.
Definition: HDFSP.h:622
void PrepareOBPGL3()
Special method to prepare OBPG Level 3 latitude and longitude information. The latitude and longitude...
Definition: HDFSP.cc:5449
std::vector< char > value
Vdata field value.
Definition: HDFSP.h:549
One instance of this class represents one Vdata field.
Definition: HDFSP.h:500
bool is_noscale_dim
Some fields have dimensions but don't have dimension scales. In HDF4, such dimension appears as a fie...
Definition: HDFSP.h:486
std::vector< Attribute * > attrs
The attributes of this field.
Definition: HDFSP.h:335
void PrepareTRMML3M_V7()
Special method to prepare TRMM multiple grid Level 3 geolocation fields(latitude,longitude,etc) information.
Definition: HDFSP.cc:4660
void PrepareTRMML2_V7()
Latitude and longitude are stored in different fields. Need to separate.
Definition: HDFSP.cc:4179
std::string newname
The CF full path(special characters replaced by underscores) of this field.
Definition: HDFSP.h:323
std::vector< AttrContainer * > dims_info
OTHERHDF dimension information. See the description of the class AttrContainer.
Definition: HDFSP.h:451
void PrepareTRMML3A_V6()
Special method to prepare TRMM Level 3A46 latitude and longitude information.
Definition: HDFSP.cc:5051
std::vector< char > value
Attribute values.
Definition: HDFSP.h:224
void ReadAttributes(int32 vdata_id)
Retrieve all attributes of this Vdata.
Definition: HDFSP.cc:2477
void setUnits(std::string uni)
Definition: HDFSP.h:393
static void Handle_NameClashing(std::vector< std::string > &newobjnamelist)
General routines to handle name clashings.
Definition: HDFCFUtil.cc:176
int32 numrec
Number of record of the vdata field.
Definition: HDFSP.h:543
This class retrieves all information of one Vdata.
Definition: HDFSP.h:642
void PrepareMODISARNSS()
MODISARNSS is a special MODIS product saved as pure HDF4 files. Dimension names of different fields n...
Definition: HDFSP.cc:5979
bool Obtain_TRMM_V7_latlon_name(const SDField *sdfield, const int latsize, const int lonsize, std::string &latname, std::string &lonname)
Definition: HDFSP.cc:4155
#define CER_SYN_NAME
Definition: HDFSP.h:64
~SD()
Destructor.
Definition: HDFSP.cc:146
int32 size
Vdata field size.
Definition: HDFSP.h:546
static VDATA * Read(int32 vdata_id, int32 obj_ref)
Retrieve all information of this Vdata.
Definition: HDFSP.cc:2312
std::vector< Dimension * > correcteddims
Corrected dimensions of this field. The only difference between the correcteddims and dims is the cor...
Definition: HDFSP.h:448
#define NULL
Definition: wcsUtil.h:65
std::set< std::string > nonmisscvdimnamelist
This set stores non-missing coordinate variable dimension names. Many third dimensions of HDF4 files ...
Definition: HDFSP.h:627
One instance of this class represents one SDS object.
Definition: HDFSP.h:344
void handle_sds_missing_fields()
Add the missing coordinate variables based on the corrected dimension name list.
Definition: HDFSP.cc:3581
bool Check_update_special(const std::string &gridname)
Definition: HDFSP.cc:825
void Prepare()
The main step to make HDF4 SDS objects CF-complaint. All dimension(coordinate variables) information ...
Definition: HDFSP.cc:3974
#define throw1(a1)
The followings are convenient functions to throw exceptions with different.
Definition: HDFSP.cc:80
bool getTreatAsAttrFlag() const
Some Vdata fields are very large in size. Some Vdata fields are very small. So we map smaller Vdata f...
Definition: HDFSP.h:681
void obtain_path(int32 file_id, int32 sd_id, char *full_path, int32 pobj_ref)
The internal function used by InsertOrigFieldPath_ReadVgVdata.
Definition: HDFSP.cc:2974
void PrepareTRMML3B_V6()
Special method to prepare TRMM Level 3B latitude and longitude information.
Definition: HDFSP.cc:4947
TRMML2_V6: TRMM Level2 1B21,2A12,2B31,2A25 TRMML3A_V6: TRMM Level3 3A46 TRMML3C_V6: TRMM Level3 CSH T...
Definition: HDFSP.h:85
void create_sds_dim_name_list()
Create the new dimension name set and the dimension name to size map.
Definition: HDFSP.cc:3558
static SD * Read(int32 sdfileid, int32 hfileid)
Read the information of all SDS objects from the HDF4 file.
Definition: HDFSP.cc:1558
static File * Read(const char *path, int32 sdid, int32 fileid)
Retrieve SDS and Vdata information from the HDF4 file.
Definition: HDFSP.cc:196
It repersents one dimension of an SDS or a VDATA. It holds the dimension name and the size of that di...
Definition: HDFSP.h:129
void handle_sds_fakedim_names()
Check name clashing for fields. Borrowed from HDFEOS.cc, unused. bool check_field_name_clashing (bool...
Definition: HDFSP.cc:3483
std::vector< Attribute * > attrs
Definition: HDFSP.h:271
const std::string & getPath() const
Obtain the path of the file.
Definition: HDFSP.h:766
const std::string & getName() const
Get the name of this field.
Definition: HDFSP.h:290
static File * Read_Hybrid(const char *path, int32 sdid, int32 fileid)
Retrieve SDS and Vdata information from the hybrid HDF-EOS file. Currently we only support the access...
Definition: HDFSP.cc:249
std::map< std::string, std::string > n2dimnamelist
Original dimension name to corrected dimension name map.
Definition: HDFSP.h:619
void PrepareCERES4IG()
Special method to prepare CERES ES4 (CER_ES4_???) and CERES ISCCP GEO(CER_ISCCP__???GEO) latitude and longitude information. Essentially the lat/lon need to be condensed to 1-D for the geographic projection.
Definition: HDFSP.cc:5652
std::vector< Dimension * > dims
Dimensions of this field.
Definition: HDFSP.h:443
std::list< int32 > sds_ref_list
SDS reference number list.
Definition: HDFSP.h:609
std::string newname
CF attribute name(special characters are replaced by underscores)
Definition: HDFSP.h:215
You should define one of the following
Definition: freeform.h:407
#define CERE_META_FIELD_NAME
Definition: HDFSP.h:56
int32 type
The datatype of this field.
Definition: HDFSP.h:329
void obtain_noneos2_sds_path(int32, char *, int32)
Obtain SDS path, this is like a clone of obtain_path in File class, except the Vdata and some minor p...
Definition: HDFSP.cc:3179
int32 vdref
Vdata reference number.
Definition: HDFSP.h:712
void handle_sds_names(bool &COARDFLAG, std::string &lldimname1, std::string &lldimname2)
Create the final CF-compliant field name list.
Definition: HDFSP.cc:3665
std::vector< SDField * > sdfields
SDS objects stored in vectors.
Definition: HDFSP.h:603
const std::vector< VDField * > & getFields() const
Obtain Vdata fields.
Definition: HDFSP.h:667
std::string name
Original attribute name.
Definition: HDFSP.h:212
std::string name
Definition: HDFSP.h:268
std::string name
The original name of this field.
Definition: HDFSP.h:326
const std::vector< Attribute * > & getAttributes() const
Public interface to obtain the SD(file) attributes.
Definition: HDFSP.h:579
void ReadVgattrs(int32 vgroup_id, char *fullpath)
Obtain vgroup attributes.
Definition: HDFSP.cc:2598
SD * sd
Pointer to the SD instance. There is only one SD instance in an HDF4 file.
Definition: HDFSP.h:803
#define throw3(a1, a2, a3)
Definition: HDFSP.cc:82
#define CER_SRB_NAME
Definition: HDFSP.h:63
#define MAX_FULL_PATH_LEN
HDFSP.h and HDFSP.cc include the core part of retrieving HDF-SP Grid and Swath metadata info and tran...
Definition: HDFSP.h:50
int32 fieldref
SDS reference number. This and the object tag are a key to identify a SDS object. ...
Definition: HDFSP.h:479
void PrepareOTHERHDF()
We still provide a hook for other HDF data product although no CF compliant is followed.
Definition: HDFSP.cc:6031
const char * _BACK_SLASH
HDFSP.h and HDFSP.cc include the core part of retrieving HDF-SP Grid and Swath metadata info and tran...
Definition: HDFSP.cc:41
void PrepareTRMML3C_V6()
Special method to prepare TRMM Level 3 CSH latitude,longitude and Height information.
Definition: HDFSP.cc:5214
int fieldtype
This flag will specify the fieldtype. 0 means this field is general field. 1 means this field is lat...
Definition: HDFSP.h:461
#define CER_ZAVG_NAME
Definition: HDFSP.h:65
This class only applies to the OTHERHDF products when there are dimensions but not dimension scales...
Definition: HDFSP.h:237
void ReadLoneVdatas(File *)
Handle non-attribute lone vdatas.
Definition: HDFSP.cc:302
int32 order
Vdata field order.
Definition: HDFSP.h:540
std::map< int32, int > refindexlist
SDS reference number to index map, use to quickly obtain the SDS id.
Definition: HDFSP.h:612
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
#define throw2(a1, a2)
Definition: HDFSP.cc:81
void * malloc(YYSIZE_T)
int32 rank
The rank of this field.
Definition: HDFSP.h:332
std::string path
The absolute path of the file.
Definition: HDFSP.h:800
std::vector< Attribute * > attrs
SD attributes stored in vectors.
Definition: HDFSP.h:606
void PrepareOBPGL2()
Special method to prepare OBPG Level 2 latitude and longitude information. The latitude and longitude...
Definition: HDFSP.cc:5364
std::vector< VDField * > vdfields
Vdata field vectors.
Definition: HDFSP.h:706
void Obtain_TRMML3S_V7_latlon_size(int &latsize, int &lonsize)
Definition: HDFSP.cc:4134
#define CERE_META_NAME
Definition: HDFSP.h:55
Representing one attribute in grid or swath.
Definition: HDFSP.h:175
std::map< std::string, int32 > n1dimnamelist
Unique dimension name to its size map, may be replaced in the current implementation. Still leave it here for potential fakeDim handling in the future.
Definition: HDFSP.h:616
void CheckSDType()
This method will check if the HDF4 file is one of TRMM or OBPG products we supported.
Definition: HDFSP.cc:1249
std::string newname
New name with path and CF compliant(no special characters and name clashing).
Definition: HDFSP.h:700
std::string rootfieldname
In some TRMM versions, latitude and longitude are combined into one field geolocation. This variable is to remember the root field for latitude and longitude.
Definition: HDFSP.h:493
#define CER_CDAY_NAME
Definition: HDFSP.h:61
#define TRUE
Definition: gse_parser.h:32
void InsertOrigFieldPath_ReadVgVdata()
The full path of SDS and Vdata will be obtained.
Definition: HDFSP.cc:2649