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