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