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