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