bes  Updated for version 3.20.13
heos5cfdap.cc
Go to the documentation of this file.
1 // This file is part of hdf5_handler: an HDF5 file handler for the OPeNDAP
2 // data server.
3 
4 // Copyright (c) 2011-2016 The HDF Group, Inc. and OPeNDAP, Inc.
5 //
6 // This is free software; you can redistribute it and/or modify it under the
7 // terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 2.1 of the License, or (at your
9 // option) any later version.
10 //
11 // This software is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 // License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
21 // You can contact The HDF Group, Inc. at 1800 South Oak Street,
22 // Suite 203, Champaign, IL 61820
23 
32 #include "config_hdf5.h"
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <iostream>
39 #include <sstream>
40 
41 #include <BESLog.h>
42 #include <BESDebug.h>
43 
44 #include <libdap/parser.h>
45 #include "heos5cfdap.h"
46 #include "h5cfdaputil.h"
47 #include "HDF5CFByte.h"
48 #include "HDF5CFInt8.h"
49 #include "HDF5CFUInt16.h"
50 #include "HDF5CFInt16.h"
51 #include "HDF5CFUInt32.h"
52 #include "HDF5CFInt32.h"
53 #include "HDF5CFUInt64.h"
54 #include "HDF5CFInt64.h"
55 #include "HDF5CFFloat32.h"
56 #include "HDF5CFFloat64.h"
57 #include "HDF5CFStr.h"
58 #include "HDF5CFArray.h"
59 #include "HDFEOS5CFMissLLArray.h"
62 #include "HDF5CFGeoCF1D.h"
63 #include "HDF5CFGeoCFProj.h"
64 #include "HDF5RequestHandler.h"
65 #include "h5apicompatible.h"
66 
67 #include "he5dds.tab.hh"
68 #include "HE5Parser.h"
69 #include "HE5Checker.h"
70 #include "he5das.tab.hh"
71 
72 struct yy_buffer_state;
73 
74 yy_buffer_state *he5dds_scan_string(const char *str);
75 int he5ddsparse(HE5Parser *he5parser);
76 int he5dasparse(libdap::parser_arg *arg);
77 int he5ddslex_destroy();
78 int he5daslex_destroy();
79 
81 yy_buffer_state *he5das_scan_string(const char *str);
82 
83 using namespace HDF5CF;
84 
85 // Map EOS5 to DAP DDS
86 void map_eos5_cfdds(DDS &dds, hid_t file_id, const string & filename) {
87 
88  BESDEBUG("h5","Coming to HDF-EOS5 products DDS mapping function map_eos5_cfdds "<<endl);
89 
90 
91  string st_str ="";
92  string core_str="";
93  string arch_str="";
94  string xml_str ="";
95  string subset_str="";
96  string product_str="";
97  string other_str ="";
98  bool st_only = true;
99 
100  // Read ECS metadata: merge them into one C++ string
101  read_ecs_metadata(file_id,st_str,core_str,arch_str,xml_str, subset_str,product_str,other_str,st_only);
102  if(""==st_str) {
103  string msg =
104  "unable to obtain the HDF-EOS5 struct metadata ";
105  throw InternalErr(__FILE__, __LINE__, msg);
106  }
107 
108  bool is_check_nameclashing = HDF5RequestHandler::get_check_name_clashing();
109 
110  EOS5File *f = nullptr;
111 
112  try {
113  f = new EOS5File(filename.c_str(),file_id);
114  }
115  catch(...) {
116  throw InternalErr(__FILE__,__LINE__,"Cannot allocate the file object.");
117  }
118 
119  bool include_attr = false;
120 
121  // This first "try-catch" block will use the parsed info
122  try {
123 
124  // Parse the structmetadata
125  HE5Parser p;
126  HE5Checker c;
127  he5dds_scan_string(st_str.c_str());
128  he5ddsparse(&p);
129  he5ddslex_destroy();
130 
131  // Retrieve ProjParams from StructMetadata
132  p.add_projparams(st_str);
133 #if 0
134  //p.print();
135 #endif
136 
137  // Check if the HDF-EOS5 grid has the valid parameters, projection codes.
138  if (c.check_grids_unknown_parameters(&p)) {
139  throw InternalErr("Unknown HDF-EOS5 grid paramters found in the file");
140  }
141 
142  if (c.check_grids_missing_projcode(&p)) {
143  throw InternalErr("The HDF-EOS5 is missing project code ");
144  }
145 
146  // We gradually add the support of different projection codes
147  if (c.check_grids_support_projcode(&p)) {
148  throw InternalErr("The current project code is not supported");
149  }
150 
151  // HDF-EOS5 provides default pixel and origin values if they are not defined.
152  c.set_grids_missing_pixreg_orig(&p);
153 
154  // Check if this multi-grid file shares the same grid.
155  bool grids_mllcv = c.check_grids_multi_latlon_coord_vars(&p);
156 
157  // Retrieve all HDF5 info(Not the values)
158  f->Retrieve_H5_Info(filename.c_str(),file_id,include_attr);
159 
160  // Adjust EOS5 Dimension names/sizes based on the parsed results
161  f->Adjust_EOS5Dim_Info(&p);
162 
163  // Translate the parsed output to HDF-EOS5 grids/swaths/zonal.
164  // Several maps related to dimension and coordiantes are set up here.
165  f->Add_EOS5File_Info(&p, grids_mllcv);
166 
167  // Add the dimension names
168  f->Add_Dim_Name(&p);
169  }
170  catch (HDF5CF::Exception &e){
171  if(f!=nullptr)
172  delete f;
173  throw InternalErr(e.what());
174  }
175  catch(...) {
176  if(f!=nullptr)
177  delete f;
178  throw;
179  }
180 
181  // The parsed struct will no longer be in this "try-catch" block.
182  try {
183 
184  // NASA Aura files need special handlings. So first check if this file is an Aura file.
186 
187  // Adjust the variable name
189 
190  // Handle coordinate variables
191  f->Handle_CVar();
192 
193  // Adjust variable and dimension names again based on the handling of coordinate variables.
195 
196 
197  // We need to use the CV units to distinguish lat/lon from th 3rd CV when
198  // memory cache is turned on.
199  if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
200  (HDF5RequestHandler::get_srdata_mem_cache() != nullptr)){
201 
202  // Handle unsupported datatypes including the attributes
203  f->Handle_Unsupported_Dtype(true);
204 
205  // Handle unsupported dataspaces including the attributes
206  f->Handle_Unsupported_Dspace(true);
207 
208  // We need to retrieve coordinate variable attributes for memory cache use.
210 
211  }
212  else {
213 
214  // Handle unsupported datatypes
215  f->Handle_Unsupported_Dtype(include_attr);
216 
217  // Handle unsupported dataspaces
218  f->Handle_Unsupported_Dspace(include_attr);
219 
220  }
221 
222 
223  // Need to retrieve the units of CV when memory cache is turned on.
224  // The units of CV will be used to distinguish whether this CV is
225  // latitude/longitude or a third-dimension CV.
226  // isLatLon() will use the units value.
227  if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
228  (HDF5RequestHandler::get_srdata_mem_cache() != nullptr))
229  f->Adjust_Attr_Info();
230 
231  // May need to adjust the object names for special objects. Currently no operations
232  // are done in this routine.
233  f->Adjust_Obj_Name();
234 
235  // Flatten the object name
236  f->Flatten_Obj_Name(include_attr);
237 
238  // Handle name clashing
239  if(true == is_check_nameclashing)
240  f->Handle_Obj_NameClashing(include_attr);
241 
242  // Check if this should follow COARDS, yes, set the COARDS flag.
243  f->Set_COARDS_Status();
244 
245  // For COARDS, the dimension name needs to be changed.
246  f->Adjust_Dim_Name();
247  if(true == is_check_nameclashing)
249 
250  // We need to turn off the very long string in the TES file to avoid
251  // the choking of netCDF Java tools. So this special variable routine
252  // is listed at last. We may need to turn off this if netCDF can handle
253  // long string better.
254  f->Handle_SpVar();
255  }
256  catch (HDF5CF::Exception &e){
257  if(f != nullptr)
258  delete f;
259  throw InternalErr(e.what());
260  }
261 
262  // Generate EOS5 DDS
263  try {
264  gen_eos5_cfdds(dds,f);
265  }
266  catch(...) {
267  if (f!=nullptr)
268  delete f;
269  throw;
270  }
271 
272  if (f!=nullptr)
273  delete f;
274 }
275 
276 // Map EOS5 to DAP DAS
277 void map_eos5_cfdas(DAS &das, hid_t file_id, const string &filename) {
278 
279  BESDEBUG("h5","Coming to HDF-EOS5 products DAS mapping function map_eos5_cfdas "<<endl);
280  string st_str ="";
281  string core_str="";
282  string arch_str="";
283  string xml_str ="";
284  string subset_str="";
285  string product_str="";
286  string other_str ="";
287  bool st_only = true;
288 
289  read_ecs_metadata(file_id,st_str,core_str,arch_str,xml_str, subset_str,product_str,other_str,st_only);
290  if(""==st_str) {
291  string msg =
292  "unable to obtain the HDF-EOS5 struct metadata ";
293  throw InternalErr(__FILE__, __LINE__, msg);
294  }
295 
296  bool is_check_nameclashing = HDF5RequestHandler::get_check_name_clashing();
297 
298  bool is_add_path_attrs = HDF5RequestHandler::get_add_path_attrs();
299 
300  EOS5File *f = nullptr;
301  try {
302  f = new EOS5File(filename.c_str(),file_id);
303  }
304  catch(...) {
305  throw InternalErr(__FILE__,__LINE__,"Cannot allocate the file object.");
306  }
307  bool include_attr = true;
308 
309  // The first "try-catch" block will use the parsed info.
310  try {
311 
312  HE5Parser p;
313  HE5Checker c;
314  he5dds_scan_string(st_str.c_str());
315 
316  he5ddsparse(&p);
317  he5ddslex_destroy();
318  p.add_projparams(st_str);
319 #if 0
320  //p.print();
321  // cerr<<"main loop p.za_list.size() = "<<p.za_list.size() <<endl;
322 #endif
323 
324  if (c.check_grids_unknown_parameters(&p)) {
325  throw InternalErr("Unknown HDF-EOS5 grid paramters found in the file");
326  }
327 
328  if (c.check_grids_missing_projcode(&p)) {
329  throw InternalErr("The HDF-EOS5 is missing project code ");
330  }
331  if (c.check_grids_support_projcode(&p)) {
332  throw InternalErr("The current project code is not supported");
333  }
334  c.set_grids_missing_pixreg_orig(&p);
335 
336  bool grids_mllcv = c.check_grids_multi_latlon_coord_vars(&p);
337 
338  f->Retrieve_H5_Info(filename.c_str(),file_id,include_attr);
339  f->Adjust_EOS5Dim_Info(&p);
340  f->Add_EOS5File_Info(&p, grids_mllcv);
341  f->Add_Dim_Name(&p);
342  }
343  catch (HDF5CF::Exception &e){
344  if(f != nullptr)
345  delete f;
346  throw InternalErr(e.what());
347  }
348  catch(...) {
349  if(f != nullptr)
350  delete f;
351  throw;
352  }
353 
354  try {
357  f->Handle_CVar();
359  f->Handle_Unsupported_Dtype(include_attr);
360 
361  // Remove unsupported dataspace
362  f->Handle_Unsupported_Dspace(include_attr);
363 
364  // Need to retrieve the attribute values.
366 
367 
368  // Handle other unsupported objects,
369  // currently it mainly generates the info. for the
370  // unsupported objects other than datatype, dataspace,links and named datatype
371  // This function needs to be called after retrieving supported attributes.
372  f->Handle_Unsupported_Others(include_attr);
373 
374  // Add/adjust CF attributes
375  f->Adjust_Attr_Info();
376  f->Adjust_Obj_Name();
377  f->Flatten_Obj_Name(include_attr);
378  if (true == is_check_nameclashing)
379  f->Handle_Obj_NameClashing(include_attr);
380  f->Set_COARDS_Status();
381 
382 #if 0
383  //f->Adjust_Dim_Name();
384  //if(true == is_check_nameclashing)
385  // f->Handle_DimNameClashing();
386 #endif
387 
388  // Add supplemental attributes
389  f->Add_Supplement_Attrs(is_add_path_attrs);
390 
391  // Handle coordinate attributes
392  f->Handle_Coor_Attr();
393  f->Handle_SpVar_Attr();
394  }
395  catch (HDF5CF::Exception &e){
396  if(f != nullptr)
397  delete f;
398  throw InternalErr(e.what());
399  }
400 
401  // Generate DAS for the EOS5
402  try {
403  gen_eos5_cfdas(das,file_id,f);
404  }
405  catch(...) {
406  if (f != nullptr)
407  delete f;
408  throw;
409  }
410 
411  if( f != nullptr)
412  delete f;
413 
414 }
415 
416 // Generate DDS for the EOS5
417 void gen_eos5_cfdds(DDS &dds, HDF5CF::EOS5File *f) {
418 
419  BESDEBUG("h5","Coming to HDF-EOS5 products DDS generation function gen_eos5_cfdds "<<endl);
420  const vector<HDF5CF::Var *>& vars = f->getVars();
421  const vector<HDF5CF::EOS5CVar *>& cvars = f->getCVars();
422  const string filename = f->getPath();
423  const hid_t file_id = f->getFileID();
424 
425  // Read Variable info.
426  vector<HDF5CF::EOS5CVar *>::const_iterator it_cv;
427 
428  for (auto it_v = vars.begin(); it_v !=vars.end();++it_v) {
429  BESDEBUG("h5","variable full path= "<< (*it_v)->getFullPath() <<endl);
430  gen_dap_onevar_dds(dds,*it_v,file_id,filename);
431  }
432 
433  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
434  BESDEBUG("h5","variable full path= "<< (*it_cv)->getFullPath() <<endl);
435  gen_dap_oneeos5cvar_dds(dds,*it_cv,file_id,filename);
436 
437  }
438 
439  // We need to provide grid_mapping info. for multiple grids.
440  // Here cv_lat_miss_index represents the missing latitude(HDF-EOS grid without the latitude field) cv index
441  // This index is used to create the grid_mapping variable for different grids.
442  unsigned short cv_lat_miss_index = 1;
443  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
444  if((*it_cv)->getCVType() == CV_LAT_MISS) {
445  if((*it_cv)->getProjCode() != HE5_GCTP_GEO) {
446  // Here we need to add grid_mapping variables for each grid
447  // For projections other than sinusoidal since attribute values for LAMAZ and PS
448  // are different for each grid.
449  gen_dap_oneeos5cf_dds(dds,*it_cv);
450  add_cf_grid_mapinfo_var(dds,(*it_cv)->getProjCode(),cv_lat_miss_index);
451  cv_lat_miss_index++;
452  }
453  }
454  }
455 }
456 
457 void gen_dap_oneeos5cf_dds(DDS &dds,const HDF5CF::EOS5CVar* cvar) {
458 
459  BESDEBUG("h5","Coming to gen_dap_oneeos5cf_dds() "<<endl);
460 
461  float cv_point_lower = cvar->getPointLower();
462  float cv_point_upper = cvar->getPointUpper();
463  float cv_point_left = cvar->getPointLeft();
464  float cv_point_right = cvar->getPointRight();
465  EOS5GridPCType cv_proj_code = cvar->getProjCode();
466  const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
467  if(dims.size() !=2)
468  throw InternalErr(__FILE__,__LINE__,"Currently we only support the 2-D CF coordinate projection system.");
469  add_cf_grid_cvs(dds,cv_proj_code,cv_point_lower,cv_point_upper,cv_point_left,cv_point_right,dims);
470 
471 }
472 
473 void gen_dap_oneeos5cf_das(DAS &das,const vector<HDF5CF::Var*>& vars, const HDF5CF::EOS5CVar* cvar,const unsigned short g_suffix) {
474 
475  BESDEBUG("h5","Coming to gen_dap_oneeos5cf_das() "<<endl);
476 #if 0
477  float cv_point_lower = cvar->getPointLower();
478  float cv_point_upper = cvar->getPointUpper();
479  float cv_point_left = cvar->getPointLeft();
480  float cv_point_right = cvar->getPointRight();
481 #endif
482  EOS5GridPCType cv_proj_code = cvar->getProjCode();
483  const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
484 
485 #if 0
486 cerr<<"cv_point_lower is "<<cv_point_lower <<endl;
487 cerr<<"cvar name is "<<cvar->getName() <<endl;
488 for(vector<HDF5CF::Dimension*>::const_iterator it_d = dims.begin(); it_d != dims.end(); ++it_d)
489  cerr<<"dim name das is "<<(*it_d)->getNewName() <<endl;
490 #endif
491 
492  if(dims.size() !=2)
493  throw InternalErr(__FILE__,__LINE__,"Currently we only support the 2-D CF coordinate projection system.");
494 #if 0
495  add_cf_grid_cv_attrs(das,vars,cv_proj_code,cv_point_lower,cv_point_upper,cv_point_left,cv_point_right,dims,cvar->getParams(),g_suffix);
496 #endif
497  add_cf_grid_cv_attrs(das,vars,cv_proj_code,dims,cvar->getParams(),g_suffix);
498 
499 }
500 
501 //For EOS5, generate the ignored object info. for the CF option
502 void gen_eos5_cf_ignored_obj_info(DAS &das, HDF5CF::EOS5File *f) {
503 
504  BESDEBUG("h5","Coming to gen_eos5_cf_ignored_obj_info() "<<endl);
505  AttrTable *at = das.get_table("Ignored_Object_Info");
506  if (nullptr == at)
507  at = das.add_table("Ignored_Object_Info", new AttrTable);
508 
509  at->append_attr("Message","String",f->Get_Ignored_Msg());
510 
511 
512 }
513 
514 // Generate DDS for EOS5 coordinate variables
515 void gen_dap_oneeos5cvar_dds(DDS &dds,const HDF5CF::EOS5CVar* cvar, const hid_t file_id, const string & filename) {
516 
517  BESDEBUG("h5","Coming to gen_dap_oneeos5cvar_dds() "<<endl);
518  BaseType *bt = nullptr;
519 
520  // TODO: need to handle 64-bit integer for DAP4 CF
521  if(cvar->getType()==H5INT64 || cvar->getType() == H5UINT64)
522  return;
523  switch(cvar->getType()) {
524 #define HANDLE_CASE(tid,type) \
525  case tid: \
526  bt = new (type)(cvar->getNewName(),cvar->getFullPath()); \
527  break;
528 
529  HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
530  HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
531  HANDLE_CASE(H5CHAR,HDF5CFInt16)
532  HANDLE_CASE(H5UCHAR, HDF5CFByte)
533  HANDLE_CASE(H5INT16, HDF5CFInt16)
534  HANDLE_CASE(H5UINT16, HDF5CFUInt16)
535  HANDLE_CASE(H5INT32, HDF5CFInt32)
536  HANDLE_CASE(H5UINT32, HDF5CFUInt32)
537  HANDLE_CASE(H5FSTRING, Str)
538  HANDLE_CASE(H5VSTRING, Str)
539  default:
540  throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
541 #undef HANDLE_CASE
542  }
543 
544  if (bt) {
545 
546  const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
547  vector <HDF5CF::Dimension*>:: const_iterator it_d;
548  vector <size_t> dimsizes;
549  dimsizes.resize(cvar->getRank());
550  for(int i = 0; i <cvar->getRank();i++)
551  dimsizes[i] = (dims[i])->getSize();
552 
553 
554  if(dims.empty())
555  throw InternalErr(__FILE__,__LINE__,"the coordinate variables cannot be scalar.");
556  switch(cvar->getCVType()) {
557 
558  case CV_EXIST:
559  {
560 
561 #if 0
562 for(vector<HDF5CF::Attribute *>::const_iterator it_ra = cvar->getAttributes().begin();
563  it_ra != cvar->getAttributes().end(); ++it_ra) {
564 cerr<<"cvar attribute name is "<<(*it_ra)->getNewName() <<endl;
565 cerr<<"cvar attribute value type is "<<(*it_ra)->getType() <<endl;
566 }
567 cerr<<"cvar new name exist at he s5cfdap.cc is "<<cvar->getNewName() <<endl;
568 #endif
569  bool is_latlon = cvar->isLatLon();
570  HDF5CFArray *ar = nullptr;
571  try {
572  ar = new HDF5CFArray (
573  cvar->getRank(),
574  file_id,
575  filename,
576  cvar->getType(),
577  dimsizes,
578  cvar->getFullPath(),
579  cvar->getTotalElems(),
580  CV_EXIST,
581  is_latlon,
582  cvar->getCompRatio(),
583  false,
584  cvar->getNewName(),
585  bt);
586  }
587  catch (...) {
588  delete bt;
589  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDF5CFArray.");
590  }
591 
592  for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
593  if (""==(*it_d)->getNewName())
594  ar->append_dim((int)((*it_d)->getSize()));
595  else
596  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
597  }
598 
599  dds.add_var(ar);
600  delete bt;
601  delete ar;
602  }
603  break;
604 
605  case CV_LAT_MISS:
606  case CV_LON_MISS:
607  {
608 
609  HDFEOS5CFMissLLArray *ar = nullptr;
610  try {
611 #if 0
612 cerr<<"cvar zone here is "<<cvar->getZone() <<endl;
613 cerr<<"cvar Sphere here is "<<cvar->getSphere() <<endl;
614 cerr<<"cvar getParams here 1 is "<<cvar->getParams()[0]<<endl;
615 #endif
616  ar = new HDFEOS5CFMissLLArray (
617  cvar->getRank(),
618  filename,
619  file_id,
620  cvar->getFullPath(),
621  cvar->getCVType(),
622  cvar->getPointLower(),
623  cvar->getPointUpper(),
624  cvar->getPointLeft(),
625  cvar->getPointRight(),
626  cvar->getPixelReg(),
627  cvar->getOrigin(),
628  cvar->getProjCode(),
629  cvar->getParams(),
630  cvar->getZone(),
631  cvar->getSphere(),
632  cvar->getXDimSize(),
633  cvar->getYDimSize(),
634  cvar->getNewName(),
635  bt);
636  }
637  catch (...) {
638  delete bt;
639  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDFEOS5CFMissLLArray.");
640  }
641 
642  for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
643  if (""==(*it_d)->getNewName())
644  ar->append_dim((int)((*it_d)->getSize()));
645  else
646  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
647  }
648 
649  dds.add_var(ar);
650  delete bt;
651  delete ar;
652  }
653  break;
654 
655  case CV_NONLATLON_MISS:
656  {
657 
658  if (cvar->getRank() !=1) {
659  delete bt;
660  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
661  }
662  auto nelem = (int)((cvar->getDimensions()[0])->getSize());
663 
664  HDFEOS5CFMissNonLLCVArray *ar = nullptr;
665  try {
666  ar = new HDFEOS5CFMissNonLLCVArray(
667  cvar->getRank(),
668  nelem,
669  cvar->getNewName(),
670  bt);
671  }
672  catch (...) {
673  delete bt;
674  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDFEOS5CFMissNonLLCVArray.");
675  }
676 
677 
678  for(it_d = dims.begin(); it_d != dims.end(); it_d++) {
679  if (""==(*it_d)->getNewName())
680  ar->append_dim((int)((*it_d)->getSize()));
681  else
682  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
683  }
684  dds.add_var(ar);
685  delete bt;
686  delete ar;
687 
688 
689  }
690  break;
691  case CV_SPECIAL:
692  // Currently only support Aura TES files. May need to revise when having more
693  // special products KY 2012-2-3
694  {
695 
696  if (cvar->getRank() !=1) {
697  delete bt;
698  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
699  }
700  auto nelem = (int)((cvar->getDimensions()[0])->getSize());
701  HDFEOS5CFSpecialCVArray *ar = nullptr;
702 
703  try {
704  ar = new HDFEOS5CFSpecialCVArray(
705  cvar->getRank(),
706  filename,
707  file_id,
708  cvar->getType(),
709  nelem,
710  cvar->getFullPath(),
711  cvar->getNewName(),
712  bt);
713  }
714  catch (...) {
715  delete bt;
716  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDF5CFArray.");
717  }
718 
719 
720  for(it_d = dims.begin(); it_d != dims.end(); ++it_d){
721  if (""==(*it_d)->getNewName())
722  ar->append_dim((int)((*it_d)->getSize()));
723  else
724  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
725  }
726  dds.add_var(ar);
727  delete bt;
728  delete ar;
729  }
730  break;
731  case CV_MODIFY:
732  default:
733  delete bt;
734  throw InternalErr(__FILE__,__LINE__,"Unsupported coordinate variable type.");
735  }
736 
737  }
738 
739 }
740 
741 // Generate EOS5 DAS
742 void gen_eos5_cfdas(DAS &das, hid_t file_id, HDF5CF::EOS5File *f) {
743 
744  BESDEBUG("h5","Coming to HDF-EOS5 products DAS generation function gen_eos5_cfdas "<<endl);
745 
746  // First check if this is for generating the ignored object info.
747  if(true == f->Get_IgnoredInfo_Flag()) {
748  gen_eos5_cf_ignored_obj_info(das, f);
749  return;
750  }
751 
752  const vector<HDF5CF::Var *>& vars = f->getVars();
753  const vector<HDF5CF::EOS5CVar *>& cvars = f->getCVars();
754  const vector<HDF5CF::Group *>& grps = f->getGroups();
755  const vector<HDF5CF::Attribute *>& root_attrs = f->getAttributes();
756 
757  vector<HDF5CF::EOS5CVar *>::const_iterator it_cv;
758  vector<HDF5CF::Attribute *>::const_iterator it_ra;
759 
760  // Handling the file attributes(attributes under the root group)
761  // The table name is "HDF_GLOBAL".
762  if (false == root_attrs.empty()) {
763  AttrTable *at = das.get_table(FILE_ATTR_TABLE_NAME);
764  if (nullptr == at)
765  at = das.add_table(FILE_ATTR_TABLE_NAME, new AttrTable);
766 
767  for (it_ra = root_attrs.begin(); it_ra != root_attrs.end(); it_ra++) {
768  gen_dap_oneobj_das(at,*it_ra,nullptr);
769  }
770  }
771 
772  if (false == grps.empty()) {
773  for (auto it_g = grps.begin(); it_g != grps.end(); ++it_g) {
774  AttrTable *at = das.get_table((*it_g)->getNewName());
775  if (nullptr == at)
776  at = das.add_table((*it_g)->getNewName(), new AttrTable);
777 
778  for (it_ra = (*it_g)->getAttributes().begin();
779  it_ra != (*it_g)->getAttributes().end(); ++it_ra) {
780 #if 0
781  //gen_dap_oneobj_das(at,*it_ra,nullptr);
782 #endif
783  // TODO: ADDING a BES KEY
784  if((*it_ra)->getNewName()=="Conventions" &&((*it_g)->getNewName() == "HDFEOS_ADDITIONAL_FILE_ATTRIBUTES")
785  && (true==HDF5RequestHandler::get_eos5_rm_convention_attr_path())) {
786  AttrTable *at_das = das.get_table(FILE_ATTR_TABLE_NAME);
787  if (nullptr == at_das)
788  at_das = das.add_table(FILE_ATTR_TABLE_NAME, new AttrTable);
789  gen_dap_oneobj_das(at_das,*it_ra,nullptr);
790  }
791  else
792  gen_dap_oneobj_das(at,*it_ra,nullptr);
793  }
794  }
795  }
796 
797  for (auto it_v = vars.begin(); it_v != vars.end(); ++it_v) {
798  if (false == ((*it_v)->getAttributes().empty())) {
799 
800  // TODO: Need to handle 64-bit int support for DAP4 CF.
801  if(H5INT64 == (*it_v)->getType() || H5UINT64 == (*it_v)->getType()){
802  continue;
803  }
804 
805  AttrTable *at = das.get_table((*it_v)->getNewName());
806  if (nullptr == at)
807  at = das.add_table((*it_v)->getNewName(), new AttrTable);
808 
809  for (it_ra = (*it_v)->getAttributes().begin();
810  it_ra != (*it_v)->getAttributes().end(); ++it_ra) {
811  gen_dap_oneobj_das(at,*it_ra,*it_v);
812  }
813  }
814  }
815 
816  for (it_cv = cvars.begin(); it_cv !=cvars.end();it_cv++) {
817 
818  if (false == ((*it_cv)->getAttributes().empty())) {
819 
820  // TODO: Need to handle 64-bit int support for DAP4 CF.
821  if(H5INT64 == (*it_cv)->getType() || H5UINT64 == (*it_cv)->getType()){
822  continue;
823  }
824 
825  AttrTable *at = das.get_table((*it_cv)->getNewName());
826  if (nullptr == at)
827  at = das.add_table((*it_cv)->getNewName(), new AttrTable);
828 
829  for (it_ra = (*it_cv)->getAttributes().begin();
830  it_ra != (*it_cv)->getAttributes().end(); ++it_ra) {
831  gen_dap_oneobj_das(at,*it_ra,*it_cv);
832  }
833  }
834  }
835 
836  // Add CF 1-D projection variables
837  unsigned short cv_lat_miss_index = 1;
838  // This code block will add grid_mapping attribute info. to corresponding variables.
839  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
840  if((*it_cv)->getCVType() == CV_LAT_MISS) {
841  if((*it_cv)->getProjCode() != HE5_GCTP_GEO) {
842  gen_dap_oneeos5cf_das(das,vars,*it_cv,cv_lat_miss_index);
843  cv_lat_miss_index++;
844  }
845  }
846  }
847 
848  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
849  if((*it_cv)->getProjCode() == HE5_GCTP_LAMAZ) {
850  if((*it_cv)->getCVType() == CV_LAT_MISS || (*it_cv)->getCVType() == CV_LON_MISS) {
851  AttrTable *at = das.get_table((*it_cv)->getNewName());
852  if (nullptr == at)
853  at = das.add_table((*it_cv)->getNewName(), new AttrTable);
854  if((*it_cv)->getCVType() == CV_LAT_MISS)
855  add_ll_valid_range(at,true);
856  else
857  add_ll_valid_range(at,false);
858  }
859  }
860  }
861 
862 
863  bool disable_ecsmetadata = HDF5RequestHandler::get_disable_ecsmeta();
864 
865  if(disable_ecsmetadata == false) {
866 
867  // To keep the backward compatiablity with the old handler,
868  // we parse the special ECS metadata to DAP attributes
869 
870  string st_str ="";
871  string core_str="";
872  string arch_str="";
873  string xml_str ="";
874  string subset_str="";
875  string product_str="";
876  string other_str ="";
877  bool st_only = false;
878 
879  read_ecs_metadata(file_id, st_str, core_str, arch_str, xml_str,
880  subset_str, product_str, other_str, st_only);
881 
882 #if 0
883 if(st_str!="") "h5","Final structmetadata "<<st_str <<endl;
884 if(core_str!="") "h5","Final coremetadata "<<core_str <<endl;
885 if(arch_str!="") "h5","Final archivedmetadata "<<arch_str <<endl;
886 if(xml_str!="") "h5","Final xmlmetadata "<<xml_str <<endl;
887 if(subset_str!="") "h5","Final subsetmetadata "<<subset_str <<endl;
888 if(product_str!="") "h5","Final productmetadata "<<product_str <<endl;
889 if(other_str!="") "h5","Final othermetadata "<<other_str <<endl;
890 
891 #endif
892  if(st_str != ""){
893 
894 #if 0
895  string check_disable_smetadata_key ="H5.DisableStructMetaAttr";
896  bool is_check_disable_smetadata = false;
897 #endif
898  bool is_check_disable_smetadata = HDF5RequestHandler::get_disable_structmeta();
899 
900  if (false == is_check_disable_smetadata) {
901 
902  AttrTable *at = das.get_table("StructMetadata");
903  if (nullptr == at)
904  at = das.add_table("StructMetadata", new AttrTable);
905  parser_arg arg(at);
906 
907  he5das_scan_string((const char*) st_str.c_str());
908  if (he5dasparse(&arg) != 0
909  || false == arg.status()){
910 
911  ERROR_LOG("HDF-EOS5 parse error while processing a "
912  << "StructMetadata " << " HDFEOS attribute" << endl);
913  }
914 
915  he5daslex_destroy();
916 
917  }
918  }
919 
920  if(core_str != ""){
921  AttrTable *at = das.get_table("CoreMetadata");
922  if (nullptr == at)
923  at = das.add_table("CoreMetadata", new AttrTable);
924  parser_arg arg(at);
925  he5das_scan_string((const char*) core_str.c_str());
926  if (he5dasparse(&arg) != 0
927  || false == arg.status()){
928 
929  ERROR_LOG("HDF-EOS5 parse error while processing a "
930  << "CoreMetadata " << " HDFEOS attribute" << endl);
931  }
932 
933  he5daslex_destroy();
934  }
935  if(arch_str != ""){
936  AttrTable *at = das.get_table("ArchiveMetadata");
937  if (nullptr == at)
938  at = das.add_table("ArchiveMetadata", new AttrTable);
939  parser_arg arg(at);
940  he5das_scan_string((const char*) arch_str.c_str());
941  if (he5dasparse(&arg) != 0
942  || false == arg.status()){
943 
944  ERROR_LOG("HDF-EOS5 parse error while processing a "
945  << "ArchiveMetadata " << " HDFEOS attribute" << endl);
946  }
947  he5daslex_destroy();
948  }
949 
950  // XML attribute includes double quote("), this will choke netCDF Java library.
951  // So we replace double_quote(") with &quote.This is currently the OPeNDAP way.
952  // XML attribute cannot parsed. So just pass the string.
953  if(xml_str != ""){
954  AttrTable *at = das.get_table("XMLMetadata");
955  if (nullptr == at)
956  at = das.add_table("XMLMetadata", new AttrTable);
957  HDF5CFDAPUtil::replace_double_quote(xml_str);
958  at->append_attr("Contents","String",xml_str);
959  }
960 
961  // SubsetMetadata and ProductMetadata exist in HDF-EOS2 files.
962  // So far we haven't found any metadata in NASA HDF-EOS5 files,
963  // but will keep an eye on it. KY 2012-3-6
964  if(subset_str != ""){
965  AttrTable *at = das.get_table("SubsetMetadata");
966  if (nullptr == at)
967  at = das.add_table("SubsetMetadata", new AttrTable);
968  parser_arg arg(at);
969  he5das_scan_string((const char*) subset_str.c_str());
970  if (he5dasparse(&arg) != 0
971  || false == arg.status()) {
972 
973  ERROR_LOG("HDF-EOS5 parse error while processing a "
974  << "SubsetMetadata " << " HDFEOS attribute" << endl);
975  }
976  he5daslex_destroy();
977  }
978  if(product_str != ""){
979  AttrTable *at = das.get_table("ProductMetadata");
980  if (nullptr == at)
981  at = das.add_table("ProductMetadata", new AttrTable);
982  parser_arg arg(at);
983  he5das_scan_string((const char*) product_str.c_str());
984  if (he5dasparse(&arg) != 0
985  || false == arg.status()){
986  ERROR_LOG("HDF-EOS5 parse error while processing a "
987  << "ProductMetadata " << " HDFEOS attribute" << endl);
988  }
989  he5daslex_destroy();
990  }
991 
992  // All other metadata under "HDF-EOS Information" will not be
993  // parsed since we don't know how to parse them.
994  // We will simply pass a string to the DAS.
995  if (other_str != ""){
996  AttrTable *at = das.get_table("OtherMetadata");
997  if (nullptr == at)
998  at = das.add_table("OtherMetadata", new AttrTable);
999  at->append_attr("Contents","String",other_str);
1000  }
1001 
1002  }
1003  // CHECK ALL UNLIMITED DIMENSIONS from the coordinate variables based on the names.
1004  if(f->HaveUnlimitedDim() == true) {
1005 
1006  AttrTable *at = das.get_table("DODS_EXTRA");
1007  if (nullptr == at)
1008  at = das.add_table("DODS_EXTRA", new AttrTable);
1009  string unlimited_names;
1010 
1011  for (it_cv = cvars.begin();
1012  it_cv != cvars.end(); it_cv++) {
1013 #if 0
1014  bool has_unlimited_dim = false;
1015 #endif
1016  // Check unlimited dimension names.
1017  for (auto ird = (*it_cv)->getDimensions().begin();
1018  ird != (*it_cv)->getDimensions().end(); ++ird) {
1019 
1020  // Currently we only check one unlimited dimension, which is the most
1021  // common case. When receiving the conventions from JG, will add
1022  // the support of multi-unlimited dimension. KY 2016-02-09
1023  if((*ird)->HaveUnlimitedDim() == true) {
1024 
1025  if(unlimited_names=="") {
1026  unlimited_names = (*ird)->getNewName();
1027  at->append_attr("Unlimited_Dimension","String",unlimited_names);
1028  }
1029  else {
1030  if(unlimited_names.rfind((*ird)->getNewName()) == string::npos) {
1031  unlimited_names = unlimited_names+" "+(*ird)->getNewName();
1032  at->append_attr("Unlimited_Dimension","String",(*ird)->getNewName());
1033  }
1034  }
1035  }
1036 
1037  }
1038 
1039 #if 0
1040  //if(true == has_unlimited_dim)
1041  // break;
1042 #endif
1043  }
1044 #if 0
1045  //if(unlimited_names!="")
1046  // at->append_attr("Unlimited_Dimension","String",unlimited_names);
1047 #endif
1048  }
1049 
1050 }
1051 
1052 // Read ECS metadata
1053 void read_ecs_metadata(hid_t s_file_id,
1054  string &total_strmeta_value,
1055  string &total_coremeta_value,
1056  string &total_archmeta_value,
1057  string &total_xmlmeta_value,
1058  string &total_submeta_value,
1059  string &total_prometa_value,
1060  string &total_othermeta_value,
1061  bool s_st_only) {
1062 
1063  BESDEBUG("h5","Coming to read_ecs_metadata() "<<endl);
1064  string ecs_group = "/HDFEOS INFORMATION";
1065  hid_t ecs_grp_id = -1;
1066  if ((ecs_grp_id = H5Gopen(s_file_id, ecs_group.c_str(),H5P_DEFAULT))<0) {
1067  string msg =
1068  "h5_ecs_meta: unable to open the HDF5 group ";
1069  msg +=ecs_group;
1070  throw InternalErr(__FILE__, __LINE__, msg);
1071  }
1072 
1073  H5G_info_t g_info;
1074  hsize_t nelems = 0;
1075 
1076  if (H5Gget_info(ecs_grp_id,&g_info) <0) {
1077  string msg =
1078  "h5_ecs_meta: unable to obtain the HDF5 group info. for ";
1079  msg +=ecs_group;
1080  H5Gclose(ecs_grp_id);
1081  throw InternalErr(__FILE__, __LINE__, msg);
1082  }
1083 
1084  nelems = g_info.nlinks;
1085 
1086  ssize_t oname_size = 0;
1087 #if 0
1088  int cur_archmeta_suffix = 0;
1089  int cur_coremeta_suffix = 0;
1090  int cur_strmeta_suffix = 0;
1091  int cur_xmlmeta_suffix = 0;
1092 #endif
1093 
1094  int archmeta_num = -1;
1095  int coremeta_num = -1;
1096  int xmlmeta_num = -1;
1097  int strmeta_num = -1;
1098  int submeta_num = -1;
1099  int prometa_num = -1;
1100 
1101  // Initalize the total number for different metadata.
1102  int archmeta_num_total = 0;
1103  int coremeta_num_total = 0;
1104  int xmlmeta_num_total = 0;
1105  int strmeta_num_total = 0;
1106  int submeta_num_total = 0;
1107  int prometa_num_total = 0;
1108  int othermeta_num_total = 0;
1109 
1110  bool archmeta_no_suffix = true;
1111  bool coremeta_no_suffix = true;
1112  bool strmeta_no_suffix = true;
1113  bool xmlmeta_no_suffix = true;
1114  bool submeta_no_suffix = true;
1115  bool prometa_no_suffix = true;
1116 
1117  // Define a vector of string to hold all dataset names.
1118  vector<string> s_oname(nelems);
1119 
1120  // Define an EOSMetadata array that can describe the metadata type for each object
1121  // We initialize the value to OtherMeta.
1122  EOS5Metadata metatype[nelems];
1123 
1124  for (unsigned int i =0; i<nelems; i++)
1125  metatype[i] = OtherMeta;
1126 
1127  for (hsize_t i = 0; i < nelems; i++) {
1128 
1129  // Query the length of the object name.
1130  oname_size =
1131  H5Lget_name_by_idx(ecs_grp_id,".",H5_INDEX_NAME,H5_ITER_NATIVE,i,nullptr,
1132  0, H5P_DEFAULT);
1133  if (oname_size <= 0) {
1134  string msg = "hdf5 object name error from: ";
1135  msg += ecs_group;
1136  H5Gclose(ecs_grp_id);
1137  throw InternalErr(__FILE__, __LINE__, msg);
1138  }
1139 
1140  // Obtain the name of the object.
1141  vector<char> oname(oname_size + 1);
1142  if (H5Lget_name_by_idx(ecs_grp_id,".",H5_INDEX_NAME,H5_ITER_NATIVE,i,oname.data(),
1143  (size_t)(oname_size+1), H5P_DEFAULT)<0){
1144  string msg = "hdf5 object name error from: ";
1145  msg += ecs_group;
1146  H5Gclose(ecs_grp_id);
1147  throw InternalErr(__FILE__, __LINE__, msg);
1148  }
1149 
1150  // Check if this object is an HDF5 dataset, not, throw an error.
1151  // First, check if it is the hard link or the soft link
1152  H5L_info_t linfo;
1153  if (H5Lget_info(ecs_grp_id,oname.data(),&linfo,H5P_DEFAULT)<0) {
1154  string msg = "hdf5 link name error from: ";
1155  msg += ecs_group;
1156  H5Gclose(ecs_grp_id);
1157  throw InternalErr(__FILE__, __LINE__, msg);
1158  }
1159 
1160  // This is the soft link.
1161  if (linfo.type == H5L_TYPE_SOFT){
1162  string msg = "hdf5 link name error from: ";
1163  msg += ecs_group;
1164  H5Gclose(ecs_grp_id);
1165  throw InternalErr(__FILE__, __LINE__, msg);
1166  }
1167 
1168  // Obtain the object type
1169  H5O_info_t oinfo;
1170  if (H5OGET_INFO_BY_IDX(ecs_grp_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE,
1171  i, &oinfo, H5P_DEFAULT)<0) {
1172  string msg = "Cannot obtain the object info ";
1173  msg += ecs_group;
1174  H5Gclose(ecs_grp_id);
1175  throw InternalErr(__FILE__, __LINE__, msg);
1176  }
1177 
1178  if(oinfo.type != H5O_TYPE_DATASET) {
1179  string msg = "hdf5 link name error from: ";
1180  msg += ecs_group;
1181  H5Gclose(ecs_grp_id);
1182  throw InternalErr(__FILE__, __LINE__, msg);
1183  }
1184 
1185  // We want to remove the last '\0' character added by C .
1186  string s_one_oname(oname.begin(),oname.end()-1);
1187  s_oname[i] = s_one_oname;
1188 
1189  // Calculate how many elements we have for each category(StructMetadata, CoreMetadata, etc.)
1190  if (((s_one_oname.find("StructMetadata"))==0) ||
1191  ((s_one_oname.find("structmetadata"))==0)){
1192 
1193  metatype[i] = StructMeta;
1194 
1195  // Do we have suffix for the metadata?
1196  // If this metadata doesn't have any suffix, it should only come to this loop once.
1197  // That's why, when checking the first time, no_suffix is always true.
1198  // If we have already found that it doesn't have any suffix,
1199  // it should not go into this loop. throw an error.
1200  if (false == strmeta_no_suffix) {
1201  string msg = "StructMetadata/structmetadata without suffix should only appear once. ";
1202  H5Gclose(ecs_grp_id);
1203  throw InternalErr(__FILE__, __LINE__, msg);
1204  }
1205 
1206  else if(strmeta_num_total >0)
1207  strmeta_num_total++;
1208  else { // either no suffix or the first time to loop the one having the suffix.
1209  if ((0 == s_one_oname.compare("StructMetadata"))||
1210  (0 == s_one_oname.compare("structmetadata")))
1211  strmeta_no_suffix = false;
1212  else strmeta_num_total++;
1213  }
1214 #if 0
1215 "h5","strmeta_num_total= "<<strmeta_num_total <<endl;
1216 if(strmeta_no_suffix) "h5","structmeta data has the suffix" <<endl;
1217 else "h5","structmeta data doesn't have the suffix" <<endl;
1218 #endif
1219  }
1220 
1221  if(false == s_st_only) {
1222 
1223  if ((0 == (s_one_oname.find("CoreMetadata"))) ||
1224  (0 == (s_one_oname.find("coremetadata")))){
1225 
1226  metatype[i] = CoreMeta;
1227 
1228  // Do we have suffix for the metadata?
1229  // When checking the first time, no_suffix is always true.
1230  // If we have already found that it doesn't have any suffix,
1231  // it should not go into this loop anyway. throw an error.
1232  if (false == coremeta_no_suffix) {
1233  string msg = "CoreMetadata/coremetadata without suffix should only appear once. ";
1234  H5Gclose(ecs_grp_id);
1235  throw InternalErr(__FILE__, __LINE__, msg);
1236  }
1237 
1238  else if(coremeta_num_total >0)
1239  coremeta_num_total++;
1240  else { // either no suffix or the first time to loop the one having the suffix.
1241  // If no suffix is true, it should be out of the loop. In case it comes
1242  // to the loop again, we set "coremeta_no_suffix" be false so an error
1243  // can be thrown. This is counter-intutitive. Hopefully people can understand it.
1244  if ((0 == s_one_oname.compare("CoreMetadata")) ||
1245  (0 == s_one_oname.compare("coremetadata")))
1246  coremeta_no_suffix = false;
1247  else coremeta_num_total++;
1248  }
1249 #if 0
1250 "h5","coremeta_num_total= "<<coremeta_num_total <<endl;
1251 if(coremeta_no_suffix) "h5","coreuctmeta data has the suffix" <<endl;
1252 else "h5","coremeta data doesn't have the suffix" <<endl;
1253 #endif
1254  }
1255 
1256  // OMI has the metadata name as "ArchiveMetadata.0"
1257  else if ((0 == (s_one_oname.find("ArchivedMetadata"))) ||
1258  (0 == (s_one_oname.find("archivedmetadata"))) ||
1259  (0 == (s_one_oname.find("ArchiveMetadata"))) ||
1260  (0 == (s_one_oname.find("archivemetadata")))){
1261 
1262  metatype[i] = ArchivedMeta;
1263  // Do we have suffix for the metadata?
1264  // When checking the first time, no_suffix is always true.
1265  // If we have already found that it doesn't have any suffix,
1266  // it should not go into this loop anyway. throw an error.
1267  if (false == archmeta_no_suffix) {
1268  string msg = "archivedmetadata/ArchivedMetadata without suffix should only appear once. ";
1269  H5Gclose(ecs_grp_id);
1270  throw InternalErr(__FILE__, __LINE__, msg);
1271  }
1272 
1273  else if(archmeta_num_total >0)
1274  archmeta_num_total++;
1275  else { // either no suffix or the first time to loop the one having the suffix.
1276  if ((0 == s_one_oname.compare("ArchivedMetadata"))||
1277  (0 == s_one_oname.compare("archivedmetadata")) ||
1278  (0 == s_one_oname.compare("archivemetadata")) ||
1279  (0 == s_one_oname.compare("ArchiveMetadata")))
1280  archmeta_no_suffix = false;
1281  else
1282  archmeta_num_total++;
1283  }
1284 #if 0
1285 "h5","archmeta_num_total= "<<archmeta_num_total <<endl;
1286 if(archmeta_no_suffix) "h5","archuctmeta data has the suffix" <<endl;
1287 else "h5","archmeta data doesn't have the suffix" <<endl;
1288 #endif
1289 
1290  }
1291 
1292  else if (((s_one_oname.find("SubsetMetadata"))==0) ||
1293  ((s_one_oname.find("subsetmetadata"))==0)){
1294 
1295  metatype[i] = SubsetMeta;
1296  // Do we have suffix for the metadata?
1297  // When checking the first time, no_suffix is always true.
1298  // If we have already found that it doesn't have any suffix,
1299  // it should not go into this loop anyway. throw an error.
1300  if (false == submeta_no_suffix) {
1301  H5Gclose(ecs_grp_id);
1302  string msg = "submetadata/SubMetadata without suffix should only appear once. ";
1303  throw InternalErr(__FILE__, __LINE__, msg);
1304  }
1305 
1306  else if(submeta_num_total >0)
1307  submeta_num_total++;
1308  else { // either no suffix or the first time to loop the one having the suffix.
1309  if ((0 == s_one_oname.compare("SubsetMetadata"))||
1310  (0 == s_one_oname.compare("subsetmetadata")))
1311  submeta_no_suffix = false;
1312  else submeta_num_total++;
1313  }
1314 #if 0
1315 "h5","submeta_num_total= "<<submeta_num_total <<endl;
1316 if(submeta_no_suffix) "h5","subuctmeta data has the suffix" <<endl;
1317 else "h5","submeta data doesn't have the suffix" <<endl;
1318 #endif
1319 
1320  }
1321 
1322  else if ((0 == (s_one_oname.find("XmlMetadata"))) ||
1323  (0 == (s_one_oname.find("xmlmetadata")))){
1324 
1325  metatype[i] = XMLMeta;
1326 
1327  // Do we have suffix for the metadata?
1328  // When checking the first time, no_suffix is always true.
1329  // If we have already found that it doesn't have any suffix,
1330  // it should not go into this loop anyway. throw an error.
1331  if (false == xmlmeta_no_suffix) {
1332  H5Gclose(ecs_grp_id);
1333  string msg = "xmlmetadata/Xmlmetadata without suffix should only appear once. ";
1334  throw InternalErr(__FILE__, __LINE__, msg);
1335  }
1336 
1337  else if(xmlmeta_num_total >0)
1338  xmlmeta_num_total++;
1339  else { // either no suffix or the first time to loop the one having the suffix.
1340  if ((0 == s_one_oname.compare("XmlMetadata"))||
1341  (0 == s_one_oname.compare("xmlmetadata")))
1342  xmlmeta_no_suffix = false;
1343  else xmlmeta_num_total++;
1344  }
1345 #if 0
1346 "h5","xmlmeta_num_total= "<<xmlmeta_num_total <<endl;
1347 if(xmlmeta_no_suffix) "h5","xmluctmeta data doesn't have the suffix" <<endl;
1348 else "h5","xmlmeta data has the suffix" <<endl;
1349 #endif
1350 
1351  }
1352 
1353  else if ((0 == (s_one_oname.find("ProductMetadata"))) ||
1354  (0 == (s_one_oname.find("productmetadata")))){
1355 
1356  metatype[i] = ProductMeta;
1357  // Do we have suffix for the metadata?
1358  // When checking the first time, no_suffix is always true.
1359  // If we have already found that it doesn't have any suffix,
1360  // it should not go into this loop anyway. throw an error.
1361  if (!prometa_no_suffix) {
1362  H5Gclose(ecs_grp_id);
1363  string msg = "productmetadata/ProductMetadata without suffix should only appear once. ";
1364  throw InternalErr(__FILE__, __LINE__, msg);
1365  }
1366 
1367  else if(prometa_num_total >0) prometa_num_total++;
1368  else { // either no suffix or the first time to loop the one having the suffix.
1369  if ((0 == s_one_oname.compare("ProductMetadata"))||
1370  (0 == s_one_oname.compare("productmetadata")))
1371  prometa_no_suffix = false;
1372  else prometa_num_total++;
1373  }
1374 
1375  }
1376 
1377  // All other metadata will be merged to one string, no need to check the name.
1378  else othermeta_num_total++;
1379  }
1380 
1381  oname.clear();
1382  s_one_oname.clear();
1383  }
1384 
1385  // Define a vector of string to hold StructMetadata.
1386  // StructMetadata must exist for a valid HDF-EOS5 file.
1387  vector<string> strmeta_value;
1388  if (strmeta_num_total <= 0) {
1389  string msg = "hdf5 object name error from: ";
1390  H5Gclose(ecs_grp_id);
1391  throw InternalErr(__FILE__, __LINE__, msg);
1392  }
1393  else {
1394  strmeta_value.resize(strmeta_num_total);
1395  for (int i = 0; i < strmeta_num_total; i++)
1396  strmeta_value[i]="";
1397  }
1398 
1399  // All other metadata are optional.
1400  // Define a vector of string to hold archivedmetadata.
1401  vector<string> archmeta_value;
1402  if (archmeta_num_total >0) {
1403  archmeta_value.resize(archmeta_num_total);
1404  for (int i = 0; i < archmeta_num_total; i++)
1405  archmeta_value[i]="";
1406  }
1407 
1408  // Define a vector of string to hold coremetadata.
1409  vector<string> coremeta_value;
1410  if (coremeta_num_total >0) {
1411  coremeta_value.resize(coremeta_num_total);
1412  for (int i = 0; i < coremeta_num_total; i++)
1413  coremeta_value[i]="";
1414  }
1415 
1416  // Define a vector of string to hold xmlmetadata.
1417  vector<string> xmlmeta_value;
1418  if (xmlmeta_num_total >0) {
1419  xmlmeta_value.resize(xmlmeta_num_total);
1420  for (int i = 0; i < xmlmeta_num_total; i++)
1421  xmlmeta_value[i]="";
1422  }
1423 
1424  // Define a vector of string to hold subsetmetadata.
1425  vector<string> submeta_value;
1426  if (submeta_num_total >0) {
1427  submeta_value.resize(submeta_num_total);
1428  for (int i = 0; i < submeta_num_total; i++)
1429  submeta_value[i]="";
1430  }
1431 
1432  // Define a vector of string to hold productmetadata.
1433  vector<string> prometa_value;
1434  if (prometa_num_total >0) {
1435  prometa_value.resize(prometa_num_total);
1436  for (int i = 0; i < prometa_num_total; i++)
1437  prometa_value[i]="";
1438  }
1439 
1440  // For all other metadata, we don't need to calculate the value, just append them.
1441 
1442  // Now we want to retrieve the metadata value and combine them into one string.
1443  // Here we have to remember the location of every element of the metadata if
1444  // this metadata has a suffix.
1445  for (hsize_t i = 0; i < nelems; i++) {
1446 
1447  // DDS parser only needs to parse the struct Metadata. So check
1448  // if st_only flag is true, will only read StructMetadata string.
1449  // Struct Metadata is generated by the HDF-EOS5 library, so the
1450  // name "StructMetadata.??" won't change for real struct metadata.
1451  //However, we still assume that somebody may not use the HDF-EOS5
1452  // library to add StructMetadata, the name may be "structmetadata".
1453  if (true == s_st_only &&
1454  (((s_oname[i].find("StructMetadata"))!=0) &&
1455  ((s_oname[i].find("structmetadata"))!=0))){
1456  continue;
1457  }
1458 
1459  // Open the dataset, dataspace, datatype, number of elements etc. for this metadata
1460  hid_t s_dset_id = -1;
1461  hid_t s_space_id = -1;
1462  hid_t s_ty_id = -1;
1463  hssize_t s_nelms = -1;
1464  size_t dtype_size = -1;
1465 
1466  if ((s_dset_id = H5Dopen(ecs_grp_id,s_oname[i].c_str(),H5P_DEFAULT))<0){
1467  string msg = "Cannot open HDF5 dataset ";
1468  msg += s_oname[i];
1469  H5Gclose(ecs_grp_id);
1470  throw InternalErr(__FILE__, __LINE__, msg);
1471  }
1472 
1473  if ((s_space_id = H5Dget_space(s_dset_id))<0) {
1474  string msg = "Cannot open the data space of HDF5 dataset ";
1475  msg += s_oname[i];
1476  H5Dclose(s_dset_id);
1477  H5Gclose(ecs_grp_id);
1478  throw InternalErr(__FILE__, __LINE__, msg);
1479  }
1480 
1481  if ((s_ty_id = H5Dget_type(s_dset_id)) < 0) {
1482  string msg = "Cannot get the data type of HDF5 dataset ";
1483  msg += s_oname[i];
1484  H5Sclose(s_space_id);
1485  H5Dclose(s_dset_id);
1486  H5Gclose(ecs_grp_id);
1487  throw InternalErr(__FILE__, __LINE__, msg);
1488  }
1489  if ((s_nelms = H5Sget_simple_extent_npoints(s_space_id))<0) {
1490  string msg = "Cannot get the number of points of HDF5 dataset ";
1491  msg += s_oname[i];
1492  H5Tclose(s_ty_id);
1493  H5Sclose(s_space_id);
1494  H5Dclose(s_dset_id);
1495  H5Gclose(ecs_grp_id);
1496  throw InternalErr(__FILE__, __LINE__, msg);
1497  }
1498  if ((dtype_size = H5Tget_size(s_ty_id))==0) {
1499 
1500  string msg = "Cannot get the data type size of HDF5 dataset ";
1501  msg += s_oname[i];
1502  H5Tclose(s_ty_id);
1503  H5Sclose(s_space_id);
1504  H5Dclose(s_dset_id);
1505  H5Gclose(ecs_grp_id);
1506  throw InternalErr(__FILE__, __LINE__, msg);
1507  }
1508 
1509  // Obtain the real value of the metadata
1510  vector<char> s_buf(dtype_size*s_nelms +1);
1511 
1512  if ((H5Dread(s_dset_id,s_ty_id,H5S_ALL,H5S_ALL,H5P_DEFAULT,s_buf.data()))<0) {
1513 
1514  string msg = "Cannot read HDF5 dataset ";
1515  msg += s_oname[i];
1516  H5Tclose(s_ty_id);
1517  H5Sclose(s_space_id);
1518  H5Dclose(s_dset_id);
1519  H5Gclose(ecs_grp_id);
1520  throw InternalErr(__FILE__, __LINE__, msg);
1521  }
1522 
1523  // Now we can safely close datatype, data space and dataset IDs.
1524  H5Tclose(s_ty_id);
1525  H5Sclose(s_space_id);
1526  H5Dclose(s_dset_id);
1527 
1528 
1529  // Convert from the vector<char> to a C++ string.
1530  string tempstr(s_buf.begin(),s_buf.end());
1531  s_buf.clear();
1532  size_t temp_null_pos = tempstr.find_first_of('\0');
1533 
1534  // temp_null_pos returns the position of nullptr,which is the last character of the string.
1535  // so the length of string before null is EQUAL to
1536  // temp_null_pos since pos starts at 0.
1537  string finstr = tempstr.substr(0,temp_null_pos);
1538 
1539  // For the DDS parser, only return StructMetadata
1540  if (StructMeta == metatype[i]) {
1541 
1542  // Now obtain the corresponding value in integer type for the suffix. '0' to 0 etc.
1543  try {
1544  strmeta_num = get_metadata_num(s_oname[i]);
1545  }
1546  catch(...) {
1547  H5Gclose(ecs_grp_id);
1548  throw InternalErr(__FILE__,__LINE__,"Obtain structmetadata suffix error.");
1549 
1550  }
1551  // This is probably not necessary, since structmetadata may always have a suffix.
1552  // Leave here just in case the rules change or a special non-HDF-EOS5 library generated file.
1553  // when strmeta_num is -1, it means no suffix for this metadata. So the total structmetadata
1554  // is this string only.
1555  if (-1 == strmeta_num)
1556  total_strmeta_value = finstr;
1557  // strmeta_value at this point should be empty before assigning any values.
1558  else if (strmeta_value[strmeta_num]!="") {
1559  string msg = "The structmeta value array at this index should be empty string ";
1560  H5Gclose(ecs_grp_id);
1561  throw InternalErr(__FILE__, __LINE__, msg);
1562  }
1563  // assign the string vector to this value.
1564  else
1565  strmeta_value[strmeta_num] = finstr;
1566  }
1567 
1568  // DAS parser needs all metadata.
1569  if (false == s_st_only &&
1570  (metatype[i] != StructMeta)) {
1571 
1572  switch (metatype[i]) {
1573 
1574  case CoreMeta:
1575  {
1576  if (coremeta_num_total < 0) {
1577  string msg = "There may be no coremetadata or coremetadata is not counted ";
1578  H5Gclose(ecs_grp_id);
1579  throw InternalErr(__FILE__, __LINE__, msg);
1580 
1581  }
1582 
1583  try {
1584  coremeta_num = get_metadata_num(s_oname[i]);
1585  }
1586  catch(...) {
1587  H5Gclose(ecs_grp_id);
1588  throw InternalErr(__FILE__,__LINE__,"Obtain coremetadata suffix error.");
1589 
1590  }
1591 
1592  // when coremeta_num is -1, it means no suffix for this metadata. So the total coremetadata
1593  // is this string only. Similar cases apply for the rest metadata.
1594  if ( -1 == coremeta_num )
1595  total_coremeta_value = finstr;
1596  else if (coremeta_value[coremeta_num]!="") {
1597  string msg = "The coremeta value array at this index should be empty string ";
1598  H5Gclose(ecs_grp_id);
1599  throw InternalErr(__FILE__, __LINE__, msg);
1600  }
1601 
1602  // assign the string vector to this value.
1603  else
1604  coremeta_value[coremeta_num] = finstr;
1605  }
1606  break;
1607 
1608  case ArchivedMeta:
1609  {
1610  if (archmeta_num_total < 0) {
1611  string msg = "There may be no archivemetadata or archivemetadata is not counted ";
1612  H5Gclose(ecs_grp_id);
1613  throw InternalErr(__FILE__, __LINE__, msg);
1614  }
1615  try {
1616  archmeta_num = get_metadata_num(s_oname[i]);
1617  }
1618  catch(...) {
1619  H5Gclose(ecs_grp_id);
1620  throw InternalErr(__FILE__,__LINE__,"Obtain archivemetadata suffix error.");
1621  }
1622  if (-1 == archmeta_num )
1623  total_archmeta_value = finstr;
1624  else if (archmeta_value[archmeta_num]!="") {
1625  string msg = "The archivemeta value array at this index should be empty string ";
1626  H5Gclose(ecs_grp_id);
1627  throw InternalErr(__FILE__, __LINE__, msg);
1628 
1629  }
1630  // assign the string vector to this value.
1631  else
1632  archmeta_value[archmeta_num] = finstr;
1633  }
1634  break;
1635  case SubsetMeta:
1636  {
1637  if (submeta_num_total < 0) {
1638  string msg = "The subsetemeta value array at this index should be empty string ";
1639  H5Gclose(ecs_grp_id);
1640  throw InternalErr(__FILE__, __LINE__, msg);
1641  }
1642  try {
1643  submeta_num = get_metadata_num(s_oname[i]);
1644  }
1645  catch(...) {
1646  H5Gclose(ecs_grp_id);
1647  throw InternalErr(__FILE__,__LINE__,"Obtain subsetmetadata suffix error.");
1648  }
1649  if (-1 == submeta_num )
1650  total_submeta_value = finstr;
1651  else if (submeta_value[submeta_num]!="") {
1652  string msg = "The submeta value array at this index should be empty string ";
1653  H5Gclose(ecs_grp_id);
1654  throw InternalErr(__FILE__, __LINE__, msg);
1655  }
1656  // assign the string vector to this value.
1657  else
1658  submeta_value[submeta_num] = finstr;
1659  }
1660  break;
1661  case ProductMeta:
1662  {
1663  if (prometa_num_total < 0) {
1664  string msg = "There may be no productmetadata or productmetadata is not counted ";
1665  H5Gclose(ecs_grp_id);
1666  throw InternalErr(__FILE__, __LINE__, msg);
1667  }
1668  try {
1669  prometa_num = get_metadata_num(s_oname[i]);
1670  }
1671  catch(...) {
1672  H5Gclose(ecs_grp_id);
1673  throw InternalErr(__FILE__,__LINE__,"Obtain productmetadata suffix error.");
1674  }
1675  if (prometa_num == -1)
1676  total_prometa_value = finstr;
1677  else if (prometa_value[prometa_num]!="") {
1678  string msg = "The productmeta value array at this index should be empty string ";
1679  H5Gclose(ecs_grp_id);
1680  throw InternalErr(__FILE__, __LINE__, msg);
1681  }
1682  // assign the string vector to this value.
1683  else
1684  prometa_value[prometa_num] = finstr;
1685  }
1686  break;
1687  case XMLMeta:
1688  {
1689  if (xmlmeta_num_total < 0) {
1690  string msg = "There may be no xmlmetadata or xmlmetadata is not counted ";
1691  H5Gclose(ecs_grp_id);
1692  throw InternalErr(__FILE__, __LINE__, msg);
1693  }
1694  try {
1695  xmlmeta_num = get_metadata_num(s_oname[i]);
1696  }
1697  catch(...) {
1698  H5Gclose(ecs_grp_id);
1699  throw InternalErr(__FILE__,__LINE__,"Obtain XMLmetadata suffix error.");
1700  }
1701  if (-1 == xmlmeta_num )
1702  total_xmlmeta_value = finstr;
1703  else if (xmlmeta_value[xmlmeta_num]!="") {
1704  string msg = "The xmlmeta value array at this index should be empty string ";
1705  H5Gclose(ecs_grp_id);
1706  throw InternalErr(__FILE__, __LINE__, msg);
1707  }
1708  // assign the string vector to this value.
1709  else
1710  xmlmeta_value[xmlmeta_num] = finstr;
1711  }
1712  break;
1713  case OtherMeta:
1714  {
1715  if (othermeta_num_total < 0) {
1716  string msg = "There may be no othermetadata or other metadata is not counted ";
1717  H5Gclose(ecs_grp_id);
1718  throw InternalErr(__FILE__, __LINE__, msg);
1719  }
1720  total_othermeta_value = total_othermeta_value + finstr;
1721  }
1722  break;
1723  default :
1724  {
1725  string msg = "Unsupported metadata type ";
1726  H5Gclose(ecs_grp_id);
1727  throw InternalErr(__FILE__, __LINE__, msg);
1728  }
1729  }
1730  }
1731  tempstr.clear();
1732  finstr.clear();
1733  }
1734 
1735  // Now we need to handle the concatenation of the metadata
1736  // first StructMetadata
1737  if (strmeta_num_total > 0) {
1738  // The no suffix one has been taken care.
1739  if (strmeta_num != -1) {
1740  for (int i = 0; i <strmeta_num_total; i++)
1741  total_strmeta_value +=strmeta_value[i];
1742  }
1743  }
1744 
1745  // For the DAS handler
1746  if ( false == s_st_only) {
1747 
1748  if (coremeta_num_total >0) {
1749  if (coremeta_num != -1) {
1750  for(int i = 0; i <coremeta_num_total; i++)
1751  total_coremeta_value +=coremeta_value[i];
1752  }
1753  }
1754 
1755  if (archmeta_num_total >0) {
1756  if (archmeta_num != -1) {
1757  for(int i = 0; i <archmeta_num_total; i++)
1758  total_archmeta_value +=archmeta_value[i];
1759  }
1760  }
1761 
1762  if (submeta_num_total >0) {
1763  if (submeta_num != -1) {
1764  for(int i = 0; i <submeta_num_total; i++)
1765  total_submeta_value +=submeta_value[i];
1766  }
1767  }
1768 
1769  if (xmlmeta_num_total >0) {
1770  if (xmlmeta_num != -1) {
1771  for(int i = 0; i <xmlmeta_num_total; i++)
1772  total_xmlmeta_value +=xmlmeta_value[i];
1773  }
1774  }
1775 
1776  if (prometa_num_total >0) {
1777  if (prometa_num != -1) {
1778  for(int i = 0; i <prometa_num_total; i++)
1779  total_prometa_value +=prometa_value[i];
1780  }
1781  }
1782  }
1783  H5Gclose(ecs_grp_id);
1784 }
1785 
1786 // Helper function for read_ecs_metadata. Get the number after metadata.
1787 int get_metadata_num(const string & meta_str) {
1788 
1789  // The normal metadata names should be like coremetadata.0, coremetadata.1 etc.
1790  // We just find a not so nice coremetadata names such as coremetadata.0, coremetadata.0.1 for a HIRDLS-MLS-Aura-L3
1791  // We need to handle them. Here we assume no more than two dots in a name series. KY 2012-11-08
1792  size_t dot_pos = meta_str.find(".");
1793  if (dot_pos == string::npos) // No dot
1794  return -1;
1795  else if (meta_str.find_first_of(".") == meta_str.find_last_of(".")) { // One dot
1796  string num_str = meta_str.substr(dot_pos+1);
1797  stringstream ssnum(num_str);
1798  int num;
1799  ssnum >> num;
1800  if (ssnum.fail())
1801  throw InternalErr(__FILE__,__LINE__,"Suffix after dots is not a number.");
1802  return num;
1803  }
1804  else { // Two dots
1805  string str_after_first_dot = meta_str.substr(dot_pos+1);
1806  if (str_after_first_dot.find_first_of(".") != str_after_first_dot.find_last_of("."))
1807  throw InternalErr(__FILE__,__LINE__,"Currently don't support metadata names containing more than two dots.");
1808  // Here we don't check if names are like coremetadata.0 coremetadata.0.0 etc., Having ".0 .0.0" is,if not mistaken,
1809  // is insane.
1810  // Instead we hope that the data producers will produce data like coremetadata.0 coremetadata.0.1 coremeatadata.0.2
1811  // KY 2012-11-08
1812  size_t second_dot_pos = str_after_first_dot.find(".");
1813  string num_str = str_after_first_dot.substr(second_dot_pos+1);
1814  stringstream ssnum(num_str);
1815  int num;
1816  ssnum >> num;
1817  return num;
1818  }
1819 
1820 }
1821 
1822 void map_eos5_cfdmr(D4Group *d4_root, hid_t file_id, const string &filename) {
1823 
1824  BESDEBUG("h5","Coming to HDF-EOS5 products DDS mapping function map_eos5_cfdds "<<endl);
1825 
1826  string st_str ="";
1827  string core_str="";
1828  string arch_str="";
1829  string xml_str ="";
1830  string subset_str="";
1831  string product_str="";
1832  string other_str ="";
1833  bool st_only = false;
1834 
1835  // Read ECS metadata: merge them into one C++ string
1836  read_ecs_metadata(file_id,st_str,core_str,arch_str,xml_str, subset_str,product_str,other_str,st_only);
1837  if(""==st_str) {
1838  string msg =
1839  "unable to obtain the HDF-EOS5 struct metadata ";
1840  throw InternalErr(__FILE__, __LINE__, msg);
1841  }
1842 
1843  bool disable_ecsmetadata = HDF5RequestHandler::get_disable_ecsmeta();
1844  if(disable_ecsmetadata == false) {
1845 
1846  bool is_check_disable_smetadata = HDF5RequestHandler::get_disable_structmeta();
1847 
1848  if (false == is_check_disable_smetadata)
1849  add_grp_dap4_attr(d4_root,"StructMetadata",attr_str_c,st_str);
1850 
1851  if(core_str != "")
1852  add_grp_dap4_attr(d4_root,"CoreMetadata",attr_str_c,core_str);
1853 
1854  if(arch_str != "")
1855  add_grp_dap4_attr(d4_root,"ArchiveMetadata",attr_str_c,arch_str);
1856 
1857  if(xml_str != "")
1858  add_grp_dap4_attr(d4_root,"XMLMetadata",attr_str_c,xml_str);
1859 
1860  if(subset_str !="")
1861  add_grp_dap4_attr(d4_root,"SubsetMetadata",attr_str_c,subset_str);
1862 
1863  if(product_str != "")
1864  add_grp_dap4_attr(d4_root,"ProductMetadata",attr_str_c,product_str);
1865 
1866  if(other_str !="")
1867  add_grp_dap4_attr(d4_root,"OtherMetadata",attr_str_c,other_str);
1868  }
1869 
1870  bool is_check_nameclashing = HDF5RequestHandler::get_check_name_clashing();
1871 
1872  bool is_add_path_attrs = HDF5RequestHandler::get_add_path_attrs();
1873 
1874  EOS5File *f = nullptr;
1875 
1876  try {
1877  f = new EOS5File(filename.c_str(),file_id);
1878  }
1879  catch(...) {
1880  throw InternalErr(__FILE__,__LINE__,"Cannot allocate the file object.");
1881  }
1882 
1883  bool include_attr = true;
1884 
1885  // This first "try-catch" block will use the parsed info
1886  try {
1887 
1888  // Parse the structmetadata
1889  // Note: he5dds_scan_string just retrieves the variable info.
1890  // It is still used to handle DMR, no need to write another parser.
1891  // KY 2021-05-21
1892  HE5Parser p;
1893  HE5Checker c;
1894  he5dds_scan_string(st_str.c_str());
1895  he5ddsparse(&p);
1896  he5ddslex_destroy();
1897 
1898  // Retrieve ProjParams from StructMetadata
1899  p.add_projparams(st_str);
1900 #if 0
1901  //p.print();
1902 #endif
1903 
1904  // Check if the HDF-EOS5 grid has the valid parameters, projection codes.
1905  if (c.check_grids_unknown_parameters(&p)) {
1906  throw InternalErr("Unknown HDF-EOS5 grid paramters found in the file");
1907  }
1908 
1909  if (c.check_grids_missing_projcode(&p)) {
1910  throw InternalErr("The HDF-EOS5 is missing project code ");
1911  }
1912 
1913  // We gradually add the support of different projection codes
1914  if (c.check_grids_support_projcode(&p)) {
1915  throw InternalErr("The current project code is not supported");
1916  }
1917 
1918  // HDF-EOS5 provides default pixel and origin values if they are not defined.
1919  c.set_grids_missing_pixreg_orig(&p);
1920 
1921  // Check if this multi-grid file shares the same grid.
1922  bool grids_mllcv = c.check_grids_multi_latlon_coord_vars(&p);
1923 
1924  // Retrieve all HDF5 info(Not the values)
1925  f->Retrieve_H5_Info(filename.c_str(),file_id,include_attr);
1926 
1927  // Adjust EOS5 Dimension names/sizes based on the parsed results
1928  f->Adjust_EOS5Dim_Info(&p);
1929 
1930  // Translate the parsed output to HDF-EOS5 grids/swaths/zonal.
1931  // Several maps related to dimension and coordiantes are set up here.
1932  f->Add_EOS5File_Info(&p, grids_mllcv);
1933 
1934  // Add the dimension names
1935  f->Add_Dim_Name(&p);
1936  }
1937  catch (HDF5CF::Exception &e){
1938  if(f!=nullptr)
1939  delete f;
1940  throw InternalErr(e.what());
1941  }
1942  catch(...) {
1943  if(f!=nullptr)
1944  delete f;
1945  throw;
1946  }
1947 
1948  // The parsed struct will no longer be in this "try-catch" block.
1949  try {
1950 
1951  // NASA Aura files need special handlings. So first check if this file is an Aura file.
1953 
1954  // Adjust the variable name
1956 
1957  // Handle coordinate variables
1958  f->Handle_CVar();
1959 
1960  // Adjust variable and dimension names again based on the handling of coordinate variables.
1962 
1963 
1964  // Old comments, leave them for the time being:
1965  // We need to use the CV units to distinguish lat/lon from th 3rd CV when
1966  // memory cache is turned on.
1967 #if 0
1968  //if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
1969  // (HDF5RequestHandler::get_srdata_mem_cache() != nullptr)){
1970 #endif
1971 
1972  // Handle unsupported datatypes including the attributes
1973  f->Handle_Unsupported_Dtype(true);
1974 
1975  // Handle unsupported dataspaces including the attributes
1976  f->Handle_Unsupported_Dspace(true);
1977 
1978  // We need to retrieve coordinate variable attributes for memory cache use.
1980 
1982 
1983  // Handle other unsupported objects,
1984  // currently it mainly generates the info. for the
1985  // unsupported objects other than datatype, dataspace,links and named datatype
1986  // This function needs to be called after retrieving supported attributes.
1987  f->Handle_Unsupported_Others(include_attr);
1988 
1989 #if 0
1990  else {
1991 
1992  // Handle unsupported datatypes
1993  f->Handle_Unsupported_Dtype(include_attr);
1994 
1995  // Handle unsupported dataspaces
1996  f->Handle_Unsupported_Dspace(include_attr);
1997 
1998  }
1999 #endif
2000 
2001 
2002  // Need to retrieve the units of CV when memory cache is turned on.
2003  // The units of CV will be used to distinguish whether this CV is
2004  // latitude/longitude or a third-dimension CV.
2005  // isLatLon() will use the units value.
2006 #if 0
2007  //if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
2008  // (HDF5RequestHandler::get_srdata_mem_cache() != nullptr))
2009 #endif
2010  f->Adjust_Attr_Info();
2011 
2012  // May need to adjust the object names for special objects. Currently no operations
2013  // are done in this routine.
2014  f->Adjust_Obj_Name();
2015 
2016  // Flatten the object name
2017  f->Flatten_Obj_Name(include_attr);
2018 
2019  // Handle name clashing
2020  if(true == is_check_nameclashing)
2021  f->Handle_Obj_NameClashing(include_attr);
2022 
2023  // Check if this should follow COARDS, yes, set the COARDS flag.
2024  f->Set_COARDS_Status();
2025 
2026  // For COARDS, the dimension name needs to be changed.
2027  f->Adjust_Dim_Name();
2028  if(true == is_check_nameclashing)
2030 
2031  f->Add_Supplement_Attrs(is_add_path_attrs);
2032 
2033  // We need to turn off the very long string in the TES file to avoid
2034  // the choking of netCDF Java tools. So this special variable routine
2035  // is listed at last. We may need to turn off this if netCDF can handle
2036  // long string better.
2037  f->Handle_SpVar_DMR();
2038 
2039  // Handle coordinate attributes
2040  f->Handle_Coor_Attr();
2041 #if 0
2042  //f->Handle_SpVar_Attr();
2043 #endif
2044  }
2045  catch (HDF5CF::Exception &e){
2046  if(f != nullptr)
2047  delete f;
2048  throw InternalErr(e.what());
2049  }
2050 
2051  // Generate EOS5 DMR
2052  try {
2053  gen_eos5_cfdmr(d4_root,f);
2054  }
2055  catch(...) {
2056  if (f!=nullptr)
2057  delete f;
2058  throw;
2059  }
2060 
2061  if (f!=nullptr)
2062  delete f;
2063 
2064 }
2065 
2066 void gen_eos5_cfdmr(D4Group *d4_root, HDF5CF::EOS5File *f) {
2067 
2068  BESDEBUG("h5","Coming to HDF-EOS5 products DDS generation function "<<endl);
2069  const vector<HDF5CF::Var *>& vars = f->getVars();
2070  const vector<HDF5CF::EOS5CVar *>& cvars = f->getCVars();
2071  const string filename = f->getPath();
2072  const hid_t file_id = f->getFileID();
2073  const vector<HDF5CF::Group *>& grps = f->getGroups();
2074  const vector<HDF5CF::Attribute *>& root_attrs = f->getAttributes();
2075 
2076  vector<HDF5CF::Attribute *>::const_iterator it_ra;
2077 
2078  if (false == root_attrs.empty()) {
2079  for (it_ra = root_attrs.begin(); it_ra != root_attrs.end(); ++it_ra)
2080  map_cfh5_grp_attr_to_dap4(d4_root,*it_ra);
2081  }
2082 
2083  // We use the container since we claim to have no hierarchy.
2084  if (false == grps.empty()) {
2085  for (auto it_g = grps.begin(); it_g != grps.end(); ++it_g) {
2086  auto tmp_grp = new D4Attribute;
2087  tmp_grp->set_name((*it_g)->getNewName());
2088  tmp_grp->set_type(attr_container_c);
2089 
2090  for (it_ra = (*it_g)->getAttributes().begin();
2091  it_ra != (*it_g)->getAttributes().end(); ++it_ra) {
2092  map_cfh5_attr_container_to_dap4(tmp_grp,(*it_ra));
2093  }
2094  d4_root->attributes()->add_attribute_nocopy(tmp_grp);
2095  }
2096  }
2097 
2098  // Read Variable info.
2099  // TODO: We may need to make the cvar first for coverage support.
2100  vector<HDF5CF::Var *>::const_iterator it_v;
2101  vector<HDF5CF::EOS5CVar *>::const_iterator it_cv;
2102 
2103  if (HDF5RequestHandler::get_add_dap4_coverage() == true) {
2104  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
2105  BESDEBUG("h5","variable full path= "<< (*it_cv)->getFullPath() <<endl);
2106  gen_dap_oneeos5cvar_dmr(d4_root,*it_cv,file_id,filename);
2107 
2108  }
2109  for (it_v = vars.begin(); it_v !=vars.end();++it_v) {
2110  BESDEBUG("h5","variable full path= "<< (*it_v)->getFullPath() <<endl);
2111  gen_dap_onevar_dmr(d4_root,*it_v,file_id,filename);
2112  }
2113 
2114  // Handle EOS5 grid mapping info.
2115  if (f->Have_EOS5_Grids()==true)
2116  gen_dap_eos5cf_gm_dmr(d4_root,f);
2117 
2118  }
2119  else {
2120  for (it_v = vars.begin(); it_v !=vars.end();++it_v) {
2121  BESDEBUG("h5","variable full path= "<< (*it_v)->getFullPath() <<endl);
2122  gen_dap_onevar_dmr(d4_root,*it_v,file_id,filename);
2123  }
2124 
2125  // Handle EOS5 grid mapping info.
2126  if (f->Have_EOS5_Grids()==true)
2127  gen_dap_eos5cf_gm_dmr(d4_root,f);
2128 
2129  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
2130  BESDEBUG("h5","variable full path= "<< (*it_cv)->getFullPath() <<endl);
2131  gen_dap_oneeos5cvar_dmr(d4_root,*it_cv,file_id,filename);
2132 
2133  }
2134 
2135  }
2136 
2137  // CHECK ALL UNLIMITED DIMENSIONS from the coordinate variables based on the names.
2138  if(f->HaveUnlimitedDim() == true) {
2139 
2140  string dods_extra = "DODS_EXTRA";
2141 
2142  // If DODS_EXTRA exists, we will not create the unlimited dimensions.
2143  if(d4_root->attributes() != nullptr) {
2144 #if 0
2145  //if((d4_root->attributes()->find(dods_extra))==nullptr) {
2146 #endif
2147  string unlimited_dim_names ="";
2148 
2149  for (it_cv = cvars.begin();
2150  it_cv != cvars.end(); it_cv++) {
2151 
2152  // Check unlimited dimension names.
2153  for (auto ird = (*it_cv)->getDimensions().begin();
2154  ird != (*it_cv)->getDimensions().end(); ++ird) {
2155 
2156  // Currently we only check one unlimited dimension, which is the most
2157  // common case. When receiving the conventions from JG, will add
2158  // the support of multi-unlimited dimension. KY 2016-02-09
2159  if((*ird)->HaveUnlimitedDim() == true) {
2160 
2161  if(unlimited_dim_names=="")
2162  unlimited_dim_names = (*ird)->getNewName();
2163  else {
2164  if(unlimited_dim_names.rfind((*ird)->getNewName()) == string::npos) {
2165  unlimited_dim_names = unlimited_dim_names+" "+(*ird)->getNewName();
2166  }
2167  }
2168  }
2169  }
2170  }
2171 
2172  if(unlimited_dim_names != "") {
2173  auto dods_extra_attr = new D4Attribute(dods_extra,attr_container_c);
2174  auto unlimited_dim_attr = new D4Attribute("Unlimited_Dimension",attr_str_c);
2175  unlimited_dim_attr->add_value(unlimited_dim_names);
2176  dods_extra_attr->attributes()->add_attribute_nocopy(unlimited_dim_attr);
2177  d4_root->attributes()->add_attribute_nocopy(dods_extra_attr);
2178  }
2179  else
2180  throw InternalErr(__FILE__, __LINE__, "Unlimited dimension should exist.");
2181  //}
2182  }
2183 
2184  }
2185 
2186  // Add DAP4 map for coverage
2187  if (HDF5RequestHandler::get_add_dap4_coverage() == true) {
2188 
2189  // Obtain the coordinate variable names, these are mapped variables.
2190  vector <string> cvar_name;
2191  for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv)
2192  cvar_name.emplace_back((*it_cv)->getNewName());
2193 
2194  add_dap4_coverage(d4_root,cvar_name,f->getIsCOARD());
2195  }
2196 }
2197 
2198 
2199 void gen_dap_oneeos5cvar_dmr(D4Group* d4_root,const EOS5CVar* cvar,const hid_t file_id,const string & filename){
2200 
2201  BESDEBUG("h5","Coming to gen_dap_oneeos5cvar_dmr() "<<endl);
2202  BaseType *bt = nullptr;
2203 
2204  switch(cvar->getType()) {
2205 #define HANDLE_CASE(tid,type) \
2206  case tid: \
2207  bt = new (type)(cvar->getNewName(),cvar->getFullPath()); \
2208  break;
2209 
2210  HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
2211  HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
2212  HANDLE_CASE(H5CHAR,HDF5CFInt8)
2213  HANDLE_CASE(H5UCHAR, HDF5CFByte)
2214  HANDLE_CASE(H5INT16, HDF5CFInt16)
2215  HANDLE_CASE(H5UINT16, HDF5CFUInt16)
2216  HANDLE_CASE(H5INT32, HDF5CFInt32)
2217  HANDLE_CASE(H5UINT32, HDF5CFUInt32)
2218  HANDLE_CASE(H5INT64, HDF5CFInt64)
2219  HANDLE_CASE(H5UINT64, HDF5CFUInt64)
2220  HANDLE_CASE(H5FSTRING, Str)
2221  HANDLE_CASE(H5VSTRING, Str)
2222  default:
2223  throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
2224 #undef HANDLE_CASE
2225  }
2226 
2227  if (bt) {
2228 
2229  const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
2230  vector <HDF5CF::Dimension*>:: const_iterator it_d;
2231  vector <size_t> dimsizes;
2232  dimsizes.resize(cvar->getRank());
2233  for(int i = 0; i <cvar->getRank();i++)
2234  dimsizes[i] = (dims[i])->getSize();
2235 
2236 
2237  if(dims.empty())
2238  throw InternalErr(__FILE__,__LINE__,"the coordinate variables cannot be scalar.");
2239  switch(cvar->getCVType()) {
2240 
2241  case CV_EXIST:
2242  {
2243 
2244  bool is_latlon = cvar->isLatLon();
2245  HDF5CFArray *ar = nullptr;
2246  try {
2247  bool is_dap4 = true;
2248  ar = new HDF5CFArray (
2249  cvar->getRank(),
2250  file_id,
2251  filename,
2252  cvar->getType(),
2253  dimsizes,
2254  cvar->getFullPath(),
2255  cvar->getTotalElems(),
2256  CV_EXIST,
2257  is_latlon,
2258  cvar->getCompRatio(),
2259  is_dap4,
2260  cvar->getNewName(),
2261  bt);
2262  }
2263  catch (...) {
2264  delete bt;
2265  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDF5CFArray.");
2266  }
2267 
2268  for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
2269  if (""==(*it_d)->getNewName())
2270  ar->append_dim((int)((*it_d)->getSize()));
2271  else
2272  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
2273  }
2274 
2275  ar->set_is_dap4(true);
2276  BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
2277  map_cfh5_var_attrs_to_dap4(cvar,d4_var);
2278  d4_root->add_var_nocopy(d4_var);
2279 
2280  delete bt;
2281  delete ar;
2282  }
2283  break;
2284 
2285  case CV_LAT_MISS:
2286  case CV_LON_MISS:
2287  {
2288 
2289  HDFEOS5CFMissLLArray *ar = nullptr;
2290  try {
2291 #if 0
2292 cerr<<"cvar zone here is "<<cvar->getZone() <<endl;
2293 cerr<<"cvar Sphere here is "<<cvar->getSphere() <<endl;
2294 cerr<<"cvar getParams here 1 is "<<cvar->getParams()[0]<<endl;
2295 #endif
2296  ar = new HDFEOS5CFMissLLArray (
2297  cvar->getRank(),
2298  filename,
2299  file_id,
2300  cvar->getFullPath(),
2301  cvar->getCVType(),
2302  cvar->getPointLower(),
2303  cvar->getPointUpper(),
2304  cvar->getPointLeft(),
2305  cvar->getPointRight(),
2306  cvar->getPixelReg(),
2307  cvar->getOrigin(),
2308  cvar->getProjCode(),
2309  cvar->getParams(),
2310  cvar->getZone(),
2311  cvar->getSphere(),
2312  cvar->getXDimSize(),
2313  cvar->getYDimSize(),
2314  cvar->getNewName(),
2315  bt);
2316  }
2317  catch (...) {
2318  delete bt;
2319  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDFEOS5CFMissLLArray.");
2320  }
2321 
2322  for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
2323  if (""==(*it_d)->getNewName())
2324  ar->append_dim((int)((*it_d)->getSize()));
2325  else
2326  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
2327  }
2328 
2329  ar->set_is_dap4(true);
2330  BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
2331  map_cfh5_var_attrs_to_dap4(cvar,d4_var);
2332  add_var_sp_attrs_to_dap4(d4_var,cvar);
2333  d4_root->add_var_nocopy(d4_var);
2334 
2335  delete bt;
2336  delete ar;
2337  }
2338  break;
2339 
2340  case CV_NONLATLON_MISS:
2341  {
2342 
2343  if (cvar->getRank() !=1) {
2344  delete bt;
2345  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
2346  }
2347  int nelem = (int)((cvar->getDimensions()[0])->getSize());
2348 
2349  HDFEOS5CFMissNonLLCVArray *ar = nullptr;
2350  try {
2351  ar = new HDFEOS5CFMissNonLLCVArray(
2352  cvar->getRank(),
2353  nelem,
2354  cvar->getNewName(),
2355  bt);
2356  }
2357  catch (...) {
2358  delete bt;
2359  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDFEOS5CFMissNonLLCVArray.");
2360  }
2361 
2362 
2363  for(it_d = dims.begin(); it_d != dims.end(); it_d++) {
2364  if (""==(*it_d)->getNewName())
2365  ar->append_dim((int)((*it_d)->getSize()));
2366  else
2367  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
2368  }
2369 
2370  ar->set_is_dap4(true);
2371  BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
2372  map_cfh5_var_attrs_to_dap4(cvar,d4_var);
2373  d4_root->add_var_nocopy(d4_var);
2374 
2375  delete bt;
2376  delete ar;
2377 
2378 
2379  }
2380  break;
2381  case CV_SPECIAL:
2382  // Currently only support Aura TES files. May need to revise when having more
2383  // special products KY 2012-2-3
2384  {
2385 
2386  if (cvar->getRank() !=1) {
2387  delete bt;
2388  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
2389  }
2390  int nelem = (int)((cvar->getDimensions()[0])->getSize());
2391  HDFEOS5CFSpecialCVArray *ar = nullptr;
2392 
2393  try {
2394  ar = new HDFEOS5CFSpecialCVArray(
2395  cvar->getRank(),
2396  filename,
2397  file_id,
2398  cvar->getType(),
2399  nelem,
2400  cvar->getFullPath(),
2401  cvar->getNewName(),
2402  bt);
2403  }
2404  catch (...) {
2405  delete bt;
2406  throw InternalErr(__FILE__,__LINE__,"unable to allocate memory for HDF5CFArray.");
2407  }
2408 
2409 
2410  for(it_d = dims.begin(); it_d != dims.end(); ++it_d){
2411  if (""==(*it_d)->getNewName())
2412  ar->append_dim((int)((*it_d)->getSize()));
2413  else
2414  ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
2415  }
2416 
2417  ar->set_is_dap4(true);
2418  BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
2419  map_cfh5_var_attrs_to_dap4(cvar,d4_var);
2420  d4_root->add_var_nocopy(d4_var);
2421  delete bt;
2422  delete ar;
2423  }
2424  break;
2425  case CV_MODIFY:
2426  default:
2427  delete bt;
2428  throw InternalErr(__FILE__,__LINE__,"Unsupported coordinate variable type.");
2429  }
2430 
2431  }
2432 
2433 }
2434 
2435 
2436 // generate dmr info for grid mapping (gm: grid mapping)
2437 void gen_dap_eos5cf_gm_dmr(libdap::D4Group* d4_root,HDF5CF::EOS5File*f) {
2438 
2439  // grid mapping projection vars
2440  // and add grid_mapping attribute for non-cv vars
2441  gen_gm_proj_var_info(d4_root,f);
2442 
2443  // special grid mapping dimension variables.
2444  gen_gm_proj_spvar_info(d4_root,f);
2445 
2446 }
2447 
2448 //(1) Add grid mapping projection vars if we have any
2449 //(2) Add grid_mapping attributes for all non-cv vars
2450 void gen_gm_proj_var_info(libdap::D4Group* d4_root,const HDF5CF::EOS5File* f) {
2451 
2452  BESDEBUG("h5","Coming to HDF-EOS5 products DDS generation function "<<endl);
2453  const vector<HDF5CF::EOS5CVar *>& cvars = f->getCVars();
2454 
2455  // For multiple grids, multiple grid mapping variables are needed.
2456  // We use EOS5 coordinate variables to track this.
2457  unsigned short cv_lat_miss_index = 1;
2458  for (auto it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
2459  if((*it_cv)->getCVType() == CV_LAT_MISS) {
2460  if((*it_cv)->getProjCode() != HE5_GCTP_GEO) {
2461  gen_gm_oneproj_var(d4_root,*it_cv,cv_lat_miss_index,f);
2462  cv_lat_miss_index++;
2463  }
2464  }
2465  }
2466 }
2467 
2468 // Generate the dummy grid_mapping variables,attributes and
2469 // grid_mapping attributes for all the non-cv variables.
2470 void gen_gm_oneproj_var(libdap::D4Group*d4_root,
2471  const HDF5CF::EOS5CVar* cvar,
2472  const unsigned short g_suffix, const HDF5CF::EOS5File* f) {
2473 
2474  BESDEBUG("h5","Coming to gen_gm_oneproj_var() "<<endl);
2475  EOS5GridPCType cv_proj_code = cvar->getProjCode();
2476  const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
2477 
2478  if(dims.size() !=2)
2479  throw InternalErr(__FILE__,__LINE__,"Currently we only support the 2-D CF coordinate projection system.");
2480 
2481  // 1. Add the grid mapping dummy projection variable dmr for each grid
2482  // 2. Add the grid_mapping attribute for each variable that this projection applies
2483  // now, we handle sinusoidal,PS and LAMAZ projections.
2484  if (HE5_GCTP_SNSOID == cv_proj_code || HE5_GCTP_PS == cv_proj_code || HE5_GCTP_LAMAZ== cv_proj_code) {
2485 
2486  // Add the dummy projection variable.
2487  // The attributes of this variable can be used to store the grid mapping info.
2488  // To handle multi-grid cases, we need to add suffixes to distinguish them.
2489  string cf_projection_base = "eos_cf_projection";
2490  string cf_projection_name;
2491 
2492  HDF5CFGeoCFProj * dummy_proj_cf = nullptr;
2493 
2494  if(HE5_GCTP_SNSOID == cv_proj_code) {
2495 
2496  // AFAIK, one grid_mapping variable is necessary for multi-grids.
2497  // So we just leave one grid here.
2498  cf_projection_name = cf_projection_base;
2499  if(g_suffix == 1)
2500  dummy_proj_cf = new HDF5CFGeoCFProj(cf_projection_name, cf_projection_name);
2501  }
2502  else {
2503  stringstream t_suffix_ss;
2504  t_suffix_ss << g_suffix;
2505  cf_projection_name = cf_projection_base + "_" + t_suffix_ss.str();
2506  dummy_proj_cf = new HDF5CFGeoCFProj(cf_projection_name, cf_projection_name);
2507  }
2508 
2509  if(dummy_proj_cf != nullptr) {
2510  dummy_proj_cf->set_is_dap4(true);
2511  add_gm_oneproj_var_dap4_attrs(dummy_proj_cf,cv_proj_code,cvar->getParams());
2512  d4_root->add_var_nocopy(dummy_proj_cf);
2513  }
2514 
2515  // Add the grid_mapping attributes to all non-cv variables for the grid.
2516  vector<string> cvar_name;
2517  if (HDF5RequestHandler::get_add_dap4_coverage() == true) {
2518  const vector<HDF5CF::EOS5CVar *>& cvars = f->getCVars();
2519  for (auto it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv)
2520  cvar_name.emplace_back((*it_cv)->getNewName());
2521 
2522  }
2523  add_cf_grid_cv_dap4_attrs(d4_root,cf_projection_name,dims,cvar_name);
2524  }
2525 
2526 }
2527 
2528 //Generate DMR of special dimension variables.
2529 void gen_gm_proj_spvar_info(libdap::D4Group* d4_root,const HDF5CF::EOS5File* f){
2530 
2531  BESDEBUG("h5","Coming to HDF-EOS5 products grid mapping variable generation function "<<endl);
2532  const vector<HDF5CF::EOS5CVar *>& cvars = f->getCVars();
2533 
2534  for (auto it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
2535  if((*it_cv)->getCVType() == CV_LAT_MISS) {
2536  if((*it_cv)->getProjCode() != HE5_GCTP_GEO)
2537  gen_gm_oneproj_spvar(d4_root,*it_cv);
2538  }
2539  }
2540 }
2541 
2542 void gen_gm_oneproj_spvar(libdap::D4Group *d4_root,const HDF5CF::EOS5CVar *cvar) {
2543 
2544  BESDEBUG("h5","Coming to gen_gm_oneproj_spvar() "<<endl);
2545 
2546  float cv_point_lower = cvar->getPointLower();
2547  float cv_point_upper = cvar->getPointUpper();
2548  float cv_point_left = cvar->getPointLeft();
2549  float cv_point_right = cvar->getPointRight();
2550  EOS5GridPCType cv_proj_code = cvar->getProjCode();
2551  const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
2552  if(dims.size() !=2)
2553  throw InternalErr(__FILE__,__LINE__,"Currently we only support the 2-D CF coordinate projection system.");
2554  add_gm_spcvs(d4_root,cv_proj_code,cv_point_lower,cv_point_upper,cv_point_left,cv_point_right,dims);
2555 
2556 }
2557 
2558 void add_var_sp_attrs_to_dap4(BaseType *d4_var,const EOS5CVar* cvar) {
2559 
2560  if(cvar->getProjCode() == HE5_GCTP_LAMAZ) {
2561  if(cvar->getCVType() == CV_LAT_MISS) {
2562  add_var_dap4_attr(d4_var,"valid_min", attr_float64_c, "-90.0");
2563  add_var_dap4_attr(d4_var,"valid_max", attr_float64_c, "90.0");
2564  }
2565  else {
2566  add_var_dap4_attr(d4_var,"valid_min", attr_float64_c, "-180.0");
2567  add_var_dap4_attr(d4_var,"valid_max", attr_float64_c, "180.0");
2568  }
2569  }
2570 
2571 }
2572 
This class includes the methods to read data array into DAP buffer from an HDF5 dataset for the CF op...
This class provides a way to map HDF5 byte to DAP byte for the CF option.
This class provides a way to map HDF5 float to DAP float for the CF option.
This class provides a way to map HDF5 64-bit floating-point(double) to DAP 64-bit floating-point for ...
This class provides a way to map HDF5 int16 to DAP int16 for the CF option.
This class provides a way to map HDF5 32-bit integer to DAP Int32 for the CF option.
This class provides a way to map HDF5 64-bit integer to DAP4 Int64 for the CF option.
This class provides a way to map HDF5 int8 to DAP int16 for the CF option.
This class provides a way to map HDF5 Str to DAP Str for the CF option.
This class provides a way to map HDF5 unsigned 16-bit integer to DAP uint16 for the CF option.
This class provides a way to map HDF5 unsigned 32-bit integer to DAP uint32 for the CF option.
This class provides a way to map HDF5 64-bit unsigned integer to DAP4 UInt64 for the CF option.
include the entry functions to execute the handlers
This class specifies the retrieval of the missing lat/lon values for HDF-EOS5 products.
This class specifies the retrieval of the missing lat/lon values for HDFEOS5 products.
This class specifies the retrieval of special coordinate variable values for HDF-EOS5 products.
A class for parsing NASA HDF-EOS5 StructMetadata.
A class for parsing NASA HDF-EOS5 StructMetadata.
CVType getCVType() const
Get the coordinate variable type of this variable.
Definition: HDF5CF.h:362
This class is a derived class of CVar. It represents a coordinate variable for HDF-EOS5 files.
Definition: HDF5CF.h:431
This class is a derived class of File. It includes methods applied to HDF-EOS5 files only.
Definition: HDF5CF.h:1164
bool Get_IgnoredInfo_Flag() override
Obtain the flag to see if ignored objects should be generated.
Definition: HDF5CF.h:1264
void Adjust_Obj_Name() override
This method is a no-op operation. Leave here since the method in the base class is pure virtual.
Definition: HDFEOS5CF.cc:4197
void Add_EOS5File_Info(HE5Parser *, bool)
Add HDF-EOS5 dimension and coordinate variable related info. to EOS5Grid,EOS5Swath etc.
Definition: HDFEOS5CF.cc:838
void Retrieve_H5_Info(const char *path, hid_t file_id, bool include_attr) override
Retrieve DDS information from the HDF5 file; a real implementation for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:161
void Add_Supplement_Attrs(bool) override
Add the supplemental attributes for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:3670
void Set_COARDS_Status()
Set COARDS flag.
Definition: HDFEOS5CF.cc:3384
void Adjust_Var_Dim_NewName_Before_Flattening()
Adjust variable dimension names before the flattening for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:3033
void Handle_CVar() override
Handle coordinate variable for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:1770
void Adjust_Attr_Info()
Adjust the attribute info for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:3407
void Handle_SpVar_Attr() override
Handle special variables for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:4099
void Handle_Obj_NameClashing(bool)
Handle the object name clashing for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:3233
void Handle_Unsupported_Dtype(bool) override
Handle unsupported HDF5 datatypes for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:207
void Handle_DimNameClashing() override
Definition: HDFEOS5CF.cc:3319
const std::vector< EOS5CVar * > & getCVars() const
Obtain coordinate variables for HDF-EOS5 products.
Definition: HDF5CF.h:1175
void Handle_Unsupported_Others(bool) override
Handle other unmapped objects/attributes for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:360
void Retrieve_H5_CVar_Supported_Attr_Values() override
Retrieve coordinate variable attributes.
Definition: HDFEOS5CF.cc:168
void Handle_SpVar() override
Handle special variables for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:3977
void Adjust_Var_NewName_After_Parsing()
Adjust variable names for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:1224
void Retrieve_H5_Supported_Attr_Values() override
Retrieve attribute values for the supported HDF5 datatypes for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:184
void Add_Dim_Name(HE5Parser *)
Add the dimension name for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:1316
void Adjust_Dim_Name() override
Adjust the dimension name for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:3640
void Handle_SpVar_DMR() override
Handle special variables and attributes for HDF-EOS5 files(for DMR)
Definition: HDFEOS5CF.cc:4139
void Handle_Unsupported_Dspace(bool) override
Handle unsupported HDF5 dataspaces for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:301
const std::string & Get_Ignored_Msg() override
Obtain the message that contains the ignored object info.
Definition: HDF5CF.h:1269
void Flatten_Obj_Name(bool include_attr) override
Flatten the object name for HDF-EOS5 files.
Definition: HDFEOS5CF.cc:3211
void Check_Aura_Product_Status()
Check if the HDF-EOS5 file is an Aura file. Special CF operations need to be used.
Definition: HDFEOS5CF.cc:1718
void Adjust_EOS5Dim_Info(HE5Parser *strmeta_info)
Adjust HDF-EOS5 dimension information.
Definition: HDFEOS5CF.cc:537
void Handle_Coor_Attr() override
Handle the coordinates attribute for HDF-EOS5 products.
Definition: HDFEOS5CF.cc:3763
bool HaveUnlimitedDim() const
Has unlimited dimensions.
Definition: HDF5CF.h:661
const std::string & getPath() const
Obtain the path of the file.
Definition: HDF5CF.h:637
hid_t getFileID() const
Obtain the HDF5 file ID.
Definition: HDF5CF.h:631
const std::vector< Attribute * > & getAttributes() const
Public interface to obtain information of all attributes under the root group.
Definition: HDF5CF.h:649
const std::vector< Var * > & getVars() const
Public interface to obtain information of all variables.
Definition: HDF5CF.h:643
const std::vector< Group * > & getGroups() const
Public interface to obtain all the group info.
Definition: HDF5CF.h:655
float getCompRatio() const
Get the compression ratio of this dataset.
Definition: HDF5CF.h:321
int getRank() const
Get the dimension rank of this variable.
Definition: HDF5CF.h:298
const std::string & getFullPath() const
Get the full path of this variable.
Definition: HDF5CF.h:276
const std::string & getName() const
Get the original name of this variable.
Definition: HDF5CF.h:264
H5DataType getType() const
Get the data type of this variable(Not HDF5 datatype id)
Definition: HDF5CF.h:304
const std::vector< Dimension * > & getDimensions() const
Get the list of the dimensions.
Definition: HDF5CF.h:315
const std::string & getNewName() const
Get the new name of this variable.
Definition: HDF5CF.h:270
Helper functions for generating DAS attributes and a function to check BES Key.
yy_buffer_state * he5das_scan_string(const char *str)
Buffer state for NASA EOS metadata scanner.
Map and generate DDS and DAS for the CF option for HDF-EOS5 products.