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