bes Updated for version 3.20.10
HDF5GMCF.cc
Go to the documentation of this file.
1// This file is part of the hdf5_handler implementing for the CF-compliant
2// Copyright (c) 2011-2016 The HDF Group, Inc. and OPeNDAP, Inc.
3//
4// This is free software; you can redistribute it and/or modify it under the
5// terms of the GNU Lesser General Public License as published by the Free
6// Software Foundation; either version 2.1 of the License, or (at your
7// option) any later version.
8//
9// This software is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12// License for more details.
13//
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17//
18// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
19// You can contact The HDF Group, Inc. at 1800 South Oak Street,
20// Suite 203, Champaign, IL 61820
21
36
37#include "HDF5CF.h"
38#include "HDF5RequestHandler.h"
39#include "h5apicompatible.h"
40#include <BESDebug.h>
41#include <algorithm>
42
43using namespace std;
44using namespace libdap;
45using namespace HDF5CF;
46
47// Copier function.
48GMCVar::GMCVar(Var*var) {
49
50 BESDEBUG("h5", "Coming to GMCVar()"<<endl);
51 newname = var->newname;
52 name = var->name;
53 fullpath = var->fullpath;
54 rank = var->rank;
55 total_elems = var->total_elems;
56 zero_storage_size = var->zero_storage_size;
57 dtype = var->dtype;
58 unsupported_attr_dtype = var->unsupported_attr_dtype;
59 unsupported_dspace = var->unsupported_dspace;
60 coord_attr_add_path = false;
61
62 for (vector<Attribute*>::iterator ira = var->attrs.begin();
63 ira!=var->attrs.end(); ++ira) {
64 Attribute* attr= new Attribute();
65 attr->name = (*ira)->name;
66 attr->newname = (*ira)->newname;
67 attr->dtype =(*ira)->dtype;
68 attr->count =(*ira)->count;
69 attr->strsize = (*ira)->strsize;
70 attr->fstrsize = (*ira)->fstrsize;
71 attr->value =(*ira)->value;
72 attrs.push_back(attr);
73 } //for (vector<Attribute*>::iterator ira = var->attrs.begin()
74
75 for (vector<Dimension*>::iterator ird = var->dims.begin();
76 ird!=var->dims.end(); ++ird) {
77 Dimension *dim = new Dimension((*ird)->size);
78 dim->name = (*ird)->name;
79 dim->newname = (*ird)->newname;
80 dim->unlimited_dim = (*ird)->unlimited_dim;
81 dims.push_back(dim);
82 } // for (vector<Dimension*>::iterator ird = var->dims.begin()
83 product_type = General_Product;
84
85}
86#if 0
87GMCVar::GMCVar(GMCVar*cvar) {
88
89 newname = cvar->newname;
90 name = cvar->name;
91 fullpath = cvar->fullpath;
92 rank = cvar->rank;
93 dtype = cvar->dtype;
94 unsupported_attr_dtype = cvar->unsupported_attr_dtype;
95 unsupported_dspace = cvar->unsupported_dspace;
96
97 for (vector<Attribute*>::iterator ira = cvar->attrs.begin();
98 ira!=cvar->attrs.end(); ++ira) {
99 Attribute* attr= new Attribute();
100 attr->name = (*ira)->name;
101 attr->newname = (*ira)->newname;
102 attr->dtype =(*ira)->dtype;
103 attr->count =(*ira)->count;
104 attr->strsize = (*ira)->strsize;
105 attr->fstrsize = (*ira)->fstrsize;
106 attr->value =(*ira)->value;
107 attrs.push_back(attr);
108 }
109
110 for (vector<Dimension*>::iterator ird = cvar->dims.begin();
111 ird!=cvar->dims.end(); ++ird) {
112 Dimension *dim = new Dimension((*ird)->size);
113//"h5","dim->name "<< (*ird)->name <<endl;
114//"h5","dim->newname "<< (*ird)->newname <<endl;
115 dim->name = (*ird)->name;
116 dim->newname = (*ird)->newname;
117 dims.push_back(dim);
118 }
119
120 GMcvar->cfdimname = latdim0;
121 GMcvar->cvartype = CV_EXIST;
122 GMcvar->product_type = product_type;
123
124
125}
126#endif
127
128//Copier function of a special variable.
129GMSPVar::GMSPVar(Var*var) {
130
131 BESDEBUG("h5", "Coming to GMSPVar()"<<endl);
132 fullpath = var->fullpath;
133 rank = var->rank;
134 total_elems = var->total_elems;
135 zero_storage_size = var->zero_storage_size;
136 unsupported_attr_dtype = var->unsupported_attr_dtype;
137 unsupported_dspace = var->unsupported_dspace;
138 coord_attr_add_path = var->coord_attr_add_path;
139 // The caller of this function should change the following fields.
140 // This is just to make data coverity happy.
141 otype = H5UNSUPTYPE;
142 sdbit = -1;
143 numofdbits = -1;
144
145 for (vector<Attribute*>::iterator ira = var->attrs.begin();
146 ira!=var->attrs.end(); ++ira) {
147 Attribute* attr= new Attribute();
148 attr->name = (*ira)->name;
149 attr->newname = (*ira)->newname;
150 attr->dtype =(*ira)->dtype;
151 attr->count =(*ira)->count;
152 attr->strsize = (*ira)->strsize;
153 attr->fstrsize = (*ira)->fstrsize;
154 attr->value =(*ira)->value;
155 attrs.push_back(attr);
156 } // "for (vector<Attribute*>::iterator ira = var->attrs.begin()"
157
158 for (vector<Dimension*>::iterator ird = var->dims.begin();
159 ird!=var->dims.end(); ++ird) {
160 Dimension *dim = new Dimension((*ird)->size);
161 dim->name = (*ird)->name;
162 dim->newname = (*ird)->newname;
163 dim->unlimited_dim = (*ird)->unlimited_dim;
164 dims.push_back(dim);
165 }
166}
167
168
169GMFile::GMFile(const char*file_fullpath, hid_t file_id, H5GCFProduct product_type, GMPattern gproduct_pattern):
170File(file_fullpath,file_id), product_type(product_type),gproduct_pattern(gproduct_pattern),iscoard(false),have_nc4_non_coord(false)
171{
172
173}
174
175// destructor
176GMFile::~GMFile()
177{
178
179 if (!this->cvars.empty()){
180 for (vector<GMCVar *>:: const_iterator i= this->cvars.begin(); i!=this->cvars.end(); ++i) {
181 delete *i;
182 }
183 }
184
185 if (!this->spvars.empty()){
186 for (vector<GMSPVar *>:: const_iterator i= this->spvars.begin(); i!=this->spvars.end(); ++i) {
187 delete *i;
188 }
189 }
190
191}
192
193// Get CF string
194string GMFile::get_CF_string(string s) {
195
196 // HDF5 group or variable path always starts with '/'. When CF naming rule is applied,
197 // the first '/' is always changes to "_", this is not necessary. However,
198 // to keep the backward compatiablity, I use a BES key for people to go back with the original name.
199
200 if(s[0] !='/')
201 return File::get_CF_string(s);
202 else if (General_Product == product_type && OTHERGMS == gproduct_pattern) {
203
204 if(true == HDF5RequestHandler::get_keep_var_leading_underscore())
205 return File::get_CF_string(s);
206 else {
207 s.erase(0,1);
208 return File::get_CF_string(s);
209 }
210 }
211 else {
212 // The leading underscore should be removed from all supported products
213 s.erase(0,1);
214 return File::get_CF_string(s);
215 }
216}
217
218// Retrieve all the HDF5 information.
219void GMFile::Retrieve_H5_Info(const char *file_fullpath,
220 hid_t file_id, bool include_attr) {
221
222 BESDEBUG("h5", "Coming to Retrieve_H5_Info()"<<endl);
223 // GPM needs the attribute info. to obtain the lat/lon.
224 // So set the include_attr to be true for these products.
225 if (product_type == Mea_SeaWiFS_L2 || product_type == Mea_SeaWiFS_L3
226 || GPMS_L3 == product_type || GPMM_L3 == product_type || GPM_L1 == product_type || OBPG_L3 == product_type
227 || Mea_Ozone == product_type || General_Product == product_type)
228 File::Retrieve_H5_Info(file_fullpath,file_id,true);
229 else
230 File::Retrieve_H5_Info(file_fullpath,file_id,include_attr);
231
232}
233
234// Update the product type. This is because the file structure may change across different versions of products
235// I need to handle them differently and still support different versions. The goal is to support two versions in a row.
236// Currently GPM level 3 is changed.
237// This routine should be called right after Retrieve_H5_Info.
239
240 BESDEBUG("h5", "Coming to Update_Product_Type()"<<endl);
241 if(GPMS_L3 == this->product_type || GPMM_L3 == this->product_type) {
242
243 // Check Dimscale attributes
244 //Check_General_Product_Pattern();
245 Check_Dimscale_General_Product_Pattern();
246 if(GENERAL_DIMSCALE == this->gproduct_pattern){
247 if(GPMS_L3 == this->product_type) {
248 for (vector<Var *>::iterator irv = this->vars.begin();
249 irv != this->vars.end(); ++irv)
250 (*irv)->newname = (*irv)->name;
251 }
252 this->product_type = General_Product;
253 }
254 }
255//#if 0
256 else if(General_Product == this->product_type)
257 Check_General_Product_Pattern();
258//#endif
259}
260
262
263 BESDEBUG("h5", "Coming to Remove_Unneeded_Objects()"<<endl);
264 if(General_Product == this->product_type) {
265 string file_path = this->path;
266 if(HDF5CFUtil::obtain_string_after_lastslash(file_path).find("OMPS-NPP")==0)
267 Remove_OMPSNPP_InputPointers();
268 }
269 if((General_Product == this->product_type) && (GENERAL_DIMSCALE == this->gproduct_pattern)) {
270 set<string> nc4_non_coord_set;
271 string nc4_non_coord="_nc4_non_coord_";
272 size_t nc4_non_coord_size= nc4_non_coord.size();
273 for (vector<Var *>::iterator irv = this->vars.begin();
274 irv != this->vars.end(); ++irv) {
275 if((*irv)->name.find(nc4_non_coord)==0)
276 nc4_non_coord_set.insert((*irv)->name.substr(nc4_non_coord_size,(*irv)->name.size()-nc4_non_coord_size));
277
278 }
279
280 for (vector<Var *>::iterator irv = this->vars.begin();
281 irv != this->vars.end();) {
282 if(nc4_non_coord_set.find((*irv)->name)!=nc4_non_coord_set.end()){
283 delete(*irv);
284 irv=this->vars.erase(irv);
285 }
286 else
287 ++irv;
288 }
289
290 if(nc4_non_coord_set.size()!=0)
291 this->have_nc4_non_coord = true;
292 }
293 else if(GPM_L3_New == this->product_type) {
294 for (vector<Group *>::iterator irg = this->groups.begin();
295 irg != this->groups.end(); ) {
296 if((*irg)->attrs.empty()) {
297 delete(*irg);
298 irg = this->groups.erase(irg);
299
300 }
301 else
302 ++irg;
303 }
304 }
305}
306
307void GMFile::Remove_OMPSNPP_InputPointers() {
308 // Here I don't check whether this is a netCDF file by
309 // using Check_Dimscale_General_Product_Pattern() to see if it returns true.
310 // We will see if we need this.
311 for (vector<Group *>::iterator irg = this->groups.begin();
312 irg != this->groups.end(); ) {
313 if((*irg)->path.find("/InputPointers")==0) {
314 delete(*irg);
315 irg = this->groups.erase(irg);
316
317 }
318 else
319 ++irg;
320 }
321
322 for (vector<Var *>::iterator irv = this->vars.begin();
323 irv != this->vars.end(); ) {
324 if((*irv)->fullpath.find("/InputPointers")==0) {
325 delete(*irv);
326 irv = this->vars.erase(irv);
327
328 }
329 else
330 ++irv;
331 }
332}
334
335 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
336 ircv != this->cvars.end(); ++ircv) {
337
338 if ((*ircv)->cvartype != CV_NONLATLON_MISS){
339 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
340 ira != (*ircv)->attrs.end(); ++ira) {
341 Retrieve_H5_Attr_Value(*ira,(*ircv)->fullpath);
342 }
343 }
344 }
345}
346
347// Retrieve HDF5 supported attribute values.
349
350 BESDEBUG("h5", "Coming to Retrieve_H5_Supported_Attr_Values()"<<endl);
351
352 // General attributes
354
355 //Coordinate variable attributes
356 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
357 ircv != this->cvars.end(); ++ircv) {
358
359 if ((*ircv)->cvartype != CV_NONLATLON_MISS){
360 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
361 ira != (*ircv)->attrs.end(); ++ira) {
362 Retrieve_H5_Attr_Value(*ira,(*ircv)->fullpath);
363 }
364 }
365 }
366
367 // Special variable attributes
368 for (vector<GMSPVar *>::iterator irspv = this->spvars.begin();
369 irspv != this->spvars.end(); ++irspv) {
370
371 for (vector<Attribute *>::iterator ira = (*irspv)->attrs.begin();
372 ira != (*irspv)->attrs.end(); ++ira) {
373 Retrieve_H5_Attr_Value(*ira,(*irspv)->fullpath);
375 }
376 }
377}
378
379// Adjust attribute values. Currently this is only for ACOS and OCO2.
380// Reason: DAP2 doesn't support 64-bit integer and they have 64-bit integer data
381// in these files. Chop them to two 32-bit integers following the data producer's information.
383
384 BESDEBUG("h5", "Coming to Adjust_H5_Attr_Value()"<<endl);
385 if (product_type == ACOS_L2S_OR_OCO2_L1B) {
386 if (("Type" == attr->name) && (H5VSTRING == attr->dtype)) {
387 string orig_attrvalues(attr->value.begin(),attr->value.end());
388 if (orig_attrvalues != "Signed64") return;
389 string new_attrvalues = "Signed32";
390 // Since the new_attrvalues size is the same as the orig_attrvalues size
391 // No need to adjust the strsize and fstrsize. KY 2011-2-1
392 attr->value.clear();
393 attr->value.resize(new_attrvalues.size());
394 copy(new_attrvalues.begin(),new_attrvalues.end(),attr->value.begin());
395 }
396 } // "end if (product_type == ACOS_L2S_OR_OCO2_L1B)"
397}
398
399// Unsupported datatype
400void GMFile:: Handle_Unsupported_Dtype(bool include_attr) {
401
402 BESDEBUG("h5", "Coming to Handle_Unsupported_Dtype()"<<endl);
403 if(true == check_ignored) {
404 Gen_Unsupported_Dtype_Info(include_attr);
405 }
406 File::Handle_Unsupported_Dtype(include_attr);
407 Handle_GM_Unsupported_Dtype(include_attr);
408}
409
410// Unsupported datatype for general data products.
411void GMFile:: Handle_GM_Unsupported_Dtype(bool include_attr) {
412
413 BESDEBUG("h5", "Coming to Handle_GM_Unsupported_Dtype()"<<endl);
414 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
415 ircv != this->cvars.end(); ) {
416 if (true == include_attr) {
417 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
418 ira != (*ircv)->attrs.end(); ) {
419 H5DataType temp_dtype = (*ira)->getType();
420 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
421 delete (*ira);
422 ira = (*ircv)->attrs.erase(ira);
423 }
424 else {
425 ++ira;
426 }
427 }
428 }
429 H5DataType temp_dtype = (*ircv)->getType();
430 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
431
432 // This may need to be checked carefully in the future,
433 // My current understanding is that the coordinate variable can
434 // be ignored if the corresponding variable is ignored.
435 // Currently we don't find any NASA files in this category.
436 // KY 2012-5-21
437 delete (*ircv);
438 ircv = this->cvars.erase(ircv);
439 }
440 else {
441 ++ircv;
442 }
443
444 } // for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
445 for (vector<GMSPVar *>::iterator ircv = this->spvars.begin();
446 ircv != this->spvars.end(); ) {
447
448 if (true == include_attr) {
449 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
450 ira != (*ircv)->attrs.end(); ) {
451 H5DataType temp_dtype = (*ira)->getType();
452 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
453 delete (*ira);
454 ira = (*ircv)->attrs.erase(ira);
455 }
456 else {
457 ++ira;
458 }
459 }
460 }
461 H5DataType temp_dtype = (*ircv)->getType();
462 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
463 delete (*ircv);
464 ircv = this->spvars.erase(ircv);
465 }
466 else {
467 ++ircv;
468 }
469
470 }// "end for (vector<GMSPVar *>::iterator ircv = this->spvars.begin()"
471}
472
473// Datatype ignore information.
474void GMFile:: Gen_Unsupported_Dtype_Info(bool include_attr) {
475
476 BESDEBUG("h5", "GMFile::Coming to Gen_Unsupported_Dtype_Info()"<<endl);
477 if(true == include_attr) {
478
479 File::Gen_Group_Unsupported_Dtype_Info();
480 File::Gen_Var_Unsupported_Dtype_Info();
481 Gen_VarAttr_Unsupported_Dtype_Info();
482 }
483
484}
485
486// Datatype ignored information for variable ttributes
487void GMFile:: Gen_VarAttr_Unsupported_Dtype_Info() {
488
489 BESDEBUG("h5", "GMFile::Coming to Gen_Unsupported_Dtype_Info()"<<endl);
490 // First general variables(non-CV and non-special variable) that use dimension scales.
491 if((General_Product == this->product_type && GENERAL_DIMSCALE== this->gproduct_pattern)
492 || (Mea_Ozone == this->product_type) || (Mea_SeaWiFS_L2 == this->product_type) || (Mea_SeaWiFS_L3 == this->product_type)
493 || (OBPG_L3 == this->product_type)) {
494 Gen_DimScale_VarAttr_Unsupported_Dtype_Info();
495 }
496
497 else
498 File::Gen_VarAttr_Unsupported_Dtype_Info();
499
500 // CV and special variables
501 Gen_GM_VarAttr_Unsupported_Dtype_Info();
502
503}
504
505// Generate ignored object,attribute information for the CVs and special variables of general supported products.
506void GMFile:: Gen_GM_VarAttr_Unsupported_Dtype_Info(){
507
508 BESDEBUG("h5", "GMFile::Coming to Gen_GM_VarAttr_Unsupported_Dtype_Info()"<<endl);
509 if((General_Product == this->product_type && GENERAL_DIMSCALE== this->gproduct_pattern)
510 || (Mea_Ozone == this->product_type) || (Mea_SeaWiFS_L2 == this->product_type) || (Mea_SeaWiFS_L3 == this->product_type)
511 || (OBPG_L3 == this->product_type)) {
512
513 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
514 irv != this->cvars.end(); ++irv) {
515 // If the attribute REFERENCE_LIST comes with the attribut CLASS, the
516 // attribute REFERENCE_LIST is okay to ignore. No need to report.
517 bool is_ignored = ignored_dimscale_ref_list((*irv));
518 if (false == (*irv)->attrs.empty()) {
519 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
520 ira != (*irv)->attrs.end(); ++ira) {
521 H5DataType temp_dtype = (*ira)->getType();
522 // TODO: check why 64-bit integer is included here.
523 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4) || temp_dtype == H5INT64 || temp_dtype == H5UINT64) {
524 // "DIMENSION_LIST" is okay to ignore and "REFERENCE_LIST"
525 // is okay to ignore if the variable has another attribute
526 // CLASS="DIMENSION_SCALE"
527 if (("DIMENSION_LIST" !=(*ira)->name) &&
528 ("REFERENCE_LIST" != (*ira)->name || true == is_ignored))
529 this->add_ignored_info_attrs(false,(*irv)->fullpath,(*ira)->name);
530 }
531 }
532 } // end "if (false == (*irv)->attrs.empty())"
533 }// end "for(vector<GMCVar*>"
534
535 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
536 irv != this->spvars.end(); ++irv) {
537 // If the attribute REFERENCE_LIST comes with the attribut CLASS, the
538 // attribute REFERENCE_LIST is okay to ignore. No need to report.
539 bool is_ignored = ignored_dimscale_ref_list((*irv));
540 if (false == (*irv)->attrs.empty()) {
541 //if (true == (*irv)->unsupported_attr_dtype) {
542 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
543 ira != (*irv)->attrs.end(); ++ira) {
544 H5DataType temp_dtype = (*ira)->getType();
545 //TODO; check why 64-bit integer is included here.
546 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4) || temp_dtype == H5INT64 || temp_dtype == H5UINT64) {
547 // "DIMENSION_LIST" is okay to ignore and "REFERENCE_LIST"
548 // is okay to ignore if the variable has another attribute
549 // CLASS="DIMENSION_SCALE"
550 if (("DIMENSION_LIST" !=(*ira)->name) &&
551 ("REFERENCE_LIST" != (*ira)->name || true == is_ignored))
552 this->add_ignored_info_attrs(false,(*irv)->fullpath,(*ira)->name);
553 }
554 }
555 } // "if (false == (*irv)->attrs.empty())"
556 }// "for(vector<GMSPVar*>"
557 }// "if((General_Product == ......)"
558 else {
559
560 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
561 irv != this->cvars.end(); ++irv) {
562 if (false == (*irv)->attrs.empty()) {
563 //if (true == (*irv)->unsupported_attr_dtype) {
564 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
565 ira != (*irv)->attrs.end(); ++ira) {
566 H5DataType temp_dtype = (*ira)->getType();
567 // TODO: check why 64-bit integer is included here.
568 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4) || temp_dtype == H5INT64 || temp_dtype == H5UINT64) {
569 this->add_ignored_info_attrs(false,(*irv)->fullpath,(*ira)->name);
570 }
571 }
572 //}
573 }
574 }// for (vector<GMCVar *>::iterator irv = this->cvars.begin() STOP adding end logic comments
575
576 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
577 irv != this->spvars.end(); ++irv) {
578 if (false == (*irv)->attrs.empty()) {
579 //if (true == (*irv)->unsupported_attr_dtype) {
580 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
581 ira != (*irv)->attrs.end(); ++ira) {
582 H5DataType temp_dtype = (*ira)->getType();
583 //TODO: check why 64-bit integer is included here.
584 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4) || temp_dtype == H5INT64 || temp_dtype == H5UINT64) {
585 this->add_ignored_info_attrs(false,(*irv)->fullpath,(*ira)->name);
586 }
587 }
588 //}
589 }
590 }// for(vector<GMSPVar *>
591
592 }// else
593
594}
595
596// Unsupported data space
597void GMFile:: Handle_Unsupported_Dspace(bool include_attr) {
598
599 BESDEBUG("h5", "Coming to GMFile:Handle_Unsupported_Dspace()"<<endl);
600 if(true == check_ignored)
601 Gen_Unsupported_Dspace_Info();
602
604 Handle_GM_Unsupported_Dspace(include_attr);
605
606}
607
608// Unsupported data space for coordinate variables and special variables of general products
609void GMFile:: Handle_GM_Unsupported_Dspace(bool include_attr) {
610
611 BESDEBUG("h5", "Coming to GMFile:Handle_GM_Unsupported_Dspace()"<<endl);
612 if(true == this->unsupported_var_dspace) {
613 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
614 ircv != this->cvars.end(); ) {
615 if (true == (*ircv)->unsupported_dspace ) {
616
617 // This may need to be checked carefully in the future,
618 // My current understanding is that the coordinate variable can
619 // be ignored if the corresponding variable is ignored.
620 // Currently we don't find any NASA files in this category.
621 // KY 2012-5-21
622 delete (*ircv);
623 ircv = this->cvars.erase(ircv);
624 }
625 else {
626 ++ircv;
627 }
628 } // "for (vector<GMCVar *>::iterator ircv = this->cvars.begin();"
629
630 for (vector<GMSPVar *>::iterator ircv = this->spvars.begin();
631 ircv != this->spvars.end(); ) {
632
633 if (true == (*ircv)->unsupported_dspace) {
634 delete (*ircv);
635 ircv = this->spvars.erase(ircv);
636 }
637 else {
638 ++ircv;
639 }
640
641 }// for (vector<GMSPVar *>::iterator ircv = this->spvars.begin();
642 }// if(true == this->unsupported_dspace)
643
644 if(true == include_attr) {
645 if(true == this->unsupported_var_attr_dspace) {
646 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
647 ircv != this->cvars.end(); ++ircv) {
648 if (false == (*ircv)->attrs.empty()) {
649 if (true == (*ircv)->unsupported_attr_dspace) {
650 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
651 ira != (*ircv)->attrs.end(); ) {
652 if (0 == (*ira)->count) {
653 delete (*ira);
654 ira = (*ircv)->attrs.erase(ira);
655 }
656 else {
657 ++ira;
658 }
659 }
660 }
661 }
662 }
663
664 for (vector<GMSPVar *>::iterator ircv = this->spvars.begin();
665 ircv != this->spvars.end(); ++ircv) {
666 if (false == (*ircv)->attrs.empty()) {
667 if (true == (*ircv)->unsupported_attr_dspace) {
668 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
669 ira != (*ircv)->attrs.end(); ) {
670 if (0 == (*ira)->count) {
671 delete (*ira);
672 ira = (*ircv)->attrs.erase(ira);
673 }
674 else {
675 ++ira;
676 }
677 }
678 }
679 }
680 }
681 }// if(true == this->unsupported_var_attr_dspace)
682 }// if(true == include_attr)
683
684}
685
686// Generate unsupported data space information
687void GMFile:: Gen_Unsupported_Dspace_Info() {
688
689 File::Gen_Unsupported_Dspace_Info();
690
691}
692
693// Handle other unsupported objects
694void GMFile:: Handle_Unsupported_Others(bool include_attr) {
695
696 BESDEBUG("h5", "Coming to GMFile:Handle_Unsupported_Others()"<<endl);
698
699 // Add the removal of CLASS=DIM_SCALE attribute if this is a netCDF-4-like attribute.
700 //
701 if(General_Product != this->product_type
702 || (General_Product == this->product_type && OTHERGMS != this->gproduct_pattern)){
703 //
704#if 0
705 if((General_Product == this->product_type && GENERAL_DIMSCALE== this->gproduct_pattern)
706 || (Mea_Ozone == this->product_type) || (Mea_SeaWiFS_L2 == this->product_type)
707 || (Mea_SeaWiFS_L3 == this->product_type)
708 || (OBPG_L3 == this->product_type))
709#endif
710 remove_netCDF_internal_attributes(include_attr);
711 if(include_attr == true) {
712 // We also need to remove the _nc3_strict from the root attributes
713 for (vector<Attribute *>::iterator ira = this->root_attrs.begin(); ira != this->root_attrs.end();) {
714
715 if((*ira)->name == "_nc3_strict") {
716 delete(*ira);
717 ira =this->root_attrs.erase(ira);
718 //If we have other root attributes to remove, remove the break statement.
719 }
720 else if((*ira)->name == "_NCProperties") {
721 delete(*ira);
722 ira =this->root_attrs.erase(ira);
723 }
724 else if((*ira)->name == "_Netcdf4Coordinates") {
725 delete(*ira);
726 ira =this->root_attrs.erase(ira);
727 }
728
729 else {
730 ++ira;
731 }
732 }
733 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
734 irv != this->cvars.end(); ++irv) {
735 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
736 ira != (*irv)->attrs.end();) {
737 if((*ira)->name == "CLASS") {
738 string class_value = Retrieve_Str_Attr_Value(*ira,(*irv)->fullpath);
739
740 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
741 // "DIMENSION_SCALE", which is 15.
742 if (0 == class_value.compare(0,15,"DIMENSION_SCALE")) {
743 delete(*ira);
744 ira = (*irv)->attrs.erase(ira);
745 // Add another block to set a key
746 }
747 else {
748 ++ira;
749 }
750 }
751 else if((*ira)->name == "NAME") {// Add a BES Key later
752 delete(*ira);
753 ira =(*irv)->attrs.erase(ira);
754 //"NAME" attribute causes the file netCDF-4 failed.
755#if 0
756
757 string name_value = Retrieve_Str_Attr_Value(*ira,(*irv)->fullpath);
758 if( 0 == name_value.compare(0,(*irv)->name.size(),(*irv)->name)) {
759 delete(*ira);
760 ira =(*irv)->attrs.erase(ira);
761 }
762 else {
763 string netcdf_dim_mark= "This is a netCDF dimension but not a netCDF variable";
764 if( 0 == name_value.compare(0,netcdf_dim_mark.size(),netcdf_dim_mark)) {
765 delete((*ira));
766 ira =(*irv)->attrs.erase(ira);
767 }
768 else {
769 ++ira;
770 }
771 }
772#endif
773 }
774 else if((*ira)->name == "_Netcdf4Dimid") {
775 delete(*ira);
776 ira =(*irv)->attrs.erase(ira);
777 }
778 else if((*ira)->name == "_Netcdf4Coordinates") {
779 delete(*ira);
780 ira =(*irv)->attrs.erase(ira);
781 }
782
783#if 0
784 else if((*ira)->name == "_nc3_strict") {
785 delete((*ira));
786 ira =(*irv)->attrs.erase(ira);
787 }
788#endif
789 else {
790 ++ira;
791 }
792 }
793 }
794 }
795 }
796 // netCDF Java lifts the string size limitation. All the string attributes can be
797 // represented by netCDF Java. So comment out the code. KY 2018/08/10
798#if 0
799 if(true == this->check_ignored && true == include_attr) {
800 if(true == HDF5RequestHandler::get_drop_long_string()){
801 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
802 irv != this->cvars.end(); ++irv) {
803 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
804 ira != (*irv)->attrs.end();++ira) {
805 if(true == Check_DropLongStr((*irv),(*ira))) {
806 this->add_ignored_droplongstr_hdr();
807 this->add_ignored_var_longstr_info((*irv),(*ira));
808 }
809 }
810 }
811
812 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
813 irv != this->spvars.end(); ++irv) {
814 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
815 ira != (*irv)->attrs.end();++ira) {
816 if(true == Check_DropLongStr((*irv),(*ira))) {
817 this->add_ignored_droplongstr_hdr();
818 this->add_ignored_var_longstr_info((*irv),(*ira));
819 }
820 }
821
822 }
823 }
824 }
825#endif
826
827 if(false == this->have_ignored)
828 this->add_no_ignored_info();
829
830}
831
832// Add dimension names
834
835 BESDEBUG("h5", "Coming to GMFile:Add_Dim_Name()"<<endl);
836 switch(product_type) {
837 case Mea_SeaWiFS_L2:
838 case Mea_SeaWiFS_L3:
839 Add_Dim_Name_Mea_SeaWiFS();
840 break;
841 case Aqu_L3:
842 Add_Dim_Name_Aqu_L3();
843 break;
844 case OSMAPL2S:
845 Add_Dim_Name_OSMAPL2S();
846 break;
847 case ACOS_L2S_OR_OCO2_L1B:
848 Add_Dim_Name_ACOS_L2S_OCO2_L1B();
849 break;
850 case Mea_Ozone:
851 Add_Dim_Name_Mea_Ozonel3z();
852 break;
853 case GPMS_L3:
854 case GPMM_L3:
855 case GPM_L1:
856 case GPM_L3_New:
857 Add_Dim_Name_GPM();
858 break;
859 case OBPG_L3:
860 Add_Dim_Name_OBPG_L3();
861 break;
862 case General_Product:
863 Add_Dim_Name_General_Product();
864 break;
865 default:
866 throw1("Cannot generate dim. names for unsupported datatype");
867 } // switch(product_type)
868
869// Just for debugging
870#if 0
871for (vector<Var*>::iterator irv2 = this->vars.begin();
872 irv2 != this->vars.end(); irv2++) {
873 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
874 ird !=(*irv2)->dims.end(); ird++) {
875 cerr<<"Dimension name afet Add_Dim_Name "<<(*ird)->newname <<endl;
876 }
877}
878#endif
879
880}
881
882//Add Dim. Names for OBPG level 3 product
883void GMFile::Add_Dim_Name_OBPG_L3() {
884
885 BESDEBUG("h5", "Coming to Add_Dim_Name_OBPG_L3()"<<endl);
886 // netCDF-4 like structure
887 // Note: We need to change the product type to netCDF-4 like product type and pattern.
888 Check_General_Product_Pattern();
889 Add_Dim_Name_General_Product();
890}
891
892//Add Dim. Names for MeaSures SeaWiFS. Future: May combine with the handling of netCDF-4 products
893void GMFile::Add_Dim_Name_Mea_SeaWiFS() {
894
895 BESDEBUG("h5", "Coming to Add_Dim_Name_Mea_SeaWiFS()"<<endl);
896 pair<set<string>::iterator,bool> setret;
897 if (Mea_SeaWiFS_L3 == product_type)
898 iscoard = true;
899 for (vector<Var *>::iterator irv = this->vars.begin();
900 irv != this->vars.end(); ++irv) {
901 Handle_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone((*irv));
902 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
903 ird !=(*irv)->dims.end();++ird) {
904 setret = dimnamelist.insert((*ird)->name);
905 if (true == setret.second)
906 Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
907 }
908 } // for (vector<Var *>::iterator irv = this->vars.begin();
909
910 if (true == dimnamelist.empty())
911 throw1("This product should have the dimension names, but no dimension names are found");
912}
913
914// Handle Dimension scales for MEasUREs SeaWiFS and OZone.
915void GMFile::Handle_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone(Var* var)
916{
917
918 BESDEBUG("h5", "Coming to Handle_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone()"<<endl);
919 Attribute* dimlistattr = NULL;
920 bool has_dimlist = false;
921 bool has_class = false;
922 bool has_reflist = false;
923
924 for(vector<Attribute *>::iterator ira = var->attrs.begin();
925 ira != var->attrs.end();ira++) {
926 if ("DIMENSION_LIST" == (*ira)->name) {
927 dimlistattr = *ira;
928 has_dimlist = true;
929 }
930 if ("CLASS" == (*ira)->name)
931 has_class = true;
932 if ("REFERENCE_LIST" == (*ira)->name)
933 has_reflist = true;
934
935 if (true == has_dimlist)
936 break;
937 if (true == has_class && true == has_reflist)
938 break;
939 } // for(vector<Attribute *>::iterator ira = var->attrs.begin(); ...
940
941 if (true == has_dimlist)
942 Add_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone(var,dimlistattr);
943
944 // Dim name is the same as the variable name for dimscale variable
945 else if(true == has_class && true == has_reflist) {
946 if (var->dims.size() !=1)
947 throw2("dimension scale dataset must be 1 dimension, this is not true for variable ",
948 var->name);
949
950 // The var name is the object name, however, we would like the dimension name to be full path.
951 // so that the dim name can be served as the key for future handling.
952 (var->dims)[0]->name = var->fullpath;
953 (var->dims)[0]->newname = var->fullpath;
954 pair<set<string>::iterator,bool> setret;
955 setret = dimnamelist.insert((var->dims)[0]->name);
956 if (true == setret.second)
957 Insert_One_NameSizeMap_Element((var->dims)[0]->name,(var->dims)[0]->size,(var->dims)[0]->unlimited_dim);
958 }
959
960 // No dimension, add fake dim names, this may never happen for MeaSure
961 // but just for coherence and completeness.
962 // For Fake dimesnion
963 else {
964
965 set<hsize_t> fakedimsize;
966 pair<set<hsize_t>::iterator,bool> setsizeret;
967 for (vector<Dimension *>::iterator ird= var->dims.begin();
968 ird != var->dims.end(); ++ird) {
969 Add_One_FakeDim_Name(*ird);
970 setsizeret = fakedimsize.insert((*ird)->size);
971 if (false == setsizeret.second)
972 Adjust_Duplicate_FakeDim_Name(*ird);
973 }
974// Just for debugging
975#if 0
976 for (int i = 0; i < var->dims.size(); ++i) {
977 Add_One_FakeDim_Name((var->dims)[i]);
978 bool gotoMainLoop = false;
979 for (int j =i-1; j>=0 && !gotoMainLoop; --j) {
980 if (((var->dims)[i])->size == ((var->dims)[j])->size){
981 Adjust_Duplicate_FakeDim_Name((var->dims)[i]);
982 gotoMainLoop = true;
983 }
984 }
985 }
986#endif
987
988 }//end of else
989}
990
991// Helper function to support dimensions of MeaSUrES SeaWiFS and OZone products
992void GMFile::Add_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone(Var *var,Attribute*dimlistattr)
993{
994
995 BESDEBUG("h5", "Coming to Add_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone()"<<endl);
996 ssize_t objnamelen = -1;
997 hobj_ref_t rbuf;
998
999 vector<hvl_t> vlbuf;
1000
1001 hid_t dset_id = -1;
1002 hid_t attr_id = -1;
1003 hid_t atype_id = -1;
1004 hid_t amemtype_id = -1;
1005 hid_t aspace_id = -1;
1006 hid_t ref_dset = -1;
1007
1008
1009 if(NULL == dimlistattr)
1010 throw2("Cannot obtain the dimension list attribute for variable ",var->name);
1011
1012 if (0==var->rank)
1013 throw2("The number of dimension should NOT be 0 for the variable ",var->name);
1014
1015 try {
1016
1017 vlbuf.resize(var->rank);
1018
1019 dset_id = H5Dopen(this->fileid,(var->fullpath).c_str(),H5P_DEFAULT);
1020 if (dset_id < 0)
1021 throw2("Cannot open the dataset ",var->fullpath);
1022
1023 attr_id = H5Aopen(dset_id,(dimlistattr->name).c_str(),H5P_DEFAULT);
1024 if (attr_id <0 )
1025 throw4("Cannot open the attribute ",dimlistattr->name," of HDF5 dataset ",var->fullpath);
1026
1027 atype_id = H5Aget_type(attr_id);
1028 if (atype_id <0)
1029 throw4("Cannot obtain the datatype of the attribute ",dimlistattr->name," of HDF5 dataset ",var->fullpath);
1030
1031 amemtype_id = H5Tget_native_type(atype_id, H5T_DIR_ASCEND);
1032
1033 if (amemtype_id < 0)
1034 throw2("Cannot obtain the memory datatype for the attribute ",dimlistattr->name);
1035
1036
1037 if (H5Aread(attr_id,amemtype_id,&vlbuf[0]) <0)
1038 throw2("Cannot obtain the referenced object for the variable ",var->name);
1039
1040
1041 vector<char> objname;
1042 int vlbuf_index = 0;
1043
1044 // The dimension names of variables will be the HDF5 dataset names dereferenced from the DIMENSION_LIST attribute.
1045 for (vector<Dimension *>::iterator ird = var->dims.begin();
1046 ird != var->dims.end(); ++ird) {
1047
1048 if(vlbuf[vlbuf_index].p== NULL)
1049 throw4("The dimension doesn't exist. Var name is ",var->name,"; the dimension index is ",vlbuf_index);
1050
1051 rbuf =((hobj_ref_t*)vlbuf[vlbuf_index].p)[0];
1052 if ((ref_dset = H5RDEREFERENCE(attr_id, H5R_OBJECT, &rbuf)) < 0)
1053 throw2("Cannot dereference from the DIMENSION_LIST attribute for the variable ",var->name);
1054 // The above code works with dereferencing references generated with new H5R(H5R_ref_t) APIs with 1.12 and 1.13.
1055 // However, in case this h5rdeference2 API stops working with new APIs, the following #if 0 #endif block is a
1056 // way to handle this issue.
1057#if 0
1058
1059 rbuf =((hobj_ref_t*)vl_ref[0].p)[0];
1060 H5E_BEGIN_TRY {
1061 dset1 = H5Rdereference2(attr_id,H5P_DEFAULT,H5R_OBJECT,&ds_ref_buf);
1062 } H5E_END_TRY;
1063
1064 H5R_ref_t new_rbuf =((H5R_ref_t*)vlbuf[vlbuf_index].p)[0];
1065 if ((ref_dset = H5Ropen_object((H5R_ref_t *)&new_rbuf, H5P_DEFAULT, H5P_DEFAULT))<0)
1066 throw2("Cannot dereference from the DIMENSION_LIST attribute for the variable ",var->name);
1067 H5Rdestroy(&new_rbuf);
1068
1069#endif
1070 if ((objnamelen= H5Iget_name(ref_dset,NULL,0))<=0)
1071 throw2("Cannot obtain the dataset name dereferenced from the DIMENSION_LIST attribute for the variable ",var->name);
1072 objname.resize(objnamelen+1);
1073 if ((objnamelen= H5Iget_name(ref_dset,&objname[0],objnamelen+1))<=0)
1074 throw2("Cannot obtain the dataset name dereferenced from the DIMENSION_LIST attribute for the variable ",var->name);
1075
1076 string objname_str = string(objname.begin(),objname.end());
1077 string trim_objname = objname_str.substr(0,objnamelen);
1078 (*ird)->name = string(trim_objname.begin(),trim_objname.end());
1079
1080 pair<set<string>::iterator,bool> setret;
1081 setret = dimnamelist.insert((*ird)->name);
1082 if (true == setret.second)
1083 Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
1084 (*ird)->newname = (*ird)->name;
1085 H5Dclose(ref_dset);
1086 objname.clear();
1087 vlbuf_index++;
1088 }// for (vector<Dimension *>::iterator ird = var->dims.begin()
1089
1090 if(vlbuf.size()!= 0) {
1091
1092 if ((aspace_id = H5Aget_space(attr_id)) < 0)
1093 throw2("Cannot get hdf5 dataspace id for the attribute ",dimlistattr->name);
1094
1095 if (H5Dvlen_reclaim(amemtype_id,aspace_id,H5P_DEFAULT,(void*)&vlbuf[0])<0)
1096 throw2("Cannot successfully clean up the variable length memory for the variable ",var->name);
1097
1098 H5Sclose(aspace_id);
1099
1100 }
1101
1102 H5Tclose(atype_id);
1103 H5Tclose(amemtype_id);
1104 H5Aclose(attr_id);
1105 H5Dclose(dset_id);
1106
1107 }
1108
1109 catch(...) {
1110
1111 if(atype_id != -1)
1112 H5Tclose(atype_id);
1113
1114 if(amemtype_id != -1)
1115 H5Tclose(amemtype_id);
1116
1117 if(aspace_id != -1)
1118 H5Sclose(aspace_id);
1119
1120 if(attr_id != -1)
1121 H5Aclose(attr_id);
1122
1123 if(dset_id != -1)
1124 H5Dclose(dset_id);
1125
1126 throw;
1127 }
1128
1129}
1130
1131// Add MeaSURES OZone level 3Z dimension names
1132void GMFile::Add_Dim_Name_Mea_Ozonel3z() {
1133
1134 BESDEBUG("h5", "Coming to Add_Dim_Name_Mea_Ozonel3z()"<<endl);
1135 iscoard = true;
1136 bool use_dimscale = false;
1137
1138 for (vector<Group *>::iterator irg = this->groups.begin();
1139 irg != this->groups.end(); ++ irg) {
1140 if ("/Dimensions" == (*irg)->path) {
1141 use_dimscale = true;
1142 break;
1143 }
1144 }
1145
1146 if (false == use_dimscale) {
1147
1148 bool has_dimlist = false;
1149 bool has_class = false;
1150 bool has_reflist = false;
1151
1152 for (vector<Var *>::iterator irv = this->vars.begin();
1153 irv != this->vars.end(); irv++) {
1154
1155 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1156 ira != (*irv)->attrs.end();ira++) {
1157 if ("DIMENSION_LIST" == (*ira)->name)
1158 has_dimlist = true;
1159 }
1160 if (true == has_dimlist)
1161 break;
1162 }
1163
1164 if (true == has_dimlist) {
1165 for (vector<Var *>::iterator irv = this->vars.begin();
1166 irv != this->vars.end(); irv++) {
1167
1168 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1169 ira != (*irv)->attrs.end();ira++) {
1170 if ("CLASS" == (*ira)->name)
1171 has_class = true;
1172 if ("REFERENCE_LIST" == (*ira)->name)
1173 has_reflist = true;
1174 if (true == has_class && true == has_reflist)
1175 break;
1176 }
1177
1178 if (true == has_class &&
1179 true == has_reflist)
1180 break;
1181
1182 }
1183 if (true == has_class && true == has_reflist)
1184 use_dimscale = true;
1185 } // if (true == has_dimlist)
1186 } // if (false == use_dimscale)
1187
1188 if (true == use_dimscale) {
1189
1190 pair<set<string>::iterator,bool> setret;
1191 for (vector<Var *>::iterator irv = this->vars.begin();
1192 irv != this->vars.end(); ++irv) {
1193 Handle_UseDimscale_Var_Dim_Names_Mea_SeaWiFS_Ozone((*irv));
1194 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
1195 ird !=(*irv)->dims.end();++ird) {
1196 setret = dimnamelist.insert((*ird)->name);
1197 if(true == setret.second)
1198 Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
1199 }
1200 }
1201
1202 if (true == dimnamelist.empty())
1203 throw1("This product should have the dimension names, but no dimension names are found");
1204 } // if (true == use_dimscale)
1205
1206 else {
1207
1208 // Since the dim. size of each dimension of 2D lat/lon may be the same, so use multimap.
1209 multimap<hsize_t,string> ozonedimsize_to_dimname;
1210 pair<multimap<hsize_t,string>::iterator,multimap<hsize_t,string>::iterator> mm_er_ret;
1211 multimap<hsize_t,string>::iterator irmm;
1212
1213 for (vector<Var *>::iterator irv = this->vars.begin();
1214 irv != this->vars.end(); ++irv) {
1215 bool is_cv = check_cv((*irv)->name);
1216 if (true == is_cv) {
1217 if ((*irv)->dims.size() != 1)
1218 throw3("The coordinate variable", (*irv)->name," must be one dimension for the zonal average product");
1219 ozonedimsize_to_dimname.insert(pair<hsize_t,string>(((*irv)->dims)[0]->size,(*irv)->fullpath));
1220 }
1221 }// for (vector<Var *>::iterator irv = this->vars.begin(); ...
1222
1223 set<hsize_t> fakedimsize;
1224 pair<set<hsize_t>::iterator,bool> setsizeret;
1225 pair<set<string>::iterator,bool> setret;
1226 pair<set<string>::iterator,bool> tempsetret;
1227 set<string> tempdimnamelist;
1228 bool fakedimflag = false;
1229
1230 for (vector<Var *>::iterator irv = this->vars.begin();
1231 irv != this->vars.end(); ++irv) {
1232
1233 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
1234 ird != (*irv)->dims.end(); ++ird) {
1235
1236 fakedimflag = true;
1237 mm_er_ret = ozonedimsize_to_dimname.equal_range((*ird)->size);
1238 for (irmm = mm_er_ret.first; irmm!=mm_er_ret.second;irmm++) {
1239 setret = tempdimnamelist.insert(irmm->second);
1240 if (true == setret.second) {
1241 (*ird)->name = irmm->second;
1242 (*ird)->newname = (*ird)->name;
1243 setret = dimnamelist.insert((*ird)->name);
1244 if(setret.second) Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
1245 fakedimflag = false;
1246 break;
1247 }
1248 }
1249
1250 if (true == fakedimflag) {
1251 Add_One_FakeDim_Name(*ird);
1252 setsizeret = fakedimsize.insert((*ird)->size);
1253 if (false == setsizeret.second)
1254 Adjust_Duplicate_FakeDim_Name(*ird);
1255 }
1256
1257 } // for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
1258 tempdimnamelist.clear();
1259 fakedimsize.clear();
1260 } // for (vector<Var *>::iterator irv = this->vars.begin();
1261 } // else
1262}
1263
1264// This is a special helper function for MeaSURES ozone products
1265bool GMFile::check_cv(const string & varname) const {
1266
1267 BESDEBUG("h5", "Coming to check_cv()"<<endl);
1268 const string lat_name ="Latitude";
1269 const string time_name ="Time";
1270 const string ratio_pressure_name ="MixingRatioPressureLevels";
1271 const string profile_pressure_name ="ProfilePressureLevels";
1272 const string wave_length_name ="Wavelength";
1273
1274 if (lat_name == varname)
1275 return true;
1276 else if (time_name == varname)
1277 return true;
1278 else if (ratio_pressure_name == varname)
1279 return true;
1280 else if (profile_pressure_name == varname)
1281 return true;
1282 else if (wave_length_name == varname)
1283 return true;
1284 else
1285 return false;
1286}
1287
1288// Add Dimension names for GPM products
1289void GMFile::Add_Dim_Name_GPM()
1290{
1291
1292 BESDEBUG("h5", "Coming to Add_Dim_Name_GPM()"<<endl);
1293 // This is used to create a dimension name set.
1294 pair<set<string>::iterator,bool> setret;
1295
1296 // The commented code is for an old version of GPM products. May remove them later. KY 2015-06-16
1297 // We need to create a fakedim name to fill in. To make the dimension name unique, we use a counter.
1298#if 0
1299 // int dim_count = 0;
1300 // map<string,string> varname_to_fakedim;
1301 // map<int,string> gpm_dimsize_to_fakedimname;
1302#endif
1303
1304 // We find that GPM has an attribute DimensionNames(nlon,nlat) in this case.
1305 // We will use this attribute to specify the dimension names.
1306 for (vector<Var *>::iterator irv = this->vars.begin();
1307 irv != this->vars.end(); irv++) {
1308
1309 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1310 ira != (*irv)->attrs.end(); ++ira) {
1311
1312 if("DimensionNames" == (*ira)->name) {
1313
1314 Retrieve_H5_Attr_Value(*ira,(*irv)->fullpath);
1315 string dimname_value((*ira)->value.begin(),(*ira)->value.end());
1316
1317 vector<string> ind_elems;
1318 char sep=',';
1319 HDF5CFUtil::Split(&dimname_value[0],sep,ind_elems);
1320
1321 if(ind_elems.size() != (size_t)((*irv)->getRank())) {
1322 throw2("The number of dims obtained from the <DimensionNames> attribute is not equal to the rank ",
1323 (*irv)->name);
1324 }
1325
1326 for(unsigned int i = 0; i<ind_elems.size(); ++i) {
1327
1328 ((*irv)->dims)[i]->name = ind_elems[i];
1329
1330 // Generate a dimension name if the dimension name is missing.
1331 // The routine will ensure that the fakeDim name is unique.
1332 if(((*irv)->dims)[i]->name==""){
1333 Add_One_FakeDim_Name(((*irv)->dims)[i]);
1334// For debugging
1335#if 0
1336 string fakedim = "FakeDim";
1337 stringstream sdim_count;
1338 sdim_count << dim_count;
1339 fakedim = fakedim + sdim_count.str();
1340 dim_count++;
1341 ((*irv)->dims)[i]->name = fakedim;
1342 ((*irv)->dims)[i]->newname = fakedim;
1343 ind_elems[i] = fakedim;
1344#endif
1345 }
1346
1347 else {
1348 ((*irv)->dims)[i]->newname = ind_elems[i];
1349 setret = dimnamelist.insert(((*irv)->dims)[i]->name);
1350
1351 if (true == setret.second) {
1352 Insert_One_NameSizeMap_Element(((*irv)->dims)[i]->name,
1353 ((*irv)->dims)[i]->size,
1354 ((*irv)->dims)[i]->unlimited_dim);
1355 }
1356 else {
1357 if(dimname_to_dimsize[((*irv)->dims)[i]->name] !=((*irv)->dims)[i]->size)
1358 throw5("Dimension ",((*irv)->dims)[i]->name, "has two sizes",
1359 ((*irv)->dims)[i]->size,dimname_to_dimsize[((*irv)->dims)[i]->name]);
1360
1361 }
1362 }
1363
1364 }// for(unsigned int i = 0; i<ind_elems.size(); ++i)
1365 break;
1366
1367 } //if("DimensionNames" == (*ira)->name)
1368 } //for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin()
1369
1370#if 0
1371 if(false == has_dim_name_attr) {
1372
1373 throw4( "The variable ", (*irv)->name, " doesn't have the DimensionNames attribute.",
1374 "We currently don't support this case. Please report to the NASA data center.");
1375 }
1376
1377#endif
1378 } //for (vector<Var *>::iterator irv = this->vars.begin();
1379
1380}
1381
1382// Add Dimension names for Aquarius level 3 products
1383void GMFile::Add_Dim_Name_Aqu_L3()
1384{
1385 BESDEBUG("h5", "Coming to Add_Dim_Name_Aqu_L3()"<<endl);
1386 for (vector<Var *>::iterator irv = this->vars.begin();
1387 irv != this->vars.end(); irv++) {
1388 if ("l3m_data" == (*irv)->name) {
1389 ((*irv)->dims)[0]->name = "lat";
1390 ((*irv)->dims)[0]->newname = "lat";
1391 ((*irv)->dims)[1]->name = "lon";
1392 ((*irv)->dims)[1]->newname = "lon";
1393 break;
1394 }
1395
1396// For the time being, don't assign dimension names to palette,
1397// we will see if tools can pick up l3m and then make decisions.
1398#if 0
1399 if ("palette" == (*irv)->name) {
1400//"h5","coming to palette" <<endl;
1401 ((*irv)->dims)[0]->name = "paldim0";
1402 ((*irv)->dims)[0]->newname = "paldim0";
1403 ((*irv)->dims)[1]->name = "paldim1";
1404 ((*irv)->dims)[1]->newname = "paldim1";
1405 }
1406#endif
1407
1408 }// for (vector<Var *>::iterator irv = this->vars.begin()
1409}
1410
1411// Add dimension names for OSMAPL2S(note: the SMAP change their structures. The code doesn't not apply to them.)
1412void GMFile::Add_Dim_Name_OSMAPL2S(){
1413
1414 BESDEBUG("h5", "Coming to Add_Dim_Name_OSMAPL2S()"<<endl);
1415 string tempvarname ="";
1416 string key = "_lat";
1417 string osmapl2sdim0 ="YDim";
1418 string osmapl2sdim1 ="XDim";
1419
1420 // Since the dim. size of each dimension of 2D lat/lon may be the same, so use multimap.
1421 multimap<hsize_t,string> osmapl2sdimsize_to_dimname;
1422 pair<multimap<hsize_t,string>::iterator,multimap<hsize_t,string>::iterator> mm_er_ret;
1423 multimap<hsize_t,string>::iterator irmm;
1424
1425 // Generate dimension names based on the size of "???_lat"(one coordinate variable)
1426 for (vector<Var *>::iterator irv = this->vars.begin();
1427 irv != this->vars.end(); ++irv) {
1428 tempvarname = (*irv)->name;
1429 if ((tempvarname.size() > key.size())&&
1430 (key == tempvarname.substr(tempvarname.size()-key.size(),key.size()))){
1431 if ((*irv)->dims.size() !=2)
1432 throw1("Currently only 2D lat/lon is supported for OSMAPL2S");
1433 osmapl2sdimsize_to_dimname.insert(pair<hsize_t,string>(((*irv)->dims)[0]->size,osmapl2sdim0));
1434 osmapl2sdimsize_to_dimname.insert(pair<hsize_t,string>(((*irv)->dims)[1]->size,osmapl2sdim1));
1435 break;
1436 }
1437 }
1438
1439 set<hsize_t> fakedimsize;
1440 pair<set<hsize_t>::iterator,bool> setsizeret;
1441 pair<set<string>::iterator,bool> setret;
1442 pair<set<string>::iterator,bool> tempsetret;
1443 set<string> tempdimnamelist;
1444 bool fakedimflag = false;
1445
1446
1447 for (vector<Var *>::iterator irv = this->vars.begin();
1448 irv != this->vars.end(); ++irv) {
1449
1450 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
1451 ird != (*irv)->dims.end(); ++ird) {
1452
1453 fakedimflag = true;
1454 mm_er_ret = osmapl2sdimsize_to_dimname.equal_range((*ird)->size);
1455 for (irmm = mm_er_ret.first; irmm!=mm_er_ret.second;irmm++) {
1456 setret = tempdimnamelist.insert(irmm->second);
1457 if (setret.second) {
1458 (*ird)->name = irmm->second;
1459 (*ird)->newname = (*ird)->name;
1460 setret = dimnamelist.insert((*ird)->name);
1461 if(setret.second) Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
1462 fakedimflag = false;
1463 break;
1464 }
1465 }
1466
1467 if (true == fakedimflag) {
1468 Add_One_FakeDim_Name(*ird);
1469 setsizeret = fakedimsize.insert((*ird)->size);
1470 if (!setsizeret.second)
1471 Adjust_Duplicate_FakeDim_Name(*ird);
1472 }
1473 } // for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
1474 tempdimnamelist.clear();
1475 fakedimsize.clear();
1476 } // for (vector<Var *>::iterator irv = this->vars.begin();
1477}
1478
1479//Add dimension names for ACOS level2S or OCO2 level1B products
1480void GMFile::Add_Dim_Name_ACOS_L2S_OCO2_L1B(){
1481
1482 BESDEBUG("h5", "Coming to Add_Dim_Name_ACOS_L2S_OCO2_L1B()"<<endl);
1483 for (vector<Var *>::iterator irv = this->vars.begin();
1484 irv != this->vars.end(); ++irv) {
1485
1486 set<hsize_t> fakedimsize;
1487 pair<set<hsize_t>::iterator,bool> setsizeret;
1488 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
1489 ird != (*irv)->dims.end(); ++ird) {
1490 Add_One_FakeDim_Name(*ird);
1491 setsizeret = fakedimsize.insert((*ird)->size);
1492 if (false == setsizeret.second)
1493 Adjust_Duplicate_FakeDim_Name(*ird);
1494 }
1495 } // for (vector<Var *>::iterator irv = this->vars.begin();
1496}
1497
1498// Add dimension names for general products. Read the descrption of Check_General_Product_Pattern() for different patterns we support.
1499void GMFile::Add_Dim_Name_General_Product(){
1500
1501 BESDEBUG("h5", "Coming to Add_Dim_Name_General_Product()"<<endl);
1502
1503 // This general product should follow the HDF5 dimension scale model.
1504 if (GENERAL_DIMSCALE == this->gproduct_pattern){
1505 Add_Dim_Name_Dimscale_General_Product();
1506}
1507 // This general product has 2-D latitude,longitude
1508 else if (GENERAL_LATLON2D == this->gproduct_pattern)
1509 Add_Dim_Name_LatLon2D_General_Product();
1510 // This general product has 1-D latitude,longitude
1511 else if (GENERAL_LATLON1D == this->gproduct_pattern || GENERAL_LATLON_COOR_ATTR == this->gproduct_pattern)
1512 Add_Dim_Name_LatLon1D_Or_CoordAttr_General_Product();
1513
1514
1515}
1516
1517// We check four patterns under the General_Product category
1518// 1. General products that uses HDF5 dimension scales following netCDF-4 data model
1519// 2. General products that have 2-D lat/lon variables(lat/lon variable names are used to identify the case) under the root group or
1520// a special geolocation group
1521// 3. General products that have 1-D lat/lon variables(lat/lon variable names are used to identify the case) under the root group or
1522// a special geolocation group
1523// 4. General products that have some variables containing CF "coordinates" attributes. We can support some products if the "coordinates"
1524// attribute contains CF lat/lon units and the variable ranks are 2 or 1.
1525void GMFile::Check_General_Product_Pattern() {
1526
1527 BESDEBUG("h5", "Coming to Check_General_Product_Pattern()"<<endl);
1528 if(false == Check_Dimscale_General_Product_Pattern()) {
1529 //HERE add a check for the GPM. (choose 5 variables equally distance for the attribute)
1530 if(false == Check_And_Update_New_GPM_L3())
1531 if(false == Check_LatLon2D_General_Product_Pattern())
1532 if(false == Check_LatLon1D_General_Product_Pattern())
1533 Check_LatLon_With_Coordinate_Attr_General_Product_Pattern();
1534 }
1535
1536}
1537
1538// Check if this general product is netCDF4-like HDF5 file.
1539// We only need to check "DIMENSION_LIST","CLASS" and CLASS values.
1540bool GMFile::Check_Dimscale_General_Product_Pattern() {
1541
1542 BESDEBUG("h5", "Coming to Check_Dimscale_General_Product_Pattern()"<<endl);
1543 bool ret_value = false;
1544 bool has_dimlist = false;
1545 bool has_dimscalelist = false;
1546
1547 // Check if containing the "DIMENSION_LIST" attribute;
1548 for (vector<Var *>::iterator irv = this->vars.begin();
1549 irv != this->vars.end(); ++irv) {
1550 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1551 ira != (*irv)->attrs.end();ira++) {
1552 if ("DIMENSION_LIST" == (*ira)->name) {
1553 has_dimlist = true;
1554 break;
1555 }
1556 }
1557 if (true == has_dimlist)
1558 break;
1559 }
1560
1561 // Check if containing both the attribute "CLASS" and the attribute "REFERENCE_LIST" for the same variable.
1562 // This is the dimension scale.
1563 // Actually "REFERENCE_LIST" is not necessary for a dimension scale dataset. If a dimension scale doesn't
1564 // have a "REFERENCE_LIST", it is still valid. But no other variables use this dimension scale. We found
1565 // such a case in a matched_airs_aqua product. KY 2012-12-03
1566 for (vector<Var *>::iterator irv = this->vars.begin();
1567 irv != this->vars.end(); ++irv) {
1568
1569
1570 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1571 ira != (*irv)->attrs.end();ira++) {
1572 if ("CLASS" == (*ira)->name) {
1573
1574 Retrieve_H5_Attr_Value(*ira,(*irv)->fullpath);
1575 string class_value;
1576 class_value.resize((*ira)->value.size());
1577 copy((*ira)->value.begin(),(*ira)->value.end(),class_value.begin());
1578
1579 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
1580 // "DIMENSION_SCALE", which is 15.
1581 if (0 == class_value.compare(0,15,"DIMENSION_SCALE")) {
1582 has_dimscalelist = true;
1583 break;
1584 }
1585 }
1586 }
1587
1588 if (true == has_dimscalelist)
1589 break;
1590
1591 }
1592
1593 if (true == has_dimscalelist) {
1594 if (true == has_dimlist ) {
1595 this->gproduct_pattern = GENERAL_DIMSCALE;
1596 ret_value = true;
1597 }
1598 else {
1599 //May fall into the single dimension scale case.
1600 //This is really, really rare,but we do have to check.
1601 // Check if NAME and _Netcdf4Dimid exists for this variable.
1602
1603 bool is_general_dimscale = false;
1604
1605 for (vector<Var *>::iterator irv = this->vars.begin();
1606 irv != this->vars.end(); ++irv) {
1607
1608 bool has_class_dscale = false;
1609 bool has_name = false;
1610 bool has_netcdf4_id = false;
1611
1612 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1613 ira != (*irv)->attrs.end();ira++) {
1614 if ("CLASS" == (*ira)->name) {
1615
1616 Retrieve_H5_Attr_Value(*ira,(*irv)->fullpath);
1617 string class_value;
1618 class_value.resize((*ira)->value.size());
1619 copy((*ira)->value.begin(),(*ira)->value.end(),class_value.begin());
1620
1621 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
1622 // "DIMENSION_SCALE", which is 15.
1623 if (0 == class_value.compare(0,15,"DIMENSION_SCALE"))
1624 has_class_dscale= true;
1625 }
1626 else if ("NAME" == (*ira)->name)
1627 has_name = true;
1628 else if ("_Netcdf4Dimid" == (*ira)->name)
1629 has_netcdf4_id = true;
1630 if(true == has_class_dscale && true == has_name && true == has_netcdf4_id)
1631 is_general_dimscale = true;
1632 }
1633
1634 if(true == is_general_dimscale)
1635 break;
1636
1637 }
1638
1639 if (true == is_general_dimscale) {
1640 this->gproduct_pattern = GENERAL_DIMSCALE;
1641 ret_value = true;
1642 }
1643 }
1644 }
1645
1646 return ret_value;
1647}
1648
1649bool GMFile::Check_And_Update_New_GPM_L3() {
1650
1651 bool is_new_gpm_l3 = false;
1652 unsigned int num_vars = this->vars.size();
1653 unsigned sel_steps = num_vars/5;
1654 string dim_name="DimensionNames";
1655 bool has_dim_name = false;
1656 if(sel_steps == 0)
1657 sel_steps = 1;
1658
1659 // Given DimensionNames exists in almost every variable in the new GPM product,
1660 // We will check the existence of this attribute for at most 5 variables.
1661//#if 0
1662 vector<Var *>::iterator it_var_end;
1663
1664 if(sel_steps ==1)
1665 it_var_end = this->vars.end();
1666 else
1667 it_var_end = this->vars.begin()+5*sel_steps;
1668
1669 for (vector<Var *>::iterator irv = this->vars.begin();
1670 irv != it_var_end; irv+=sel_steps) {
1671 //irv != this->vars.end(); irv+=sel_steps) {
1672 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
1673 ira != (*irv)->attrs.end();ira++) {
1674 if(H5FSTRING == (*ira)->getType()) {
1675 if((*ira)->name == dim_name){
1676 has_dim_name = true;
1677 break;
1678 }
1679 }
1680 }
1681 if(true == has_dim_name)
1682 break;
1683 }
1684//#endif
1685
1686
1687
1688 // Files that can go to this step should be a small subset, now
1689 // we will check the "??GridHeader" for all the groups.
1690 if(true == has_dim_name) {
1691 string attr_name_subset = "GridHeader";
1692 BESDEBUG("h5", "GMFile::Check_And_Update_New_GPM_L3() has attribute <DimensionNames>. "<<endl);
1693 for (vector<Group *>::iterator irg = this->groups.begin();
1694 irg != this->groups.end(); ++ irg) {
1695 for(vector<Attribute *>::iterator ira = (*irg)->attrs.begin();
1696 ira != (*irg)->attrs.end();ira++) {
1697 string attr_name = (*ira)->name;
1698 // We identify this as a new GPM level 3 product.
1699 if(attr_name.find(attr_name_subset)!=string::npos) {
1700 this->product_type = GPM_L3_New;
1701 is_new_gpm_l3 = true;
1702 break;
1703 }
1704 }
1705 if(true == is_new_gpm_l3)
1706 break;
1707 }
1708 }
1709 return is_new_gpm_l3;
1710}
1711
1712// If having 2-D latitude/longitude,set the general product pattern.
1713// In this version, we only check if we have "latitude,longitude","Latitude,Longitude","lat,lon" and "cell_lat,cell_lon"names.
1714// The "cell_lat" and "cell_lon" come from SMAP. KY 2015-12-2
1715bool GMFile::Check_LatLon2D_General_Product_Pattern() {
1716
1717 BESDEBUG("h5", "Coming to Check_LatLon2D_General_Product_Pattern()"<<endl);
1718 bool ret_value = false;
1719
1720 ret_value = Check_LatLon2D_General_Product_Pattern_Name_Size("latitude","longitude");
1721 if(false == ret_value) {
1722 ret_value = Check_LatLon2D_General_Product_Pattern_Name_Size("Latitude","Longitude");
1723 if(false == ret_value) {
1724 ret_value = Check_LatLon2D_General_Product_Pattern_Name_Size("lat","lon");
1725 if(false == ret_value)
1726 ret_value = Check_LatLon2D_General_Product_Pattern_Name_Size("cell_lat","cell_lon");
1727 }
1728 }
1729
1730 // Make sure set the general product pattern flag for this case.
1731 if(true == ret_value)
1732 this->gproduct_pattern = GENERAL_LATLON2D;
1733 return ret_value;
1734
1735}
1736
1737// Helper function for Check_LatLon2D_General_Product_Pattern,we assume the lat and lon only present either under the root or
1738// a specific group Geolocation.
1739bool GMFile::Check_LatLon2D_General_Product_Pattern_Name_Size(const string & latname,const string & lonname) {
1740
1741 BESDEBUG("h5", "Coming to Check_LatLon2D_General_Product_Pattern_Name_Size()"<<endl);
1742 bool ret_value = false;
1743 bool ll_flag = false;
1744
1745 vector<size_t>lat_size(2,0);
1746 vector<size_t>lon_size(2,0);
1747
1748 const string designed_group1 = "/";
1749 const string designed_group2 = "/Geolocation/";
1750
1751 bool lat_flag_g1 = false;
1752 bool lon_flag_g1 = false;
1753 bool lat_flag_g2 = false;
1754 bool lon_flag_g2 = false;
1755
1756
1757 // This case allows to have both "lat and lon" under either group 1 or group 2 but on not both group 1 and 2.
1758 // This case doesn't allow "lat" and "lon" under separate groups.
1759 // Check if we have lat and lon at the only designated group,group 1 "/"
1760 lat_flag_g1 = is_var_under_group(latname,designed_group1,2,lat_size);
1761 lon_flag_g1 = is_var_under_group(lonname,designed_group1,2,lon_size);
1762 if(lat_flag_g1 == true && lon_flag_g1 == true) {
1763
1764 // Make sure the group 2 "/Geolocation" doesn't have the lat/lon
1765 lat_flag_g2 = is_var_under_group(latname,designed_group2,2,lat_size);
1766 if(lat_flag_g2 == false) {
1767 lon_flag_g2 = is_var_under_group(lonname,designed_group2,2,lon_size);
1768 if(lon_flag_g2 == false)
1769 ll_flag = true;
1770 }
1771 }// If the root doesn't have lat/lon, check the group 2 "/Geolocation".
1772 else if(lat_flag_g1 == false && lon_flag_g1 == false) {
1773 lat_flag_g2 = is_var_under_group(latname,designed_group2,2,lat_size);
1774 if(lat_flag_g2 == true) {
1775 lon_flag_g2 = is_var_under_group(lonname,designed_group2,2,lon_size);
1776 if(lon_flag_g2 == true)
1777 ll_flag = true;
1778 }
1779 }
1780
1781 // We are loose here since this is just to support some NASA products in a customized way.
1782 // If the first two cases don't exist, we allow to check another group"GeolocationData" and
1783 // see if Latitude and Longitude are present. (4 years ? from the first implementation, we got this case.)
1784 // KY 2020-02-27
1785 if(false == ll_flag) {
1786
1787 const string designed_group3 = "/GeolocationData/";
1788 if(is_var_under_group(latname,designed_group3,2,lat_size) &&
1789 is_var_under_group(lonname,designed_group3,2,lon_size))
1790 ll_flag = true;
1791 }
1792
1793#if 0
1794
1795 for (vector<Var *>::iterator irv = this->vars.begin();
1796 irv != this->vars.end(); ++irv) {
1797
1798 if((*irv)->rank == 2) {
1799 if((*irv)->name == latname) {
1800
1801 // Obtain the variable path
1802 string lat_path =HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath);
1803
1804 // Tackle only the root group or the name of the group as "/Geolocation"
1805 // By doing this, we assume that the file has lat/lon either under the root or under the "Geolocation
1806 // but not BOTH. The following code may generate wrong results if the file contains lat/lon under
1807 // both the root and /Geolocation. This is documented in https://jira.hdfgroup.org/browse/HFVHANDLER-175
1808 bool has_right_lat = false;
1809 if("/" == lat_path || "/Geolocation/" == lat_path)
1810 if("/" == lat_path || "/Geolocation/" == lat_path) {
1811 ll_flag++;
1812 lat_size[0] = (*irv)->getDimensions()[0]->size;
1813 lat_size[1] = (*irv)->getDimensions()[1]->size;
1814 }
1815
1816 }
1817 else if((*irv)->name == lonname) {
1818 string lon_path = HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath);
1819 if("/" == lon_path || "/Geolocation/" == lon_path) {
1820 ll_flag++;
1821 lon_size[0] = (*irv)->getDimensions()[0]->size;
1822 lon_size[1] = (*irv)->getDimensions()[1]->size;
1823 }
1824 }
1825 if(2 == ll_flag)
1826 break;
1827 } // if((*irv)->rank == 2)
1828 } // for (vector<Var *>::iterator irv = this->vars.begin();
1829
1830#endif
1831
1832 // Only when both lat/lon are found can we support this case.
1833 // Before that, we also need to check if the lat/lon shares the same dimensions.
1834 //if(2 == ll_flag)
1835 if(true == ll_flag) {
1836
1837 bool latlon_size_match = true;
1838 for (unsigned int size_index = 0; size_index <lat_size.size();size_index++) {
1839 if(lat_size[size_index] != lon_size[size_index]){
1840 latlon_size_match = false;
1841 break;
1842 }
1843 }
1844 if (true == latlon_size_match) {
1845 // If we do find the lat/lon pair, save them for later use.
1846 gp_latname = latname;
1847 gp_lonname = lonname;
1848 ret_value = true;
1849 }
1850
1851 }
1852
1853 return ret_value;
1854
1855}
1856
1857// If having 1-D latitude/longitude,set the general product pattern.
1858// In this version, we only check if we have "latitude,longitude","Latitude,Longitude","lat,lon" and "cell_lat,cell_lon"names.
1859// The "cell_lat" and "cell_lon" come from SMAP. KY 2015-12-2
1860bool GMFile::Check_LatLon1D_General_Product_Pattern() {
1861
1862 BESDEBUG("h5", "Coming to Check_LatLon1D_General_Product_Pattern()"<<endl);
1863 bool ret_value = false;
1864
1865 ret_value = Check_LatLon1D_General_Product_Pattern_Name_Size("latitude","longitude");
1866 if(false == ret_value) {
1867 ret_value = Check_LatLon1D_General_Product_Pattern_Name_Size("Latitude","Longitude");
1868 if(false == ret_value) {
1869 ret_value = Check_LatLon1D_General_Product_Pattern_Name_Size("lat","lon");
1870 if(false == ret_value)
1871 ret_value = Check_LatLon1D_General_Product_Pattern_Name_Size("cell_lat","cell_lon");
1872 }
1873 }
1874
1875 if(true == ret_value)
1876 this->gproduct_pattern = GENERAL_LATLON1D;
1877 return ret_value;
1878
1879}
1880
1881// Helper function for Check_LatLon1D_General_Product_Pattern.
1882// We only check if the lat/lon etc. pairs are under "/" or "/Geolocation". Other cases can be easily added.
1883bool GMFile::Check_LatLon1D_General_Product_Pattern_Name_Size(const string & latname,const string & lonname) {
1884
1885 BESDEBUG("h5", "Coming to Check_LatLon1D_General_Product_Pattern_Name_Size()"<<endl);
1886 bool ret_value = false;
1887 short ll_flag = 0;
1888 size_t lat_size = 0;
1889 size_t lon_size = 0;
1890
1891 for (vector<Var *>::iterator irv = this->vars.begin();
1892 irv != this->vars.end(); ++irv) {
1893
1894 if((*irv)->rank == 1) {
1895 if((*irv)->name == latname) {
1896
1897 string lat_path =HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath);
1898
1899 // Tackle only the root group or the name of the group as "/Geolocation"
1900 // May not generate the correct output. See https://jira.hdfgroup.org/browse/HFVHANDLER-175
1901 if("/" == lat_path || "/Geolocation/" == lat_path) {
1902 ll_flag++;
1903 lat_size = (*irv)->getDimensions()[0]->size;
1904 }
1905 }
1906 else if((*irv)->name == lonname) {
1907 string lon_path = HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath);
1908 if("/" == lon_path || "/Geolocation/" == lon_path) {
1909 ll_flag++;
1910 lon_size = (*irv)->getDimensions()[0]->size;
1911 }
1912 }
1913 if(2 == ll_flag)
1914 break;
1915 }
1916 }
1917
1918 if(2 == ll_flag) {
1919
1920 bool latlon_size_match_grid = true;
1921
1922 // When the size of latitude is equal to the size of longitude for a 1-D lat/lon, it is very possible
1923 // that this is not a regular grid but rather a profile with the lat,lon recorded as the function of time.
1924 // Adding the coordinate/dimension as the normal grid is wrong, so check out this case.
1925 // KY 2015-12-2
1926 if(lat_size == lon_size) {
1927
1928 // It is very unusual that lat_size = lon_size for a grid.
1929 latlon_size_match_grid = false;
1930
1931 // For a normal grid, a >2D variable should exist to have both lat and lon size,
1932 // if such a variable that has the same size exists, we will treat it as a normal grid.
1933 for (vector<Var *>::iterator irv = this->vars.begin();
1934 irv != this->vars.end(); ++irv) {
1935 if((*irv)->rank >=2) {
1936 short ll_size_flag = 0;
1937 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
1938 ird != (*irv)->dims.end(); ++ird) {
1939 if(lat_size == (*ird)->size) {
1940 ll_size_flag++;
1941 if(2 == ll_size_flag){
1942 break;
1943 }
1944 }
1945 }
1946 if(2 == ll_size_flag) {
1947 latlon_size_match_grid = true;
1948 break;
1949 }
1950 }
1951 }
1952 }
1953
1954 // If the sizes of lat and lon match the grid, this is the lat/lon candidate.
1955 // Save the latitude and longitude names for later use.
1956 if (true == latlon_size_match_grid) {
1957 gp_latname = latname;
1958 gp_lonname = lonname;
1959 ret_value = true;
1960 }
1961 }
1962
1963 return ret_value;
1964}
1965
1966// This function checks if this general product contains "coordinates" attributes in some variables
1967// that can be used to handle CF friendly.
1968bool GMFile::Check_LatLon_With_Coordinate_Attr_General_Product_Pattern() {
1969
1970 BESDEBUG("h5", "Coming to Check_LatLon_With_Coordinate_Attr_General_Product_Pattern()"<<endl);
1971 bool ret_value = false;
1972 string co_attrname = "coordinates";
1973 string co_attrvalue="";
1974 string unit_attrname = "units";
1975 string lat_unit_attrvalue ="degrees_north";
1976 string lon_unit_attrvalue ="degrees_east";
1977
1978 bool coor_has_lat_flag = false;
1979 bool coor_has_lon_flag = false;
1980
1981 vector<Var*> tempvar_lat;
1982 vector<Var*> tempvar_lon;
1983
1984 // Check if having both lat, lon names stored in the coordinate attribute value by looping through rank >1 variables.
1985 for (vector<Var *>::iterator irv = this->vars.begin();
1986 irv != this->vars.end(); ++irv) {
1987 if((*irv)->rank >=2) {
1988 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin();
1989 ira !=(*irv)->attrs.end();++ira) {
1990
1991 // If having attribute "coordinates" for this variable, checking the values and
1992 // see if having lat/lon,latitude/longitude, Latitude/Longitude pairs.
1993 if((*ira)->name == co_attrname) {
1994 Retrieve_H5_Attr_Value((*ira),(*irv)->fullpath);
1995 string orig_attr_value((*ira)->value.begin(),(*ira)->value.end());
1996 vector<string> coord_values;
1997 char sep=' ';
1998 HDF5CFUtil::Split_helper(coord_values,orig_attr_value,sep);
1999
2000 for(vector<string>::iterator irs=coord_values.begin();irs!=coord_values.end();++irs) {
2001 string coord_value_suffix1;
2002 string coord_value_suffix2;
2003 string coord_value_suffix3;
2004
2005 if((*irs).size() >=3) {
2006
2007 // both "lat" and "lon" have 3 characters.
2008 coord_value_suffix1 = (*irs).substr((*irs).size()-3,3);
2009
2010 // The word "latitude" has 8 characters and the word "longitude" has 9 characters.
2011 if((*irs).size() >=8){
2012 coord_value_suffix2 = (*irs).substr((*irs).size()-8,8);
2013 if((*irs).size() >=9)
2014 coord_value_suffix3 = (*irs).substr((*irs).size()-9,9);
2015 }
2016 }
2017
2018 // lat/longitude or latitude/lon pairs in theory are fine.
2019 if(coord_value_suffix1=="lat" || coord_value_suffix2 =="latitude" || coord_value_suffix2 == "Latitude")
2020 coor_has_lat_flag = true;
2021 else if(coord_value_suffix1=="lon" || coord_value_suffix3 =="longitude" || coord_value_suffix3 == "Longitude")
2022 coor_has_lon_flag = true;
2023 }
2024
2025 if(true == coor_has_lat_flag && true == coor_has_lon_flag)
2026 break;
2027 }// end if((*ira)->name
2028 }// for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin()
2029 if(true == coor_has_lat_flag && true == coor_has_lon_flag)
2030 break;
2031 else {
2032 coor_has_lat_flag = false;
2033 coor_has_lon_flag = false;
2034 }
2035 } // if((*irv)->rank >=2)
2036 }// for (vector<Var *>::iterator irv = this->vars.begin()
2037
2038 // Check the variable names that include latitude and longitude suffixes such as lat,latitude and Latitude.
2039 if(true == coor_has_lat_flag && true == coor_has_lon_flag) {
2040
2041 for (vector<Var *>::iterator irv = this->vars.begin();
2042 irv != this->vars.end(); ++irv) {
2043 bool var_is_lat = false;
2044 bool var_is_lon = false;
2045
2046 string varname = (*irv)->name;
2047 string ll_ssuffix;
2048 string ll_lsuffix1;
2049 string ll_lsuffix2;
2050 if(varname.size() >=3) {//lat/lon
2051 ll_ssuffix = varname.substr(varname.size()-3,3);
2052 if(varname.size() >=8) {//latitude/Latitude
2053 ll_lsuffix1 = varname.substr(varname.size()-8,8);
2054 if(varname.size() >=9)//Longitude/longitude
2055 ll_lsuffix2 = varname.substr(varname.size()-9,9);
2056 }
2057 }
2058 if(ll_ssuffix=="lat" || ll_lsuffix1 =="latitude" || ll_lsuffix1 == "Latitude")
2059 var_is_lat = true;
2060 else if(ll_ssuffix=="lon" || ll_lsuffix2 =="longitude" || ll_lsuffix2 == "Longitude")
2061 var_is_lon = true;
2062
2063 // Find the lat/lon candidate, save them to temporary vectors
2064 if(true == var_is_lat) {
2065 if((*irv)->rank > 0) {
2066 Var * lat = new Var(*irv);
2067 tempvar_lat.push_back(lat);
2068 }
2069 }
2070 else if(true == var_is_lon) {
2071 if((*irv)->rank >0) {
2072 Var * lon = new Var(*irv);
2073 tempvar_lon.push_back(lon);
2074 }
2075 }
2076 }// for (vector<Var *>::iterator
2077
2078 // Build up latloncv_candidate_pairs, Name_Size_2Pairs struct,
2079 // 1) Compare the rank, dimension sizes and the dimension orders of tempvar_lon against tempvar_lat
2080 // rank >=2 the sizes,orders, should be consistent
2081 // rank =1, no check issue.
2082 // 2) If the conditions are fulfilled, save them to the Name_Size struct
2083 for(vector<Var*>:: iterator irlat = tempvar_lat.begin(); irlat!=tempvar_lat.end();++irlat) {
2084
2085 // Check the rank =1 case
2086 if((*irlat)->rank == 1)
2087 Build_lat1D_latlon_candidate(*irlat,tempvar_lon);
2088
2089 // Check the reank>=2 case
2090 else if((*irlat)->rank >1)
2091 Build_latg1D_latlon_candidate(*irlat,tempvar_lon);
2092 }
2093
2094#if 0
2095for(vector<struct Name_Size_2Pairs>::iterator ivs=latloncv_candidate_pairs.begin(); ivs!=latloncv_candidate_pairs.end();++ivs) {
2096cerr<<"struct lat lon names are " <<(*ivs).name1 <<" and " << (*ivs).name2 <<endl;
2097}
2098#endif
2099
2100 // Check if there is duplicate latitude variables for one longitude variable in the latloncv_candidate_pairs.
2101 // if yes, remove the ones that have duplicate latitude variables.
2102 // This will assure that the latloncv_candidate_pairs is one-to-one mapping between latitude and longitude.
2103 Build_unique_latlon_candidate();
2104
2105
2106 // Even if we find that there are qualified geo-location coordinate pairs, we still need to check
2107 // the geo-location variable rank.
2108 // If the rank of any one-pair is 2, this case is qualified for the category GENERAL_LATLON_COOR_ATTR.
2109 // If the rank of any one-pair is 1,
2110 // we will check if the sizes of the lat and the lon in a pair are the same.
2111 // If they are not the same, this case is qualified for the category GENERAL_LATLON_COOR_ATTR
2112 // else check if there is any variable that has the "coordinates" attribute and the "coordinates" attribute includes
2113 // the paths of this lat/lon pair. If the dimensions of such a variable have two sizes that are equal to the size of the lat,
2114 // this case is still qualfied for the category GENERAL_LATLON_COOR_ATTR.
2115 // NOTE: here we deliberately ignore the case when the rank of lat/lon is >2. In some recent developments, we find that
2116 // there are 3D lat/lon and some tools like Panoply can visualize those data. So maybe we need to accept some 3D lat/lon in the futurei(KY 2016-07-07).
2117 if(latloncv_candidate_pairs.size() >0) {
2118 int num_1d_rank = 0;
2119 int num_2d_rank = 0;
2120 int num_g2d_rank = 0;
2121 vector<struct Name_Size_2Pairs> temp_1d_latlon_pairs;
2122 for(vector<struct Name_Size_2Pairs>::iterator ivs=latloncv_candidate_pairs.begin();
2123 ivs!=latloncv_candidate_pairs.end();++ivs) {
2124 if(1 == (*ivs).rank) {
2125 num_1d_rank++;
2126 temp_1d_latlon_pairs.push_back(*ivs);
2127 }
2128 else if(2 == (*ivs).rank)
2129 num_2d_rank++;
2130 else if((*ivs).rank >2)
2131 num_g2d_rank++;
2132 }
2133
2134 // This is the GENERAL_LATLON_COOR_ATTR case.
2135 if (num_2d_rank !=0)
2136 ret_value = true;
2137 else if(num_1d_rank!=0) {
2138
2139 // Check if lat and lon share the same size and the dimension of a variable
2140 // that has the "coordinates" only holds one size.
2141 for(vector<struct Name_Size_2Pairs>::iterator ivs=temp_1d_latlon_pairs.begin();
2142 ivs!=temp_1d_latlon_pairs.end();++ivs) {
2143 if((*ivs).size1 != (*ivs).size2) {
2144 ret_value = true;
2145 break;
2146 }
2147 else {
2148
2149 // If 1-D lat and lon share the same size,we need to check if there is a variable
2150 // that has both lat and lon as the coordinates but only has one dimension that holds the size.
2151 // If this is true, this is not the GENERAL_LATLON_COOR_ATTR case(SMAP level 2 follows into the category).
2152
2153 ret_value = true;
2154 for (vector<Var *>::iterator irv = this->vars.begin();
2155 irv != this->vars.end(); ++irv) {
2156 if((*irv)->rank >=2) {
2157 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin();
2158 ira !=(*irv)->attrs.end();++ira) {
2159 // Check if this variable has the "coordinates" attribute
2160 if((*ira)->name == co_attrname) {
2161 Retrieve_H5_Attr_Value((*ira),(*irv)->fullpath);
2162 string orig_attr_value((*ira)->value.begin(),(*ira)->value.end());
2163 vector<string> coord_values;
2164 char sep=' ';
2165 HDF5CFUtil::Split_helper(coord_values,orig_attr_value,sep);
2166 bool has_lat_flag = false;
2167 bool has_lon_flag = false;
2168 for (vector<string>::iterator itcv=coord_values.begin();itcv!=coord_values.end();++itcv) {
2169 if((*ivs).name1 == (*itcv))
2170 has_lat_flag = true;
2171 else if((*ivs).name2 == (*itcv))
2172 has_lon_flag = true;
2173 }
2174 // Find both lat and lon, now check the dim. size
2175 if(true == has_lat_flag && true == has_lon_flag) {
2176 short has_same_ll_size = 0;
2177 for(vector<Dimension *>::iterator ird = (*irv)->dims.begin();ird!=(*irv)->dims.end();++ird){
2178 if((*ird)->size == (*ivs).size1)
2179 has_same_ll_size++;
2180 }
2181 if(has_same_ll_size!=2){
2182 ret_value = false;
2183 break;
2184 }
2185 }
2186 }
2187 }// for (vector<Attribute *>:: iterator ira
2188 if(false == ret_value)
2189 break;
2190 }// if((*irv)->rank >=2)
2191 }// for (vector<Var *>::iterator irv
2192
2193 if(true == ret_value)
2194 break;
2195 }// else
2196 }// for(vector<struct Name_Size_2Pairs>::iterator ivs
2197 } // else if(num_1d_rank!=0)
2198 }// if(latloncv_candidate_pairs.size() >0)
2199
2200 release_standalone_var_vector(tempvar_lat);
2201 release_standalone_var_vector(tempvar_lon);
2202
2203 }
2204#if 0
2205if(true == ret_value)
2206cerr<<"This product is the coordinate type "<<endl;
2207#endif
2208 // Don't forget to set the flag for this general product pattern.
2209 if(true == ret_value)
2210 this->gproduct_pattern = GENERAL_LATLON_COOR_ATTR;
2211
2212 return ret_value;
2213}
2214
2215// Build 1-D latlon coordinate variables candidate for GENERAL_LATLON_COOR_ATTR.
2216void GMFile::Build_lat1D_latlon_candidate(Var *lat,const vector<Var*> &lon_vec) {
2217
2218 BESDEBUG("h5", "Coming to Build_lat1D_latlon_candidate()"<<endl);
2219 set<string> lon_candidate_path;
2220 vector< pair<string,hsize_t> > lon_path_size_vec;
2221
2222 // Obtain the path and the size info. from all the potential qualified longitude candidate.
2223 for(vector<Var *>::const_iterator irlon = lon_vec.begin(); irlon!=lon_vec.end();++irlon) {
2224
2225 if (lat->rank == (*irlon)->rank) {
2226 pair<string,hsize_t>lon_path_size;
2227 lon_path_size.first = (*irlon)->fullpath;
2228 lon_path_size.second = (*irlon)->getDimensions()[0]->size;
2229 lon_path_size_vec.push_back(lon_path_size);
2230 }
2231 }
2232
2233 // If there is only one potential qualified longitude for this latitude, just save this pair.
2234 if(lon_path_size_vec.size() == 1) {
2235
2236 Name_Size_2Pairs latlon_pair;
2237 latlon_pair.name1 = lat->fullpath;
2238 latlon_pair.name2 = lon_path_size_vec[0].first;
2239 latlon_pair.size1 = lat->getDimensions()[0]->size;
2240 latlon_pair.size2 = lon_path_size_vec[0].second;
2241 latlon_pair.rank = lat->rank;
2242 latloncv_candidate_pairs.push_back(latlon_pair);
2243
2244 }
2245 else if(lon_path_size_vec.size() >1) {
2246
2247 // For more than one potential qualified longitude, we can still find a qualified one
2248 // if we find there is only one longitude under the same group of this latitude.
2249 string lat_path = HDF5CFUtil::obtain_string_before_lastslash(lat->fullpath);
2250 pair<string,hsize_t> lon_final_path_size;
2251 short num_lon_match = 0;
2252 for(vector <pair<string,hsize_t> >::iterator islon =lon_path_size_vec.begin();islon!=lon_path_size_vec.end();++islon) {
2253 // Search the longitude path and see if it matches with the latitude.
2254 if(HDF5CFUtil::obtain_string_before_lastslash((*islon).first)==lat_path) {
2255 num_lon_match++;
2256 if(1 == num_lon_match)
2257 lon_final_path_size = *islon;
2258 else if(num_lon_match > 1)
2259 break;
2260 }
2261 }
2262 if(num_lon_match ==1) {// insert this lat/lon pair to the struct
2263 Name_Size_2Pairs latlon_pair;
2264 latlon_pair.name1 = lat->fullpath;
2265 latlon_pair.name2 = lon_final_path_size.first;
2266 latlon_pair.size1 = lat->getDimensions()[0]->size;
2267 latlon_pair.size2 = lon_final_path_size.second;
2268 latlon_pair.rank = lat->rank;
2269 latloncv_candidate_pairs.push_back(latlon_pair);
2270 }
2271 }
2272
2273}
2274
2275// Build >1D latlon coordinate variables candidate for GENERAL_LATLON_COOR_ATTR.
2276void GMFile::Build_latg1D_latlon_candidate(Var *lat,const vector<Var*> & lon_vec) {
2277
2278 BESDEBUG("h5", "Coming to Build_latg1D_latlon_candidate()"<<endl);
2279 set<string> lon_candidate_path;
2280
2281 // We will check if the longitude shares the same dimensions of the latitude
2282 for(vector<Var*>:: const_iterator irlon = lon_vec.begin(); irlon!=lon_vec.end();++irlon) {
2283
2284 if (lat->rank == (*irlon)->rank) {
2285
2286 // Check the dim order and size.
2287 bool same_dim = true;
2288 for(int dim_index = 0; dim_index <lat->rank; dim_index++) {
2289 if(lat->getDimensions()[dim_index]->size !=
2290 (*irlon)->getDimensions()[dim_index]->size){
2291 same_dim = false;
2292 break;
2293 }
2294 }
2295 if(true == same_dim)
2296 lon_candidate_path.insert((*irlon)->fullpath);
2297 }
2298 }
2299
2300 // Check the size of the lon., if the size is not 1, see if we can find the pair under the same group.
2301 if(lon_candidate_path.size() > 1) {
2302
2303 string lat_path = HDF5CFUtil::obtain_string_before_lastslash(lat->fullpath);
2304 vector <string> lon_final_candidate_path_vec;
2305 for(set<string>::iterator islon_path =lon_candidate_path.begin();islon_path!=lon_candidate_path.end();++islon_path) {
2306
2307 // Search the path.
2308 if(HDF5CFUtil::obtain_string_before_lastslash(*islon_path)==lat_path)
2309 lon_final_candidate_path_vec.push_back(*islon_path);
2310 }
2311
2312 if(lon_final_candidate_path_vec.size() == 1) {// insert this lat/lon pair to the struct
2313
2314 Name_Size_2Pairs latlon_pair;
2315
2316 latlon_pair.name1 = lat->fullpath;
2317 latlon_pair.name2 = lon_final_candidate_path_vec[0];
2318 latlon_pair.size1 = lat->getDimensions()[0]->size;
2319 latlon_pair.size2 = lat->getDimensions()[1]->size;
2320 latlon_pair.rank = lat->rank;
2321 latloncv_candidate_pairs.push_back(latlon_pair);
2322 }
2323 else if(lon_final_candidate_path_vec.size() >1) {
2324
2325 // Under the same group, if we have two pairs lat/lon such as foo1_lat,foo1_lon, foo2_lat,foo2_lon, we will
2326 // treat {foo1_lat,foo1_lon} and {foo2_lat,foo2_lon} as two lat,lon coordinate candidates. This is essentially the SMAP L1B case.
2327 // We only compare three potential suffixes, lat/lon, latitude/longitude,Latitude/Longitude. We will treat the pair
2328 // latitude/Longitude and Latitude/longitude as a valid one.
2329
2330 string lat_name = HDF5CFUtil::obtain_string_after_lastslash(lat->fullpath);
2331 string lat_name_prefix1;
2332 string lat_name_prefix2;
2333
2334 // name prefix before the pair lat,note: no need to check if the last 3 characters are lat or lon. We've checked already.
2335 if(lat_name.size() >3) {
2336 lat_name_prefix1 = lat_name.substr(0,lat_name.size()-3);
2337 if(lat_name.size() >8)
2338 lat_name_prefix2 = lat_name.substr(0,lat_name.size()-8);
2339 }
2340 string lon_name_prefix1;
2341 string lon_name_prefix2;
2342
2343 for(vector<string>::iterator ilon = lon_final_candidate_path_vec.begin(); ilon!=lon_final_candidate_path_vec.end();++ilon) {
2344 string lon_name = HDF5CFUtil::obtain_string_after_lastslash(*ilon);
2345 if(lon_name.size() >3) {
2346 lon_name_prefix1 = lon_name.substr(0,lon_name.size()-3);
2347 if(lon_name.size() >9)
2348 lon_name_prefix2 = lon_name.substr(0,lon_name.size()-9);
2349 }
2350 if((lat_name_prefix1 !="" && lat_name_prefix1 == lon_name_prefix1) ||
2351 (lat_name_prefix2 !="" && lat_name_prefix2 == lon_name_prefix2)) {// match lat,lon this one is the candidate
2352
2353 Name_Size_2Pairs latlon_pair;
2354 latlon_pair.name1 = lat->fullpath;
2355 latlon_pair.name2 = *ilon;
2356 latlon_pair.size1 = lat->getDimensions()[0]->size;
2357 latlon_pair.size2 = lat->getDimensions()[1]->size;
2358 latlon_pair.rank = lat->rank;
2359 latloncv_candidate_pairs.push_back(latlon_pair);
2360
2361 }
2362 }
2363 }// else if(lon_final_candidate_path_vec.size() >1)
2364 }// if(lon_candidate_path.size() > 1)
2365
2366 else if(lon_candidate_path.size() == 1) {//insert this lat/lon pair to the struct
2367
2368 Name_Size_2Pairs latlon_pair;
2369
2370 latlon_pair.name1 = lat->fullpath;
2371 latlon_pair.name2 = *(lon_candidate_path.begin());
2372 latlon_pair.size1 = lat->getDimensions()[0]->size;
2373 latlon_pair.size2 = lat->getDimensions()[1]->size;
2374 latlon_pair.rank = lat->rank;
2375 latloncv_candidate_pairs.push_back(latlon_pair);
2376
2377 }
2378
2379}
2380
2381// We need to make sure that one lat maps to one lon in the lat/lon pairs.
2382// This routine removes the duplicate ones like (lat1,lon1) and (lat2,lon1).
2383void GMFile::Build_unique_latlon_candidate() {
2384
2385 BESDEBUG("h5", "Coming to Build_unique_latlon_candidate()"<<endl);
2386 set<int> duplicate_index;
2387 for(unsigned int i= 0; i<latloncv_candidate_pairs.size();i++) {
2388 for(unsigned int j=i+1;j<latloncv_candidate_pairs.size();j++) {
2389 if(latloncv_candidate_pairs[i].name2 == latloncv_candidate_pairs[j].name2) {
2390 duplicate_index.insert(i);
2391 duplicate_index.insert(j);
2392 }
2393 }
2394 }
2395
2396 // set is pre-sorted. we used a quick way to remove multiple elements.
2397 for(set<int>::reverse_iterator its= duplicate_index.rbegin();its!=duplicate_index.rend();++its) {
2398 latloncv_candidate_pairs[*its] = latloncv_candidate_pairs.back();
2399 latloncv_candidate_pairs.pop_back();
2400 }
2401}
2402// Leave the following code for the time being.
2403#if 0
2404// In this version, we only check if we have "latitude,longitude","Latitude,Longitude","lat,lon" names.
2405// This routine will check this case.
2406bool GMFile::Check_LatLonName_General_Product(int ll_rank) {
2407
2408 if(ll_rank <1 || ll_rank >2)
2409 throw2("Only support rank = 1 or 2 lat/lon case for the general product. The current rank is ",ll_rank);
2410 bool ret_value = false;
2411 size_t lat2D_dimsize0 = 0;
2412 size_t lat2D_dimsize1 = 0;
2413 size_t lon2D_dimsize0 = 0;
2414 size_t lon2D_dimsize1 = 0;
2415
2416 // The element order is latlon_flag,latilong_flag and LatLon_flag.
2417 vector<short>ll_flag(3,0);
2418
2419 vector<size_t>lat_size;
2420 vector<size_t>lon_size;
2421
2422 // We only need to check 2-D latlon
2423 if(2 == ll_rank) {
2424 //lat/lon is 2-D array, so the size is doubled.
2425 lat_size.assign(6,0);
2426 lon_size.assign(6,0);
2427 }
2428
2429 for (vector<Var *>::iterator irv = this->vars.begin();
2430 irv != this->vars.end(); ++irv) {
2431
2432 if((*irv)->rank == ll_rank) {
2433 if((*irv)->name == "lat") {
2434 ll_flag[0]++;
2435 if(ll_rank == 2) {
2436 lat_size[0] = (*irv)->getDimensions()[0]->size;
2437 lat_size[1] = (*irv)->getDimensions()[1]->size;
2438
2439 }
2440
2441 }
2442 else if((*irv)->name == "lon") {
2443 ll_flag[0]++;
2444 if(ll_rank == 2) {
2445 lon_size[0] = (*irv)->getDimensions()[0]->size;
2446 lon_size[1] = (*irv)->getDimensions()[1]->size;
2447
2448 }
2449
2450 }
2451 else if((*irv)->name == "latitude"){
2452 ll_flag[1]++;
2453 if(ll_rank == 2) {
2454 lat_size[2] = (*irv)->getDimensions()[0]->size;
2455 lat_size[3] = (*irv)->getDimensions()[1]->size;
2456
2457 }
2458 }
2459 else if((*irv)->name == "longitude"){
2460 ll_flag[1]++;
2461 if(ll_rank == 2) {
2462 lon_size[2] = (*irv)->getDimensions()[0]->size;
2463 lon_size[3] = (*irv)->getDimensions()[1]->size;
2464
2465 }
2466
2467 }
2468 else if((*irv)->name == "Latitude"){
2469 ll_flag[2]++;
2470 if(ll_rank == 2) {
2471 lat_size[4] = (*irv)->getDimensions()[0]->size;
2472 lat_size[5] = (*irv)->getDimensions()[1]->size;
2473
2474 }
2475
2476 }
2477 else if((*irv)->name == "Longitude"){
2478 ll_flag[2]++;
2479 if(ll_rank == 2) {
2480 lon_size[4] = (*irv)->getDimensions()[0]->size;
2481 lon_size[5] = (*irv)->getDimensions()[1]->size;
2482 }
2483 }
2484 }
2485 }
2486
2487 int total_llflag = 0;
2488 for (int i = 0; i < ll_flag.size();i++)
2489 if(2 == ll_flag[i])
2490 total_llflag ++;
2491
2492 // We only support 1 (L)lat(i)/(L)lon(g) pair.
2493 if(1 == total_llflag) {
2494 bool latlon_size_match = true;
2495 if(2 == ll_rank) {
2496 for (int size_index = 0; size_index <lat_size.size();size_index++) {
2497 if(lat_size[size_index] != lon_size[size_index]){
2498 latlon_size_match = false;
2499 break;
2500 }
2501 }
2502 }
2503
2504 if(true == latlon_size_match) {
2505 ret_value = true;
2506 if(2 == ll_flag[0]) {
2507 gp_latname = "lat";
2508 gp_lonname = "lon";
2509 }
2510 else if ( 2 == ll_flag[1]) {
2511 gp_latname = "latitude";
2512 gp_lonname = "longitude";
2513 }
2514
2515 else if (2 == ll_flag[2]){
2516 gp_latname = "Latitude";
2517 gp_lonname = "Longitude";
2518 }
2519 }
2520 }
2521
2522 return ret_value;
2523}
2524#endif
2525
2526// Add dimension names for the case that has 2-D lat/lon.
2527void GMFile::Add_Dim_Name_LatLon2D_General_Product() {
2528
2529 BESDEBUG("h5", "Coming to Add_Dim_Name_LatLon2D_General_Product()"<<endl);
2530 string latdimname0;
2531 string latdimname1;
2532 size_t latdimsize0 = 0;
2533 size_t latdimsize1 = 0;
2534
2535 // Need to generate fake dimensions.
2536 for (vector<Var *>::iterator irv = this->vars.begin();
2537 irv != this->vars.end(); ++irv) {
2538
2539 set<hsize_t> fakedimsize;
2540 pair<set<hsize_t>::iterator,bool> setsizeret;
2541 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
2542 ird != (*irv)->dims.end(); ++ird) {
2543 Add_One_FakeDim_Name(*ird);
2544 setsizeret = fakedimsize.insert((*ird)->size);
2545
2546 // Avoid the same size dimension sharing the same dimension name.
2547 if (false == setsizeret.second)
2548 Adjust_Duplicate_FakeDim_Name(*ird);
2549 }
2550
2551 // Find variable name that is latitude or lat or Latitude
2552 // Note that we don't need to check longitude since longitude dim. sizes should be the same as the latitude for this case.
2553 if((*irv)->name == gp_latname) {
2554 if((*irv)->rank != 2) {
2555 throw4("coordinate variables ",gp_latname,
2556 " must have rank 2 for the 2-D latlon case , the current rank is ",
2557 (*irv)->rank);
2558 }
2559 latdimname0 = (*irv)->getDimensions()[0]->name;
2560 latdimsize0 = (*irv)->getDimensions()[0]->size;
2561
2562 latdimname1 = (*irv)->getDimensions()[1]->name;
2563 latdimsize1 = (*irv)->getDimensions()[1]->size;
2564 }
2565 }
2566
2567
2568 // Now we need to change a dimension of a general variable that shares the same size of lat
2569 // to the dimension name of the lat.
2570 for (vector<Var *>::iterator irv = this->vars.begin();
2571 irv != this->vars.end(); ++irv) {
2572 int lat_dim0_index = 0;
2573 int lat_dim1_index = 0;
2574 bool has_lat_dims_size = false;
2575
2576 for (unsigned int dim_index = 0; dim_index <(*irv)->dims.size(); dim_index++) {
2577
2578 // Find if having the first dimension size of lat
2579 if(((*irv)->dims[dim_index])->size == latdimsize0) {
2580
2581 // Find if having the second dimension size of lat
2582 lat_dim0_index = dim_index;
2583 for(unsigned int dim_index2 = dim_index+1;dim_index2 < (*irv)->dims.size();dim_index2++) {
2584 if(((*irv)->dims[dim_index2])->size == latdimsize1) {
2585 lat_dim1_index = dim_index2;
2586 has_lat_dims_size = true;
2587 break;
2588 }
2589 }
2590 }
2591 if(true == has_lat_dims_size)
2592 break;
2593 }
2594 // Find the lat's dimension sizes, change the (fake) dimension names.
2595 if(true == has_lat_dims_size) {
2596 ((*irv)->dims[lat_dim0_index])->name = latdimname0;
2597 //((*irv)->dims[lat_dim0_index])->newname = latdimname0;
2598
2599 ((*irv)->dims[lat_dim1_index])->name = latdimname1;
2600 //((*irv)->dims[lat_dim1_index])->newname = latdimname1;
2601
2602 }
2603 }
2604
2605 //When we generate Fake dimensions, we may encounter discontiguous Fake dimension names such
2606 // as FakeDim0, FakeDim9 etc. We would like to make Fake dimension names in contiguous order
2607 // FakeDim0,FakeDim1,etc.
2608
2609 // Obtain the tempdimnamelist set.
2610 set<string>tempdimnamelist;
2611
2612 for (vector<Var *>::iterator irv = this->vars.begin();
2613 irv != this->vars.end(); ++irv) {
2614 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
2615 ird != (*irv)->dims.end(); ++ird)
2616 tempdimnamelist.insert((*ird)->name);
2617
2618 }
2619
2620 // Generate the final dimnamelist,it is a contiguous order: FakeDim0,FakeDim1 etc.
2621 set<string>finaldimnamelist;
2622 string finaldimname_base = "FakeDim";
2623
2624 for(unsigned int i = 0; i<tempdimnamelist.size();i++) {
2625 stringstream sfakedimindex;
2626 sfakedimindex << i;
2627 string finaldimname = finaldimname_base + sfakedimindex.str();
2628 finaldimnamelist.insert(finaldimname);
2629 }
2630
2631 // If the original tempdimnamelist is not the same as the finaldimnamelist,
2632 // we need to generate a map from original name to the final name.
2633 if(finaldimnamelist != tempdimnamelist) {
2634 map<string,string> tempdimname_to_finaldimname;
2635 set<string>:: iterator tempit = tempdimnamelist.begin();
2636 set<string>:: iterator finalit = finaldimnamelist.begin();
2637 while(tempit != tempdimnamelist.end()) {
2638 tempdimname_to_finaldimname[*tempit] = *finalit;
2639 tempit++;
2640 finalit++;
2641 }
2642
2643 // Change the dimension names of every variable to the final dimension name list.
2644 for (vector<Var *>::iterator irv = this->vars.begin();
2645 irv != this->vars.end(); ++irv) {
2646 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
2647 ird != (*irv)->dims.end(); ++ird) {
2648 if(tempdimname_to_finaldimname.find((*ird)->name) !=tempdimname_to_finaldimname.end()){
2649 (*ird)->name = tempdimname_to_finaldimname[(*ird)->name];
2650 }
2651 else
2652 throw3("The dimension names ",(*ird)->name, "cannot be found in the dim. name list.");
2653 }
2654 }
2655 }
2656
2657
2658 dimnamelist.clear();
2659 dimnamelist = finaldimnamelist;
2660
2661 // We need to update dimname_to_dimsize map. This may be used in the future.
2662 dimname_to_dimsize.clear();
2663 for (vector<Var *>::iterator irv = this->vars.begin();
2664 irv != this->vars.end(); ++irv) {
2665 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
2666 ird != (*irv)->dims.end(); ++ird) {
2667 if(finaldimnamelist.find((*ird)->name)!=finaldimnamelist.end()) {
2668 dimname_to_dimsize[(*ird)->name] = (*ird)->size;
2669 dimname_to_unlimited[(*ird)->name] = (*ird)->unlimited_dim;
2670 finaldimnamelist.erase((*ird)->name);
2671 }
2672
2673 }
2674 if(true == finaldimnamelist.empty())
2675 break;
2676 }
2677
2678 // Finally set dimension newname
2679 for (vector<Var *>::iterator irv = this->vars.begin();
2680 irv != this->vars.end(); ++irv) {
2681 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
2682 ird != (*irv)->dims.end(); ++ird) {
2683 (*ird)->newname = (*ird)->name;
2684 }
2685 }
2686
2687}
2688
2689// Add dimension names for the case that has 1-D lat/lon or CoordAttr..
2690//
2691void GMFile::Add_Dim_Name_LatLon1D_Or_CoordAttr_General_Product() {
2692
2693 BESDEBUG("h5", "Coming to Add_Dim_Name_LatLon1D_Or_CoordAttr_General_Product()"<<endl);
2694 // Only need to add the fake dimension names
2695 for (vector<Var *>::iterator irv = this->vars.begin();
2696 irv != this->vars.end(); ++irv) {
2697
2698 set<hsize_t> fakedimsize;
2699 pair<set<hsize_t>::iterator,bool> setsizeret;
2700 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
2701 ird != (*irv)->dims.end(); ++ird) {
2702 Add_One_FakeDim_Name(*ird);
2703 setsizeret = fakedimsize.insert((*ird)->size);
2704 // Avoid the same size dimension sharing the same dimension name.
2705 if (false == setsizeret.second)
2706 Adjust_Duplicate_FakeDim_Name(*ird);
2707 }
2708 }
2709}
2710
2711// For netCDF-4-like HDF5 products, we need to add the dimension scales.
2712void GMFile::Add_Dim_Name_Dimscale_General_Product() {
2713
2714 BESDEBUG("h5", "Coming to Add_Dim_Name_Dimscale_General_Product()"<<endl);
2715 //cerr<<"coming to Add_Dim_Name_Dimscale_General_Product"<<endl;
2716 pair<set<string>::iterator,bool> setret;
2717 this->iscoard = true;
2718
2719 for (vector<Var *>::iterator irv = this->vars.begin();
2720 irv != this->vars.end(); ++irv) {
2721
2722 // Obtain all the dimension names for this variable
2723 Handle_UseDimscale_Var_Dim_Names_General_Product((*irv));
2724
2725 // Need to update dimenamelist and dimname_to_dimsize and dimname_to_unlimited maps for future use.
2726 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
2727 ird !=(*irv)->dims.end();++ird) {
2728 setret = dimnamelist.insert((*ird)->name);
2729 if (true == setret.second)
2730 Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
2731 }
2732 } // for (vector<Var *>::iterator irv = this->vars.begin();
2733
2734 if (true == dimnamelist.empty())
2735 throw1("This product should have the dimension names, but no dimension names are found");
2736
2737}
2738
2739// Obtain dimension names for this variable when netCDF-4 model(using dimension scales) is followed.
2740void GMFile::Handle_UseDimscale_Var_Dim_Names_General_Product(Var *var) {
2741
2742 BESDEBUG("h5", "Coming to Handle_UseDimscale_Var_Dim_Names_General_Product()"<<endl);
2743 Attribute* dimlistattr = NULL;
2744 bool has_dimlist = false;
2745 bool has_dimclass = false;
2746
2747 for(vector<Attribute *>::iterator ira = var->attrs.begin();
2748 ira != var->attrs.end();ira++) {
2749 if ("DIMENSION_LIST" == (*ira)->name) {
2750 dimlistattr = *ira;
2751 has_dimlist = true;
2752 }
2753 if ("CLASS" == (*ira)->name) {
2754
2755 Retrieve_H5_Attr_Value(*ira,var->fullpath);
2756 string class_value;
2757 class_value.resize((*ira)->value.size());
2758 copy((*ira)->value.begin(),(*ira)->value.end(),class_value.begin());
2759
2760 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
2761 // "DIMENSION_SCALE", which is 15.
2762 if (0 == class_value.compare(0,15,"DIMENSION_SCALE")) {
2763 has_dimclass = true;
2764 break;
2765 }
2766 }
2767
2768 } // for(vector<Attribute *>::iterator ira = var->attrs.begin(); ...
2769
2770 // This is a general variable, we need to find the corresponding coordinate variables.
2771 if (true == has_dimlist)
2772 Add_UseDimscale_Var_Dim_Names_General_Product(var,dimlistattr);
2773
2774 // Dim name is the same as the variable name for dimscale variable
2775 else if(true == has_dimclass) {
2776 if (var->dims.size() !=1)
2777 throw2("Currently dimension scale dataset must be 1 dimension, this is not true for the dataset ",
2778 var->name);
2779
2780 // The var name is the object name, however, we would like the dimension name to be the full path.
2781 // so that the dim name can be served as the key for future handling.
2782 (var->dims)[0]->name = var->fullpath;
2783 (var->dims)[0]->newname = var->fullpath;
2784 pair<set<string>::iterator,bool> setret;
2785 setret = dimnamelist.insert((var->dims)[0]->name);
2786 if (true == setret.second)
2787 Insert_One_NameSizeMap_Element((var->dims)[0]->name,(var->dims)[0]->size,(var->dims)[0]->unlimited_dim);
2788 }
2789
2790 // No dimension, add fake dim names, this will rarely happen.
2791 else {
2792
2793 set<hsize_t> fakedimsize;
2794 pair<set<hsize_t>::iterator,bool> setsizeret;
2795 for (vector<Dimension *>::iterator ird= var->dims.begin();
2796 ird != var->dims.end(); ++ird) {
2797 Add_One_FakeDim_Name(*ird);
2798 setsizeret = fakedimsize.insert((*ird)->size);
2799 // Avoid the same size dimension sharing the same dimension name.
2800 if (false == setsizeret.second)
2801 Adjust_Duplicate_FakeDim_Name(*ird);
2802 }
2803 }
2804
2805}
2806
2807// Add dimension names for the case when HDF5 dimension scale is followed(netCDF4-like)
2808void GMFile::Add_UseDimscale_Var_Dim_Names_General_Product(Var *var,Attribute*dimlistattr)
2809{
2810
2811 BESDEBUG("h5", "Coming to Add_UseDimscale_Var_Dim_Names_General_Product()"<<endl);
2812 ssize_t objnamelen = -1;
2813 hobj_ref_t rbuf;
2814 //hvl_t *vlbuf = NULL;
2815 vector<hvl_t> vlbuf;
2816
2817 hid_t dset_id = -1;
2818 hid_t attr_id = -1;
2819 hid_t atype_id = -1;
2820 hid_t amemtype_id = -1;
2821 hid_t aspace_id = -1;
2822 hid_t ref_dset = -1;
2823
2824 if(NULL == dimlistattr)
2825 throw2("Cannot obtain the dimension list attribute for variable ",var->name);
2826
2827 else if (0==var->rank)
2828 throw2("The number of dimension should NOT be 0 for the variable ",var->name);
2829
2830 else {
2831 try {
2832
2833 vlbuf.resize(var->rank);
2834
2835 dset_id = H5Dopen(this->fileid,(var->fullpath).c_str(),H5P_DEFAULT);
2836 if (dset_id < 0)
2837 throw2("Cannot open the dataset ",var->fullpath);
2838
2839 attr_id = H5Aopen(dset_id,(dimlistattr->name).c_str(),H5P_DEFAULT);
2840 if (attr_id <0 )
2841 throw4("Cannot open the attribute ",dimlistattr->name," of HDF5 dataset ",var->fullpath);
2842
2843 atype_id = H5Aget_type(attr_id);
2844 if (atype_id <0)
2845 throw4("Cannot obtain the datatype of the attribute ",dimlistattr->name," of HDF5 dataset ",var->fullpath);
2846
2847 amemtype_id = H5Tget_native_type(atype_id, H5T_DIR_ASCEND);
2848
2849 if (amemtype_id < 0)
2850 throw2("Cannot obtain the memory datatype for the attribute ",dimlistattr->name);
2851
2852
2853 if (H5Aread(attr_id,amemtype_id,&vlbuf[0]) <0)
2854 throw2("Cannot obtain the referenced object for the variable ",var->name);
2855
2856
2857 vector<char> objname;
2858 int vlbuf_index = 0;
2859
2860 // The dimension names of variables will be the HDF5 dataset names dereferenced from the DIMENSION_LIST attribute.
2861 for (vector<Dimension *>::iterator ird = var->dims.begin();
2862 ird != var->dims.end(); ++ird) {
2863
2864 if(vlbuf[vlbuf_index].p== NULL)
2865 throw4("The dimension doesn't exist. Var name is ",var->name,"; the dimension index is ",vlbuf_index);
2866 rbuf =((hobj_ref_t*)vlbuf[vlbuf_index].p)[0];
2867 if ((ref_dset = H5RDEREFERENCE(attr_id, H5R_OBJECT, &rbuf)) < 0)
2868 throw2("Cannot dereference from the DIMENSION_LIST attribute for the variable ",var->name);
2869
2870 if ((objnamelen= H5Iget_name(ref_dset,NULL,0))<=0)
2871 throw2("Cannot obtain the dataset name dereferenced from the DIMENSION_LIST attribute for the variable ",var->name);
2872 objname.resize(objnamelen+1);
2873 if ((objnamelen= H5Iget_name(ref_dset,&objname[0],objnamelen+1))<=0)
2874 throw2("Cannot obtain the dataset name dereferenced from the DIMENSION_LIST attribute for the variable ",var->name);
2875
2876 string objname_str = string(objname.begin(),objname.end());
2877
2878 // We need to remove the first character of the object name since the first character
2879 // of the object full path is always "/" and this will be changed to "_".
2880 // The convention of handling the dimension-scale general product is to remove the first "_".
2881 // Check the get_CF_string function of HDF5GMCF.cc.
2882 string trim_objname = objname_str.substr(0,objnamelen);
2883 (*ird)->name = string(trim_objname.begin(),trim_objname.end());
2884
2885 pair<set<string>::iterator,bool> setret;
2886 setret = dimnamelist.insert((*ird)->name);
2887 if (true == setret.second)
2888 Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size,(*ird)->unlimited_dim);
2889 (*ird)->newname = (*ird)->name;
2890 H5Dclose(ref_dset);
2891#if 0
2892 ref_dset = -1;
2893#endif
2894 objname.clear();
2895 vlbuf_index++;
2896 }// for (vector<Dimension *>::iterator ird = var->dims.begin()
2897 if(vlbuf.size()!= 0) {
2898
2899 if ((aspace_id = H5Aget_space(attr_id)) < 0)
2900 throw2("Cannot get hdf5 dataspace id for the attribute ",dimlistattr->name);
2901
2902 if (H5Dvlen_reclaim(amemtype_id,aspace_id,H5P_DEFAULT,(void*)&vlbuf[0])<0)
2903 throw2("Cannot successfully clean up the variable length memory for the variable ",var->name);
2904
2905 H5Sclose(aspace_id);
2906
2907 }
2908
2909 H5Tclose(atype_id);
2910 H5Tclose(amemtype_id);
2911 H5Aclose(attr_id);
2912 H5Dclose(dset_id);
2913 }
2914
2915 catch(...) {
2916
2917 if(atype_id != -1)
2918 H5Tclose(atype_id);
2919
2920 if(amemtype_id != -1)
2921 H5Tclose(amemtype_id);
2922
2923 if(aspace_id != -1)
2924 H5Sclose(aspace_id);
2925
2926 if(attr_id != -1)
2927 H5Aclose(attr_id);
2928
2929 if(dset_id != -1)
2930 H5Dclose(dset_id);
2931
2932 throw;
2933 }
2934 }
2935
2936}
2937
2938// Handle coordinate variables
2940
2941 BESDEBUG("h5", "GMFile:: Coming to Handle_CVar()"<<endl);
2942 // No coordinate variables are generated for ACOS_L2S or OCO2_L1B
2943 // Currently we support the three patterns for the general products:
2944 // 1) Dimensions follow HDF5 dimension scale specification
2945 // 2) Dimensions don't follow HDF5 dimension scale specification but have 1D lat/lon
2946 // 3) Dimensions don't follow HDF5 dimension scale specification bu have 2D lat/lon
2947 if (General_Product == this->product_type ||
2948 ACOS_L2S_OR_OCO2_L1B == this->product_type) {
2949 if (GENERAL_DIMSCALE == this->gproduct_pattern)
2950 Handle_CVar_Dimscale_General_Product();
2951 else if (GENERAL_LATLON1D == this->gproduct_pattern)
2952 Handle_CVar_LatLon1D_General_Product();
2953 else if (GENERAL_LATLON2D == this->gproduct_pattern)
2954 Handle_CVar_LatLon2D_General_Product();
2955 return;
2956 }
2957
2958 else if (Mea_SeaWiFS_L2 == this->product_type ||
2959 Mea_SeaWiFS_L3 == this->product_type)
2960 Handle_CVar_Mea_SeaWiFS();
2961 else if (Aqu_L3 == this->product_type)
2962 Handle_CVar_Aqu_L3();
2963 else if (OBPG_L3 == this->product_type)
2964 Handle_CVar_OBPG_L3();
2965 else if (OSMAPL2S == this->product_type)
2966 Handle_CVar_OSMAPL2S();
2967 else if (Mea_Ozone == this->product_type)
2968 Handle_CVar_Mea_Ozone();
2969 else if (GPMS_L3 == this->product_type || GPMM_L3 == this->product_type
2970 || GPM_L3_New == this->product_type )
2971 Handle_CVar_GPM_L3();
2972 else if (GPM_L1 == this->product_type)
2973 Handle_CVar_GPM_L1();
2974}
2975
2976// Handle GPM level 1 coordinate variables
2977void GMFile::Handle_CVar_GPM_L1() {
2978
2979 BESDEBUG("h5", "Coming to Handle_CVar_GPM_L1()"<<endl);
2980#if 0
2981 // Loop through the variable list to build the coordinates.
2982 for (vector<Var *>::iterator irv = this->vars.begin();
2983 irv != this->vars.end(); ++irv) {
2984 if((*irv)->name=="AlgorithmRuntimeInfo") {
2985 delete(*irv);
2986 this->vars.erase(irv);
2987 break;
2988 }
2989 }
2990#endif
2991
2992 // Loop through all variables to check 2-D "Latitude" and "Longitude".
2993 // Create coordinate variables based on 2-D "Latitude" and "Longitude".
2994 // Latitude[Xdim][YDim] Longitude[Xdim][YDim], Latitude <->Xdim, Longitude <->YDim.
2995 // Make sure to build cf dimension names cfdimname = latpath+ the lat dimension name.
2996 // We want to save dimension names of Latitude and Longitude since
2997 // the fake coordinate variables of these two dimensions should not be generated.
2998 // So we need to remember these dimension names.
2999 set<string> ll_dim_set;
3000 for (vector<Var *>::iterator irv = this->vars.begin();
3001 irv != this->vars.end(); ) {
3002 if((*irv)->rank == 2 && (*irv)->name == "Latitude") {
3003 GMCVar* GMcvar = new GMCVar(*irv);
3004 size_t lat_pos = (*irv)->fullpath.rfind("Latitude");
3005 string lat_path = (*irv)->fullpath.substr(0,lat_pos);
3006 GMcvar->cfdimname = lat_path + ((*irv)->dims)[0]->name;
3007 ll_dim_set.insert(((*irv)->dims)[0]->name);
3008 GMcvar->cvartype = CV_EXIST;
3009 GMcvar->product_type = product_type;
3010 this->cvars.push_back(GMcvar);
3011 delete(*irv);
3012 irv = this->vars.erase(irv);
3013 }
3014
3015 if((*irv)->rank == 2 && (*irv)->name == "Longitude") {
3016 GMCVar* GMcvar = new GMCVar(*irv);
3017 size_t lon_pos = (*irv)->fullpath.rfind("Longitude");
3018 string lon_path = (*irv)->fullpath.substr(0,lon_pos);
3019 GMcvar->cfdimname = lon_path + ((*irv)->dims)[1]->name;
3020 ll_dim_set.insert(((*irv)->dims)[1]->name);
3021 GMcvar->cvartype = CV_EXIST;
3022 GMcvar->product_type = product_type;
3023 this->cvars.push_back(GMcvar);
3024 delete(*irv);
3025 irv = this->vars.erase(irv);
3026 }
3027 else {
3028 ++irv;
3029 }
3030 }// for (vector<Var *>::iterator irv = this->vars.begin();...
3031
3032#if 0
3033 // Loop through all variables and create a dim set.
3034 set<string> cvdimset;
3035 pair<set<string>::iterator,bool> setret;
3036 for (vector<Var *>::iterator irv = this->vars.begin();
3037 irv != this->vars.end(); ++irv) {
3038 for(vector<Dimension *>::iterator ird = (*irv)->dims.begin();
3039 ird != (*irv)->dims.end(); ++ird) {
3040 setret = cvdimset.insert((*ird)->name);
3041cerr<<"var name is "<<(*irv)->fullpath <<endl;
3042 if (true == setret.second) {
3043cerr<<"dim name is "<<(*ird)->name <<endl;
3044 Insert_One_NameSizeMap_Element((*ird)->name,(*ird)->size);
3045 }
3046 }
3047 }// for (vector<Var *>::iterator irv = this->vars.begin();...
3048#endif
3049
3050 // For each dimension, create a coordinate variable.
3051 // Here we just need to loop through the map dimname_to_dimsize,
3052 // use the name and the size to create coordinate variables.
3053 for (map<string,hsize_t>::const_iterator itd = dimname_to_dimsize.begin();
3054 itd!=dimname_to_dimsize.end();++itd) {
3055 // We will not create fake coordinate variables for the
3056 // dimensions of latitude and longitude.
3057 if((ll_dim_set.find(itd->first)) == ll_dim_set.end()) {
3058 GMCVar*GMcvar = new GMCVar();
3059 Create_Missing_CV(GMcvar,itd->first);
3060 this->cvars.push_back(GMcvar);
3061 }
3062 }//for (map<string,hsize_t>::iterator itd = dimname_to_dimsize.begin(); ...
3063
3064}
3065
3066// Handle coordinate variables for GPM level 3
3067void GMFile::Handle_CVar_GPM_L3() {
3068
3069 BESDEBUG("h5", "Coming to Handle_CVar_GPM_L3()"<<endl);
3070 iscoard = true;
3071
3072 // Here we just need to loop through the map dimname_to_dimsize,
3073 // use the name and the size to create coordinate variables.
3074 for (map<string,hsize_t>::const_iterator itd = dimname_to_dimsize.begin();
3075 itd!=dimname_to_dimsize.end();++itd) {
3076
3077 GMCVar*GMcvar = new GMCVar();
3078 if("nlon" == itd->first || "nlat" == itd->first
3079 || "lnH" == itd->first || "ltH" == itd->first
3080 || "lnL" == itd->first || "ltL" == itd->first) {
3081 GMcvar->name = itd->first;
3082 GMcvar->newname = GMcvar->name;
3083 GMcvar->fullpath = GMcvar->name;
3084 GMcvar->rank = 1;
3085 GMcvar->dtype = H5FLOAT32;
3086 Dimension* gmcvar_dim = new Dimension(itd->second);
3087 gmcvar_dim->name = GMcvar->name;
3088 gmcvar_dim->newname = gmcvar_dim->name;
3089 GMcvar->dims.push_back(gmcvar_dim);
3090 GMcvar->cfdimname = gmcvar_dim->name;
3091 if ("nlat" ==GMcvar->name || "ltH" == GMcvar->name
3092 || "ltL" == GMcvar->name)
3093 GMcvar->cvartype = CV_LAT_MISS;
3094 else if ("nlon" == GMcvar->name || "lnH" == GMcvar->name
3095 || "lnL" == GMcvar->name)
3096 GMcvar->cvartype = CV_LON_MISS;
3097 GMcvar->product_type = product_type;
3098 }
3099 else if (("nlayer" == itd->first && (28 == itd->second || 19 == itd->second)) ||
3100 ("hgt" == itd->first && 5 == itd->second) ||
3101 ("nalt" == itd->first && 5 == itd->second)){
3102 GMcvar->name = itd->first;
3103 GMcvar->newname = GMcvar->name;
3104 GMcvar->fullpath = GMcvar->name;
3105 GMcvar->rank = 1;
3106 GMcvar->dtype = H5FLOAT32;
3107 Dimension* gmcvar_dim = new Dimension(itd->second);
3108 gmcvar_dim->name = GMcvar->name;
3109 gmcvar_dim->newname = gmcvar_dim->name;
3110 GMcvar->dims.push_back(gmcvar_dim);
3111 GMcvar->cfdimname = gmcvar_dim->name;
3112 GMcvar->cvartype = CV_SPECIAL;
3113 GMcvar->product_type = product_type;
3114 }
3115 else
3116 Create_Missing_CV(GMcvar,itd->first);
3117 this->cvars.push_back(GMcvar);
3118 }//for (map<string,hsize_t>::iterator itd = dimname_to_dimsize.begin(); ...
3119}
3120
3121// Handle Coordinate variables for MeaSuRES SeaWiFS
3122void GMFile::Handle_CVar_Mea_SeaWiFS() {
3123
3124 BESDEBUG("h5", "Coming to Handle_CVar_Mea_SeaWiFS()"<<endl);
3125 pair<set<string>::iterator,bool> setret;
3126 set<string>tempdimnamelist = dimnamelist;
3127
3128 for (set<string>::iterator irs = dimnamelist.begin();
3129 irs != dimnamelist.end();++irs) {
3130 for (vector<Var *>::iterator irv = this->vars.begin();
3131 irv != this->vars.end(); ) {
3132 if ((*irs)== (*irv)->fullpath) {
3133
3134 if (!iscoard && (("/natrack" == (*irs))
3135 || "/nxtrack" == (*irs))) {
3136 ++irv;
3137 continue;
3138 }
3139
3140 if((*irv)->dims.size()!=1)
3141 throw3("Coard coordinate variable ",(*irv)->name, "is not 1D");
3142
3143 // Create Coordinate variables.
3144 tempdimnamelist.erase(*irs);
3145 GMCVar* GMcvar = new GMCVar(*irv);
3146 GMcvar->cfdimname = *irs;
3147 GMcvar->cvartype = CV_EXIST;
3148 GMcvar->product_type = product_type;
3149 this->cvars.push_back(GMcvar);
3150 delete(*irv);
3151 irv = this->vars.erase(irv);
3152 //irv--;
3153 } // if ((*irs)== (*irv)->fullpath)
3154 else if(false == iscoard) {
3155 // 2-D lat/lon, natrack maps to lat, nxtrack maps to lon.
3156
3157 if ((((*irs) =="/natrack") && ((*irv)->fullpath == "/latitude"))
3158 ||(((*irs) =="/nxtrack") && ((*irv)->fullpath == "/longitude"))) {
3159 tempdimnamelist.erase(*irs);
3160 GMCVar* GMcvar = new GMCVar(*irv);
3161 GMcvar->cfdimname = *irs;
3162 GMcvar->cvartype = CV_EXIST;
3163 GMcvar->product_type = product_type;
3164 this->cvars.push_back(GMcvar);
3165 delete(*irv);
3166 irv = this->vars.erase(irv);
3167 }
3168 else {
3169 ++irv;
3170 }
3171
3172 }// else if(false == iscoard)
3173 else {
3174 ++irv;
3175 }
3176 } // for (vector<Var *>::iterator irv = this->vars.begin() ...
3177 } // for (set<string>::iterator irs = dimnamelist.begin() ...
3178
3179 // Creating the missing "third-dimension" according to the dimension names.
3180 // This may never happen for the current MeaSure SeaWiFS, but put it here for code coherence and completeness.
3181 // KY 12-30-2011
3182 for (set<string>::iterator irs = tempdimnamelist.begin();
3183 irs != tempdimnamelist.end();++irs) {
3184 GMCVar*GMcvar = new GMCVar();
3185 Create_Missing_CV(GMcvar,*irs);
3186 this->cvars.push_back(GMcvar);
3187 }
3188}
3189
3190// Handle Coordinate varibles for OSMAPL2S(Note: this function doesn't apply to SMAP)
3191void GMFile::Handle_CVar_OSMAPL2S() {
3192
3193 BESDEBUG("h5", "Coming to Handle_CVar_OSMAPL2S()"<<endl);
3194 pair<set<string>::iterator,bool> setret;
3195 set<string>tempdimnamelist = dimnamelist;
3196 string tempvarname;
3197 string key0 = "_lat";
3198 string key1 = "_lon";
3199 string osmapl2sdim0 ="YDim";
3200 string osmapl2sdim1 ="XDim";
3201
3202 bool foundkey0 = false;
3203 bool foundkey1 = false;
3204
3205 set<string> itset;
3206
3207 for (vector<Var *>::iterator irv = this->vars.begin();
3208 irv != this->vars.end(); ) {
3209
3210 tempvarname = (*irv)->name;
3211
3212 if ((tempvarname.size() > key0.size())&&
3213 (key0 == tempvarname.substr(tempvarname.size()-key0.size(),key0.size()))){
3214
3215 foundkey0 = true;
3216
3217 if (dimnamelist.find(osmapl2sdim0)== dimnamelist.end())
3218 throw5("variable ",tempvarname," must have dimension ",osmapl2sdim0," , but not found ");
3219
3220 tempdimnamelist.erase(osmapl2sdim0);
3221 GMCVar* GMcvar = new GMCVar(*irv);
3222 GMcvar->newname = GMcvar->name; // Remove the path, just use the variable name
3223 GMcvar->cfdimname = osmapl2sdim0;
3224 GMcvar->cvartype = CV_EXIST;
3225 GMcvar->product_type = product_type;
3226 this->cvars.push_back(GMcvar);
3227 delete(*irv);
3228 irv = this->vars.erase(irv);
3229 }// if ((tempvarname.size() > key0.size())&& ...
3230
3231 else if ((tempvarname.size() > key1.size())&&
3232 (key1 == tempvarname.substr(tempvarname.size()-key1.size(),key1.size()))){
3233
3234 foundkey1 = true;
3235
3236 if (dimnamelist.find(osmapl2sdim1)== dimnamelist.end())
3237 throw5("variable ",tempvarname," must have dimension ",osmapl2sdim1," , but not found ");
3238
3239 tempdimnamelist.erase(osmapl2sdim1);
3240
3241 GMCVar* GMcvar = new GMCVar(*irv);
3242 GMcvar->newname = GMcvar->name;
3243 GMcvar->cfdimname = osmapl2sdim1;
3244 GMcvar->cvartype = CV_EXIST;
3245 GMcvar->product_type = product_type;
3246 this->cvars.push_back(GMcvar);
3247 delete(*irv);
3248 irv = this->vars.erase(irv);
3249 }// else if ((tempvarname.size() > key1.size())&& ...
3250 else {
3251 ++irv;
3252 }
3253 if (true == foundkey0 && true == foundkey1)
3254 break;
3255 } // for (vector<Var *>::iterator irv = this->vars.begin(); ...
3256
3257 for (set<string>::iterator irs = tempdimnamelist.begin();
3258 irs != tempdimnamelist.end();++irs) {
3259
3260 GMCVar*GMcvar = new GMCVar();
3261 Create_Missing_CV(GMcvar,*irs);
3262 this->cvars.push_back(GMcvar);
3263 }
3264
3265}
3266
3267// Handle coordinate variables for Aquarius level 3 products
3268void GMFile::Handle_CVar_Aqu_L3() {
3269
3270 BESDEBUG("h5", "Coming to Handle_CVar_Aqu_L3()"<<endl);
3271 iscoard = true;
3272 for (vector<Var *>::iterator irv = this->vars.begin();
3273 irv != this->vars.end(); ++irv) {
3274
3275 if ( "l3m_data" == (*irv)->name) {
3276 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
3277 ird != (*irv)->dims.end(); ++ird) {
3278 GMCVar*GMcvar = new GMCVar();
3279 GMcvar->name = (*ird)->name;
3280 GMcvar->newname = GMcvar->name;
3281 GMcvar->fullpath = GMcvar->name;
3282 GMcvar->rank = 1;
3283 GMcvar->dtype = H5FLOAT32;
3284 Dimension* gmcvar_dim = new Dimension((*ird)->size);
3285 gmcvar_dim->name = GMcvar->name;
3286 gmcvar_dim->newname = gmcvar_dim->name;
3287 GMcvar->dims.push_back(gmcvar_dim);
3288 GMcvar->cfdimname = gmcvar_dim->name;
3289 if ("lat" ==GMcvar->name ) GMcvar->cvartype = CV_LAT_MISS;
3290 if ("lon" == GMcvar->name ) GMcvar->cvartype = CV_LON_MISS;
3291 GMcvar->product_type = product_type;
3292 this->cvars.push_back(GMcvar);
3293 } // for (vector<Dimension *>::iterator ird = (*irv)->dims.begin(); ...
3294 } // if ( "l3m_data" == (*irv)->name)
3295 }//for (vector<Var *>::iterator irv = this->vars.begin(); ...
3296
3297}
3298
3299//Handle coordinate variables for MeaSuRES Ozone products
3300void GMFile::Handle_CVar_Mea_Ozone() {
3301
3302 BESDEBUG("h5", "Coming to Handle_CVar_Mea_Ozone()"<<endl);
3303 pair<set<string>::iterator,bool> setret;
3304 set<string>tempdimnamelist = dimnamelist;
3305
3306 if(false == iscoard)
3307 throw1("Measure Ozone level 3 zonal average product must follow COARDS conventions");
3308
3309 for (set<string>::iterator irs = dimnamelist.begin();
3310 irs != dimnamelist.end();++irs) {
3311 for (vector<Var *>::iterator irv = this->vars.begin();
3312 irv != this->vars.end(); ) {
3313 if ((*irs)== (*irv)->fullpath) {
3314
3315 if((*irv)->dims.size()!=1)
3316 throw3("Coard coordinate variable",(*irv)->name, "is not 1D");
3317
3318 // Create Coordinate variables.
3319 tempdimnamelist.erase(*irs);
3320 GMCVar* GMcvar = new GMCVar(*irv);
3321 GMcvar->cfdimname = *irs;
3322 GMcvar->cvartype = CV_EXIST;
3323 GMcvar->product_type = product_type;
3324 this->cvars.push_back(GMcvar);
3325 delete(*irv);
3326 irv = this->vars.erase(irv);
3327 } // if ((*irs)== (*irv)->fullpath)
3328 else {
3329 ++irv;
3330 }
3331 } // for (vector<Var *>::iterator irv = this->vars.begin();
3332 } // for (set<string>::iterator irs = dimnamelist.begin();
3333
3334 for (set<string>::iterator irs = tempdimnamelist.begin();
3335 irs != tempdimnamelist.end();irs++) {
3336
3337 GMCVar*GMcvar = new GMCVar();
3338 Create_Missing_CV(GMcvar,*irs);
3339 this->cvars.push_back(GMcvar);
3340 }
3341}
3342
3343// Handle coordinate variables for general products that use HDF5 dimension scales.
3344void GMFile::Handle_CVar_Dimscale_General_Product() {
3345
3346 BESDEBUG("h5", "Coming to Handle_CVar_Dimscale_General_Product"<<endl);
3347 pair<set<string>::iterator,bool> setret;
3348 set<string>tempdimnamelist = dimnamelist;
3349
3350 for (set<string>::iterator irs = dimnamelist.begin();
3351 irs != dimnamelist.end();++irs) {
3352 for (vector<Var *>::iterator irv = this->vars.begin();
3353 irv != this->vars.end(); ) {
3354
3355 // This is the dimension scale dataset; it should be changed to a coordinate variable.
3356 if ((*irs)== (*irv)->fullpath) {
3357 if((*irv)->dims.size()!=1)
3358 throw3("COARDS coordinate variable",(*irv)->name, "is not 1D");
3359
3360 // Create Coordinate variables.
3361 tempdimnamelist.erase(*irs);
3362 GMCVar* GMcvar = new GMCVar(*irv);
3363 GMcvar->cfdimname = *irs;
3364
3365 // Check if this is just a netCDF-4 dimension.
3366 bool is_netcdf_dimension = Is_netCDF_Dimension(*irv);
3367
3368 // If this is just the netcdf dimension, we
3369 // will fill in the index numbers.
3370 if (true == is_netcdf_dimension)
3371 GMcvar->cvartype = CV_FILLINDEX;
3372 else
3373 GMcvar->cvartype = CV_EXIST;
3374 GMcvar->product_type = product_type;
3375 this->cvars.push_back(GMcvar);
3376 delete(*irv);
3377 irv = this->vars.erase(irv);
3378 } // if ((*irs)== (*irv)->fullpath)
3379 else {
3380 ++irv;
3381 }
3382 } // for (vector<Var *>::iterator irv = this->vars.begin();
3383 } // for (set<string>::iterator irs = dimnamelist.begin();
3384
3385 // Check if we have 2-D lat/lon CVs, and if yes, add those to the CV list.
3386 Update_M2DLatLon_Dimscale_CVs();
3387
3388 // Add other missing coordinate variables.
3389 for (set<string>::iterator irs = tempdimnamelist.begin();
3390 irs != tempdimnamelist.end();irs++) {
3391 GMCVar*GMcvar = new GMCVar();
3392 Create_Missing_CV(GMcvar,*irs);
3393 this->cvars.push_back(GMcvar);
3394 }
3395
3396
3397//Debugging
3398#if 0
3399for (set<string>::iterator irs = dimnamelist.begin();
3400 irs != dimnamelist.end();irs++) {
3401cerr<<"dimension name is "<<(*irs)<<endl;
3402}
3403#endif
3404
3405}
3406
3407
3408// Check if we have 2-D lat/lon CVs in a netCDF-4-like file, and if yes, add those to the CV list.
3409// This routine is a really complicate one. There are 9 steps to generate right 2-D lat/lon CVs.
3410void GMFile::Update_M2DLatLon_Dimscale_CVs() {
3411
3412 BESDEBUG("h5", "Coming to Update_M2DLatLon_Dimscale_CVs()"<<endl);
3413 // If this is not a file that only includes 1-D lat/lon CVs
3414 if(false == Check_1DGeolocation_Dimscale()) {
3415
3416 // Define temporary vectors to store 1-D lat/lon CVs
3417 vector<GMCVar*> tempcvar_1dlat;
3418 vector<GMCVar*> tempcvar_1dlon;
3419
3420 // 1. Obtain 1-D lat/lon CVs(only search the CF units and the reserved lat/lon names)
3421 Obtain_1DLatLon_CVs(tempcvar_1dlat,tempcvar_1dlon);
3422
3423 // Define temporary vectors to store 2-D lat/lon Vars
3424 vector<Var*> tempcvar_2dlat;
3425 vector<Var*> tempcvar_2dlon;
3426
3427 // This map remembers the positions of the latlon vars in the vector var.
3428 // Remembering the positions avoids the searching of these lat and lon again when
3429 // deleting them for the var vector and adding them(only the CVs) to the CV vector.
3430 // KY 2015-12-23
3431 map<string,int> latlon2d_path_to_index;
3432
3433 // 2. Obtain 2-D lat/lon variables(only search the CF units and the reserved names)
3434 Obtain_2DLatLon_Vars(tempcvar_2dlat,tempcvar_2dlon,latlon2d_path_to_index);
3435
3436#if 0
3437for(vector<GMCVar *>::iterator irv = tempcvar_1dlat.begin();irv != tempcvar_1dlat.end();++irv)
3438cerr<<"1-D lat variable full path is "<<(*irv)->fullpath <<endl;
3439for(vector<GMCVar *>::iterator irv = tempcvar_1dlon.begin();irv != tempcvar_1dlon.end();++irv)
3440cerr<<"1-D lon variable full path is "<<(*irv)->fullpath <<endl;
3441
3442for(vector<Var *>::iterator irv = tempcvar_2dlat.begin();irv != tempcvar_2dlat.end();++irv)
3443cerr<<"2-D lat variable full path is "<<(*irv)->fullpath <<endl;
3444for(vector<Var *>::iterator irv = tempcvar_2dlon.begin();irv != tempcvar_2dlon.end();++irv)
3445cerr<<"2-D lon variable full path is "<<(*irv)->fullpath <<endl;
3446#endif
3447
3448 // 3. Sequeeze the 2-D lat/lon vectors by removing the ones that share the same dims with 1-D lat/lon CVs.
3449 Obtain_2DLLVars_With_Dims_not_1DLLCVars(tempcvar_2dlat,tempcvar_2dlon,tempcvar_1dlat,tempcvar_1dlon,latlon2d_path_to_index);
3450
3451#if 0
3452for(vector<Var *>::iterator irv = tempcvar_2dlat.begin();irv != tempcvar_2dlat.end();++irv)
3453cerr<<"2-D Left lat variable full path is "<<(*irv)->fullpath <<endl;
3454for(vector<Var *>::iterator irv = tempcvar_2dlon.begin();irv != tempcvar_2dlon.end();++irv)
3455cerr<<"2-D Left lon variable full path is "<<(*irv)->fullpath <<endl;
3456#endif
3457
3458 // 4. Assemble the final 2-D lat/lon CV candidate vectors by checking if the corresponding 2-D lon of a 2-D lat shares
3459 // the same dimension and under the same group and if there is another pair of 2-D lat/lon under the same group.
3460 Obtain_2DLLCVar_Candidate(tempcvar_2dlat,tempcvar_2dlon,latlon2d_path_to_index);
3461
3462#if 0
3463for(vector<Var *>::iterator irv = tempcvar_2dlat.begin();irv != tempcvar_2dlat.end();++irv)
3464cerr<<"Final candidate 2-D Left lat variable full path is "<<(*irv)->fullpath <<endl;
3465for(vector<Var *>::iterator irv = tempcvar_2dlon.begin();irv != tempcvar_2dlon.end();++irv)
3466cerr<<"Final candidate 2-D Left lon variable full path is "<<(*irv)->fullpath <<endl;
3467#endif
3468
3469 // 5. Remove the 2-D lat/lon variables that are to be used as CVs from the vector that stores general variables
3470 // var2d_index, remembers the index of the 2-D lat/lon CVs in the original vector of vars.
3471 vector<int> var2d_index;
3472 for (map<string,int>::const_iterator it= latlon2d_path_to_index.begin();it!=latlon2d_path_to_index.end();++it)
3473 var2d_index.push_back(it->second);
3474
3475 Remove_2DLLCVar_Final_Candidate_from_Vars(var2d_index);
3476
3477 // 6. If we have 2-D CVs, COARDS should be turned off.
3478 if(tempcvar_2dlat.size()>0)
3479 iscoard = false;
3480
3481 // 7. Add the CVs based on the final 2-D lat/lon CV candidates.
3482 // We need to remember the dim names that the 2-D lat/lon CVs are associated with.
3483 set<string>dim_names_2d_cvs;
3484
3485 for(vector<Var *>::iterator irv = tempcvar_2dlat.begin();irv != tempcvar_2dlat.end();++irv){
3486 GMCVar *lat = new GMCVar(*irv);
3487 // Latitude is always corresponding to the first dimension.
3488 lat->cfdimname = (*irv)->getDimensions()[0]->name;
3489 dim_names_2d_cvs.insert(lat->cfdimname);
3490 lat->cvartype = CV_EXIST;
3491 lat->product_type = product_type;
3492 this->cvars.push_back(lat);
3493 }
3494 for(vector<Var *>::iterator irv = tempcvar_2dlon.begin();irv != tempcvar_2dlon.end();++irv){
3495 GMCVar *lon = new GMCVar(*irv);
3496 // Longitude is always corresponding to the second dimension.
3497 lon->cfdimname = (*irv)->getDimensions()[1]->name;
3498 dim_names_2d_cvs.insert(lon->cfdimname);
3499 lon->cvartype = CV_EXIST;
3500 lon->product_type = product_type;
3501 this->cvars.push_back(lon);
3502 }
3503
3504 // 8. Move the originally assigned 1-D CVs that are replaced by 2-D CVs back to the general variable list.
3505 // Also remove the CV created by the pure dimensions.
3506 // Dimension names are used to identify those 1-D CVs.
3507 for(vector<GMCVar*>::iterator ircv= this->cvars.begin();ircv !=this->cvars.end();) {
3508 if(1 == (*ircv)->rank) {
3509 if(dim_names_2d_cvs.find((*ircv)->cfdimname)!=dim_names_2d_cvs.end()) {
3510 if(CV_FILLINDEX == (*ircv)->cvartype) {// This is pure dimension
3511 delete(*ircv);
3512 ircv = this->cvars.erase(ircv);
3513 }
3514 else if(CV_EXIST == (*ircv)->cvartype) {// This var exists already
3515
3516 // Add this var. to the var list.
3517 Var *var = new Var(*ircv);
3518 this->vars.push_back(var);
3519
3520 // Remove this var. from the GMCVar list.
3521 delete(*ircv);
3522 ircv = this->cvars.erase(ircv);
3523
3524 }
3525 else {// the removed 1-D coordinate variable should be either the CV_FILLINDEX or CV_EXIST.
3526 if(CV_LAT_MISS == (*ircv)->cvartype)
3527 throw3("For the 2-D lat/lon case, the latitude dimension name ",(*ircv)->cfdimname, "is a coordinate variable of type CV_LAT_MISS");
3528 else if(CV_LON_MISS == (*ircv)->cvartype)
3529 throw3("For the 2-D lat/lon case, the latitude dimension name ",(*ircv)->cfdimname, "is a coordinate variable of type CV_LON_MISS");
3530 else if(CV_NONLATLON_MISS == (*ircv)->cvartype)
3531 throw3("For the 2-D lat/lon case, the latitude dimension name ",(*ircv)->cfdimname, "is a coordinate variable of type CV_NONLATLON_MISS");
3532 else if(CV_MODIFY == (*ircv)->cvartype)
3533 throw3("For the 2-D lat/lon case, the latitude dimension name ",(*ircv)->cfdimname, "is a coordinate variable of type CV_MODIFY");
3534 else if(CV_SPECIAL == (*ircv)->cvartype)
3535 throw3("For the 2-D lat/lon case, the latitude dimension name ",(*ircv)->cfdimname, "is a coordinate variable of type CV_SPECIAL");
3536 else
3537 throw3("For the 2-D lat/lon case, the latitude dimension name ",(*ircv)->cfdimname, "is a coordinate variable of type CV_UNSUPPORTED");
3538 }
3539
3540 }
3541 else
3542 ++ircv;
3543
3544 }
3545 else
3546 ++ircv;
3547
3548 }
3549
3550
3551#if 0
3552//if(iscoard == true)
3553//cerr<<"COARD is true"<<endl;
3554for(set<string>::iterator irs = grp_cv_paths.begin();irs != grp_cv_paths.end();++irs) {
3555cerr<<"group path is "<< (*irs)<<endl;
3556
3557}
3558#endif
3559
3560#if 0
3561//Print CVs
3562cerr<<"File name is "<< this->path <<endl;
3563cerr<<"CV names are the following "<<endl;
3564for (vector<GMCVar *>:: iterator i= this->cvars.begin(); i!=this->cvars.end(); ++i)
3565cerr<<(*i)->fullpath <<endl;
3566#endif
3567
3568
3569 // 9. release the resources allocated by the temporary vectors.
3570 release_standalone_GMCVar_vector(tempcvar_1dlat);
3571 release_standalone_GMCVar_vector(tempcvar_1dlon);
3572 release_standalone_var_vector(tempcvar_2dlat);
3573 release_standalone_var_vector(tempcvar_2dlon);
3574 }// if(false == Check_1DGeolocation_Dimscale())
3575#if 0
3576for (vector<GMCVar *>:: iterator i= this->cvars.begin(); i!=this->cvars.end(); ++i)
3577cerr<<(*i)->fullpath <<endl;
3578#endif
3579
3580}
3581
3582// If Check_1DGeolocation_Dimscale() is true, no need to build 2-D lat/lon coordinate variables.
3583// This function is introduced to avoid the performance penalty caused by handling the general 2-D lat/lon case.
3584bool GMFile::Check_1DGeolocation_Dimscale() {
3585
3586 BESDEBUG("h5", "Coming to Check_1DGeolocation_Dimscale()"<<endl);
3587 bool has_only_1d_geolocation_cv = false;
3588 bool has_1d_lat_cv_flag = false;
3589 bool has_1d_lon_cv_flag = false;
3590
3591 string lat_dimname;
3592 hsize_t lat_size = 0;
3593
3594 string lon_dimname;
3595 hsize_t lon_size = 0;
3596
3597 // We need to consider both 1-D lat/lon and the 1-D zonal average case(1-D lat only).
3598 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
3599 ircv != this->cvars.end(); ++ircv) {
3600 if((*ircv)->cvartype == CV_EXIST) {
3601 string attr_name ="units";
3602 string lat_unit_value = "degrees_north";
3603 string lon_unit_value = "degrees_east";
3604
3605 for(vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
3606 ira != (*ircv)->attrs.end();ira++) {
3607
3608 if(true == Is_Str_Attr(*ira,(*ircv)->fullpath,attr_name,lat_unit_value)) {
3609 lat_size = (*ircv)->getDimensions()[0]->size;
3610 lat_dimname = (*ircv)->getDimensions()[0]->name;
3611 has_1d_lat_cv_flag = true;
3612 break;
3613 }
3614 else if(true == Is_Str_Attr(*ira,(*ircv)->fullpath,attr_name,lon_unit_value)){
3615 lon_size = (*ircv)->getDimensions()[0]->size;
3616 lon_dimname = (*ircv)->getDimensions()[0]->name;
3617 has_1d_lon_cv_flag = true;
3618 break;
3619 }
3620 }
3621 }
3622 }
3623
3624 // If having 1-D lat/lon CVs, this is a good sign for only 1-D lat/lon CVs ,
3625 // just need to have a couple of checks.
3626 if(true == has_1d_lat_cv_flag ) {
3627
3628 if(true == has_1d_lon_cv_flag) {
3629
3630 // Come to the possible classic netCDF-4 case,
3631 if(0 == this->groups.size()) {
3632
3633 // Rarely happens when lat_size is the same as the lon_size.
3634 // However, still want to make sure there is a 2-D variable that uses both lat and lon dims.
3635 if(lat_size == lon_size) {
3636 bool var_has_latdim = false;
3637 bool var_has_londim = false;
3638 for (vector<Var *>::iterator irv = this->vars.begin();
3639 irv != this->vars.end(); ++irv) {
3640 if((*irv)->rank >= 2) {
3641 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
3642 ird !=(*irv)->dims.end();++ird) {
3643 if((*ird)->name == lat_dimname)
3644 var_has_latdim = true;
3645 else if((*ird)->name == lon_dimname)
3646 var_has_londim = true;
3647 }
3648 if(true == var_has_latdim && true == var_has_londim) {
3649 has_only_1d_geolocation_cv = true;
3650 break;
3651 }
3652 else {
3653 var_has_latdim = false;
3654 var_has_londim = false;
3655 }
3656 }
3657 }
3658 }
3659 else
3660 has_only_1d_geolocation_cv = true;
3661 }// if(0 == this->groups.size())
3662 else {
3663 // Multiple groups, need to check if having 2-D lat/lon pairs
3664 bool has_2d_latname_flag = false;
3665 bool has_2d_lonname_flag = false;
3666 for (vector<Var *>::iterator irv = this->vars.begin();
3667 irv != this->vars.end(); ++irv) {
3668 if((*irv)->rank == 2) {
3669
3670 //Note: When the 2nd parameter is true in the function Is_geolatlon, it checks the lat/latitude/Latitude
3671 if(true == Is_geolatlon((*irv)->name,true))
3672 has_2d_latname_flag = true;
3673
3674 //Note: When the 2nd parameter is false in the function Is_geolatlon, it checks the lon/longitude/Longitude
3675 else if(true == Is_geolatlon((*irv)->name,false))
3676 has_2d_lonname_flag = true;
3677
3678 if((true == has_2d_latname_flag) && (true == has_2d_lonname_flag))
3679 break;
3680 }
3681 }
3682
3683 if(has_2d_latname_flag != true || has_2d_lonname_flag != true) {
3684
3685 //Check if having the 2-D lat/lon by checking if having lat/lon CF units(lon's units: degrees_east lat's units: degrees_north)
3686 has_2d_latname_flag = false;
3687 has_2d_lonname_flag = false;
3688
3689 for (vector<Var *>::iterator irv = this->vars.begin();
3690 irv != this->vars.end(); ++irv) {
3691 if((*irv)->rank == 2) {
3692 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
3693 ira != (*irv)->attrs.end(); ++ira) {
3694
3695 if (false == has_2d_latname_flag) {
3696
3697 // When the third parameter of the function has_latlon_cf_units is set to true, it checks latitude
3698 has_2d_latname_flag = has_latlon_cf_units((*ira),(*irv)->fullpath,true);
3699 if(true == has_2d_latname_flag)
3700 break;
3701 else if(false == has_2d_lonname_flag) {
3702
3703 // When the third parameter of the function has_latlon_cf_units is set to false, it checks longitude
3704 has_2d_lonname_flag = has_latlon_cf_units((*ira),(*irv)->fullpath,false);
3705 if(true == has_2d_lonname_flag)
3706 break;
3707 }
3708 }
3709 else if(false == has_2d_lonname_flag) {
3710
3711 // Now has_2d_latname_flag is true, just need to check the has_2d_lonname_flag
3712 // When the third parameter of has_latlon_cf_units is set to false, it checks longitude
3713 has_2d_lonname_flag = has_latlon_cf_units((*ira),(*irv)->fullpath,false);
3714 if(true == has_2d_lonname_flag)
3715 break;
3716 }
3717 }
3718 if(true == has_2d_latname_flag && true == has_2d_lonname_flag)
3719 break;
3720 }
3721 }
3722 }// if(has_2d_latname_flag != true || has_2d_lonname_flag != true)
3723
3724 // If we cannot find either of 2-D any lat/lon variables, this file is treated as having only 1-D lat/lon.
3725 if(has_2d_latname_flag != true || has_2d_lonname_flag != true)
3726 has_only_1d_geolocation_cv = true;
3727 }
3728
3729 }//
3730 else {//Zonal average case, we do not need to find 2-D lat/lon CVs.
3731 has_only_1d_geolocation_cv = true;
3732 }
3733
3734 }
3735
3736#if 0
3737if(has_only_1d_geolocation_cv == true)
3738cerr <<"has only 1D lat/lon CVs. "<<endl;
3739else
3740cerr<<"Possibly has 2D lat/lon CVs. "<<endl;
3741#endif
3742
3743 return has_only_1d_geolocation_cv;
3744
3745}
3746
3747// Obtain the originally assigned 1-D lat/lon coordinate variables.
3748// This function should be used before generating any 2-D lat/lon CVs.
3749void GMFile::Obtain_1DLatLon_CVs(vector<GMCVar*> &cvar_1dlat,vector<GMCVar*> &cvar_1dlon) {
3750
3751 BESDEBUG("h5", "Coming to Obtain_1DLatLon_CVs()"<<endl);
3752 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
3753 ircv != this->cvars.end(); ++ircv) {
3754
3755 if((*ircv)->cvartype == CV_EXIST) {
3756
3757 string attr_name ="units";
3758 string lat_unit_value = "degrees_north";
3759 string lon_unit_value = "degrees_east";
3760
3761 for(vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
3762 ira != (*ircv)->attrs.end();ira++) {
3763
3764 // 1-D latitude
3765 if(true == Is_Str_Attr(*ira,(*ircv)->fullpath,attr_name,lat_unit_value)) {
3766 GMCVar *lat = new GMCVar(*ircv);
3767 lat->cfdimname = (*ircv)->getDimensions()[0]->name;
3768 lat->cvartype = (*ircv)->cvartype;
3769 lat->product_type = (*ircv)->product_type;
3770 cvar_1dlat.push_back(lat);
3771 }
3772 // 1-D longitude
3773 else if(true == Is_Str_Attr(*ira,(*ircv)->fullpath,attr_name,lon_unit_value)){
3774 GMCVar *lon = new GMCVar(*ircv);
3775 lon->cfdimname = (*ircv)->getDimensions()[0]->name;
3776 lon->cvartype = (*ircv)->cvartype;
3777 lon->product_type = (*ircv)->product_type;
3778 cvar_1dlon.push_back(lon);
3779 }
3780 }
3781 }// if((*ircv)->cvartype == CV_EXIST)
3782 }// for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
3783
3784}
3785
3786// Obtain all 2-D lat/lon variables. We first check the lat/latitude/Latitude names, if not found, we check if CF lat/lon units are present.
3787// Latitude variables are saved in the vector var_2dlat. Longitude variables are saved in the vector var_2dlon.
3788// We also remember the index of these lat/lon in the original var vector.
3789void GMFile::Obtain_2DLatLon_Vars(vector<Var*> &var_2dlat,vector<Var*> &var_2dlon,map<string,int> & latlon2d_path_to_index) {
3790
3791 BESDEBUG("h5", "Coming to Obtain_2DLatLon_Vars()"<<endl);
3792 for (vector<Var *>::iterator irv = this->vars.begin();
3793 irv != this->vars.end(); ++irv) {
3794 if((*irv)->rank == 2) {
3795
3796 //Note: When the 2nd parameter is true in the function Is_geolatlon, it checks the lat/latitude/Latitude
3797 if(true == Is_geolatlon((*irv)->name,true)) {
3798 Var *lat = new Var(*irv);
3799 var_2dlat.push_back(lat);
3800 latlon2d_path_to_index[(*irv)->fullpath]= distance(this->vars.begin(),irv);
3801 continue;
3802 }
3803 else {
3804
3805 bool has_2dlat = false;
3806 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
3807 ira != (*irv)->attrs.end(); ++ira) {
3808
3809 // When the third parameter of has_latlon_cf_units is set to true, it checks latitude
3810 if(true == has_latlon_cf_units((*ira),(*irv)->fullpath,true)) {
3811 Var *lat = new Var(*irv);
3812 var_2dlat.push_back(lat);
3813 latlon2d_path_to_index[(*irv)->fullpath] = distance(this->vars.begin(),irv);
3814 has_2dlat = true;
3815 break;
3816 }
3817 }
3818
3819 if(true == has_2dlat)
3820 continue;
3821 }
3822
3823 //Note: When the 2nd parameter is false in the function Is_geolatlon, it checks the lon/longitude/Longitude
3824 if(true == Is_geolatlon((*irv)->name,false)) {
3825 Var *lon = new Var(*irv);
3826 latlon2d_path_to_index[(*irv)->fullpath] = distance(this->vars.begin(),irv);
3827 var_2dlon.push_back(lon);
3828 }
3829 else {
3830 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
3831 ira != (*irv)->attrs.end(); ++ira) {
3832
3833 // When the third parameter of has_latlon_cf_units is set to false, it checks longitude
3834 if(true == has_latlon_cf_units((*ira),(*irv)->fullpath,false)) {
3835 Var *lon = new Var(*irv);
3836 latlon2d_path_to_index[(*irv)->fullpath] = distance(this->vars.begin(),irv);
3837 var_2dlon.push_back(lon);
3838 break;
3839 }
3840 }
3841 }
3842 } // if((*irv)->rank == 2)
3843 } // for (vector<Var *>::iterator irv
3844}
3845
3846// Sequeeze the 2-D lat/lon vectors by removing the ones that share the same dims with 1-D lat/lon CVs.
3847// The latlon2d_path_to_index map also needs to be updated.
3848void GMFile::Obtain_2DLLVars_With_Dims_not_1DLLCVars(vector<Var*> &var_2dlat,
3849 vector<Var*> &var_2dlon,
3850 vector<GMCVar*> &cvar_1dlat,
3851 vector<GMCVar*> &cvar_1dlon,
3852 map<string,int> &latlon2d_path_to_index) {
3853
3854 BESDEBUG("h5", "Coming to Obtain_2DLLVars_With_Dims_not_1DLLCVars()"<<endl);
3855 // First latitude at var_2dlat
3856 for(vector<Var *>::iterator irv = var_2dlat.begin();irv != var_2dlat.end();) {
3857 bool remove_2dlat = false;
3858 for(vector<GMCVar *>::iterator ircv = cvar_1dlat.begin();ircv != cvar_1dlat.end();++ircv) {
3859 for (vector<Dimension*>::iterator ird = (*irv)->dims.begin();
3860 ird!=(*irv)->dims.end(); ++ird) {
3861 if((*ird)->name == (*ircv)->getDimensions()[0]->name &&
3862 (*ird)->size == (*ircv)->getDimensions()[0]->size) {
3863 latlon2d_path_to_index.erase((*irv)->fullpath);
3864 delete(*irv);
3865 irv = var_2dlat.erase(irv);
3866 remove_2dlat = true;
3867 break;
3868 }
3869 }
3870 if(true == remove_2dlat)
3871 break;
3872 }
3873
3874 if(false == remove_2dlat)
3875 ++irv;
3876 }// for(vector<Var *>::iterator irv = var_2dlat.begin()
3877
3878 // Second longitude
3879 for(vector<Var *>::iterator irv = var_2dlon.begin();irv != var_2dlon.end();) {
3880 bool remove_2dlon = false;
3881 for(vector<GMCVar *>::iterator ircv = cvar_1dlon.begin();ircv != cvar_1dlon.end();++ircv) {
3882 for (vector<Dimension*>::iterator ird = (*irv)->dims.begin();
3883 ird!=(*irv)->dims.end(); ++ird) {
3884 if((*ird)->name == (*ircv)->getDimensions()[0]->name &&
3885 (*ird)->size == (*ircv)->getDimensions()[0]->size) {
3886 latlon2d_path_to_index.erase((*irv)->fullpath);
3887 delete(*irv);
3888 irv = var_2dlon.erase(irv);
3889 remove_2dlon = true;
3890 break;
3891 }
3892 }
3893 if(true == remove_2dlon)
3894 break;
3895 }
3896
3897 if(false == remove_2dlon)
3898 ++irv;
3899 } // for(vector<Var *>::iterator irv = var_2dlon.begin()
3900
3901}
3902
3903//Out of the collected 2-D lat/lon variables, we will select the final qualified 2-D lat/lon as CVs.
3904void GMFile::Obtain_2DLLCVar_Candidate(vector<Var*> &var_2dlat,
3905 vector<Var*> &var_2dlon,
3906 map<string,int>& latlon2d_path_to_index) {
3907 BESDEBUG("h5", "Coming to Obtain_2DLLCVar_Candidate()"<<endl);
3908 // First check 2-D lat, see if we have the corresponding 2-D lon(same dims, under the same group).
3909 // If no, remove that lat from the vector.
3910 vector<string> lon2d_group_paths;
3911
3912 for(vector<Var *>::iterator irv_2dlat = var_2dlat.begin();irv_2dlat !=var_2dlat.end();) {
3913 for(vector<Var *>::iterator irv_2dlon = var_2dlon.begin();irv_2dlon != var_2dlon.end();++irv_2dlon) {
3914 if(((*irv_2dlat)->getDimensions()[0]->name == (*irv_2dlon)->getDimensions()[0]->name) &&
3915 ((*irv_2dlat)->getDimensions()[0]->size == (*irv_2dlon)->getDimensions()[0]->size) &&
3916 ((*irv_2dlat)->getDimensions()[1]->name == (*irv_2dlon)->getDimensions()[1]->name) &&
3917 ((*irv_2dlat)->getDimensions()[1]->size == (*irv_2dlon)->getDimensions()[1]->size))
3918 lon2d_group_paths.push_back(HDF5CFUtil::obtain_string_before_lastslash((*irv_2dlon)->fullpath));
3919 }
3920 // Doesn't find any lons that shares the same dims,remove this lat from the 2dlat vector,
3921 // also update the latlon2d_path_to_index map
3922 if(0 == lon2d_group_paths.size()) {
3923 latlon2d_path_to_index.erase((*irv_2dlat)->fullpath);
3924 delete(*irv_2dlat);
3925 irv_2dlat = var_2dlat.erase(irv_2dlat);
3926 }
3927 else {// Find lons,check if they are under the same group
3928 //string lat2d_group_path = (*irv_2dlat)->fullpath.substr(0,(*irv_2dlat)->fullpath.find_last_of("/"));
3929 string lat2d_group_path = HDF5CFUtil::obtain_string_before_lastslash((*irv_2dlat)->fullpath);
3930
3931 // Check how many lon2d shares the same group with the lat2d
3932 short lon2d_has_lat2d_group_path_flag = 0;
3933 for(vector<string>::iterator ivs = lon2d_group_paths.begin();ivs!=lon2d_group_paths.end();++ivs) {
3934 if((*ivs)==lat2d_group_path)
3935 lon2d_has_lat2d_group_path_flag++;
3936 }
3937
3938 // No lon2d shares the same group with the lat2d, remove this lat2d
3939 if(0 == lon2d_has_lat2d_group_path_flag) {
3940 latlon2d_path_to_index.erase((*irv_2dlat)->fullpath);
3941 delete(*irv_2dlat);
3942 irv_2dlat = var_2dlat.erase(irv_2dlat);
3943 }
3944 // Only one lon2d, yes, keep it.
3945 else if (1== lon2d_has_lat2d_group_path_flag) {
3946 ++irv_2dlat;
3947 }
3948 // More than 1 lon2d, we will remove the lat2d, but save the group path so that we may
3949 // flatten the variable path stored in the coordinates attribute under this group.
3950 else {
3951 // Save the group path for the future use.
3952 grp_cv_paths.insert(lat2d_group_path);
3953 latlon2d_path_to_index.erase((*irv_2dlat)->fullpath);
3954 delete(*irv_2dlat);
3955 irv_2dlat = var_2dlat.erase(irv_2dlat);
3956 }
3957 }
3958
3959 //Clear the vector that stores the same dim. since it is only applied to this lat,
3960 lon2d_group_paths.clear();
3961 }
3962
3963#if 0
3964for(vector<Var *>::iterator irv_2dlat = var_2dlat.begin();irv_2dlat !=var_2dlat.end();++irv_2dlat)
3965cerr<<"2 left 2-D lat variable full path is: "<<(*irv_2dlat)->fullpath <<endl;
3966#endif
3967
3968
3969 // Second check 2-D lon, see if we have the corresponding 2-D lat(same dims, under the same group).
3970 // If no, remove that lon from the vector.
3971 vector<string> lat2d_group_paths;
3972
3973 // Check the longitude
3974 for(vector<Var *>::iterator irv_2dlon = var_2dlon.begin();irv_2dlon !=var_2dlon.end();) {
3975 for(vector<Var *>::iterator irv_2dlat = var_2dlat.begin();irv_2dlat != var_2dlat.end();++irv_2dlat) {
3976 if(((*irv_2dlat)->getDimensions()[0]->name == (*irv_2dlon)->getDimensions()[0]->name) &&
3977 ((*irv_2dlat)->getDimensions()[0]->size == (*irv_2dlon)->getDimensions()[0]->size) &&
3978 ((*irv_2dlat)->getDimensions()[1]->name == (*irv_2dlon)->getDimensions()[1]->name) &&
3979 ((*irv_2dlat)->getDimensions()[1]->size == (*irv_2dlon)->getDimensions()[1]->size))
3980 lat2d_group_paths.push_back(HDF5CFUtil::obtain_string_before_lastslash((*irv_2dlat)->fullpath));
3981 //lat2d_group_paths.push_back((*irv_2dlat)->fullpath.substr(0,(*irv_2dlat)->fullpath.find_last_of("/")));
3982 }
3983 // Doesn't find any lats that shares the same dims,remove this lon from this vector
3984 if(0 == lat2d_group_paths.size()) {
3985 latlon2d_path_to_index.erase((*irv_2dlon)->fullpath);
3986 delete(*irv_2dlon);
3987 irv_2dlon = var_2dlon.erase(irv_2dlon);
3988 }
3989 else {
3990 string lon2d_group_path = HDF5CFUtil::obtain_string_before_lastslash((*irv_2dlon)->fullpath);
3991
3992 // Check how many lat2d shares the same group with the lon2d
3993 short lat2d_has_lon2d_group_path_flag = 0;
3994 for(vector<string>::iterator ivs = lat2d_group_paths.begin();ivs!=lat2d_group_paths.end();++ivs) {
3995 if((*ivs)==lon2d_group_path)
3996 lat2d_has_lon2d_group_path_flag++;
3997 }
3998
3999 // No lat2d shares the same group with the lon2d, remove this lon2d
4000 if(0 == lat2d_has_lon2d_group_path_flag) {
4001 latlon2d_path_to_index.erase((*irv_2dlon)->fullpath);
4002 delete(*irv_2dlon);
4003 irv_2dlon = var_2dlon.erase(irv_2dlon);
4004 }
4005 // Only one lat2d shares the same group with the lon2d, yes, keep it.
4006 else if (1== lat2d_has_lon2d_group_path_flag) {
4007 ++irv_2dlon;
4008 }
4009 // more than 1 lat2d, we will remove the lon2d, but save the group path so that we can
4010 // change the coordinates attribute for variables under this group later.
4011 else {
4012 // Save the group path for future "coordinates" modification.
4013 grp_cv_paths.insert(lon2d_group_path);
4014 latlon2d_path_to_index.erase((*irv_2dlon)->fullpath);
4015 delete(*irv_2dlon);
4016 irv_2dlon = var_2dlon.erase(irv_2dlon);
4017 }
4018 }
4019 //Clear the vector that stores the same dim. since it is only applied to this lon,
4020 lat2d_group_paths.clear();
4021 }
4022#if 0
4023for(vector<Var*>::iterator itv = var_2dlat.begin(); itv!= var_2dlat.end();++itv) {
4024cerr<<"Before unique, 2-D CV latitude name is "<<(*itv)->fullpath <<endl;
4025}
4026for(vector<Var*>::iterator itv = var_2dlon.begin(); itv!= var_2dlon.end();++itv) {
4027cerr<<"Before unique, 2-D CV longitude name is "<<(*itv)->fullpath <<endl;
4028}
4029#endif
4030
4031 // Final check var_2dlat and var_2dlon to remove non-qualified CVs.
4032 Obtain_unique_2dCV(var_2dlat,latlon2d_path_to_index);
4033 Obtain_unique_2dCV(var_2dlon,latlon2d_path_to_index);
4034#if 0
4035for(vector<Var*>::iterator itv = var_2dlat.begin(); itv!= var_2dlat.end();++itv) {
4036cerr<<"2-D CV latitude name is "<<(*itv)->fullpath <<endl;
4037}
4038for(vector<Var*>::iterator itv = var_2dlon.begin(); itv!= var_2dlon.end();++itv) {
4039cerr<<"2-D CV longitude name is "<<(*itv)->fullpath <<endl;
4040}
4041#endif
4042
4043 // This is to serve as a sanity check. This can help us find bugs in the first place.
4044 if(var_2dlat.size() != var_2dlon.size()) {
4045 throw1("Error in generating 2-D lat/lon CVs. The size of 2d-lat should be the same as that of 2d-lon.");
4046 }
4047}
4048
4049// If two vars in the 2-D lat or 2-D lon CV candidate vector share the same dim. , these two vars cannot be CVs.
4050// The group they belong to is the group candidate that the coordinates attribute of the variable under that group may be modified..
4051void GMFile::Obtain_unique_2dCV(vector<Var*> &var_ll,map<string,int>&latlon2d_path_to_index){
4052
4053 BESDEBUG("h5", "Coming to Obtain_unique_2dCV()"<<endl);
4054 vector<bool> var_share_dims(var_ll.size(),false);
4055
4056 for(unsigned int i = 0; i <var_ll.size();i++) {
4057
4058 // obtain the path of var_ll
4059 string var_ll_i_path = HDF5CFUtil::obtain_string_before_lastslash(var_ll[i]->fullpath);
4060
4061 // Check if two vars share the same dims.
4062 for(unsigned int j = i+1; j<var_ll.size();j++) {
4063 if((var_ll[i]->getDimensions()[0]->name == var_ll[j]->getDimensions()[0]->name)
4064 ||(var_ll[i]->getDimensions()[0]->name == var_ll[j]->getDimensions()[1]->name)
4065 ||(var_ll[i]->getDimensions()[1]->name == var_ll[j]->getDimensions()[0]->name)
4066 ||(var_ll[i]->getDimensions()[1]->name == var_ll[j]->getDimensions()[1]->name)){
4067 string var_ll_j_path = HDF5CFUtil::obtain_string_before_lastslash(var_ll[j]->fullpath);
4068
4069 // Compare var_ll_i_path and var_ll_j_path,only set the child group path be true and remember the path.
4070 // The variable at the parent group can be the coordinate variable.
4071 // Obtain the string size,
4072 // compare the string size, long.compare(0,shortlength,short)==0,
4073 // yes, save the long path(child group path), set the long path one true. Else save two paths, set both true
4074 if(var_ll_i_path.size() > var_ll_j_path.size()) {
4075
4076 // If var_ll_j_path is the parent group of var_ll_i_path,
4077 // set the shared dim. be true for the child group only,remember the path.
4078 if(var_ll_i_path.compare(0,var_ll_j_path.size(),var_ll_j_path)==0) {
4079 var_share_dims[i] = true;
4080 grp_cv_paths.insert(var_ll_i_path);
4081 }
4082 else {// Save both as shared, they cannot be CVs.
4083 var_share_dims[i] = true;
4084 var_share_dims[j] = true;
4085
4086 grp_cv_paths.insert(var_ll_i_path);
4087 grp_cv_paths.insert(var_ll_j_path);
4088 }
4089 }
4090 else if (var_ll_i_path.size() == var_ll_j_path.size()) {// Share the same group, remember both group paths.
4091 var_share_dims[i] = true;
4092 var_share_dims[j] = true;
4093 if(var_ll_i_path == var_ll_j_path)
4094 grp_cv_paths.insert(var_ll_i_path);
4095 else {
4096 grp_cv_paths.insert(var_ll_i_path);
4097 grp_cv_paths.insert(var_ll_j_path);
4098 }
4099 }
4100 else {
4101 // var_ll_i_path is the parent group of var_ll_j_path,
4102 // set the shared dim. be true for the child group,remember the path.
4103 if(var_ll_j_path.compare(0,var_ll_i_path.size(),var_ll_i_path)==0) {
4104 var_share_dims[j] = true;
4105 grp_cv_paths.insert(var_ll_j_path);
4106 }
4107 else {// Save both as shared, they cannot be CVs.
4108 var_share_dims[i] = true;
4109 var_share_dims[j] = true;
4110
4111 grp_cv_paths.insert(var_ll_i_path);
4112 grp_cv_paths.insert(var_ll_j_path);
4113
4114 }
4115 }
4116 }// if((var_ll[i]->getDimensions()[0]->name == var_ll[j]->getDimensions()[0]->name)
4117 }// for(int j = i+1; j<var_ll.size();j++)
4118 }// for( int i = 0; i <var_ll.size();i++)
4119
4120 // Remove the shared 2-D lat/lon CVs from the 2-D lat/lon CV candidates.
4121 int var_index = 0;
4122 for(vector<Var*>::iterator itv = var_ll.begin(); itv!= var_ll.end();) {
4123 if(true == var_share_dims[var_index]) {
4124 latlon2d_path_to_index.erase((*itv)->fullpath);
4125 delete(*itv);
4126 itv = var_ll.erase(itv);
4127 }
4128 else {
4129 ++itv;
4130 }
4131 ++var_index;
4132 }
4133
4134}
4135
4136// When promoting a 2-D lat or lon to a coordinate variable, we need to remove them from the general variable vector.
4137void GMFile::Remove_2DLLCVar_Final_Candidate_from_Vars(vector<int> &var2d_index) {
4138
4139 BESDEBUG("h5", "Coming to Remove_2DLLCVar_Final_Candidate_from_Vars()"<<endl);
4140 //Sort the 2-D lat/lon var index according to the ascending order before removing the 2-D lat/lon vars
4141 sort(var2d_index.begin(),var2d_index.end());
4142 vector<Var *>::iterator it = this->vars.begin();
4143
4144 // This is a performance optimiziation operation.
4145 // We find it is typical for swath files that have many many general variables but only have very few lat/lon CVs.
4146 // To reduce the looping through all variables and comparing the fullpath(string), we use index and remember
4147 // the position of 2-D CVs in the iterator. In this way, only a few operations are needed.
4148 for (unsigned int i = 0; i <var2d_index.size();i++) {
4149 if ( i == 0)
4150 advance(it,var2d_index[i]);
4151 else
4152 advance(it,var2d_index[i]-var2d_index[i-1]-1);
4153
4154 if(it == this->vars.end())
4155 throw1("Out of range to obtain 2D lat/lon variables");
4156 else {
4157 delete(*it);
4158 it = this->vars.erase(it);
4159 }
4160 }
4161}
4162
4163//This function is for generating the coordinates attribute for the 2-D lat/lon.
4164//It will check if this var can keep its "coordinates" attribute rather than rebuilding it.
4165//This function is used by Handle_Coor_Attr().
4166bool GMFile::Check_Var_2D_CVars(Var *var) {
4167
4168 BESDEBUG("h5", "Coming to Check_Var_2D_CVars()"<<endl);
4169 bool ret_value = true;
4170 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
4171 ircv != this->cvars.end(); ++ircv) {
4172 if((*ircv)->rank==2) {
4173 short first_dim_index = 0;
4174 short first_dim_times = 0;
4175 short second_dim_index = 0;
4176 short second_dim_times = 0;
4177 for (vector<Dimension *>::iterator ird = var->dims.begin();
4178 ird != var->dims.end(); ++ird) {
4179 if((*ird)->name == ((*ircv)->getDimensions()[0])->name) {
4180 first_dim_index = distance(var->dims.begin(),ird);
4181 first_dim_times++;
4182 }
4183 else if((*ird)->name == ((*ircv)->getDimensions()[1])->name) {
4184 second_dim_index = distance(var->dims.begin(),ird);
4185 second_dim_times++;
4186 }
4187 }
4188 // The 2-D CV dimensions must only appear once as the dimension of the variable
4189 // It also must follow the dimension order of the 2-D lat/lon dimensions.
4190 if(first_dim_times == 1 && second_dim_times == 1) {
4191 if(first_dim_index < second_dim_index) {
4192 ret_value = false;
4193 break;
4194 }
4195 }
4196 }
4197 }
4198 return ret_value;
4199
4200}
4201
4202// This function flattens the variable path in the "coordinates" attribute.
4203// It is also used by Handle_Coor_Attr().
4204bool GMFile::Flatten_VarPath_In_Coordinates_Attr(Var *var) {
4205
4206 BESDEBUG("h5", "Coming to Flatten_VarPath_In_Coordinates_Attr()"<<endl);
4207 string co_attrname = "coordinates";
4208 bool need_flatten_coor_attr = false;
4209 string orig_coor_value;
4210 string flatten_coor_value;
4211 // Assume the separator is always a space.
4212 char sc = ' ';
4213 char backslash = '/';
4214
4215 for (vector<Attribute *>:: iterator ira =var->attrs.begin(); ira !=var->attrs.end();) {
4216
4217 // We only check the original attribute name
4218 // Remove the original "coordinates" attribute.
4219 // There is a case that the "coordinates" attribute doesn't need to be flattened.
4220 // We will skip this case. This is necessary since the "coordinates" may be revised
4221 // to add a path to follow the CF. Without skipping the case, the "coordinates" is
4222 // actually not handled but "makes the impression" it is handled. That makes the
4223 // this case ignored when the EnableCoorattrAddPath BES key is supposed to work on.
4224 // https://bugs.earthdata.nasa.gov/browse/HDFFEATURE-45
4225 if((*ira)->name == co_attrname) {
4226 Retrieve_H5_Attr_Value((*ira),var->fullpath);
4227 string orig_attr_value((*ira)->value.begin(),(*ira)->value.end());
4228 if(orig_attr_value.find_first_of(backslash)!=string::npos){
4229 orig_coor_value = orig_attr_value;
4230 need_flatten_coor_attr = true;
4231 delete(*ira);
4232 ira = var->attrs.erase(ira);
4233 }
4234 break;
4235 }
4236 else
4237 ++ira;
4238 }
4239
4240 if(true == need_flatten_coor_attr) {
4241
4242 // We need to loop through each element in the "coordinates".
4243 size_t ele_start_pos = 0;
4244 size_t cur_pos = orig_coor_value.find_first_of(sc);
4245 while(cur_pos !=string::npos) {
4246 string tempstr = orig_coor_value.substr(ele_start_pos,cur_pos-ele_start_pos);
4247 tempstr = get_CF_string(tempstr);
4248 flatten_coor_value += tempstr + sc;
4249 ele_start_pos = cur_pos+1;
4250 cur_pos = orig_coor_value.find_first_of(sc,cur_pos+1);
4251 }
4252 // Only one element
4253 if(ele_start_pos == 0)
4254 flatten_coor_value = get_CF_string(orig_coor_value);
4255 else // Add the last element
4256 flatten_coor_value += get_CF_string(orig_coor_value.substr(ele_start_pos));
4257
4258 // Generate the new "coordinates" attribute.
4259 Attribute *attr = new Attribute();
4260 Add_Str_Attr(attr,co_attrname,flatten_coor_value);
4261 var->attrs.push_back(attr);
4262 var->coord_attr_add_path = false;
4263
4264 }
4265
4266 return true;
4267
4268}
4269// This function flattens the variable path in the "coordinates" attribute for hybrid EOS5.
4270// Will implement it later.
4271// It is also used by Handle_Coor_Attr().
4272#if 0
4273bool GMFile::Flatten_VarPath_In_Coordinates_Attr_EOS5(Var *var) {
4274
4275 BESDEBUG("h5", "Coming to Flatten_VarPath_In_Coordinates_Attr_EOS5()"<<endl);
4276 string co_attrname = "coordinates";
4277 bool has_coor_attr = false;
4278 string orig_coor_value;
4279 string flatten_coor_value;
4280 // Assume the separator is always a space.
4281 char sc = ' ';
4282
4283 for (vector<Attribute *>:: iterator ira =var->attrs.begin(); ira !=var->attrs.end();) {
4284
4285 // We only check the original attribute name
4286 // Remove the original "coordinates" attribute.
4287 if((*ira)->name == co_attrname) {
4288 Retrieve_H5_Attr_Value((*ira),var->fullpath);
4289
4290 string orig_attr_value((*ira)->value.begin(),(*ira)->value.end());
4291 orig_coor_value = orig_attr_value;
4292 has_coor_attr = true;
4293 delete(*ira);
4294 ira = var->attrs.erase(ira);
4295 break;
4296 }
4297 else
4298 ++ira;
4299 }
4300
4301 if(true == has_coor_attr) {
4302
4303 // We need to loop through each element in the "coordinates".
4304 // For EOS5: we need to find the swath name.
4305 size_t ele_start_pos = 0;
4306// cerr<<"orig_coor_value is "<<orig_coor_value <<endl;
4307 size_t cur_pos = orig_coor_value.find_first_of(sc);
4308 while(cur_pos !=string::npos) {
4309 string tempstr = orig_coor_value.substr(ele_start_pos,cur_pos-ele_start_pos);
4310 // Find the swath name
4311 // tempstr = "swath name" +"_"+tempstr;
4312 tempstr = get_CF_string(tempstr);
4313 flatten_coor_value += tempstr + sc;
4314 ele_start_pos = cur_pos+1;
4315 cur_pos = orig_coor_value.find_first_of(sc,cur_pos+1);
4316 }
4317 // Only one element
4318 if(ele_start_pos == 0) {
4319 // Find the swath name
4320 // tempstr = "swath name" +"_"+tempstr;
4321 flatten_coor_value = get_CF_string(tempstr);
4322 }
4323 else // Add the last element
4324 flatten_coor_value += get_CF_string(orig_coor_value.substr(ele_start_pos));
4325
4326 // Generate the new "coordinates" attribute.
4327 Attribute *attr = new Attribute();
4328 Add_Str_Attr(attr,co_attrname,flatten_coor_value);
4329 var->attrs.push_back(attr);
4330 }
4331
4332 return true;
4333
4334}
4335#endif
4336
4337
4338// The following two routines only handle one 2-D lat/lon CVs. It is replaced by the more general
4339// multi 2-D lat/lon CV routines. Leave it here just for references.
4340#if 0
4341bool GMFile::Check_2DLatLon_Dimscale(string & latname, string &lonname) {
4342
4343 // New code to support 2-D lat/lon, still in development.
4344 // Need to handle 2-D latitude and longitude cases.
4345 // 1. Searching only the coordinate variables and if getting either of the following, keep the current way,
4346 // (A) GMcvar no CV_FILLINDEX:(The 2-D latlon case should have fake CVs)
4347 // (B) CV_EXIST: Attributes contain units and units value is degrees_east or degrees_north(have lat/lon)
4348 // (B) CV_EXIST: variables have name pair{lat/latitude/Latitude,lon/longitude/Longitude}(have lat/lon)
4349 //
4350 // 2. if not 1), searching all the variables and see if finding variables {lat/latitude/Latitude,lon/longitude/Longitude};
4351 // If finding {lat/lon},{latitude,longitude},{latitude,Longitude} pair,
4352 // if the number of dimension of either variable is not 2, keep the current way.
4353 // else check if the dimension name of latitude and longitude are the same, not, keep the current way
4354 // check the units of this CV pair, if units of the latitude is not degrees_north,
4355 // change it to degrees_north.
4356 // if units of the longitude is not degrees_east, change it to degrees_east.
4357 // make iscoard false.
4358
4359 bool latlon_2d_cv_check1 = false;
4360
4361 // Some products(TOM MEaSURE) provide the true dimension scales for 2-D lat,lon. So relax this check.
4362 latlon_2d_cv_check1 = true;
4363#if 0
4364 // If having 2-D lat/lon, the corresponding dimension must be pure and the CV type must be FILLINDEX.
4365 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
4366 ircv != this->cvars.end(); ++ircv) {
4367 if((*ircv)->cvartype == CV_FILLINDEX){
4368 latlon_2d_cv_check1 = true;
4369 break;
4370 }
4371 }
4372#endif
4373
4374 bool latlon_2d_cv_check2 = true;
4375
4376 // There may still not be 2-D lat/lon. Check the units attributes and lat/lon pairs.
4377 if(true == latlon_2d_cv_check1) {
4378 BESDEBUG("h5","Coming to check if having 2d latlon coordinates for a netCDF-4 like product. "<<endl);
4379
4380 // check if units attribute values have CF lat/lon units "degrees_north" or "degrees_east".
4381 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
4382 ircv != this->cvars.end(); ++ircv) {
4383 if((*ircv)->cvartype == CV_EXIST) {
4384 for(vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
4385 ira != (*ircv)->attrs.end();ira++) {
4386 string attr_name ="units";
4387 string lat_unit_value = "degrees_north";
4388 string lon_unit_value = "degrees_east";
4389
4390 // Considering the cross-section case, either is fine.
4391 if((true == Is_Str_Attr(*ira,(*ircv)->fullpath,attr_name,lat_unit_value)) ||
4392 (true == Is_Str_Attr(*ira,(*ircv)->fullpath,attr_name,lon_unit_value))) {
4393 latlon_2d_cv_check2= false;
4394 break;
4395 }
4396 }
4397 }
4398
4399 if(false == latlon_2d_cv_check2)
4400 break;
4401 }
4402 }
4403
4404 bool latlon_2d_cv_check3 = true;
4405
4406 // Even we cannot find the CF lat/lon attributes, we may still find lat/lon etc pairs.
4407 if(true == latlon_2d_cv_check1 && true == latlon_2d_cv_check2) {
4408
4409 short latlon_flag = 0;
4410 short LatLon_flag = 0;
4411 short latilong_flag = 0;
4412
4413 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
4414 ircv != this->cvars.end(); ++ircv) {
4415 if((*ircv)->cvartype == CV_EXIST) {
4416 if((*ircv)->name == "lat")
4417 latlon_flag++;
4418 else if((*ircv)->name == "lon")
4419 latlon_flag++;
4420 else if((*ircv)->name == "latitude")
4421 latilong_flag++;
4422 else if((*ircv)->name == "longitude")
4423 latilong_flag++;
4424 else if((*ircv)->name == "Latitude")
4425 LatLon_flag++;
4426 else if((*ircv)->name == "Longitude")
4427 LatLon_flag++;
4428 }
4429
4430 }
4431 if((2== latlon_flag) || (2 == latilong_flag) || (2 == LatLon_flag ))
4432 latlon_2d_cv_check3 = false;
4433 }
4434
4435 bool latlon_2d = false;
4436 short latlon_flag = 0;
4437 string latdim1,latdim2,londim1,londim2;
4438
4439 short LatLon_flag = 0;
4440 string Latdim1,Latdim2,Londim1,Londim2;
4441
4442 short latilong_flag = 0;
4443 string latidim1,latidim2,longdim1,longdim2;
4444
4445
4446 // Final check, we need to check if we have 2-D {lat/latitude/Latitude, lon/longitude/Longitude}
4447 // in the general variable list.
4448 // Here, depending on the future support, lat/lon pairs with other names(cell_lat,cell_lon etc) may be supported.
4449 // KY 2015-12-03
4450 if(true == latlon_2d_cv_check1 && true == latlon_2d_cv_check2 && true == latlon_2d_cv_check3) {
4451
4452 for (vector<Var *>::iterator irv = this->vars.begin();
4453 irv != this->vars.end(); ++irv) {
4454
4455 //
4456 if((*irv)->rank == 2) {
4457 if((*irv)->name == "lat") {
4458 latlon_flag++;
4459 latdim1 = (*irv)->getDimensions()[0]->name;
4460 latdim2 = (*irv)->getDimensions()[1]->name;
4461
4462 }
4463 else if((*irv)->name == "lon") {
4464 latlon_flag++;
4465 londim1 = (*irv)->getDimensions()[0]->name;
4466 londim2 = (*irv)->getDimensions()[1]->name;
4467 }
4468 else if((*irv)->name == "latitude"){
4469 latilong_flag++;
4470 latidim1 = (*irv)->getDimensions()[0]->name;
4471 latidim2 = (*irv)->getDimensions()[1]->name;
4472 }
4473 else if((*irv)->name == "longitude"){
4474 latilong_flag++;
4475 longdim1 = (*irv)->getDimensions()[0]->name;
4476 longdim2 = (*irv)->getDimensions()[1]->name;
4477
4478 }
4479 else if((*irv)->name == "Latitude"){
4480 LatLon_flag++;
4481 Latdim1 = (*irv)->getDimensions()[0]->name;
4482 Latdim2 = (*irv)->getDimensions()[1]->name;
4483
4484 }
4485 else if((*irv)->name == "Longitude"){
4486 LatLon_flag++;
4487 Londim1 = (*irv)->getDimensions()[0]->name;
4488 Londim2 = (*irv)->getDimensions()[1]->name;
4489 }
4490
4491 }
4492 }
4493
4494 // Here we ensure that only one lat/lon(lati/long,Lati/Long) is in the file.
4495 // If we find >=2 pairs lat/lon and latitude/longitude, or Latitude/Longitude,
4496 // we will not treat this as a 2-D latlon Dimscale case. The data producer
4497 // should correct their mistakes.
4498 if(2 == latlon_flag) {
4499 if((2 == latilong_flag) || ( 2 == LatLon_flag))
4500 latlon_2d = false;
4501 else if((latdim1 == londim1) && (latdim2 == londim2)) {
4502 latname = "lat";
4503 lonname = "lon";
4504 latlon_2d = true;
4505 }
4506 }
4507 else if ( 2 == latilong_flag) {
4508 if( 2 == LatLon_flag)
4509 latlon_2d = false;
4510 else if ((latidim1 == longdim1) ||(latidim2 == longdim2)) {
4511 latname = "latitude";
4512 lonname = "longitude";
4513 latlon_2d = true;
4514 }
4515 }
4516 else if (2 == LatLon_flag){
4517 if ((Latdim1 == Londim1) ||(Latdim2 == Londim2)) {
4518 latname = "Latitude";
4519 lonname = "Longitude";
4520 latlon_2d = true;
4521 }
4522 }
4523 }
4524
4525 return latlon_2d;
4526}
4527
4528
4529// Update the coordinate variables for files that use HDF5 dimension scales and have 2-D lat/lon.
4530void GMFile::Update_2DLatLon_Dimscale_CV(const string &latname,const string &lonname) {
4531
4532 iscoard = false;
4533
4534 // Update latitude.
4535 for (vector<Var *>::iterator irv = this->vars.begin();
4536 irv != this->vars.end(); ++irv) {
4537
4538 if((*irv)->rank == 2) {
4539
4540 // Find 2-D latitude
4541 if((*irv)->name == latname) {
4542
4543 // Obtain the first dimension of this variable
4544 string latdim0 = (*irv)->getDimensions()[0]->name;
4545//cerr<<"latdim0 is "<<latdim0 <<endl;
4546
4547 // Remove the CV corresponding to latdim0
4548 for (vector<GMCVar *>:: iterator i= this->cvars.begin(); i!=this->cvars.end(); ) {
4549 if((*i)->cfdimname == latdim0) {
4550 if(CV_FILLINDEX == (*i)->cvartype) {
4551 delete(*i);
4552 i = this->cvars.erase(i);
4553 }
4554 else if(CV_EXIST == (*i)->cvartype) {
4555 // Add this var. to the var list.
4556 Var *var = new Var(*i);
4557 this->vars.push_back(var);
4558 // Remove this var. from the GMCVar list.
4559 delete(*i);
4560 i = this->cvars.erase(i);
4561
4562 }
4563 else {// the latdimname should be either the CV_FILLINDEX or CV_EXIST.
4564 if(CV_LAT_MISS == (*i)->cvartype)
4565 throw3("For the 2-D lat/lon case, the latitude dimension name ",latdim0, "is a coordinate variable of type CV_LAT_MISS");
4566 else if(CV_LON_MISS == (*i)->cvartype)
4567 throw3("For the 2-D lat/lon case, the latitude dimension name ",latdim0, "is a coordinate variable of type CV_LON_MISS");
4568 else if(CV_NONLATLON_MISS == (*i)->cvartype)
4569 throw3("For the 2-D lat/lon case, the latitude dimension name ",latdim0, "is a coordinate variable of type CV_NONLATLON_MISS");
4570 else if(CV_MODIFY == (*i)->cvartype)
4571 throw3("For the 2-D lat/lon case, the latitude dimension name ",latdim0, "is a coordinate variable of type CV_MODIFY");
4572 else if(CV_SPECIAL == (*i)->cvartype)
4573 throw3("For the 2-D lat/lon case, the latitude dimension name ",latdim0, "is a coordinate variable of type CV_SPECIAL");
4574 else
4575 throw3("For the 2-D lat/lon case, the latitude dimension name ",latdim0, "is a coordinate variable of type CV_UNSUPPORTED");
4576
4577 }
4578 }
4579 else
4580 ++i;
4581 }
4582 // Add the 2-D latitude(latname) to the CV list.
4583 GMCVar* GMcvar = new GMCVar(*irv);
4584 GMcvar->cfdimname = latdim0;
4585 GMcvar->cvartype = CV_EXIST;
4586 GMcvar->product_type = product_type;
4587 this->cvars.push_back(GMcvar);
4588 delete(*irv);
4589 this->vars.erase(irv);
4590 break;
4591 }
4592 }
4593 }
4594
4595 // Update longitude.
4596 for (vector<Var *>::iterator irv = this->vars.begin();
4597 irv != this->vars.end(); ++irv) {
4598
4599 if((*irv)->rank == 2) {
4600
4601 // Find 2-D longitude
4602 if((*irv)->name == lonname) {
4603
4604 // Obtain the second dimension of this variable
4605 string londim0 = (*irv)->getDimensions()[1]->name;
4606
4607 // Remove the CV corresponding to londim0
4608 for (vector<GMCVar *>:: iterator i= this->cvars.begin(); i!=this->cvars.end(); ) {
4609 // NEED more work!!! should also remove ntime from the GMCVar list but add it to the cvar list.Same for Lon.
4610 if((*i)->cfdimname == londim0) {
4611 if(CV_FILLINDEX == (*i)->cvartype) {
4612 delete(*i);
4613 i= this->cvars.erase(i);
4614 }
4615 else if(CV_EXIST == (*i)->cvartype) {
4616 // Add this var. to the var list.
4617 Var *var = new Var(*i);
4618 this->vars.push_back(var);
4619 // Remove this var. from the GMCVar list.
4620 delete(*i);
4621 i = this->cvars.erase(i);
4622 }
4623 else {// the latdimname should be either the CV_FILLINDEX or CV_EXIST.
4624 if(CV_LAT_MISS == (*i)->cvartype)
4625 throw3("For the 2-D lat/lon case, the longitude dimension name ",londim0, "is a coordinate variable of type CV_LAT_MISS");
4626 else if(CV_LON_MISS == (*i)->cvartype)
4627 throw3("For the 2-D lat/lon case, the longitude dimension name ",londim0, "is a coordinate variable of type CV_LON_MISS");
4628 else if(CV_NONLATLON_MISS == (*i)->cvartype)
4629 throw3("For the 2-D lat/lon case, the longitude dimension name ",londim0, "is a coordinate variable of type CV_NONLATLON_MISS");
4630 else if(CV_MODIFY == (*i)->cvartype)
4631 throw3("For the 2-D lat/lon case, the longitude dimension name ",londim0, "is a coordinate variable of type CV_MODIFY");
4632 else if(CV_SPECIAL == (*i)->cvartype)
4633 throw3("For the 2-D lat/lon case, the longitude dimension name ",londim0, "is a coordinate variable of type CV_SPECIAL");
4634 else
4635 throw3("For the 2-D lat/lon case, the longitude dimension name ",londim0, "is a coordinate variable of type CV_UNSUPPORTED");
4636 }
4637 }
4638 else
4639 ++i;
4640 }
4641
4642 // Add the 2-D longitude(lonname) to the CV list.
4643 GMCVar* GMcvar = new GMCVar(*irv);
4644 GMcvar->cfdimname = londim0;
4645 GMcvar->cvartype = CV_EXIST;
4646 GMcvar->product_type = product_type;
4647 this->cvars.push_back(GMcvar);
4648 delete(*irv);
4649 this->vars.erase(irv);
4650 break;
4651 }
4652 }
4653 }
4654}
4655#endif
4656
4657// Handle coordinate variables for general HDF5 products that have 1-D lat/lon
4658void GMFile::Handle_CVar_LatLon1D_General_Product() {
4659
4660 BESDEBUG("h5", "Coming to Handle_CVar_LatLon1D_General_Product()"<<endl);
4661 this->iscoard = true;
4662 Handle_CVar_LatLon_General_Product();
4663
4664}
4665
4666// Handle coordinate variables for general HDF5 products that have 2-D lat/lon
4667void GMFile::Handle_CVar_LatLon2D_General_Product() {
4668
4669 BESDEBUG("h5", "Coming to Handle_CVar_LatLon2D_General_Product()"<<endl);
4670 Handle_CVar_LatLon_General_Product();
4671
4672}
4673
4674// Routine to handle coordinate variables for general HDF5 product
4675// that have either 1-D or 2-D lat/lon
4676void GMFile::Handle_CVar_LatLon_General_Product() {
4677
4678 BESDEBUG("h5", "Coming to Handle_CVar_LatLon_General_Product()"<<endl);
4679 if((GENERAL_LATLON2D != this->gproduct_pattern)
4680 && GENERAL_LATLON1D != this->gproduct_pattern)
4681 throw1("This function only supports latlon 1D or latlon 2D general products");
4682
4683 pair<set<string>::iterator,bool> setret;
4684 set<string>tempdimnamelist = dimnamelist;
4685
4686 for (vector<Var *>::iterator irv = this->vars.begin();
4687 irv != this->vars.end(); ++irv) {
4688
4689 // This is the dimension scale dataset; it should be changed to a coordinate variable.
4690 if (gp_latname== (*irv)->name) {
4691
4692 // For latitude, regardless 1D or 2D, the first dimension needs to be updated.
4693 // Create Coordinate variables.
4694 tempdimnamelist.erase(((*irv)->dims[0])->name);
4695 GMCVar* GMcvar = new GMCVar(*irv);
4696 GMcvar->cfdimname = ((*irv)->dims[0])->name;
4697 GMcvar->cvartype = CV_EXIST;
4698 GMcvar->product_type = product_type;
4699 this->cvars.push_back(GMcvar);
4700 delete(*irv);
4701 this->vars.erase(irv);
4702 break;
4703 } // if ((*irs)== (*irv)->fullpath)
4704 } // for (vector<Var *>::iterator irv = this->vars.begin();
4705
4706 for (vector<Var *>::iterator irv = this->vars.begin();
4707 irv != this->vars.end(); ++irv) {
4708
4709 // This is the dimension scale dataset; it should be changed to a coordinate variable.
4710 if (gp_lonname== (*irv)->name) {
4711
4712 // For 2-D lat/lon, the londimname should be the second dimension of the longitude
4713 // For 1-D lat/lon, the londimname should be the first dimension of the longitude
4714 // Create Coordinate variables.
4715 string londimname;
4716 if(GENERAL_LATLON2D == this->gproduct_pattern)
4717 londimname = ((*irv)->dims[1])->name;
4718 else
4719 londimname = ((*irv)->dims[0])->name;
4720
4721 tempdimnamelist.erase(londimname);
4722 GMCVar* GMcvar = new GMCVar(*irv);
4723 GMcvar->cfdimname = londimname;
4724 GMcvar->cvartype = CV_EXIST;
4725 GMcvar->product_type = product_type;
4726 this->cvars.push_back(GMcvar);
4727 delete(*irv);
4728 this->vars.erase(irv);
4729 break;
4730 } // if ((*irs)== (*irv)->fullpath)
4731 } // for (vector<Var *>::iterator irv = this->vars.begin();
4732
4733 //
4734 // Add other missing coordinate variables.
4735 for (set<string>::iterator irs = tempdimnamelist.begin();
4736 irs != tempdimnamelist.end();irs++) {
4737 GMCVar*GMcvar = new GMCVar();
4738 Create_Missing_CV(GMcvar,*irs);
4739 this->cvars.push_back(GMcvar);
4740 }
4741
4742}
4743
4744// Handle coordinate variables for OBPG level 3
4745void GMFile::Handle_CVar_OBPG_L3() {
4746
4747 BESDEBUG("h5", "Coming to Handle_CVar_OBPG_L3()"<<endl);
4748 if (GENERAL_DIMSCALE == this->gproduct_pattern)
4749 Handle_CVar_Dimscale_General_Product();
4750
4751 // Change the CV Type of the corresponding CVs of lat and lon from CV_FILLINDEX to CV_LATMISS or CV_LONMISS
4752 for (vector<Var *>::iterator irv = this->vars.begin();
4753 irv != this->vars.end(); ++irv) {
4754
4755 // Here I try to avoid using the dimension name row and column to find the lat/lon dimension size.
4756 // So I am looking for a 2-D floating-point array or a 2-D array under the group geophsical_data.
4757 // This may be subject to change if OBPG level 3 change its arrangement of variables.
4758 // KY 2014-09-29
4759
4760 if((*irv)->rank == 2) {
4761
4762 if(((*irv)->fullpath.find("/geophsical_data") == 0) || ((*irv)->dtype == H5FLOAT32)) {
4763
4764 size_t lat_size = (*irv)->getDimensions()[0]->size;
4765 string lat_name = (*irv)->getDimensions()[0]->name;
4766 size_t lon_size = (*irv)->getDimensions()[1]->size;
4767 string lon_name = (*irv)->getDimensions()[1]->name;
4768 size_t temp_size = 0;
4769 string temp_name;
4770 H5DataType ll_dtype = (*irv)->dtype;
4771
4772 // We always assume that longitude size is greater than latitude size.
4773 if(lat_size >lon_size) {
4774 temp_size = lon_size;
4775 temp_name = lon_name;
4776 lon_size = lat_size;
4777 lon_name = lat_name;
4778 lat_size = temp_size;
4779 lat_name = temp_name;
4780 }
4781 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
4782 ircv != this->cvars.end(); ++ircv) {
4783 if((*ircv)->cvartype == CV_FILLINDEX) {
4784 if((*ircv)->getDimensions()[0]->size == lat_size &&
4785 (*ircv)->getDimensions()[0]->name == lat_name) {
4786 (*ircv)->cvartype = CV_LAT_MISS;
4787 (*ircv)->dtype = ll_dtype;
4788 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
4789 ira != (*ircv)->attrs.end(); ++ira) {
4790 if ((*ira)->name == "NAME") {
4791 delete (*ira);
4792 (*ircv)->attrs.erase(ira);
4793 break;
4794 }
4795 }
4796 }
4797 else if((*ircv)->getDimensions()[0]->size == lon_size &&
4798 (*ircv)->getDimensions()[0]->name == lon_name) {
4799 (*ircv)->cvartype = CV_LON_MISS;
4800 (*ircv)->dtype = ll_dtype;
4801 for (vector<Attribute *>::iterator ira = (*ircv)->attrs.begin();
4802 ira != (*ircv)->attrs.end(); ++ira) {
4803 if ((*ira)->name == "NAME") {
4804 delete (*ira);
4805 (*ircv)->attrs.erase(ira);
4806 break;
4807 }
4808 }
4809 }
4810
4811 }
4812 }
4813 break;
4814
4815 } // if(((*irv)->fullpath.find("/geophsical_data") == 0) || ((*irv)->dtype == H5FLOAT32))
4816 } // if((*irv)->rank == 2)
4817 } // for (vector<Var *>::iterator irv = this->vars.begin();
4818
4819}
4820
4821// Handle some special variables. Currently only GPM and ACOS have these variables.
4823
4824 BESDEBUG("h5", "Coming to Handle_SpVar()"<<endl);
4825 if (ACOS_L2S_OR_OCO2_L1B == product_type)
4826 Handle_SpVar_ACOS_OCO2();
4827 else if(GPM_L1 == product_type) {
4828 // Loop through the variable list to build the coordinates.
4829 // These variables need to be removed.
4830 for (vector<Var *>::iterator irv = this->vars.begin();
4831 irv != this->vars.end(); ++irv) {
4832 if((*irv)->name=="AlgorithmRuntimeInfo") {
4833 delete(*irv);
4834 this->vars.erase(irv);
4835 break;
4836 }
4837 }
4838 }
4839
4840 // GPM level-3 These variables need to be removed.
4841 else if(GPMM_L3 == product_type || GPMS_L3 == product_type || GPM_L3_New==product_type) {
4842
4843 for (vector<Var *>::iterator irv = this->vars.begin();
4844 irv != this->vars.end(); ) {
4845 if((*irv)->name=="InputFileNames") {
4846 delete(*irv);
4847 irv = this->vars.erase(irv);
4848 }
4849 else if((*irv)->name=="InputAlgorithmVersions") {
4850 delete(*irv);
4851 irv = this->vars.erase(irv);
4852 }
4853 else if((*irv)->name=="InputGenerationDateTimes") {
4854 delete(*irv);
4855 irv = this->vars.erase(irv);
4856 }
4857 else {
4858 ++irv;
4859 }
4860
4861 }
4862
4863 }
4864
4865}
4866
4867// Handle special variables for ACOS.
4868void GMFile::Handle_SpVar_ACOS_OCO2() {
4869
4870 BESDEBUG("h5", "Coming to Handle_SpVar_ACOS_OCO2()"<<endl);
4871 //The ACOS or OCO2 have 64-bit variables. DAP2 doesn't support 64-bit variables.
4872 // So we will not handle attributes yet.
4873 for (vector<Var *>::iterator irv = this->vars.begin();
4874 irv != this->vars.end(); ) {
4875 if (H5INT64 == (*irv)->getType()) {
4876
4877 // First: Time Part of soundingid
4878 GMSPVar * spvar = new GMSPVar(*irv);
4879 spvar->name = (*irv)->name +"_Time";
4880 spvar->newname = (*irv)->newname+"_Time";
4881 spvar->dtype = H5INT32;
4882 spvar->otype = (*irv)->getType();
4883 spvar->sdbit = 1;
4884
4885 // 2 digit hour, 2 digit min, 2 digit seconds
4886 spvar->numofdbits = 6;
4887 this->spvars.push_back(spvar);
4888
4889 // Second: Date Part of soundingid
4890 GMSPVar * spvar2 = new GMSPVar(*irv);
4891 spvar2->name = (*irv)->name +"_Date";
4892 spvar2->newname = (*irv)->newname+"_Date";
4893 spvar2->dtype = H5INT32;
4894 spvar2->otype = (*irv)->getType();
4895 spvar2->sdbit = 7;
4896
4897 // 4 digit year, 2 digit month, 2 digit day
4898 spvar2->numofdbits = 8;
4899 this->spvars.push_back(spvar2);
4900
4901 delete(*irv);
4902 irv = this->vars.erase(irv);
4903 } // if (H5INT64 == (*irv)->getType())
4904 else {
4905 ++irv;
4906 }
4907 } // for (vector<Var *>::iterator irv = this->vars.begin(); ...
4908}
4909
4910// Adjust Object names, For some products, NASA data centers don't need
4911// the fullpath of objects.
4913
4914 BESDEBUG("h5", "Coming to Adjust_Obj_Name()"<<endl);
4915 if(Mea_Ozone == product_type)
4916 Adjust_Mea_Ozone_Obj_Name();
4917
4918 if(GPMS_L3 == product_type || GPMM_L3 == product_type)
4919 Adjust_GPM_L3_Obj_Name();
4920
4921// Just for debugging
4922#if 0
4923for (vector<Var*>::iterator irv2 = this->vars.begin();
4924 irv2 != this->vars.end(); irv2++) {
4925 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
4926 ird !=(*irv2)->dims.end(); ird++) {
4927 cerr<<"Dimension name afet Adjust_Obj_Name "<<(*ird)->newname <<endl;
4928 }
4929}
4930#endif
4931
4932}
4933
4934// Adjust object names for GPM level 3 products
4935void GMFile:: Adjust_GPM_L3_Obj_Name() {
4936
4937 BESDEBUG("h5", "Coming to Adjust_GPM_L3_Obj_Name()"<<endl);
4938 string objnewname;
4939 // In this definition, root group is not considered as a group.
4940 if(this->groups.size() <= 1) {
4941 for (vector<Var *>::iterator irv = this->vars.begin();
4942 irv != this->vars.end(); ++irv) {
4943 objnewname = HDF5CFUtil::obtain_string_after_lastslash((*irv)->newname);
4944 if (objnewname !="")
4945 (*irv)->newname = objnewname;
4946 }
4947 }
4948 else {
4949 for (vector<Var *>::iterator irv = this->vars.begin();
4950 irv != this->vars.end(); ++irv) {
4951 size_t grid_group_path_pos = ((*irv)->newname.substr(1)).find_first_of("/");
4952 objnewname = ((*irv)->newname).substr(grid_group_path_pos+2);
4953 (*irv)->newname = objnewname;
4954 }
4955 }
4956}
4957
4958// Adjust object names for MeaSUREs OZone
4959void GMFile:: Adjust_Mea_Ozone_Obj_Name() {
4960
4961 BESDEBUG("h5", "Coming to Adjust_Mea_Ozone_Obj_Name()"<<endl);
4962 string objnewname;
4963 for (vector<Var *>::iterator irv = this->vars.begin();
4964 irv != this->vars.end(); ++irv) {
4965 objnewname = HDF5CFUtil::obtain_string_after_lastslash((*irv)->newname);
4966 if (objnewname !="")
4967 (*irv)->newname = objnewname;
4968
4969#if 0
4970//Just for debugging
4971for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
4972 ird !=(*irv)->dims.end();++ird) {
4973 cerr<<"Ozone dim. name "<<(*ird)->name <<endl;
4974 cerr<<"Ozone dim. new name "<<(*ird)->newname <<endl;
4975}
4976#endif
4977
4978 }
4979
4980 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
4981 irv != this->cvars.end(); ++irv) {
4982 objnewname = HDF5CFUtil::obtain_string_after_lastslash((*irv)->newname);
4983 if (objnewname !="")
4984 (*irv)->newname = objnewname;
4985#if 0
4986 //Just for debugging
4987for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
4988 ird !=(*irv)->dims.end();++ird) {
4989 cerr<<"Ozone CV dim. name "<<(*ird)->name <<endl;
4990 cerr<<"Ozone CV dim. new name "<<(*ird)->newname <<endl;
4991}
4992#endif
4993 }
4994}
4995
4996// Flatten object names.
4997void GMFile::Flatten_Obj_Name(bool include_attr) {
4998
4999 BESDEBUG("h5", "GMFile::Coming to Flatten_Obj_Name()"<<endl);
5000 // General variables
5001 File::Flatten_Obj_Name(include_attr);
5002
5003 // Coordinate variables
5004 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5005 irv != this->cvars.end(); ++irv) {
5006 (*irv)->newname = get_CF_string((*irv)->newname);
5007
5008 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
5009 ird != (*irv)->dims.end(); ++ird) {
5010 (*ird)->newname = get_CF_string((*ird)->newname);
5011 }
5012
5013 if (true == include_attr) {
5014 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
5015 ira != (*irv)->attrs.end(); ++ira)
5016 (*ira)->newname = File::get_CF_string((*ira)->newname);
5017
5018 }
5019
5020 }
5021
5022 // Special variables
5023 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
5024 irv != this->spvars.end(); ++irv) {
5025 (*irv)->newname = get_CF_string((*irv)->newname);
5026
5027 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
5028 ird != (*irv)->dims.end(); ++ird)
5029 (*ird)->newname = get_CF_string((*ird)->newname);
5030
5031 if (true == include_attr) {
5032 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
5033 ira != (*irv)->attrs.end(); ++ira)
5034 (*ira)->newname = File::get_CF_string((*ira)->newname);
5035
5036 }
5037 }
5038
5039// Just for debugging
5040#if 0
5041for (vector<Var*>::iterator irv2 = this->vars.begin();
5042 irv2 != this->vars.end(); irv2++) {
5043 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
5044 ird !=(*irv2)->dims.end(); ird++) {
5045 cerr<<"Dimension name afet Flatten_Obj_Name "<<(*ird)->newname <<endl;
5046 }
5047}
5048#endif
5049
5050
5051}
5052
5053// Rarely object name clashings may occur. This routine makes sure
5054// all object names are unique.
5055void GMFile::Handle_Obj_NameClashing(bool include_attr) {
5056
5057 BESDEBUG("h5", "GMFile::Coming to Handle_Obj_NameClashing()"<<endl);
5058 // objnameset will be filled with all object names that we are going to check the name clashing.
5059 // For example, we want to see if there are any name clashings for all variable names in this file.
5060 // objnameset will include all variable names. If a name clashing occurs, we can figure out from the set operation immediately.
5061 set<string>objnameset;
5062 Handle_GMCVar_NameClashing(objnameset);
5063 Handle_GMSPVar_NameClashing(objnameset);
5064 File::Handle_GeneralObj_NameClashing(include_attr,objnameset);
5065 if (true == include_attr) {
5066 Handle_GMCVar_AttrNameClashing();
5067 Handle_GMSPVar_AttrNameClashing();
5068 }
5069 // Moving to h5gmcfdap.cc, right after Adjust_Dim_Name
5070 //Handle_DimNameClashing();
5071}
5072
5073// Name clashings for coordinate variables
5074void GMFile::Handle_GMCVar_NameClashing(set<string> &objnameset ) {
5075
5076 GMHandle_General_NameClashing(objnameset,this->cvars);
5077}
5078
5079// Name clashings for special variables(like 64-bit integer variables)
5080void GMFile::Handle_GMSPVar_NameClashing(set<string> &objnameset ) {
5081
5082 GMHandle_General_NameClashing(objnameset,this->spvars);
5083}
5084
5085// This routine handles attribute name clashings for coordinate variables.
5086void GMFile::Handle_GMCVar_AttrNameClashing() {
5087
5088 BESDEBUG("h5", "Coming to Handle_GMCVar_AttrNameClashing()"<<endl);
5089 set<string> objnameset;
5090
5091 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5092 irv != this->cvars.end(); ++irv) {
5093 Handle_General_NameClashing(objnameset,(*irv)->attrs);
5094 objnameset.clear();
5095 }
5096}
5097
5098// Attribute name clashings for special variables
5099void GMFile::Handle_GMSPVar_AttrNameClashing() {
5100
5101 BESDEBUG("h5", "Coming to Handle_GMSPVar_AttrNameClashing()"<<endl);
5102 set<string> objnameset;
5103
5104 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
5105 irv != this->spvars.end(); ++irv) {
5106 Handle_General_NameClashing(objnameset,(*irv)->attrs);
5107 objnameset.clear();
5108 }
5109}
5110
5111//class T must have member string newname
5112// The subroutine to handle name clashings,
5113// it builds up a map from original object names to clashing-free object names.
5114template<class T> void
5115GMFile::GMHandle_General_NameClashing(set <string>&objnameset, vector<T*>& objvec) {
5116
5117 BESDEBUG("h5", "Coming to GMHandle_General_NameClashing()"<<endl);
5118 pair<set<string>::iterator,bool> setret;
5119 set<string>::iterator iss;
5120
5121 vector<string> clashnamelist;
5122 vector<string>::iterator ivs;
5123
5124 map<int,int> cl_to_ol;
5125 int ol_index = 0;
5126 int cl_index = 0;
5127
5128 typename vector<T*>::iterator irv;
5129
5130 for (irv = objvec.begin();
5131 irv != objvec.end(); ++irv) {
5132
5133 setret = objnameset.insert((*irv)->newname);
5134 if (false == setret.second ) {
5135 clashnamelist.insert(clashnamelist.end(),(*irv)->newname);
5136 cl_to_ol[cl_index] = ol_index;
5137 cl_index++;
5138 }
5139 ol_index++;
5140 }
5141
5142
5143 // Now change the clashed elements to unique elements;
5144 // Generate the set which has the same size as the original vector.
5145 for (ivs=clashnamelist.begin(); ivs!=clashnamelist.end(); ++ivs) {
5146 int clash_index = 1;
5147 string temp_clashname = *ivs +'_';
5148 HDF5CFUtil::gen_unique_name(temp_clashname,objnameset,clash_index);
5149 *ivs = temp_clashname;
5150 }
5151
5152
5153 // Now go back to the original vector, make it unique.
5154 for (unsigned int i =0; i <clashnamelist.size(); i++)
5155 objvec[cl_to_ol[i]]->newname = clashnamelist[i];
5156
5157}
5158
5159// Handle dimension name clashings
5161
5162
5163 BESDEBUG("h5", "GMFile: Coming to Handle_DimNameClashing()"<<endl);
5164 // ACOS L2S or OCO2 L1B products doesn't need the dimension name clashing check based on our current understanding. KY 2012-5-16
5165 if (ACOS_L2S_OR_OCO2_L1B == product_type)
5166 return;
5167
5168 map<string,string>dimname_to_dimnewname;
5169 pair<map<string,string>::iterator,bool>mapret;
5170 set<string> dimnameset;
5171 vector<Dimension*>vdims;
5172 set<string> dimnewnameset;
5173 pair<set<string>::iterator,bool> setret;
5174
5175 // First: Generate the dimset/dimvar based on coordinate variables.
5176 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5177 irv !=this->cvars.end(); ++irv) {
5178 for (vector <Dimension *>:: iterator ird = (*irv)->dims.begin();
5179 ird !=(*irv)->dims.end();++ird) {
5180 setret = dimnameset.insert((*ird)->name);
5181 if (true == setret.second)
5182 vdims.push_back(*ird);
5183 }
5184 }
5185
5186 // For some cases, dimension names are provided but there are no corresponding coordinate
5187 // variables. For now, we will assume no such cases.
5188 // Actually, we find such a case in our fake testsuite. So we need to fix it.
5189 for(vector<Var *>::iterator irv= this->vars.begin();
5190 irv != this->vars.end();++irv) {
5191 for (vector <Dimension *>:: iterator ird = (*irv)->dims.begin();
5192 ird !=(*irv)->dims.end();++ird) {
5193 //setret = dimnameset.insert((*ird)->newname);
5194 setret = dimnameset.insert((*ird)->name);
5195 if (setret.second) vdims.push_back(*ird);
5196 }
5197 }
5198
5199 GMHandle_General_NameClashing(dimnewnameset,vdims);
5200
5201 // Third: Make dimname_to_dimnewname map
5202 for (vector<Dimension*>::iterator ird = vdims.begin();ird!=vdims.end();++ird) {
5203 mapret = dimname_to_dimnewname.insert(pair<string,string>((*ird)->name,(*ird)->newname));
5204 if (false == mapret.second)
5205 throw4("The dimension name ",(*ird)->name," should map to ",
5206 (*ird)->newname);
5207 }
5208
5209 // Fourth: Change the original dimension new names to the unique dimension new names
5210 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5211 irv !=this->cvars.end(); ++irv)
5212 for (vector <Dimension *>:: iterator ird = (*irv)->dims.begin();
5213 ird!=(*irv)->dims.end();++ird)
5214 (*ird)->newname = dimname_to_dimnewname[(*ird)->name];
5215
5216 for (vector<Var *>::iterator irv = this->vars.begin();
5217 irv != this->vars.end(); ++irv)
5218 for (vector <Dimension *>:: iterator ird = (*irv)->dims.begin();
5219 ird !=(*irv)->dims.end();++ird)
5220 (*ird)->newname = dimname_to_dimnewname[(*ird)->name];
5221
5222}
5223
5224// For COARDS, dim. names need to be the same as obj. names.
5226
5227 BESDEBUG("h5", "GMFile:Coming to Adjust_Dim_Name()"<<endl);
5228#if 0
5229 // Just for debugging
5230for (vector<Var*>::iterator irv2 = this->vars.begin();
5231 irv2 != this->vars.end(); irv2++) {
5232 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
5233 ird !=(*irv2)->dims.end(); ird++) {
5234 cerr<<"Dimension new name "<<(*ird)->newname <<endl;
5235 }
5236}
5237#endif
5238
5239 // Only need for COARD conventions.
5240 if( true == iscoard) {
5241 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5242 irv !=this->cvars.end(); ++irv) {
5243#if 0
5244cerr<<"1D Cvariable name is "<<(*irv)->name <<endl;
5245cerr<<"1D Cvariable new name is "<<(*irv)->newname <<endl;
5246cerr<<"1D Cvariable dim name is "<<((*irv)->dims)[0]->name <<endl;
5247cerr<<"1D Cvariable dim new name is "<<((*irv)->dims)[0]->newname <<endl;
5248#endif
5249 if ((*irv)->dims.size()!=1)
5250 throw3("Coard coordinate variable ",(*irv)->name, "is not 1D");
5251 if ((*irv)->newname != (((*irv)->dims)[0]->newname)) {
5252 ((*irv)->dims)[0]->newname = (*irv)->newname;
5253
5254 // For all variables that have this dimension,the dimension newname should also change.
5255 for (vector<Var*>::iterator irv2 = this->vars.begin();
5256 irv2 != this->vars.end(); ++irv2) {
5257 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
5258 ird !=(*irv2)->dims.end(); ++ird) {
5259 // This is the key, the dimension name of this dimension
5260 // should be equal to the dimension name of the coordinate variable.
5261 // Then the dimension name matches and the dimension name should be changed to
5262 // the new dimension name.
5263 if ((*ird)->name == ((*irv)->dims)[0]->name)
5264 (*ird)->newname = ((*irv)->dims)[0]->newname;
5265 }
5266 }
5267 } // if ((*irv)->newname != (((*irv)->dims)[0]->newname))
5268 }// for (vector<GMCVar *>::iterator irv = this->cvars.begin(); ...
5269 } // if( true == iscoard)
5270
5271// Just for debugging
5272#if 0
5273for (vector<Var*>::iterator irv2 = this->vars.begin();
5274 irv2 != this->vars.end(); irv2++) {
5275 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
5276 ird !=(*irv2)->dims.end(); ird++) {
5277 cerr<<"Dimension name afet Adjust_Dim_Name "<<(*ird)->newname <<endl;
5278 }
5279}
5280#endif
5281
5282
5283}
5284
5285// Add supplemental CF attributes for some products.
5286void
5288
5289 BESDEBUG("h5", "GMFile::Coming to Add_Supplement_Attrs()"<<endl);
5290 if (General_Product == product_type || true == add_path) {
5291 File::Add_Supplement_Attrs(add_path);
5292
5293 if(true == add_path) {
5294 // Adding variable original name(origname) and full path(fullpath)
5295 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5296 irv != this->cvars.end(); ++irv) {
5297 if (((*irv)->cvartype == CV_EXIST) || ((*irv)->cvartype == CV_MODIFY)) {
5298 Attribute * attr = new Attribute();
5299 const string varname = (*irv)->name;
5300 const string attrname = "origname";
5301 Add_Str_Attr(attr,attrname,varname);
5302 (*irv)->attrs.push_back(attr);
5303 }
5304 }
5305
5306 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5307 irv != this->cvars.end(); ++irv) {
5308 // Turn off the fullnamepath attribute when zero_storage_size is 0.
5309 // Use the BES key since quite a few testing cases will be affected.
5310 // KY 2020-03-23
5311 if((*irv)->zero_storage_size == false
5312 || HDF5RequestHandler::get_no_zero_size_fullnameattr() == false) {
5313 if (((*irv)->cvartype == CV_EXIST) || ((*irv)->cvartype == CV_MODIFY)) {
5314 Attribute * attr = new Attribute();
5315 const string varname = (*irv)->fullpath;
5316 const string attrname = "fullnamepath";
5317 Add_Str_Attr(attr,attrname,varname);
5318 (*irv)->attrs.push_back(attr);
5319 }
5320 }
5321 }
5322
5323 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
5324 irv != this->spvars.end(); ++irv) {
5325 Attribute * attr = new Attribute();
5326 const string varname = (*irv)->name;
5327 const string attrname = "origname";
5328 Add_Str_Attr(attr,attrname,varname);
5329 (*irv)->attrs.push_back(attr);
5330 }
5331
5332 for (vector<GMSPVar *>::iterator irv = this->spvars.begin();
5333 irv != this->spvars.end(); ++irv) {
5334 // Turn off the fullnamepath attribute when zero_storage_size is 0.
5335 // Use the BES key since quite a few testing cases will be affected.
5336 // KY 2020-03-23
5337 if((*irv)->zero_storage_size == false
5338 || HDF5RequestHandler::get_no_zero_size_fullnameattr() == false) {
5339 Attribute * attr = new Attribute();
5340 const string varname = (*irv)->fullpath;
5341 const string attrname = "fullnamepath";
5342 Add_Str_Attr(attr,attrname,varname);
5343 (*irv)->attrs.push_back(attr);
5344 }
5345 }
5346 }
5347 } // if (General_Product == product_type || true == add_path)
5348
5349 if(GPM_L1 == product_type || GPMS_L3 == product_type || GPMM_L3 == product_type)
5350 Add_GPM_Attrs();
5351 else if (Aqu_L3 == product_type)
5352 Add_Aqu_Attrs();
5353 else if (Mea_SeaWiFS_L2 == product_type || Mea_SeaWiFS_L3 == product_type)
5354 Add_SeaWiFS_Attrs();
5355
5356}
5357
5358// Add CF attributes for GPM products
5359void
5360GMFile:: Add_GPM_Attrs() {
5361
5362 BESDEBUG("h5", "Coming to Add_GPM_Attrs()"<<endl);
5363 vector<HDF5CF::Var *>::const_iterator it_v;
5364 vector<HDF5CF::Attribute *>::const_iterator ira;
5365 const string attr_name_be_replaced = "CodeMissingValue";
5366 const string attr_new_name = "_FillValue";
5367 const string attr2_name_be_replaced = "Units";
5368 const string attr2_new_name ="units";
5369
5370 // Need to convert String type CodeMissingValue to the corresponding _FilLValue
5371 // Create a function at HDF5CF.cc. use strtod,strtof,strtol etc. function to convert
5372 // string to the corresponding type.
5373 for (it_v = vars.begin(); it_v != vars.end(); ++it_v) {
5374 bool has_fvalue_attr = false;
5375 for(ira = (*it_v)->attrs.begin(); ira!= (*it_v)->attrs.end();ira++) {
5376 if(attr_new_name == (*ira)->name) {
5377 has_fvalue_attr = true;
5378 break;
5379 }
5380 }
5381
5382 if(false == has_fvalue_attr) {
5383 for(ira = (*it_v)->attrs.begin(); ira!= (*it_v)->attrs.end();ira++) {
5384 if(attr_name_be_replaced == (*ira)->name) {
5385 if((*ira)->dtype == H5FSTRING)
5386 Change_Attr_One_Str_to_Others((*ira),(*it_v));
5387 (*ira)->name = attr_new_name;
5388 (*ira)->newname = attr_new_name;
5389 }
5390 }
5391 }
5392
5393 }
5394
5395
5396 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
5397 irv != this->cvars.end(); ++irv) {
5398 bool has_fvalue_attr = false;
5399
5400 for(ira = (*irv)->attrs.begin(); ira!= (*irv)->attrs.end();ira++) {
5401
5402 if(attr_new_name == (*ira)->name) {
5403 has_fvalue_attr = true;
5404 break;
5405 }
5406 }
5407 if(false == has_fvalue_attr) {
5408 for(ira = (*irv)->attrs.begin(); ira!= (*irv)->attrs.end();ira++) {
5409
5410 if(attr_name_be_replaced == (*ira)->name) {
5411 if((*ira)->dtype == H5FSTRING)
5412 Change_Attr_One_Str_to_Others((*ira),(*irv));
5413 (*ira)->name = attr_new_name;
5414 (*ira)->newname = attr_new_name;
5415 break;
5416 }
5417 }
5418 }
5419
5420
5421 if(product_type == GPM_L1) {
5422
5423 if ((*irv)->cvartype == CV_EXIST) {
5424 if((*irv)->name.find("Latitude") !=string::npos) {
5425 string unit_value = "degrees_north";
5426 Correct_GPM_L1_LatLon_units(*irv,unit_value);
5427
5428 }
5429 else if((*irv)->name.find("Longitude") !=string::npos) {
5430 string unit_value = "degrees_east";
5431 Correct_GPM_L1_LatLon_units(*irv,unit_value);
5432 }
5433 }
5434
5435
5436 else if ((*irv)->cvartype == CV_NONLATLON_MISS) {
5437
5438 string comment;
5439 const string attrname = "comment";
5440 Attribute*attr = new Attribute();
5441
5442 {
5443 if((*irv)->name == "nchannel1")
5444 comment = "Number of Swath S1 channels (10V 10H 19V 19H 23V 37V 37H 89V 89H).";
5445 else if((*irv)->name == "nchannel2")
5446 comment = "Number of Swath S2 channels (166V 166H 183+/-3V 183+/-8V).";
5447 else if((*irv)->name == "nchan1")
5448 comment = "Number of channels in Swath 1.";
5449 else if((*irv)->name == "nchan2")
5450 comment = "Number of channels in Swath 2.";
5451 else if((*irv)->name == "VH")
5452 comment = "Number of polarizations.";
5453 else if((*irv)->name == "GMIxyz")
5454 comment = "x, y, z components in GMI instrument coordinate system.";
5455 else if((*irv)->name == "LNL")
5456 comment = "Linear and non-linear.";
5457 else if((*irv)->name == "nscan")
5458 comment = "Number of scans in the granule.";
5459 else if((*irv)->name == "nscan1")
5460 comment = "Typical number of Swath S1 scans in the granule.";
5461 else if((*irv)->name == "nscan2")
5462 comment = "Typical number of Swath S2 scans in the granule.";
5463 else if((*irv)->name == "npixelev")
5464 comment = "Number of earth view pixels in one scan.";
5465 else if((*irv)->name == "npixelht")
5466 comment = "Number of hot load pixels in one scan.";
5467 else if((*irv)->name == "npixelcs")
5468 comment = "Number of cold sky pixels in one scan.";
5469 else if((*irv)->name == "npixelfr")
5470 comment = "Number of full rotation earth view pixels in one scan.";
5471 else if((*irv)->name == "nfreq1")
5472 comment = "Number of frequencies in Swath 1.";
5473 else if((*irv)->name == "nfreq2")
5474 comment = "Number of frequencies in Swath 2.";
5475 else if((*irv)->name == "npix1")
5476 comment = "Number of pixels in Swath 1.";
5477 else if((*irv)->name == "npix2")
5478 comment = "Number of pixels in Swath 2.";
5479 else if((*irv)->name == "npix3")
5480 comment = "Number of pixels in Swath 3.";
5481 else if((*irv)->name == "npix4")
5482 comment = "Number of pixels in Swath 4.";
5483 else if((*irv)->name == "ncolds1")
5484 comment = "Maximum number of cold samples in Swath 1.";
5485 else if((*irv)->name == "ncolds2")
5486 comment = "Maximum number of cold samples in Swath 2.";
5487 else if((*irv)->name == "nhots1")
5488 comment = "Maximum number of hot samples in Swath 1.";
5489 else if((*irv)->name == "nhots2")
5490 comment = "Maximum number of hot samples in Swath 2.";
5491 else if((*irv)->name == "ntherm")
5492 comment = "Number of hot load thermisters.";
5493 else if((*irv)->name == "ntach")
5494 comment = "Number of tachometer readings.";
5495 else if((*irv)->name == "nsamt"){
5496 comment = "Number of sample types. ";
5497 comment = +"The types are: total science GSDR, earthview,hot load, cold sky.";
5498 }
5499 else if((*irv)->name == "nndiode")
5500 comment = "Number of noise diodes.";
5501 else if((*irv)->name == "n7")
5502 comment = "Number seven.";
5503 else if((*irv)->name == "nray")
5504 comment = "Number of angle bins in each NS scan.";
5505 else if((*irv)->name == "nrayMS")
5506 comment = "Number of angle bins in each MS scan.";
5507 else if((*irv)->name == "nrayHS")
5508 comment = "Number of angle bins in each HS scan.";
5509 else if((*irv)->name == "nbin")
5510 comment = "Number of range bins in each NS and MS ray. Bin interval is 125m.";
5511 else if((*irv)->name == "nbinHS")
5512 comment = "Number of range bins in each HS ray. Bin interval is 250m.";
5513 else if((*irv)->name == "nbinSZP")
5514 comment = "Number of range bins for sigmaZeroProfile.";
5515 else if((*irv)->name == "nbinSZPHS")
5516 comment = "Number of range bins for sigmaZeroProfile in each HS scan.";
5517 else if((*irv)->name == "nNP")
5518 comment = "Number of NP kinds.";
5519 else if((*irv)->name == "nearFar")
5520 comment = "Near reference, Far reference.";
5521 else if((*irv)->name == "foreBack")
5522 comment = "Forward, Backward.";
5523 else if((*irv)->name == "method")
5524 comment = "Number of SRT methods.";
5525 else if((*irv)->name == "nNode")
5526 comment = "Number of binNode.";
5527 else if((*irv)->name == "nDSD")
5528 comment = "Number of DSD parameters. Parameters are N0 and D0";
5529 else if((*irv)->name == "LS")
5530 comment = "Liquid, solid.";
5531 }
5532
5533 if(""==comment)
5534 delete attr;
5535 else {
5536 Add_Str_Attr(attr,attrname,comment);
5537 (*irv)->attrs.push_back(attr);
5538 }
5539
5540 }
5541 }
5542
5543 if(product_type == GPMS_L3 || product_type == GPMM_L3) {
5544 if ((*irv)->cvartype == CV_NONLATLON_MISS) {
5545
5546 string comment;
5547 const string attrname = "comment";
5548 Attribute*attr = new Attribute();
5549
5550 {
5551 if((*irv)->name == "chn")
5552 comment = "Number of channels:Ku,Ka,KaHS,DPR.";
5553 else if((*irv)->name == "inst")
5554 comment = "Number of instruments:Ku,Ka,KaHS.";
5555 else if((*irv)->name == "tim")
5556 comment = "Number of hours(local time).";
5557 else if((*irv)->name == "ang"){
5558 comment = "Number of angles.The meaning of ang is different for each channel.";
5559 comment +=
5560 "For Ku channel all indices are used with the meaning 0,1,2,..6 =angle bins 24,";
5561 comment +=
5562 "(20,28),(16,32),(12,36),(8,40),(3,44),and (0,48).";
5563 comment +=
5564 "For Ka channel 4 indices are used with the meaning 0,1,2,3 = angle bins 12,(8,16),";
5565 comment +=
5566 "(4,20),and (0,24). For KaHS channel 4 indices are used with the meaning 0,1,2,3 =";
5567 comment += "angle bins(11,2),(7,16),(3,20),and (0.23).";
5568
5569 }
5570 else if((*irv)->name == "rt")
5571 comment = "Number of rain types: stratiform, convective,all.";
5572 else if((*irv)->name == "st")
5573 comment = "Number of surface types:ocean,land,all.";
5574 else if((*irv)->name == "bin"){
5575 comment = "Number of bins in histogram. The thresholds are different for different";
5576 comment +=" variables. see the file specification for this algorithm.";
5577 }
5578 else if((*irv)->name == "nvar") {
5579 comment = "Number of phase bins. Bins are counts of phase less than 100, ";
5580 comment +="counts of phase greater than or equal to 100 and less than 200, ";
5581 comment +="counts of phase greater than or equal to 200.";
5582 }
5583 else if((*irv)->name == "AD")
5584 comment = "Ascending or descending half of the orbit.";
5585 }
5586
5587 if(""==comment)
5588 delete attr;
5589 else {
5590 Add_Str_Attr(attr,attrname,comment);
5591 (*irv)->attrs.push_back(attr);
5592 }
5593
5594 }
5595 }
5596
5597
5598 if ((*irv)->cvartype == CV_SPECIAL) {
5599 if((*irv)->name == "nlayer" || (*irv)->name == "hgt"
5600 || (*irv)->name == "nalt") {
5601 Attribute*attr = new Attribute();
5602 string unit_value = "km";
5603 Add_Str_Attr(attr,attr2_new_name,unit_value);
5604 (*irv)->attrs.push_back(attr);
5605
5606 Attribute*attr1 = new Attribute();
5607 string attr1_axis="axis";
5608 string attr1_value = "Z";
5609 Add_Str_Attr(attr1,attr1_axis,attr1_value);
5610 (*irv)->attrs.push_back(attr1);
5611
5612 Attribute*attr2 = new Attribute();
5613 string attr2_positive="positive";
5614 string attr2_value = "up";
5615 Add_Str_Attr(attr2,attr2_positive,attr2_value);
5616 (*irv)->attrs.push_back(attr2);
5617
5618 }
5619 if((*irv)->name == "hgt" || (*irv)->name == "nalt"){
5620 Attribute*attr1 = new Attribute();
5621 string comment ="Number of heights above the earth ellipsoid";
5622 Add_Str_Attr(attr1,"comment",comment);
5623 (*irv)->attrs.push_back(attr1);
5624 }
5625
5626 }
5627
5628 }
5629
5630
5631// Old code, leave it for the time being
5632#if 0
5633 const string fill_value_attr_name = "_FillValue";
5634 vector<HDF5CF::Var *>::const_iterator it_v;
5635 vector<HDF5CF::Attribute *>::const_iterator ira;
5636
5637 for (it_v = vars.begin();
5638 it_v != vars.end(); ++it_v) {
5639
5640 bool has_fillvalue = false;
5641 for(ira = (*it_v)->attrs.begin(); ira!= (*it_v)->attrs.end();ira++) {
5642 if (fill_value_attr_name == (*ira)->name){
5643 has_fillvalue = true;
5644 break;
5645 }
5646
5647 }
5648
5649 // Add the fill value
5650 if (has_fillvalue != true ) {
5651
5652 if(H5FLOAT32 == (*it_v)->dtype) {
5653 Attribute* attr = new Attribute();
5654 float _FillValue = -9999.9;
5655 Add_One_Float_Attr(attr,fill_value_attr_name,_FillValue);
5656 (*it_v)->attrs.push_back(attr);
5657 }
5658 }
5659 }// for (it_v = vars.begin(); ...
5660#endif
5661
5662}
5663
5664// For GPM level 1 data, var must have names that contains either "Latitude" nor "Longitude".
5665void
5666GMFile:: Correct_GPM_L1_LatLon_units(Var *var, const string unit_value) {
5667
5668 BESDEBUG("h5", "Coming to Correct_GPM_L1_LatLon_units()"<<endl);
5669 const string Unit_name = "Units";
5670 const string unit_name = "units";
5671
5672 vector<HDF5CF::Attribute *>::iterator ira;
5673
5674 // Delete "units" and "Units"
5675 for(ira = var->attrs.begin(); ira!= var->attrs.end();) {
5676 if(unit_name == (*ira)->name) {
5677 delete(*ira);
5678 ira = var->attrs.erase(ira);
5679 }
5680 else if(Unit_name == (*ira)->name) {
5681 delete(*ira);
5682 ira = var->attrs.erase(ira);
5683 }
5684 else
5685 ++ira;
5686 }
5687 // Add the correct units for Latitude and Longitude
5688 // Note: the reason we do this way, for some versions of GPM, units is degrees,
5689 // rather than degrees_north.. So units also needs to be corrected to follow CF.
5690 Attribute *attr = new Attribute();
5691 Add_Str_Attr(attr,unit_name,unit_value);
5692 var->attrs.push_back(attr);
5693}
5694
5695
5696
5697// Add attributes for Aquarius products
5698void
5699GMFile:: Add_Aqu_Attrs() {
5700
5701 BESDEBUG("h5", "Coming to Add_Aqu_Attrs()"<<endl);
5702 vector<HDF5CF::Var *>::const_iterator it_v;
5703 vector<HDF5CF::Attribute *>::const_iterator ira;
5704
5705 const string orig_longname_attr_name = "Parameter";
5706 const string longname_attr_name ="long_name";
5707 string longname_value;
5708
5709
5710 const string orig_units_attr_name = "Units";
5711 const string units_attr_name = "units";
5712 string units_value;
5713
5714 const string orig_valid_min_attr_name = "Data Minimum";
5715 const string valid_min_attr_name = "valid_min";
5716 float valid_min_value = 0;
5717
5718 const string orig_valid_max_attr_name = "Data Maximum";
5719 const string valid_max_attr_name = "valid_max";
5720 float valid_max_value = 0;
5721
5722 // The fill value is -32767.0. However, No _FillValue attribute is added.
5723 // So add it here. KY 2012-2-16
5724
5725 const string fill_value_attr_name = "_FillValue";
5726 float _FillValue = -32767.0;
5727
5728 for (ira = this->root_attrs.begin(); ira != this->root_attrs.end(); ++ira) {
5729 if (orig_longname_attr_name == (*ira)->name) {
5730 Retrieve_H5_Attr_Value(*ira,"/");
5731 longname_value.resize((*ira)->value.size());
5732 copy((*ira)->value.begin(),(*ira)->value.end(),longname_value.begin());
5733
5734 }
5735 else if (orig_units_attr_name == (*ira)->name) {
5736 Retrieve_H5_Attr_Value(*ira,"/");
5737 units_value.resize((*ira)->value.size());
5738 copy((*ira)->value.begin(),(*ira)->value.end(),units_value.begin());
5739
5740 }
5741 else if (orig_valid_min_attr_name == (*ira)->name) {
5742 Retrieve_H5_Attr_Value(*ira,"/");
5743 memcpy(&valid_min_value,(void*)(&((*ira)->value[0])),(*ira)->value.size());
5744 }
5745
5746 else if (orig_valid_max_attr_name == (*ira)->name) {
5747 Retrieve_H5_Attr_Value(*ira,"/");
5748 memcpy(&valid_max_value,(void*)(&((*ira)->value[0])),(*ira)->value.size());
5749 }
5750
5751 }// for (ira = this->root_attrs.begin(); ira != this->root_attrs.end(); ++ira)
5752
5753 // New version Aqu(Q20112132011243.L3m_MO_SCI_V3.0_SSS_1deg.bz2) files seem to have CF attributes added.
5754 // In this case, we should not add extra CF attributes, or duplicate values may appear. KY 2015-06-20
5755 bool has_long_name = false;
5756 bool has_units = false;
5757 bool has_valid_min = false;
5758 bool has_valid_max = false;
5759 bool has_fillvalue = false;
5760
5761 for (it_v = vars.begin();
5762 it_v != vars.end(); ++it_v) {
5763 if ("l3m_data" == (*it_v)->name) {
5764 for (ira = (*it_v)->attrs.begin(); ira != (*it_v)->attrs.end(); ++ira) {
5765 if (longname_attr_name == (*ira)->name)
5766 has_long_name = true;
5767 else if(units_attr_name == (*ira)->name)
5768 has_units = true;
5769 else if(valid_min_attr_name == (*ira)->name)
5770 has_valid_min = true;
5771 else if(valid_max_attr_name == (*ira)->name)
5772 has_valid_max = true;
5773 else if(fill_value_attr_name == (*ira)->name)
5774 has_fillvalue = true;
5775 }
5776 break;
5777 }
5778 } // for (it_v = vars.begin(); ...
5779
5780
5781 // Level 3 variable name is l3m_data
5782 for (it_v = vars.begin();
5783 it_v != vars.end(); ++it_v) {
5784 if ("l3m_data" == (*it_v)->name) {
5785
5786 Attribute *attr = NULL;
5787 // 1. Add the long_name attribute if no
5788 if(false == has_long_name) {
5789 attr = new Attribute();
5790 Add_Str_Attr(attr,longname_attr_name,longname_value);
5791 (*it_v)->attrs.push_back(attr);
5792 }
5793
5794 // 2. Add the units attribute
5795 if(false == has_units) {
5796 attr = new Attribute();
5797 Add_Str_Attr(attr,units_attr_name,units_value);
5798 (*it_v)->attrs.push_back(attr);
5799 }
5800
5801 // 3. Add the valid_min attribute
5802 if(false == has_valid_min) {
5803 attr = new Attribute();
5804 Add_One_Float_Attr(attr,valid_min_attr_name,valid_min_value);
5805 (*it_v)->attrs.push_back(attr);
5806 }
5807
5808 // 4. Add the valid_max attribute
5809 if(false == has_valid_max) {
5810 attr = new Attribute();
5811 Add_One_Float_Attr(attr,valid_max_attr_name,valid_max_value);
5812 (*it_v)->attrs.push_back(attr);
5813 }
5814
5815 // 5. Add the _FillValue attribute
5816 if(false == has_fillvalue) {
5817 attr = new Attribute();
5818 Add_One_Float_Attr(attr,fill_value_attr_name,_FillValue);
5819 (*it_v)->attrs.push_back(attr);
5820 }
5821
5822 break;
5823 }
5824 } // for (it_v = vars.begin(); ...
5825}
5826
5827// Add SeaWiFS attributes
5828void
5829GMFile:: Add_SeaWiFS_Attrs() {
5830
5831 BESDEBUG("h5", "Coming to Add_SeaWiFS_Attrs()"<<endl);
5832 // The fill value is -999.0. However, No _FillValue attribute is added.
5833 // So add it here. KY 2012-2-16
5834 const string fill_value_attr_name = "_FillValue";
5835 float _FillValue = -999.0;
5836 const string valid_range_attr_name = "valid_range";
5837 vector<HDF5CF::Var *>::const_iterator it_v;
5838 vector<HDF5CF::Attribute *>::const_iterator ira;
5839
5840
5841 for (it_v = vars.begin();
5842 it_v != vars.end(); ++it_v) {
5843 if (H5FLOAT32 == (*it_v)->dtype) {
5844 bool has_fillvalue = false;
5845 bool has_validrange = false;
5846 for(ira = (*it_v)->attrs.begin(); ira!= (*it_v)->attrs.end();ira++) {
5847 if (fill_value_attr_name == (*ira)->name){
5848 has_fillvalue = true;
5849 break;
5850 }
5851
5852 else if(valid_range_attr_name == (*ira)->name) {
5853 has_validrange = true;
5854 break;
5855 }
5856
5857 }
5858 // Add the fill value
5859 if (has_fillvalue != true && has_validrange != true ) {
5860 Attribute* attr = new Attribute();
5861 Add_One_Float_Attr(attr,fill_value_attr_name,_FillValue);
5862 (*it_v)->attrs.push_back(attr);
5863 }
5864 }// if (H5FLOAT32 == (*it_v)->dtype)
5865 }// for (it_v = vars.begin(); ...
5866}
5867
5868// Leave the following code for the time being
5869#if 0
5870// Handle the "coordinates" and "units" attributes of coordinate variables.
5872
5873 string co_attrname = "coordinates";
5874 string co_attrvalue="";
5875 string unit_attrname = "units";
5876 string nonll_unit_attrvalue ="level";
5877 string lat_unit_attrvalue ="degrees_north";
5878 string lon_unit_attrvalue ="degrees_east";
5879
5880 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
5881 ircv != this->cvars.end(); ++ircv) {
5882//cerr<<"CV name is "<<(*ircv)->name << " cv type is "<<(*ircv)->cvartype <<endl;
5883
5884 if ((*ircv)->cvartype == CV_NONLATLON_MISS) {
5885 Attribute * attr = new Attribute();
5886 Add_Str_Attr(attr,unit_attrname,nonll_unit_attrvalue);
5887 (*ircv)->attrs.push_back(attr);
5888 }
5889
5890 else if ((*ircv)->cvartype == CV_LAT_MISS) {
5891//cerr<<"Should add new attribute "<<endl;
5892 Attribute * attr = new Attribute();
5893// float temp = -999.9;
5894// Add_One_Float_Attr(attr,unit_attrname,temp);
5895 Add_Str_Attr(attr,unit_attrname,lat_unit_attrvalue);
5896 (*ircv)->attrs.push_back(attr);
5897//cerr<<"After adding new attribute "<<endl;
5898 }
5899
5900 else if ((*ircv)->cvartype == CV_LON_MISS) {
5901 Attribute * attr = new Attribute();
5902 Add_Str_Attr(attr,unit_attrname,lon_unit_attrvalue);
5903 (*ircv)->attrs.push_back(attr);
5904 }
5905 } // for (vector<GMCVar *>::iterator ircv = this->cvars.begin(); ...
5906
5907 // No need to handle MeaSUREs SeaWiFS level 2 products
5908 if(product_type == Mea_SeaWiFS_L2)
5909 return;
5910
5911 // GPM level 1 needs to be handled separately
5912 else if(product_type == GPM_L1) {
5913 Handle_GPM_l1_Coor_Attr();
5914 return;
5915 }
5916 // No need to handle products that follow COARDS.
5917 else if (true == iscoard) {
5918 // May need to check coordinates for 2-D lat/lon but cannot treat those lat/lon as CV case. KY 2015-12-10-TEMPPP
5919 return;
5920 }
5921
5922
5923 // Now handle the 2-D lat/lon case(note: this only applies to the one that dim. scale doesn't apply)
5924 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
5925 ircv != this->cvars.end(); ++ircv) {
5926 if((*ircv)->rank == 2) {
5927
5928 // The following code makes sure that the replacement only happens with the general 2-D lat/lon case.
5929 if(gp_latname == (*ircv)->name)
5930 Replace_Var_Str_Attr((*ircv),unit_attrname,lat_unit_attrvalue);
5931 else if(gp_lonname ==(*ircv)->name)
5932 Replace_Var_Str_Attr((*ircv),unit_attrname,lon_unit_attrvalue);
5933 }
5934 }
5935
5936 // Check the dimension names of 2-D lat/lon CVs
5937 string ll2d_dimname0,ll2d_dimname1;
5938 bool has_ll2d_coords = false;
5939 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
5940 ircv != this->cvars.end(); ++ircv) {
5941 if((*ircv)->rank == 2) {
5942 // Note: we should still use the original dim. name to match the general variables.
5943 ll2d_dimname0 = (*ircv)->getDimensions()[0]->name;
5944 ll2d_dimname1 = (*ircv)->getDimensions()[1]->name;
5945 if(ll2d_dimname0 !="" && ll2d_dimname1 !="")
5946 has_ll2d_coords = true;
5947 break;
5948 }
5949 }
5950
5951 if(true == has_ll2d_coords) {
5952
5953 for (vector<Var *>::iterator irv = this->vars.begin();
5954 irv != this->vars.end(); ++irv) {
5955
5956 bool coor_attr_keep_exist = false;
5957
5958 // May need to delete only the "coordinates" with both 2-D lat/lon dim. KY 2015-12-07
5959 if(((*irv)->rank >=2)) {
5960
5961 short ll2dim_flag = 0;
5962 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
5963 ird != (*irv)->dims.end(); ++ ird) {
5964 if((*ird)->name == ll2d_dimname0)
5965 ll2dim_flag++;
5966 else if((*ird)->name == ll2d_dimname1)
5967 ll2dim_flag++;
5968 }
5969
5970 if(ll2dim_flag != 2)
5971 coor_attr_keep_exist = true;
5972
5973 // The following line doesn't apply to SMAP,it applies to Old SMAP Level 2 Simulation files.
5974 if(product_type == OSMAPL2S)
5975 coor_attr_keep_exist = true;
5976
5977 if (false == coor_attr_keep_exist) {
5978 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin();
5979 ira !=(*irv)->attrs.end();) {
5980 if ((*ira)->newname == co_attrname) {
5981 delete (*ira);
5982 ira = (*irv)->attrs.erase(ira);
5983 }
5984 else {
5985 ++ira;
5986 }
5987 }// for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin(); ...
5988
5989 // Generate the "coordinates" attribute only for variables that have both 2-D lat/lon dim. names.
5990 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
5991 ird != (*irv)->dims.end(); ++ ird) {
5992 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
5993 ircv != this->cvars.end(); ++ircv) {
5994 if ((*ird)->name == (*ircv)->cfdimname)
5995 co_attrvalue = (co_attrvalue.empty())
5996 ?(*ircv)->newname:co_attrvalue + " "+(*ircv)->newname;
5997 }
5998 }
5999
6000 if (false == co_attrvalue.empty()) {
6001 Attribute * attr = new Attribute();
6002 Add_Str_Attr(attr,co_attrname,co_attrvalue);
6003 (*irv)->attrs.push_back(attr);
6004 }
6005
6006 co_attrvalue.clear();
6007 } // for (vector<Var *>::iterator irv = this->vars.begin(); ...
6008 }
6009 }
6010 }
6011}
6012#endif
6013
6014
6015// Handle the "coordinates" and "units" attributes of coordinate variables.
6017
6018 BESDEBUG("h5", "GMFile::Coming to Handle_Coor_Attr()"<<endl);
6019 string co_attrname = "coordinates";
6020 string co_attrvalue="";
6021 string unit_attrname = "units";
6022 string nonll_unit_attrvalue ="level";
6023 string lat_unit_attrvalue ="degrees_north";
6024 string lon_unit_attrvalue ="degrees_east";
6025
6026 // Attribute units should be added for coordinate variables that
6027 // have the type CV_NONLATLON_MISS,CV_LAT_MISS and CV_LON_MISS.
6028 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
6029 ircv != this->cvars.end(); ++ircv) {
6030
6031 if ((*ircv)->cvartype == CV_NONLATLON_MISS) {
6032 Attribute * attr = new Attribute();
6033 Add_Str_Attr(attr,unit_attrname,nonll_unit_attrvalue);
6034 (*ircv)->attrs.push_back(attr);
6035 }
6036 else if ((*ircv)->cvartype == CV_LAT_MISS) {
6037 Attribute * attr = new Attribute();
6038 Add_Str_Attr(attr,unit_attrname,lat_unit_attrvalue);
6039 (*ircv)->attrs.push_back(attr);
6040 }
6041 else if ((*ircv)->cvartype == CV_LON_MISS) {
6042 Attribute * attr = new Attribute();
6043 Add_Str_Attr(attr,unit_attrname,lon_unit_attrvalue);
6044 (*ircv)->attrs.push_back(attr);
6045 }
6046 } // for (vector<GMCVar *>::iterator ircv = this->cvars.begin(); ...
6047
6048 // No need to handle MeaSUREs SeaWiFS level 2 products
6049 if(product_type == Mea_SeaWiFS_L2)
6050 return;
6051
6052 // GPM level 1 needs to be handled separately
6053 else if(product_type == GPM_L1) {
6054 Handle_GPM_l1_Coor_Attr();
6055 return;
6056 }
6057
6058 // Handle Lat/Lon with "coordinates" attribute.
6059 else if(product_type == General_Product && gproduct_pattern == GENERAL_LATLON_COOR_ATTR){
6060 Handle_LatLon_With_CoordinateAttr_Coor_Attr();
6061 return;
6062 }
6063 // No need to handle products that follow COARDS.
6064 else if (true == iscoard) {
6065
6066 // If we find that there are groups that should check the coordinates attribute of the variable.
6067 // We should flatten the path inside the coordinates.(this is the case mainly for netcdf-4 2D lat/lon case)
6068 if(grp_cv_paths.size() >0) {
6069 for (vector<Var *>::iterator irv = this->vars.begin();
6070 irv != this->vars.end(); ++irv) {
6071 if(grp_cv_paths.find(HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath)) != grp_cv_paths.end()){
6072
6073 // Check the "coordinates" attribute and flatten the values.
6074 Flatten_VarPath_In_Coordinates_Attr(*irv);
6075 }
6076 }
6077 }
6078 return;
6079 }
6080
6081 // Now handle the 2-D lat/lon case
6082 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
6083 ircv != this->cvars.end(); ++ircv) {
6084
6085 if((*ircv)->rank == 2 && (*ircv)->cvartype == CV_EXIST) {
6086
6087 //Note: When the 2nd parameter is true in the function Is_geolatlon, it checks the lat/latitude/Latitude
6088 // When the 2nd parameter is false in the function Is_geolatlon, it checks the lon/longitude/Longitude
6089 // The following code makes sure that the replacement only happens with the general 2-D lat/lon case.
6090 // The following code is commented out since we find an OMPS-NPP case that has the no-CF unit for
6091 // "Latitude". So just to check the latitude and longitude and if the units are not CF-compliant,
6092 // change them. KY 2020-02-27
6093#if 0
6094 if(gp_latname == (*ircv)->name) {
6095 // Only if gp_latname is not lat/latitude/Latitude, change the units
6096 if(false == Is_geolatlon(gp_latname,true))
6097 Replace_Var_Str_Attr((*ircv),unit_attrname,lat_unit_attrvalue);
6098 }
6099 else if(gp_lonname ==(*ircv)->name) {
6100 // Only if gp_lonname is not lon/longitude/Longitude, change the units
6101 if(false == Is_geolatlon(gp_lonname,false))
6102 Replace_Var_Str_Attr((*ircv),unit_attrname,lon_unit_attrvalue);
6103 }
6104#endif
6105
6106 // We meet several products that miss the 2-D latitude and longitude CF units although they
6107 // have the CV names like latitude/longitude, we should double check this case,
6108 // and add the correct CF units if possible. We will watch if this is the right way.
6109 //else if(true == Is_geolatlon((*ircv)->name,true))
6110 if(true == Is_geolatlon((*ircv)->name,true))
6111 Replace_Var_Str_Attr((*ircv),unit_attrname,lat_unit_attrvalue);
6112
6113 else if(true == Is_geolatlon((*ircv)->name,false))
6114 Replace_Var_Str_Attr((*ircv),unit_attrname,lon_unit_attrvalue);
6115 }
6116 } // for (vector<GMCVar *>::iterator ircv = this->cvars.begin()
6117
6118 // If we find that there are groups that we should check the coordinates attribute of the variable under,
6119 // we should flatten the path inside the coordinates. Note this is for 2D-latlon CV netCDF-4-like case.
6120 if(grp_cv_paths.size() >0) {
6121 for (vector<Var *>::iterator irv = this->vars.begin();
6122 irv != this->vars.end(); ++irv) {
6123 if(grp_cv_paths.find(HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath)) != grp_cv_paths.end()){
6124
6125 // Check the "coordinates" attribute and flatten the values.
6126 Flatten_VarPath_In_Coordinates_Attr(*irv);
6127 }
6128 }
6129 }
6130
6131 // Check if having 2-D lat/lon CVs
6132 bool has_ll2d_coords = false;
6133
6134 // Since iscoard is false up to this point, So the netCDF-4 like 2-D lat/lon case must fulfill if the program comes here.
6135 if(General_Product == this->product_type && GENERAL_DIMSCALE == this->gproduct_pattern)
6136 has_ll2d_coords = true;
6137 else {// For other cases. Need to see if there is a case. KY 2016-07-07
6138 string ll2d_dimname0;
6139 string ll2d_dimname1;
6140 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
6141 ircv != this->cvars.end(); ++ircv) {
6142 if((*ircv)->rank == 2) {
6143 // Note: we should still use the original dim. name to match the general variables.
6144 ll2d_dimname0 = (*ircv)->getDimensions()[0]->name;
6145 ll2d_dimname1 = (*ircv)->getDimensions()[1]->name;
6146 if(ll2d_dimname0 !="" && ll2d_dimname1 !="")
6147 has_ll2d_coords = true;
6148 break;
6149 }
6150 }
6151 }
6152
6153 // We now walk through all the >=2 vars and flatten the "coordinates"
6154 if(true == has_ll2d_coords) {
6155
6156 // For some netCDF-4-like 2-D lat/lon cases, we may need to forcely flatten the coordinates.
6157 // This case usually happens when the data producers follow the CF and the NASA DIWG guideline to
6158 // provide the absolute path of the coordinates as the value of the "coordinates" attribute.
6159 // The handler doesn't need to figure out the contents of the coordinates attribute but to
6160 // flatten the path inside.
6161 // However, the BES Key FORCENDCoorAttr must be set.
6162 bool force_flatten_coor_attr = HDF5RequestHandler::get_force_flatten_coor_attr();
6163
6164 // We also need to find if we have coordinates attribute for >=2D variables.
6165 // If not, the handler has to figure out the coordinates.
6166 bool has_coor_attr_ge_2d_vars = false;
6167 for (vector<Var *>::iterator irv = this->vars.begin();
6168 irv != this->vars.end(); ++irv) {
6169 if((*irv)->rank >=2){
6170 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin(); ira !=(*irv)->attrs.end();++ira) {
6171 // We will check if we have the coordinate attribute
6172 if((*ira)->name == co_attrname) {
6173 has_coor_attr_ge_2d_vars = true;
6174 break;
6175 }
6176 }
6177 if(has_coor_attr_ge_2d_vars == true)
6178 break;
6179 }
6180 }
6181#if 0
6182 // Here we may need to consider the special case for HDF-EOS5. The "Data Fields" etc should not be
6183 // in the group path. May need to let DIWG provide a guideline for this issue.
6184 bool is_hybrid_eos5= false;
6185 if(force_flatten_coor_attr == true && has_coor_attr_ge_2d_vars == true)
6186 is_hybrid_eos5 = Is_Hybrid_EOS5();
6187#endif
6188 for (vector<Var *>::iterator irv = this->vars.begin();
6189 irv != this->vars.end(); ++irv) {
6190
6191 bool has_coor = false;
6192 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin(); ira !=(*irv)->attrs.end();++ira) {
6193 // We will check if we have the coordinate attribute
6194 if((*ira)->name == co_attrname) {
6195 has_coor = true;
6196 break;
6197 }
6198 }
6199
6200 // The coordinates attribute is flattened by force.
6201 if(true == force_flatten_coor_attr && true == has_coor) {
6202#if 0
6203 if(is_hybrid_eos5 == true) {
6204 Flatten_VarPath_In_Coordinates_Attr_EOS5((*irv));
6205 }
6206 else
6207#endif
6208 Flatten_VarPath_In_Coordinates_Attr((*irv));
6209 }
6210
6211 else if(((*irv)->rank >=2) && (has_coor_attr_ge_2d_vars == false || false == force_flatten_coor_attr)) {
6212
6213 bool coor_attr_keep_exist = false;
6214
6215 // Check if this var is under group_cv_paths, no, then check if this var's dims are the same as the dims of 2-D CVars
6216 if(grp_cv_paths.find(HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath)) == grp_cv_paths.end())
6217
6218 // If finding this var is associated with 2-D lat/lon CVs, not keep the original "coordinates" attribute.
6219 coor_attr_keep_exist = Check_Var_2D_CVars(*irv);
6220 else {
6221 coor_attr_keep_exist = true;
6222 }
6223
6224 // The following two lines are just for old smap level 2 case.
6225 if(product_type == OSMAPL2S)
6226 coor_attr_keep_exist = true;
6227
6228 // Need to delete the original "coordinates" and rebuild the "coordinates" if this var is associated with the 2-D lat/lon CVs.
6229 if (false == coor_attr_keep_exist) {
6230 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin();
6231 ira !=(*irv)->attrs.end();) {
6232 if ((*ira)->newname == co_attrname) {
6233 delete (*ira);
6234 ira = (*irv)->attrs.erase(ira);
6235 }
6236 else {
6237 ++ira;
6238 }
6239 }// for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin(); ...
6240
6241 // Generate the new "coordinates" attribute.
6242 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
6243 ird != (*irv)->dims.end(); ++ ird) {
6244 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
6245 ircv != this->cvars.end(); ++ircv) {
6246 if ((*ird)->name == (*ircv)->cfdimname)
6247 co_attrvalue = (co_attrvalue.empty())
6248 ?(*ircv)->newname:co_attrvalue + " "+(*ircv)->newname;
6249 }
6250 }
6251
6252 if (false == co_attrvalue.empty()) {
6253 Attribute * attr = new Attribute();
6254 Add_Str_Attr(attr,co_attrname,co_attrvalue);
6255 (*irv)->attrs.push_back(attr);
6256 }
6257
6258 co_attrvalue.clear();
6259 (*irv)->coord_attr_add_path = false;
6260 } // for (vector<Var *>::iterator irv = this->vars.begin(); ...
6261 }
6262 }
6263 }
6264}
6265
6266// Handle GPM level 1 coordiantes attributes.
6267void GMFile:: Handle_GPM_l1_Coor_Attr() {
6268
6269 BESDEBUG("h5", "Coming to Handle_GPM_l1_Coor_Attr()"<<endl);
6270 // Build a map from CFdimname to 2-D lat/lon variable name, should be something like: aa_list[cfdimname]=s1_latitude .
6271 // Loop all variables
6272 // Inner loop: for all dims of a var
6273 // if(dimname matches the dim(not cfdim) name of one of 2-D lat/lon,
6274 // check if the variable's full path contains the path of one of 2-D lat/lon,
6275 // yes, build its cfdimname = path+ dimname, check this cfdimname with the cfdimname of the corresponding 2-D lat/lon
6276 // If matched, save this latitude variable name as one of the coordinate variable.
6277 // else this is a 3rd-dimension cv, just use the dimension name(or the corresponding cv name maybe through a map).
6278
6279 // Prepare 1) 2-D CVar(lat,lon) corresponding dimension name set.
6280 // 2) cfdim name to cvar name map(don't need to use a map, just a holder. It should be fine.
6281
6282 // "coordinates" attribute name and value. We only need to provide this atttribute for variables that have 2-D lat/lon
6283 string co_attrname = "coordinates";
6284 string co_attrvalue="";
6285
6286 // 2-D cv dimname set.
6287 set<string> cvar_2d_dimset;
6288
6289 pair<map<string,string>::iterator,bool>mapret;
6290
6291 // Hold the mapping from cfdimname to 2-D cvar name. Something like nscan->lat, npixel->lon
6292 map<string,string>cfdimname_to_cvar2dname;
6293
6294 // Loop through cv variables to build 2-D cv dimname set and the mapping from cfdimname to 2-D cvar name.
6295 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
6296 irv != this->cvars.end(); ++irv) {
6297
6298 //This CVar must be 2-D array.
6299 if((*irv)->rank == 2) {
6300
6301//cerr<<"2-D cv name is "<<(*irv)->name <<endl;
6302//cerr<<"2-D cv new name is "<<(*irv)->newname <<endl;
6303//cerr<<"(*irv)->cfdimname is "<<(*irv)->cfdimname <<endl;
6304
6305 for(vector<Dimension *>::iterator ird = (*irv)->dims.begin();
6306 ird != (*irv)->dims.end(); ++ird) {
6307 cvar_2d_dimset.insert((*ird)->name);
6308 }
6309
6310 // Generate cfdimname to cvar2d map
6311 mapret = cfdimname_to_cvar2dname.insert(pair<string,string>((*irv)->cfdimname,(*irv)->newname));
6312 if (false == mapret.second)
6313 throw4("The cf dimension name ",(*irv)->cfdimname," should map to 2-D coordinate variable",
6314 (*irv)->newname);
6315 }
6316 }
6317
6318 // Loop through the variable list to build the coordinates.
6319 for (vector<Var *>::iterator irv = this->vars.begin();
6320 irv != this->vars.end(); ++irv) {
6321
6322 // Only apply to >2D variables.
6323 if((*irv)->rank >=2) {
6324
6325 // The variable dimension names must be found in the 2D cvar dim. nameset.
6326 // The flag must be at least 2.
6327 short have_2d_dimnames_flag = 0;
6328 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
6329 ird !=(*irv)->dims.end();++ird) {
6330 if (cvar_2d_dimset.find((*ird)->name)!=cvar_2d_dimset.end())
6331 have_2d_dimnames_flag++;
6332 }
6333
6334 // Final candidates to have 2-D CVar coordinates.
6335 if(have_2d_dimnames_flag >=2) {
6336
6337 // Obtain the variable path
6338 string var_path;
6339 if((*irv)->fullpath.size() > (*irv)->name.size())
6340 var_path=(*irv)->fullpath.substr(0,(*irv)->fullpath.size()-(*irv)->name.size());
6341 else
6342 throw4("The variable full path ",(*irv)->fullpath," doesn't contain the variable name ",
6343 (*irv)->name);
6344
6345 // A flag to identify if this variable really needs the 2-D coordinate variables.
6346 short cv_2d_flag = 0;
6347
6348 // 2-D coordinate variable names for the potential variable candidate
6349 vector<string> cv_2d_names;
6350
6351 // Dimension names of the 2-D coordinate variables.
6352 set<string> cv_2d_dimnames;
6353
6354 // Loop through the map from dim. name to coordinate name.
6355 for(map<string,string>::const_iterator itm = cfdimname_to_cvar2dname.begin();
6356 itm != cfdimname_to_cvar2dname.end();++itm) {
6357
6358 // Obtain the dimension name from the cfdimname.
6359 string reduced_dimname = HDF5CFUtil::obtain_string_after_lastslash(itm->first);
6360 string cfdim_path;
6361 if(itm->first.size() <= reduced_dimname.size())
6362 throw2("The cf dim. name of this dimension is not right.",itm->first);
6363 else
6364 cfdim_path= itm->first.substr(0,itm->first.size() - reduced_dimname.size());
6365 // cfdim_path will not be NULL only when the cfdim name is for the 2-D cv var.
6366
6367 // Find the correct path,
6368 // Note:
6369 // var_path doesn't have to be the same as cfdim_path
6370 // consider the variable /a1/a2/foo and the latitude /a1/latitude(cfdimpath is /a1)
6371 // If there is no /a1/a2/latitude, the /a1/latitude can be used as the coordinate of /a1/a2/foo.
6372 // But we want to check if var_path is the same as cfdim_path first. So we check cfdimname_to_cvarname again.
6373 if(var_path == cfdim_path) {
6374 for (vector<Dimension*>::iterator ird = (*irv)->dims.begin();
6375 ird!=(*irv)->dims.end();++ird) {
6376 if(reduced_dimname == (*ird)->name) {
6377 cv_2d_flag++;
6378 cv_2d_names.push_back(itm->second);
6379 cv_2d_dimnames.insert((*ird)->name);
6380 }
6381 }
6382 }
6383 }
6384
6385 // Note:
6386 // var_path doesn't have to be the same as cfdim_path
6387 // consider the variable /a1/a2/foo and the latitude /a1/latitude(cfdimpath is /a1)
6388 // If there is no /a1/a2/latitude, the /a1/latitude can be used as the coordinate of /a1/a2/foo.
6389 // The variable has 2 coordinates(dimensions) if the flag is 2
6390 // If the flag is not 2, we will see if the above case stands.
6391 if(cv_2d_flag != 2) {
6392 cv_2d_flag = 0;
6393 // Loop through the map from dim. name to coordinate name.
6394 for(map<string,string>::const_iterator itm = cfdimname_to_cvar2dname.begin();
6395 itm != cfdimname_to_cvar2dname.end();++itm) {
6396 // Obtain the dimension name from the cfdimname.
6397 string reduced_dimname = HDF5CFUtil::obtain_string_after_lastslash(itm->first);
6398 string cfdim_path;
6399 if(itm->first.size() <= reduced_dimname.size())
6400 throw2("The cf dim. name of this dimension is not right.",itm->first);
6401 else
6402 cfdim_path= itm->first.substr(0,itm->first.size() - reduced_dimname.size());
6403 // cfdim_path will not be NULL only when the cfdim name is for the 2-D cv var.
6404
6405 // Find the correct path,
6406 // Note:
6407 // var_path doesn't have to be the same as cfdim_path
6408 // consider the variable /a1/a2/foo and the latitude /a1/latitude(cfdimpath is /a1)
6409 // If there is no /a1/a2/latitude, the /a1/latitude can be used as the coordinate of /a1/a2/foo.
6410 //
6411 if(var_path.find(cfdim_path)!=string::npos) {
6412 for (vector<Dimension*>::iterator ird = (*irv)->dims.begin();
6413 ird!=(*irv)->dims.end();++ird) {
6414 if(reduced_dimname == (*ird)->name) {
6415 cv_2d_flag++;
6416 cv_2d_names.push_back(itm->second);
6417 cv_2d_dimnames.insert((*ird)->name);
6418 }
6419 }
6420 }
6421
6422 }
6423 }
6424
6425 // Now we got all cases.
6426 if(2 == cv_2d_flag) {
6427
6428 // Add latitude and longitude to the 'coordinates' attribute.
6429 co_attrvalue = cv_2d_names[0] + " " + cv_2d_names[1];
6430 if((*irv)->rank >2) {
6431 for (vector<Dimension *>::iterator ird = (*irv)->dims.begin();
6432 ird !=(*irv)->dims.end();++ird) {
6433
6434 // Add 3rd-dimension to the 'coordinates' attribute.
6435 if(cv_2d_dimnames.find((*ird)->name) == cv_2d_dimnames.end())
6436 co_attrvalue = co_attrvalue + " " +(*ird)->newname;
6437 }
6438 }
6439 Attribute * attr = new Attribute();
6440 Add_Str_Attr(attr,co_attrname,co_attrvalue);
6441 (*irv)->attrs.push_back(attr);
6442 (*irv)->coord_attr_add_path = false;
6443 }
6444 }
6445 }
6446 }
6447}
6448
6449// This routine is for handling "coordinates" for the GENERAL_LATLON_COOR_ATTR pattern of General_Product.
6450void GMFile::Handle_LatLon_With_CoordinateAttr_Coor_Attr() {
6451
6452 BESDEBUG("h5", "Coming to Handle_LatLon_With_CoordinateAttr_Coor_Attr()"<<endl);
6453 string co_attrname = "coordinates";
6454
6455 // Loop through all rank >1 variables
6456 for (vector<Var *>::iterator irv = this->vars.begin();
6457 irv != this->vars.end(); ++irv) {
6458 if((*irv)->rank >= 2) {
6459 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin(); ira !=(*irv)->attrs.end(); ++ira) {
6460 if((*ira)->name == co_attrname) {
6461 // If having the coordinates attribute, check if the "coordinates" variables match 2-D lat/lon CV condition,
6462 // if yes, flatten the coordinates attribute.
6463 string coor_value = Retrieve_Str_Attr_Value(*ira,(*irv)->fullpath);
6464 if(Coord_Match_LatLon_NameSize(coor_value) == true)
6465 Flatten_VarPath_In_Coordinates_Attr(*irv);
6466 // If the "coordinates" variables don't match the first condition, we can still check
6467 // if we can find the corresponding "coordinates" variables that match the names under the same group,
6468 // if yes, we add the path to the attribute "coordinates".
6469 else if(Coord_Match_LatLon_NameSize_Same_Group(coor_value,HDF5CFUtil::obtain_string_before_lastslash((*irv)->fullpath)) == true)
6470 Add_VarPath_In_Coordinates_Attr(*irv,coor_value);
6471 // For other cases, we don't do anything with the "coordinates".
6472 break;
6473 }
6474 }
6475 }
6476 }
6477
6478}
6479
6480// We will check the "coordinates variables" stored in the coordinate attribute match the
6481// checked latlon_name_pairs for the GENERAL_LATLON_COOR_ATTR case.
6482bool GMFile::Coord_Match_LatLon_NameSize(const string & coord_values) {
6483
6484 BESDEBUG("h5", "Coming to Coord_Match_LatLon_NameSize()"<<endl);
6485 bool ret_value =false;
6486 vector<string> coord_values_vec;
6487 char sep=' ';
6488 int match_lat_name_pair_index = -1;
6489 int match_lon_name_pair_index = -2;
6490 int num_match_lat = 0;
6491 int num_match_lon = 0;
6492
6493
6494 // Decompose the coordinates attribute into a string vector.
6495 HDF5CFUtil::Split_helper(coord_values_vec,coord_values,sep);
6496
6497 // Some products ignore the first "/" of the coordinate path in the coordinate attribute, we will correct this
6498 if((coord_values_vec[0])[0] !='/') {
6499 for(vector<string>::iterator irs=coord_values_vec.begin();irs!=coord_values_vec.end();++irs){
6500 if(((*irs).find_first_of('/'))!=string::npos) {
6501 *irs = '/' + (*irs);
6502 }
6503 }
6504 }
6505
6506 //Loop through all coordinate path stored in the coordinate patch vector,
6507 for(vector<string>::iterator irs=coord_values_vec.begin();irs!=coord_values_vec.end();++irs){
6508
6509 // Loop through all the lat/lon pairs generated in the Check_LatLon_With_Coordinate_Attr routine
6510 // Remember the index and number appeared for both lat and lon.
6511 for(vector<struct Name_Size_2Pairs>::iterator ivs=latloncv_candidate_pairs.begin(); ivs!=latloncv_candidate_pairs.end();++ivs) {
6512 if((*irs) == (*ivs).name1){
6513 match_lat_name_pair_index = distance(latloncv_candidate_pairs.begin(),ivs);
6514 num_match_lat++;
6515 }
6516 else if ((*irs) == (*ivs).name2) {
6517 match_lon_name_pair_index = distance(latloncv_candidate_pairs.begin(),ivs);
6518 num_match_lon++;
6519 }
6520 }
6521 }
6522 //Only when both index and the number of appearence match, we can set this be true.
6523 if((match_lat_name_pair_index == match_lon_name_pair_index) && (num_match_lat ==1) && (num_match_lon ==1))
6524 ret_value = true;
6525
6526 return ret_value;
6527
6528}
6529
6530//Some products only store the coordinate name(not full path) in the attribute coordinates, as
6531//long as it is valid, we should add the path to this coordinates.
6532bool GMFile::Coord_Match_LatLon_NameSize_Same_Group(const string &coord_values,const string &var_path) {
6533
6534 BESDEBUG("h5", "Coming to Coord_Match_LatLon_NameSize_Same_Group()"<<endl);
6535 bool ret_value =false;
6536 vector<string> coord_values_vec;
6537 char sep=' ';
6538 int match_lat_name_pair_index = -1;
6539 int match_lon_name_pair_index = -2;
6540 int num_match_lat = 0;
6541 int num_match_lon = 0;
6542
6543 HDF5CFUtil::Split_helper(coord_values_vec,coord_values,sep);
6544
6545 // Assume the 3rd-variable is also located under the same group if rank >=2
6546 for(vector<string>::iterator irs=coord_values_vec.begin();irs!=coord_values_vec.end();++irs){
6547//cerr<<"coordinate values are "<<*irs <<endl;
6548 for(vector<struct Name_Size_2Pairs>::iterator ivs=latloncv_candidate_pairs.begin(); ivs!=latloncv_candidate_pairs.end();++ivs) {
6549 string lat_name = HDF5CFUtil::obtain_string_after_lastslash((*ivs).name1);
6550 string lat_path = HDF5CFUtil::obtain_string_before_lastslash((*ivs).name1);
6551 string lon_name = HDF5CFUtil::obtain_string_after_lastslash((*ivs).name2);
6552 string lon_path = HDF5CFUtil::obtain_string_before_lastslash((*ivs).name2);
6553 if((*irs) == lat_name && lat_path == var_path){
6554 match_lat_name_pair_index = distance(latloncv_candidate_pairs.begin(),ivs);
6555 num_match_lat++;
6556 }
6557 else if ((*irs) == lon_name && lon_path == var_path) {
6558 match_lon_name_pair_index = distance(latloncv_candidate_pairs.begin(),ivs);
6559 num_match_lon++;
6560 }
6561 }
6562 }
6563
6564 if((match_lat_name_pair_index == match_lon_name_pair_index) && (num_match_lat ==1) && (num_match_lon ==1))
6565 ret_value = true;
6566
6567 return ret_value;
6568}
6569
6570// This is for the GENERAL_LATLON_COOR_ATTR pattern of General_Product.
6571void GMFile::Add_VarPath_In_Coordinates_Attr(Var *var, const string &coor_value) {
6572
6573 BESDEBUG("h5", "Coming to Add_VarPath_In_Coordinates_Attr()"<<endl);
6574 string new_coor_value;
6575 char sep =' ';
6576 string var_path = HDF5CFUtil::obtain_string_before_lastslash(var->fullpath) ;
6577 string var_flatten_path = get_CF_string(var_path);
6578
6579 // We need to loop through each element in the "coor_value".
6580 size_t ele_start_pos = 0;
6581 size_t cur_pos = coor_value.find_first_of(sep);
6582 while(cur_pos !=string::npos) {
6583 string tempstr = coor_value.substr(ele_start_pos,cur_pos-ele_start_pos);
6584 tempstr = var_flatten_path + tempstr;
6585 new_coor_value += tempstr + sep;
6586 ele_start_pos = cur_pos+1;
6587 cur_pos = coor_value.find_first_of(sep,cur_pos+1);
6588 }
6589
6590 if(ele_start_pos == 0)
6591 new_coor_value = var_flatten_path + coor_value;
6592 else
6593 new_coor_value += var_flatten_path + coor_value.substr(ele_start_pos);
6594
6595 string coor_attr_name = "coordinates";
6596 Replace_Var_Str_Attr(var,coor_attr_name,new_coor_value);
6597 var->coord_attr_add_path = false;
6598
6599}
6600
6601// Create Missing coordinate variables. Index numbers are used for these variables.
6602void GMFile:: Create_Missing_CV(GMCVar *GMcvar, const string& dimname) {
6603
6604 BESDEBUG("h5", "GMFile::Coming to Create_Missing_CV()"<<endl);
6605
6606 GMcvar->name = dimname;
6607 GMcvar->newname = GMcvar->name;
6608 GMcvar->fullpath = GMcvar->name;
6609 GMcvar->rank = 1;
6610 GMcvar->dtype = H5INT32;
6611 hsize_t gmcvar_dimsize = dimname_to_dimsize[dimname];
6612 bool unlimited_flag = dimname_to_unlimited[dimname];
6613 Dimension* gmcvar_dim = new Dimension(gmcvar_dimsize);
6614 gmcvar_dim->unlimited_dim = unlimited_flag;
6615 gmcvar_dim->name = dimname;
6616 gmcvar_dim->newname = dimname;
6617 GMcvar->dims.push_back(gmcvar_dim);
6618 GMcvar->cfdimname = dimname;
6619 GMcvar->cvartype = CV_NONLATLON_MISS;
6620 GMcvar->product_type = product_type;
6621}
6622
6623 // Check if this is just a netCDF-4 dimension. We need to check the dimension scale dataset attribute "NAME",
6624 // the value should start with "This is a netCDF dimension but not a netCDF variable".
6625bool GMFile::Is_netCDF_Dimension(Var *var) {
6626
6627 string netcdf_dim_mark = "This is a netCDF dimension but not a netCDF variable";
6628
6629 bool is_only_dimension = false;
6630
6631 for(vector<Attribute *>::iterator ira = var->attrs.begin();
6632 ira != var->attrs.end();ira++) {
6633
6634 if ("NAME" == (*ira)->name) {
6635
6636 Retrieve_H5_Attr_Value(*ira,var->fullpath);
6637 string name_value;
6638 name_value.resize((*ira)->value.size());
6639 copy((*ira)->value.begin(),(*ira)->value.end(),name_value.begin());
6640
6641 // Compare the attribute "NAME" value with the string netcdf_dim_mark. We only compare the string with the size of netcdf_dim_mark
6642 if (0 == name_value.compare(0,netcdf_dim_mark.size(),netcdf_dim_mark))
6643 is_only_dimension = true;
6644
6645 break;
6646 }
6647 } // for(vector<Attribute *>::iterator ira = var->attrs.begin(); ...
6648
6649 return is_only_dimension;
6650}
6651
6652// Handle attributes for special variables.
6653void
6655
6656}
6657
6658bool
6659GMFile::Is_Hybrid_EOS5() {
6660
6661 bool has_group_hdfeos = false;
6662 bool has_group_hdfeos_info = false;
6663
6664 // Too costly to check the dataset.
6665 // We will just check the attribute under /HDFEOS INFORMATION.
6666
6667 // First check if the HDFEOS groups are included
6668 for (vector<Group *>::iterator irg = this->groups.begin();
6669 irg != this->groups.end(); ++ irg) {
6670 if ("/HDFEOS" == (*irg)->path)
6671 has_group_hdfeos = true;
6672 else if("/HDFEOS INFORMATION" == (*irg)->path) {
6673 for(vector<Attribute *>::iterator ira = (*irg)->attrs.begin();
6674 ira != (*irg)->attrs.end();ira++) {
6675 if("HDFEOSVersion" == (*ira)->name)
6676 has_group_hdfeos_info = true;
6677 }
6678 }
6679 if(true == has_group_hdfeos && true == has_group_hdfeos_info)
6680 break;
6681 }
6682
6683
6684 if(true == has_group_hdfeos && true == has_group_hdfeos_info)
6685 return true;
6686 else
6687 return false;
6688}
6689
6690void GMFile::Handle_Hybrid_EOS5() {
6691
6692 string eos_str="HDFEOS_";
6693 string eos_info_str="HDFEOS_INFORMATION_";
6694 string grid_str="GRIDS_";
6695 string swath_str="SWATHS_";
6696 string zas_str="ZAS_";
6697 string df_str="Data_Fields_";
6698 string gf_str="Geolocation_Fields_";
6699 for (vector<Var *>::iterator irv = this->vars.begin();
6700 irv != this->vars.end(); irv++) {
6701 string temp_var_name = (*irv)->newname;
6702
6703 bool remove_eos = Remove_EOS5_Strings(temp_var_name);
6704
6705 if(true == remove_eos)
6706 (*irv)->newname = get_CF_string(temp_var_name);
6707 else {//HDFEOS info and extra fields
6708 string::size_type eos_info_pos = temp_var_name.find(eos_info_str);
6709 if(eos_info_pos !=string::npos)
6710 (*irv)->newname = temp_var_name.erase(eos_info_pos,eos_info_str.size());
6711 else {// Check the extra fields
6712 if(Remove_EOS5_Strings_NonEOS_Fields(temp_var_name)==true)
6713 (*irv)->newname = get_CF_string(temp_var_name);
6714 }
6715 }
6716 }
6717
6718 // Now we need to handle the dimension names.
6719 for (vector<Var *>::iterator irv = this->vars.begin();
6720 irv != this->vars.end(); irv++) {
6721 for (vector<Dimension*>::iterator ird = (*irv)->dims.begin();
6722 ird!=(*irv)->dims.end(); ++ird) {
6723 string temp_dim_name = (*ird)->newname;
6724 bool remove_eos = Remove_EOS5_Strings(temp_dim_name);
6725
6726 if(true == remove_eos)
6727 (*ird)->newname = get_CF_string(temp_dim_name);
6728 else {//HDFEOS info and extra fields
6729 string::size_type eos_info_pos = temp_dim_name.find(eos_info_str);
6730 if(eos_info_pos !=string::npos)
6731 (*ird)->newname = temp_dim_name.erase(eos_info_pos,eos_info_str.size());
6732 else {// Check the extra fields
6733 if(Remove_EOS5_Strings_NonEOS_Fields(temp_dim_name)==true)
6734 (*ird)->newname = get_CF_string(temp_dim_name);
6735 }
6736 }
6737 }
6738 }
6739
6740 // We have to loop through all CVs.
6741 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
6742 irv != this->cvars.end(); ++irv) {
6743 string temp_var_name = (*irv)->newname;
6744
6745 bool remove_eos = Remove_EOS5_Strings(temp_var_name);
6746
6747 if(true == remove_eos)
6748 (*irv)->newname = get_CF_string(temp_var_name);
6749 else {//HDFEOS info and extra "fields"
6750 string::size_type eos_info_pos = temp_var_name.find(eos_info_str);
6751 if(eos_info_pos !=string::npos)
6752 (*irv)->newname = temp_var_name.erase(eos_info_pos,eos_info_str.size());
6753 else {// Check the extra fields
6754 if(Remove_EOS5_Strings_NonEOS_Fields(temp_var_name)==true)
6755 (*irv)->newname = get_CF_string(temp_var_name);
6756 }
6757 }
6758 }
6759 // Now we need to handle the dimension names.
6760 for (vector<GMCVar *>::iterator irv = this->cvars.begin();
6761 irv != this->cvars.end(); irv++) {
6762 for (vector<Dimension*>::iterator ird = (*irv)->dims.begin();
6763 ird!=(*irv)->dims.end(); ++ird) {
6764 string temp_dim_name = (*ird)->newname;
6765 bool remove_eos = Remove_EOS5_Strings(temp_dim_name);
6766
6767 if(true == remove_eos)
6768 (*ird)->newname = get_CF_string(temp_dim_name);
6769 else {// HDFEOS info and extra "fields"
6770 string::size_type eos_info_pos = temp_dim_name.find(eos_info_str);
6771 if(eos_info_pos !=string::npos)
6772 (*ird)->newname = temp_dim_name.erase(eos_info_pos,eos_info_str.size());
6773 else {// Check the extra "fields"
6774 if(Remove_EOS5_Strings_NonEOS_Fields(temp_dim_name)==true)
6775 (*ird)->newname = get_CF_string(temp_dim_name);
6776 }
6777 }
6778 }
6779 }
6780
6781 // Update the coordinate attribute values
6782 // We need to remove the HDFEOS special information from the coordinates attributes
6783 // since the variable names in the DAP output are already updated.
6784 for (vector<Var *>::iterator irv = this->vars.begin();
6785 irv != this->vars.end(); irv++) {
6786 for(vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
6787 ira != (*irv)->attrs.end();ira++) {
6788 // We cannot use Retrieve_Str_Attr_value for "coordinates" since "coordinates" may be added by the handler.
6789 // KY 2017-11-3
6790 if((*ira)->name == "coordinates") {
6791 string cor_values((*ira)->value.begin(),(*ira)->value.end()) ;
6792 bool change_cor_values = false;
6793 // Find the HDFEOS string
6794 if(cor_values.find(eos_str)==0) {
6795 if(cor_values.find(grid_str)!=string::npos) {// Grid
6796 cor_values = HDF5CFUtil::remove_substrings(cor_values,eos_str);
6797 cor_values = HDF5CFUtil::remove_substrings(cor_values,grid_str);
6798 string new_cor_values = HDF5CFUtil::remove_substrings(cor_values,df_str);
6799 if(new_cor_values.size() < cor_values.size()){//df_str is also removed.
6800 change_cor_values = true;
6801 cor_values = new_cor_values;
6802 }
6803 }
6804 else if(cor_values.find(zas_str)!=string::npos) {//ZA
6805 cor_values = HDF5CFUtil::remove_substrings(cor_values,eos_str);
6806 cor_values = HDF5CFUtil::remove_substrings(cor_values,zas_str);
6807 string new_cor_values = HDF5CFUtil::remove_substrings(cor_values,df_str);
6808 if(new_cor_values.size() < cor_values.size()){//df_str is also removed.
6809 change_cor_values = true;
6810 cor_values = new_cor_values;
6811 }
6812 }
6813 else if(cor_values.find(swath_str)!=string::npos) {//Swath
6814 cor_values = HDF5CFUtil::remove_substrings(cor_values,eos_str);
6815 cor_values = HDF5CFUtil::remove_substrings(cor_values,swath_str);
6816 string new_cor_values = HDF5CFUtil::remove_substrings(cor_values,df_str);
6817 if(new_cor_values.size() < cor_values.size()){//df_str is also removed.
6818 change_cor_values = true;
6819 cor_values = new_cor_values;
6820 }
6821 else {
6822 new_cor_values = HDF5CFUtil::remove_substrings(cor_values,gf_str);
6823 if(new_cor_values.size() < cor_values.size()){//gf_str is also removed.
6824 change_cor_values = true;
6825 cor_values = new_cor_values;
6826 }
6827 }
6828 }
6829 }
6830 if(true == change_cor_values) {//Update the coordinate values
6831 (*ira)->value.resize(cor_values.size());
6832 (*ira)->fstrsize=cor_values.size();
6833 (*ira)->strsize[0] = cor_values.size();
6834 copy(cor_values.begin(), cor_values.end(), (*ira)->value.begin());
6835 (*irv)->coord_attr_add_path = false;
6836 }
6837
6838 break;
6839 }
6840 }
6841
6842 }
6843}
6844
6845// This routine is for handling the hybrid-HDFEOS5 products that have to be treated as "general products"
6846bool GMFile:: Remove_EOS5_Strings(string &var_name) {
6847
6848 string eos_str="HDFEOS_";
6849 string grid_str="GRIDS_";
6850 string swath_str="SWATHS_";
6851 string zas_str="ZAS_";
6852 string df_str="Data_Fields_";
6853 string gf_str="Geolocation_Fields_";
6854 string temp_var_name = var_name;
6855
6856 bool remove_eos = false;
6857
6858 string::size_type eos_pos = temp_var_name.find(eos_str);
6859 if(eos_pos!=string::npos) {
6860 temp_var_name.erase(eos_pos,eos_str.size());
6861 // Check grid,swath and zonal
6862 string::size_type grid_pos=temp_var_name.find(grid_str);
6863 string::size_type grid_df_pos=string::npos;
6864 if(grid_pos!=string::npos)
6865 grid_df_pos = temp_var_name.find(df_str,grid_pos);
6866 string::size_type zas_pos = string::npos;
6867 string::size_type zas_df_pos=string::npos;
6868 if(grid_pos==string::npos || grid_df_pos ==string::npos)
6869 zas_pos=temp_var_name.find(zas_str);
6870 if(zas_pos!=string::npos)
6871 zas_df_pos=temp_var_name.find(df_str,zas_pos);
6872
6873 if(grid_pos !=string::npos && grid_df_pos!=string::npos) {
6874 temp_var_name.erase(grid_pos,grid_str.size());
6875 grid_df_pos = temp_var_name.find(df_str);
6876 temp_var_name.erase(grid_df_pos,df_str.size());
6877 remove_eos = true;
6878 }
6879 else if(zas_pos!=string::npos && zas_df_pos!=string::npos){
6880 temp_var_name.erase(zas_pos,zas_str.size());
6881 zas_df_pos = temp_var_name.find(df_str);
6882 temp_var_name.erase(zas_df_pos,df_str.size());
6883 remove_eos = true;
6884 }
6885 else {//Check both Geolocation and Data for Swath
6886
6887 string::size_type swath_pos=temp_var_name.find(swath_str);
6888 string::size_type swath_df_pos=string::npos;
6889 if(swath_pos!=string::npos)
6890 swath_df_pos=temp_var_name.find(df_str,swath_pos);
6891
6892 string::size_type swath_gf_pos=string::npos;
6893 if(swath_pos!=string::npos && swath_df_pos == string::npos)
6894 swath_gf_pos=temp_var_name.find(gf_str,swath_pos);
6895
6896 if(swath_pos !=string::npos) {
6897
6898 if(swath_df_pos!=string::npos) {
6899 temp_var_name.erase(swath_pos,swath_str.size());
6900 swath_df_pos = temp_var_name.find(df_str);
6901 temp_var_name.erase(swath_df_pos,df_str.size());
6902 remove_eos = true;
6903 }
6904 else if(swath_gf_pos!=string::npos) {
6905 temp_var_name.erase(swath_pos,swath_str.size());
6906 swath_gf_pos = temp_var_name.find(gf_str);
6907 temp_var_name.erase(swath_gf_pos,gf_str.size());
6908 remove_eos = true;
6909 }
6910 }
6911 }
6912 }
6913 if(true == remove_eos)
6914 var_name = temp_var_name;
6915
6916 return remove_eos;
6917}
6918
6919bool GMFile:: Remove_EOS5_Strings_NonEOS_Fields(string &var_name) {
6920
6921 string eos_str="HDFEOS_";
6922 string grid_str="GRIDS_";
6923 string swath_str="SWATHS_";
6924 string zas_str="ZAS_";
6925 string temp_var_name = var_name;
6926
6927 bool remove_eos = false;
6928
6929 string::size_type eos_pos = temp_var_name.find(eos_str);
6930 if(eos_pos!=string::npos) {
6931 temp_var_name.erase(eos_pos,eos_str.size());
6932 remove_eos = true;
6933
6934 // See if we need to further remove some fields
6935 if(temp_var_name.find(grid_str)==0)
6936 temp_var_name.erase(0,grid_str.size());
6937 else if(temp_var_name.find(swath_str)==0)
6938 temp_var_name.erase(0,swath_str.size());
6939 else if(temp_var_name.find(zas_str)==0)
6940 temp_var_name.erase(0,zas_str.size());
6941 }
6942 if(true == remove_eos)
6943 var_name = temp_var_name;
6944
6945
6946 return remove_eos;
6947}
6948
6949// We do have an AirMSPI HDF-EOS5 hybrid UTM product that has grid_mapping attribute.
6952}
6953
6956}
6957
6959
6960 // We need to remove the FakeDim added for the unsupported variables.
6961 // We found such a case in the AirMSPR product. A compound dataype array
6962 // is assigned to a FakeDim. We need to remove them.
6963 // KY 2017-11-2: no need to even check the unsupported_var_dspace now.
6964 if(this->unsupported_var_dtype == true) {
6965
6966 // Need to check if we have coordinate variables such as FakeDim?
6967 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
6968 ircv != this->cvars.end();) {
6969 if((*ircv)->newname.find("FakeDim")==0) {
6970 bool var_has_fakedim = false;
6971 for (vector<Var*>::iterator irv2 = this->vars.begin();
6972 irv2 != this->vars.end(); irv2++) {
6973 for (vector<Dimension *>::iterator ird = (*irv2)->dims.begin();
6974 ird !=(*irv2)->dims.end(); ird++) {
6975 if((*ird)->newname == (*ircv)->newname){
6976 var_has_fakedim = true;
6977 break;
6978 }
6979 }
6980 if(var_has_fakedim == true)
6981 break;
6982 }
6983 if(var_has_fakedim == false) {
6984 // Remove this cv, the variable is unsupported.
6985 delete(*ircv);
6986 ircv = this->cvars.erase(ircv);
6987 }
6988 else
6989 ++ircv;
6990 }
6991 else
6992 ++ircv;
6993 }
6994#if 0
6995 // We need to handle unlimited dimensions
6996 //if(removed_fakedim_vars.size()!=0) {
6997 //}
6998#endif
6999 }
7000
7001}
7002
7003//Rename NC4 NonCoordVars back to the original name. This is detected by CAR_ARCTAS files.
7004//By handling this way, the output will be the same as the netCDF handler output.
7005//Check HFVHANDLER-254 for more information.
7007
7008 if(true == this->have_nc4_non_coord) {
7009 string nc4_non_coord="_nc4_non_coord_";
7010 size_t nc4_non_coord_size= nc4_non_coord.size();
7011 for (vector<Var*>::iterator irv = this->vars.begin();
7012 irv != this->vars.end(); irv++) {
7013 if((*irv)->name.find(nc4_non_coord)==0)
7014 (*irv)->newname = (*irv)->newname.substr(nc4_non_coord_size,(*irv)->newname.size()-nc4_non_coord_size);
7015 }
7016
7017 for (vector<GMCVar *>::iterator ircv = this->cvars.begin();
7018 ircv != this->cvars.end();++ircv) {
7019 if((*ircv)->name.find(nc4_non_coord)==0)
7020 (*ircv)->newname = (*ircv)->newname.substr(nc4_non_coord_size,(*ircv)->newname.size()-nc4_non_coord_size);
7021 }
7022 }
7023
7024}
7025
7027
7028 BESDEBUG("h5", "GMFile::Coming to Add_Path_Coor_Attr()"<<endl);
7029 string co_attrname = "coordinates";
7030 for (vector<Var *>::iterator irv = this->vars.begin();
7031 irv != this->vars.end(); ++irv) {
7032 if((*irv)->coord_attr_add_path == true) {
7033 for (vector<Attribute *>:: iterator ira =(*irv)->attrs.begin(); ira !=(*irv)->attrs.end();++ira) {
7034 // We will check if we have the coordinate attribute
7035 if((*ira)->name == co_attrname) {
7036 string coor_value = Retrieve_Str_Attr_Value(*ira,(*irv)->fullpath);
7037 char sep=' ';
7038 vector<string>cvalue_vec;
7039 HDF5CFUtil::Split_helper(cvalue_vec,coor_value,sep);
7040 string new_coor_value;
7041 for (int i = 0; i<cvalue_vec.size();i++) {
7042 HDF5CFUtil::cha_co(cvalue_vec[i],(*irv)->fullpath);
7043 cvalue_vec[i] = get_CF_string(cvalue_vec[i]);
7044 if(i == 0)
7045 new_coor_value = cvalue_vec[i];
7046 else
7047 new_coor_value += sep+cvalue_vec[i];
7048
7049//cout<<"co1["<<i<<"]= "<<cvalue_vec[i]<<endl;
7050 }
7051//cout<<"new_coor_value is "<<new_coor_value<<endl;
7052 Replace_Var_Str_Attr((*irv),co_attrname,new_coor_value);
7053 break;
7054 }
7055 }
7056
7057 }
7058 }
7059}
7060
7061
7062
7063
7064// We will create some temporary coordinate variables. The resource allocoated
7065// for these variables need to be released.
7066void
7067GMFile::release_standalone_GMCVar_vector(vector<GMCVar*>&tempgc_vars){
7068
7069 for (vector<GMCVar *>::iterator i = tempgc_vars.begin();
7070 i != tempgc_vars.end(); ) {
7071 delete(*i);
7072 i = tempgc_vars.erase(i);
7073 }
7074
7075}
7076
7077#if 0
7078void
7079GMFile::add_ignored_info_attrs(bool is_grp,bool is_first){
7080
7081}
7082void
7083GMFile::add_ignored_info_objs(bool is_dim_related, bool is_first) {
7084
7085}
7086#endif
7087
7088#if 0
7089bool
7090GMFile::ignored_dimscale_ref_list(Var *var) {
7091
7092 bool ignored_dimscale = true;
7093 if(General_Product == this->product_type && GENERAL_DIMSCALE== this->gproduct_pattern) {
7094
7095 bool has_dimscale = false;
7096 bool has_reference_list = false;
7097 for(vector<Attribute *>::iterator ira = var->attrs.begin();
7098 ira != var->attrs.end();ira++) {
7099 if((*ira)->name == "REFERENCE_LIST" &&
7100 false == HDF5CFUtil::cf_strict_support_type((*ira)->getType()))
7101 has_reference_list = true;
7102 if((*ira)->name == "CLASS") {
7103 Retrieve_H5_Attr_Value(*ira,var->fullpath);
7104 string class_value;
7105 class_value.resize((*ira)->value.size());
7106 copy((*ira)->value.begin(),(*ira)->value.end(),class_value.begin());
7107
7108 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
7109 // "DIMENSION_SCALE", which is 15.
7110 if (0 == class_value.compare(0,15,"DIMENSION_SCALE")) {
7111 has_dimscale = true;
7112 }
7113 }
7114
7115 if(true == has_dimscale && true == has_reference_list) {
7116 ignored_dimscale= false;
7117 break;
7118 }
7119
7120 }
7121 }
7122 return ignored_dimscale;
7123}
7124
7125#endif
This class specifies the core engineering of mapping HDF5 to DAP by following CF.
#define throw1(a1)
The followings are convenient functions to throw exceptions with different.
Definition: HDF5CF.h:128
include the entry functions to execute the handlers
This class represents one attribute.
Definition: HDF5CF.h:189
This class repersents one dimension of an HDF5 dataset(variable).
Definition: HDF5CF.h:145
This class retrieves all information from an HDF5 file.
Definition: HDF5CF.h:593
std::vector< Group * > groups
Non-root group vectors.
Definition: HDF5CF.h:816
virtual void Handle_Unsupported_Dspace(bool)
Handle unsupported HDF5 dataspaces for datasets.
Definition: HDF5CF.cc:1275
virtual void Handle_Grid_Mapping_Vars()
Handle Grid Mapping Vars.
Definition: HDF5CF.cc:2151
virtual void Handle_Unsupported_Others(bool)
Handle other unmapped objects/attributes.
Definition: HDF5CF.cc:1322
virtual void Retrieve_H5_Supported_Attr_Values()
Retrieve attribute values for the supported HDF5 datatypes.
Definition: HDF5CF.cc:729
std::vector< Var * > vars
Var vectors.
Definition: HDF5CF.h:810
virtual void Add_Supplement_Attrs(bool)
Add supplemental attributes such as fullpath and original name.
Definition: HDF5CF.cc:1970
virtual void Retrieve_H5_Info(const char *path, hid_t file_id, bool)
Definition: HDF5CF.cc:171
std::vector< Attribute * > root_attrs
Root attribute vectors.
Definition: HDF5CF.h:813
virtual void Handle_Unsupported_Dtype(bool)
Handle unsupported HDF5 datatypes.
Definition: HDF5CF.cc:918
virtual void Flatten_Obj_Name(bool)
Flatten the object name.
Definition: HDF5CF.cc:1372
virtual bool Have_Grid_Mapping_Attrs()
Check if having Grid Mapping Attrs.
Definition: HDF5CF.cc:2131
This class is a derived class of CVar. It represents a coordinate variable for general HDF5 files.
Definition: HDF5CF.h:427
virtual void Handle_Unsupported_Dtype(bool)
Handle unsupported HDF5 datatypes for general HDF5 products.
Definition: HDF5GMCF.cc:400
virtual void Adjust_Obj_Name()
Adjust object names based on different general NASA HDF5 products.
Definition: HDF5GMCF.cc:4912
virtual void Retrieve_H5_CVar_Supported_Attr_Values()
Retrieve coordinate variable attributes.
Definition: HDF5GMCF.cc:333
void Add_Path_Coord_Attr()
Update the coordinate attribute to include path and also flatten.
Definition: HDF5GMCF.cc:7026
virtual bool Have_Grid_Mapping_Attrs()
Check if having Grid Mapping Attrs.
Definition: HDF5GMCF.cc:6950
virtual void Adjust_Dim_Name()
Adjust dimension name for general NASA HDF5 products.
Definition: HDF5GMCF.cc:5225
void Handle_Obj_NameClashing(bool)
Handle object name clashing for general NASA HDF5 products.
Definition: HDF5GMCF.cc:5055
void Remove_Unused_FakeDimVars()
Unsupported datatype array may generate FakeDim. Remove them.
Definition: HDF5GMCF.cc:6958
void Update_Product_Type()
Update "product type" attributes for general HDF5 products.
Definition: HDF5GMCF.cc:238
virtual void Retrieve_H5_Info(const char *path, hid_t file_id, bool include_attr)
Retrieve DDS information from the HDF5 file; real implementation for general HDF5 products.
Definition: HDF5GMCF.cc:219
virtual void Handle_SpVar()
Handle special variables for general NASA HDF5 products.
Definition: HDF5GMCF.cc:4822
void Adjust_H5_Attr_Value(Attribute *attr)
Adjust attribute values for general HDF5 products.
Definition: HDF5GMCF.cc:382
virtual void Handle_Unsupported_Dspace(bool)
Handle unsupported HDF5 dataspaces for general HDF5 products.
Definition: HDF5GMCF.cc:597
virtual void Handle_SpVar_Attr()
Handle special variable attributes for general NASA HDF5 products.
Definition: HDF5GMCF.cc:6654
virtual void Handle_Unsupported_Others(bool)
Handle other unmapped objects/attributes for general HDF5 products.
Definition: HDF5GMCF.cc:694
void Remove_Unneeded_Objects()
Remove unneeded objects.
Definition: HDF5GMCF.cc:261
void Add_Dim_Name()
Add dimension name.
Definition: HDF5GMCF.cc:833
virtual void Flatten_Obj_Name(bool include_attr)
Flatten the object name for general NASA HDF5 products.
Definition: HDF5GMCF.cc:4997
virtual void Handle_Grid_Mapping_Vars()
Handle Grid Mapping Vars.
Definition: HDF5GMCF.cc:6954
virtual void Handle_DimNameClashing()
Definition: HDF5GMCF.cc:5160
virtual void Handle_Coor_Attr()
Handle "coordinates" attributes for general HDF5 products.
Definition: HDF5GMCF.cc:6016
void Rename_NC4_NonCoordVars()
Remove the _nc4_non_coord from the variable new names.
Definition: HDF5GMCF.cc:7006
virtual void Retrieve_H5_Supported_Attr_Values()
Retrieve attribute values for the supported HDF5 datatypes for general HDF5 products.
Definition: HDF5GMCF.cc:348
virtual void Add_Supplement_Attrs(bool)
Add supplemental attributes such as fullpath and original name for general NASA HDF5 products.
Definition: HDF5GMCF.cc:5287
virtual void Handle_CVar()
Handle coordinate variables for general NASA HDF5 products.
Definition: HDF5GMCF.cc:2939
This class is a derived class of Var. It represents a special general HDF5 product(currently ACOS and...
Definition: HDF5CF.h:392
This class represents one HDF5 dataset(CF variable)
Definition: HDF5CF.h:259
const std::vector< Dimension * > & getDimensions() const
Get the list of the dimensions.
Definition: HDF5CF.h:322
static void Split(const char *s, int len, char sep, std::vector< std::string > &names)
Definition: HDF5CFUtil.cc:341