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