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