bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
h5gmcfdap.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-2023 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 410 E University Ave,
22// Suite 200, Champaign, IL 61820
23
32
33#include <fcntl.h>
34#include <iostream>
35
36#include <BESDebug.h>
37#include <libdap/InternalErr.h>
38
39#include "HDF5RequestHandler.h"
40#include "h5cfdaputil.h"
41#include "h5gmcfdap.h"
42#include "HDF5CFInt8.h"
43#include "HDF5CFByte.h"
44#include "HDF5CFUInt16.h"
45#include "HDF5CFInt16.h"
46#include "HDF5CFUInt32.h"
47#include "HDF5CFInt32.h"
48#include "HDF5CFInt64.h"
49#include "HDF5CFUInt64.h"
50#include "HDF5CFFloat32.h"
51#include "HDF5CFFloat64.h"
52#include "HDF5CFStr.h"
53#include "HDF5CFArray.h"
54#include "HDF5GMCFMissLLArray.h"
58#include "HDF5GMSPCFArray.h"
59
60using namespace std;
61using namespace libdap;
62using namespace HDF5CF;
63
64// Map general HDF5 products to DAP DDS
65void map_gmh5_cfdds(DDS &dds, hid_t file_id, const string& filename){
66
67 BESDEBUG("h5","Coming to GM products DDS mapping function map_gmh5_cfdds() "<<endl);
68
69 H5GCFProduct product_type = check_product(file_id);
70
71 GMPattern gproduct_pattern = OTHERGMS;
72
73
74 auto f_unique = make_unique<GMFile>(filename.c_str(),file_id,product_type,gproduct_pattern);
75 auto f = f_unique.get();
76
77 // Generally don't need to handle attributes when handling DDS.
78 bool include_attr = false;
79 try {
80 // Retrieve all HDF5 info(Not the values)
81 f->Retrieve_H5_Info(filename.c_str(),file_id,include_attr);
82
83 // Update product type
84 // Newer version of a product may have different layout and the
85 // product type needs to be changed to reflect it. We also want
86 // to support the older version in case people still use them.
87 // This routine will check if newer layout can be applied. If yes,
88 // update the product type.
89 f->Update_Product_Type();
90
91 f->Remove_Unneeded_Objects();
92
93 // Need to add dimension names.
94 f->Add_Dim_Name();
95
96 // Handle coordinate variables
97 f->Handle_CVar();
98#if 0
99 // We need to retrieve coordinate variable attributes for memory cache use.
100 //f->Retrieve_H5_CVar_Supported_Attr_Values();
101 //if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
102 // (HDF5RequestHandler::get_srdata_mem_cache() != nullptr)){
103 // f->Retrieve_H5_Supported_Attr_Values();
104#endif
105
106 // Handle special variables
107 f->Handle_SpVar();
108
109 // When cv memory cache is on, the unit attributes are needed to
110 // distinguish whether this is lat/lon. Generally, memory cache
111 // is not used. This snipnet will not be accessed.
112 if ((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
113 (HDF5RequestHandler::get_srdata_mem_cache() != nullptr)){
114
115 // Handle unsupported datatypes including the attributes
116 f->Handle_Unsupported_Dtype(true);
117
118 // Handle unsupported dataspaces including the attributes
119 f->Handle_Unsupported_Dspace(true);
120
121 // We need to retrieve coordinate variable attributes for memory cache use.
122 f->Retrieve_H5_CVar_Supported_Attr_Values();
123
124 }
125 else {
126
127 // Handle unsupported datatypes
128 f->Handle_Unsupported_Dtype(include_attr);
129
130 // Handle unsupported dataspaces
131 f->Handle_Unsupported_Dspace(include_attr);
132
133 }
134
135 // Need to handle the "coordinate" attributes when memory cache is turned on.
136 if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
137 (HDF5RequestHandler::get_srdata_mem_cache() != nullptr))
138 f->Add_Supplement_Attrs(HDF5RequestHandler::get_add_path_attrs());
139
140 // Adjust object names(may remove redundant paths)
141 f->Adjust_Obj_Name();
142
143 // Flatten the object names
144 f->Flatten_Obj_Name(include_attr);
145
146 // Handle Object name clashings
147 // Only when the check_nameclashing key is turned on or
148 // general product.
149 if(General_Product == product_type ||
150 true == HDF5RequestHandler::get_check_name_clashing())
151 f->Handle_Obj_NameClashing(include_attr);
152
153 // Adjust Dimension name
154 f->Adjust_Dim_Name();
155 if(General_Product == product_type ||
156 true == HDF5RequestHandler::get_check_name_clashing())
157 f->Handle_DimNameClashing();
158
159 f->Handle_Hybrid_EOS5();
160 if(true == f->Have_Grid_Mapping_Attrs())
161 f->Handle_Grid_Mapping_Vars();
162 // Need to handle the "coordinate" attributes when memory cache is turned on.
163 if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
164 (HDF5RequestHandler::get_srdata_mem_cache() != nullptr))
165 f->Handle_Coor_Attr();
166
167 f->Remove_Unused_FakeDimVars();
168 f->Rename_NC4_NonCoordVars();
169#if 0
170 if (f->HaveUnlimitedDim())
171 f->Update_NC4_PureDimSize();
172#endif
173 }
174 catch (HDF5CF::Exception &e){
175 throw InternalErr(e.what());
176 }
177
178 // generate DDS.
179 try {
180 gen_gmh5_cfdds(dds,f);
181 }
182 catch(...) {
183 throw;
184 }
185
186}
187
188// Map general HDF5 products to DAP DAS
189void map_gmh5_cfdas(DAS &das, hid_t file_id, const string& filename){
190
191 BESDEBUG("h5","Coming to GM products DAS mapping function map_gmh5_cfdas() "<<endl);
192
193 H5GCFProduct product_type = check_product(file_id);
194 GMPattern gproduct_pattern = OTHERGMS;
195
196 auto f_unique = make_unique<GMFile>(filename.c_str(),file_id,product_type,gproduct_pattern);
197 auto f = f_unique.get();
198
199 bool include_attr = true;
200 try {
201 f->Retrieve_H5_Info(filename.c_str(),file_id,include_attr);
202
203 // Update product type(check comments of map_gmh5_cfdds)
204 f->Update_Product_Type();
205
206 f->Remove_Unneeded_Objects();
207
208 f->Add_Dim_Name();
209 f->Handle_CVar();
210 f->Handle_SpVar();
211 f->Handle_Unsupported_Dtype(include_attr);
212
213 // Remove unsupported dataspace
214 f->Handle_Unsupported_Dspace(include_attr);
215
216 // Need to retrieve the attribute values to feed DAS
217 f->Retrieve_H5_Supported_Attr_Values();
218
219 // Handle other unsupported objects,
220 // currently it mainly generates the info. for the
221 // unsupported objects other than datatype, dataspace,links and named datatype
222 // One area is maybe very long string. So we retrieve the attribute
223 // values before calling this function.
224 f->Handle_Unsupported_Others(include_attr);
225
226
227 // Need to add original variable name and path
228 // and other special attributes
229 // Can be turned on/off by using the check_path_attrs keys.
230 f->Add_Supplement_Attrs(HDF5RequestHandler::get_add_path_attrs());
231 f->Adjust_Obj_Name();
232 f->Flatten_Obj_Name(include_attr);
233 if(General_Product == product_type ||
234 true == HDF5RequestHandler::get_check_name_clashing())
235 f->Handle_Obj_NameClashing(include_attr);
236 if(f->HaveUnlimitedDim() == true)
237 f->Adjust_Dim_Name();
238 // Handle the "coordinate" attributes.
239 if (f->is_special_gpm_l3()==false)
240 f->Handle_Coor_Attr();
241
242 f->Handle_Hybrid_EOS5();
243 if(true == f->Have_Grid_Mapping_Attrs())
244 f->Handle_Grid_Mapping_Vars();
245
246 f->Remove_Unused_FakeDimVars();
247
248 f->Rename_NC4_NonCoordVars();
249
250 if(true == HDF5RequestHandler::get_enable_coord_attr_add_path() && f->is_special_gpm_l3()==false)
251 f->Add_Path_Coord_Attr();
252
253 f->Update_Bounds_Attr();
254 }
255 catch (HDF5CF::Exception &e){
256 throw InternalErr(e.what());
257 }
258
259 // Generate the DAS attributes.
260 try {
261 gen_gmh5_cfdas(das,f);
262 }
263 catch (...) {
264 throw;
265 }
266
267}
268
269
270void map_gmh5_cfdmr(D4Group *d4_root, hid_t file_id, const string& filename){
271
272 BESDEBUG("h5","Coming to GM products DMR mapping function map_gmh5_cfdmr() "<<endl);
273
274 H5GCFProduct product_type = check_product(file_id);
275
276 GMPattern gproduct_pattern = OTHERGMS;
277
278 auto f_unique = make_unique<GMFile>(filename.c_str(),file_id,product_type,gproduct_pattern);
279 auto f = f_unique.get();
280
281 // Both variables and attributes are in DMR.
282 bool include_attr = true;
283 try {
284
285 // Set the is_dap4 flag be true.
286 f->setDap4(true);
287
288 // Retrieve all HDF5 info(Not the values)
289 f->Retrieve_H5_Info(filename.c_str(),file_id,include_attr);
290
291 // Update product type
292 // Newer version of a product may have different layout and the
293 // product type needs to be changed to reflect it. We also want
294 // to support the older version in case people still use them.
295 // This routine will check if newer layout can be applied. If yes,
296 // update the product type.
297 f->Update_Product_Type();
298
299 f->Remove_Unneeded_Objects();
300
301 // Need to add dimension names.
302 f->Add_Dim_Name();
303
304 // Handle coordinate variables
305 f->Handle_CVar();
306#if 0
307 // We need to retrieve coordinate variable attributes for memory cache use.
308 //f->Retrieve_H5_CVar_Supported_Attr_Values();
309 //if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
310 // (HDF5RequestHandler::get_srdata_mem_cache() != nullptr)){
311 // f->Retrieve_H5_Supported_Attr_Values();
312#endif
313
314 // Handle special variables
315 f->Handle_SpVar();
316
317 // Handle unsupported datatypes including the attributes
318 f->Handle_Unsupported_Dtype(true);
319
320 // Handle unsupported dataspaces including the attributes
321 f->Handle_Unsupported_Dspace(true);
322
323 // We need to retrieve variable attributes.
324 f->Retrieve_H5_Supported_Attr_Values();
325
326 // Include handling internal netCDF-4 attributes
327 f->Handle_Unsupported_Others(include_attr);
328
329 // Need to handle the "coordinate" attributes
330 f->Add_Supplement_Attrs(HDF5RequestHandler::get_add_path_attrs());
331
332 // Adjust object names(may remove redundant paths)
333 f->Adjust_Obj_Name();
334
335 // Flatten the object names
336 f->Flatten_Obj_Name(include_attr);
337
338 // Handle Object name clashings
339 // Only when the check_nameclashing key is turned on or
340 // general product.
341 if (General_Product == product_type ||
342 true == HDF5RequestHandler::get_check_name_clashing())
343 f->Handle_Obj_NameClashing(include_attr);
344
345 // Adjust Dimension name, CHECK: the das generation has a f->HaveUnlimitedDim() condition
346 f->Adjust_Dim_Name();
347 if (General_Product == product_type ||
348 true == HDF5RequestHandler::get_check_name_clashing())
349 f->Handle_DimNameClashing();
350
351 // Handle the "coordinate" attributes.
352 f->Handle_Coor_Attr();
353
354 f->Handle_Hybrid_EOS5();
355 if(true == f->Have_Grid_Mapping_Attrs())
356 f->Handle_Grid_Mapping_Vars();
357#if 0
358 // Need to handle the "coordinate" attributes when memory cache is turned on.
359 if((HDF5RequestHandler::get_lrdata_mem_cache() != nullptr) ||
360 (HDF5RequestHandler::get_srdata_mem_cache() != nullptr))
361 f->Handle_Coor_Attr();
362#endif
363
364 f->Remove_Unused_FakeDimVars();
365 f->Rename_NC4_NonCoordVars();
366
367 if(true == HDF5RequestHandler::get_enable_coord_attr_add_path())
368 f->Add_Path_Coord_Attr();
369
370 f->Update_Bounds_Attr();
371
372 if (f->HaveUnlimitedDim())
373 f->Update_NC4_PureDimSize();
374
375 }
376 catch (HDF5CF::Exception &e){
377 throw InternalErr(e.what());
378 }
379
380 // generate DMR.
381 try {
382 gen_gmh5_cfdmr(d4_root,f);
383 }
384 catch(...) {
385 throw;
386 }
387
388}
389
390// Generate DDS mapped from general HDF5 products
391void gen_gmh5_cfdds( DDS & dds, HDF5CF:: GMFile *f) {
392
393 BESDEBUG("h5","Coming to GM DDS generation function gen_gmh5_cfdds() "<<endl);
394
395 const vector<HDF5CF::Var *>& vars = f->getVars();
396 const vector<HDF5CF::GMCVar *>& cvars = f->getCVars();
397 const vector<HDF5CF::GMSPVar *>& spvars = f->getSPVars();
398 const string filename = f->getPath();
399 const hid_t fileid = f->getFileID();
400
401 // Read Variable info.
402 // Since we need to use dds to add das for 64-bit dmr,we need to check if
403 // this case includes 64-bit integer variables and this is for dmr response.
404 bool dmr_64bit_support = false;
405 if (HDF5RequestHandler::get_dmr_long_int()==true &&
406 HDF5RequestHandler::get_dmr_64bit_int()!=nullptr) {
407 for (const auto &var:vars) {
408 if (H5INT64 == var->getType() || H5UINT64 == var->getType()){
409 dmr_64bit_support = true;
410 break;
411 }
412 }
413 }
414
415 // We need to remove the unsupported attributes.
416 if(true == dmr_64bit_support) {
417 //STOP: add non-support stuff
418 f->Handle_Unsupported_Dtype(true);
419
420 // Remove unsupported dataspace
421 f->Handle_Unsupported_Dspace(true);
422
423 }
424
425 for (auto &var:vars) {
426 BESDEBUG("h5","variable full path= "<< var->getFullPath() <<endl);
427 // Handle 64-integer DAP4 CF mapping
428 if(need_attr_values_for_dap4(var) == true)
429 f->Retrieve_H5_Var_Attr_Values(var);
430 gen_dap_onevar_dds(dds,var,fileid, filename);
431 }
432 for (const auto &cvar:cvars) {
433 BESDEBUG("h5","variable full path= "<< cvar->getFullPath() <<endl);
434 gen_dap_onegmcvar_dds(dds,cvar,fileid, filename);
435 }
436
437 for (const auto &spvar:spvars) {
438 BESDEBUG("h5","variable full path= "<< spvar->getFullPath() <<endl);
439 gen_dap_onegmspvar_dds(dds,spvar,fileid, filename);
440 }
441
442}
443
444// Generate DAS mapped from general HDF5 products
445void gen_gmh5_cfdas( DAS & das, HDF5CF:: GMFile *f) {
446
447 BESDEBUG("h5","Coming to GM DAS generation function gen_gmh5_cfdas() "<<endl);
448
449 // First check if this is for generating the ignored object info.
450 if(true == f->Get_IgnoredInfo_Flag()) {
451 gen_gmh5_cf_ignored_obj_info(das, f);
452 return;
453 }
454
455 const vector<HDF5CF::Var *>& vars = f->getVars();
456 const vector<HDF5CF::GMCVar *>& cvars = f->getCVars();
457 const vector<HDF5CF::GMSPVar *>& spvars = f->getSPVars();
458 const vector<HDF5CF::Group *>& grps = f->getGroups();
459 const vector<HDF5CF::Attribute *>& root_attrs = f->getAttributes();
460
461
462 // Handling the file attributes(attributes under the root group)
463 // The table name is "HDF_GLOBAL".
464
465 if (false == root_attrs.empty()) {
466
467 AttrTable *at = das.get_table(FILE_ATTR_TABLE_NAME);
468 if (nullptr == at) {
469 at = das.add_table(FILE_ATTR_TABLE_NAME, obtain_new_attr_table());
470 }
471 for (const auto &root_attr:root_attrs) {
472 // Check and may update the 64-bit integer attributes in DAP4.
473 check_update_int64_attr("",root_attr);
474 gen_dap_oneobj_das(at,root_attr,nullptr);
475 }
476 }
477
478 if (false == grps.empty()) {
479 for (const auto &grp:grps) {
480 AttrTable *at = das.get_table(grp->getNewName());
481 if (nullptr == at) {
482 at = das.add_table(grp->getNewName(), obtain_new_attr_table());
483 }
484 for (const auto &grp_attr:grp->getAttributes()) {
485 check_update_int64_attr(grp->getNewName(),grp_attr);
486 gen_dap_oneobj_das(at,grp_attr,nullptr);
487 }
488 }
489 }
490
491 for (const auto &var:vars) {
492
493 if (false == (var->getAttributes().empty())) {
494
495 // Skip the 64-bit integer variables. The attribute mapping of
496 // DAP4 CF 64-bit integer variable support
497 // has been taken care at the routine gen_dap_onevar_dds()
498 // defined at h5commoncfdap.cc
499 if(H5INT64 == var->getType() || H5UINT64 == var->getType()){
500 continue;
501 }
502
503 AttrTable *at = das.get_table(var->getNewName());
504 if (nullptr == at) {
505 at = das.add_table(var->getNewName(), obtain_new_attr_table());
506 }
507 for (const auto &attr:var->getAttributes())
508 gen_dap_oneobj_das(at,attr,var);
509
510 // TODO: If a var has integer-64 bit datatype attributes, maybe
511 // we can just keep that attributes(not consistent but
512 // easy to implement) or we have to duplicate all
513 // the var in dmr and delete this var from dds.
514
515 }
516
517 // GPM needs to be handled in a special way(mostly _FillValue)
518 if (GPMS_L3 == f->getProductType() || GPMM_L3 == f->getProductType()
519 || GPM_L1 == f->getProductType())
520 update_GPM_special_attrs(das,var,false);
521
522 }
523
524 for (const auto &cvar:cvars) {
525 if (false == (cvar->getAttributes().empty())) {
526
527 // TODO: Add 64-bit int support for coordinates, this has not been tackled.
528 if(H5INT64 == cvar->getType() || H5UINT64 == cvar->getType()){
529 continue;
530 }
531
532 AttrTable *at = das.get_table(cvar->getNewName());
533 if (nullptr == at) {
534 at = das.add_table(cvar->getNewName(), obtain_new_attr_table());
535 }
536 for (const auto &attr:cvar->getAttributes())
537 gen_dap_oneobj_das(at,attr,cvar);
538
539 }
540 // Though CF doesn't allow _FillValue, still keep it to keep the original form.
541 if(GPMS_L3 == f->getProductType() || GPMM_L3 == f->getProductType()
542 || GPM_L1 == f->getProductType())
543 update_GPM_special_attrs(das,cvar,true);
544
545 }
546
547 // Currently the special variables are only limited to the ACOS/OCO2 64-bit integer variables
548 for (const auto &spvar:spvars) {
549 if (false == (spvar->getAttributes().empty())) {
550
551 AttrTable *at = das.get_table(spvar->getNewName());
552 if (nullptr == at)
553 at = das.add_table(spvar->getNewName(), obtain_new_attr_table());
554
555 for (const auto &attr:spvar->getAttributes())
556 gen_dap_oneobj_das(at,attr,spvar);
557 }
558 }
559
560 // CHECK ALL UNLIMITED DIMENSIONS from the coordinate variables based on the names.
561 if(f->HaveUnlimitedDim() == true) {
562
563 BESDEBUG("h5","Find unlimited dimension in the GM DAS generation function gen_gmh5_cfdas() "<<endl);
564
565 // Currently there is no way for DAP to present the unlimited dimension info.
566 // when there are no dimension names. So don't create DODS_EXTRA even if
567 // there is an unlimited dimension in the file. KY 2016-02-18
568 if(cvars.empty()==false ){
569
570 // First check if we do have unlimited dimension in the coordinate variables.
571 // Since unsupported fakedims are removed, we may not have unlimited dimensions.
572 bool still_has_unlimited = false;
573 for (const auto &cvar:cvars) {
574
575 // Check unlimited dimension names.
576 for (const auto &dim:cvar->getDimensions()) {
577
578 // Currently we only check one unlimited dimension, which is the most
579 // common case. When receiving the conventions from JG, will add
580 // the support of multi-unlimited dimension. KY 2016-02-09
581 if(dim->HaveUnlimitedDim() == true) {
582 still_has_unlimited = true;
583 break;
584 }
585 }
586 if (true == still_has_unlimited)
587 break;
588 }
589
590 if (true == still_has_unlimited) {
591 AttrTable* at = das.get_table("DODS_EXTRA");
592 if (nullptr == at)
593 at = das.add_table("DODS_EXTRA", obtain_new_attr_table());
594
595 string unlimited_names;
596
597 for (const auto &cvar:cvars) {
598
599 // Check unlimited dimension names.
600 for (const auto &dim:cvar->getDimensions()) {
601
602 // Currently we only check one unlimited dimension, which is the most
603 // common case. When receiving the conventions from JG, will add
604 // the support of multi-unlimited dimension. KY 2016-02-09
605 if (dim->HaveUnlimitedDim() == true) {
606 if (unlimited_names=="") {
607 unlimited_names = dim->getNewName();
608 if (at !=nullptr)
609 at->append_attr("Unlimited_Dimension","String",unlimited_names);
610 }
611 else {
612 if(unlimited_names.rfind(dim->getNewName()) == string::npos) {
613 unlimited_names = unlimited_names+" "+dim->getNewName();
614 if(at !=nullptr)
615 at->append_attr("Unlimited_Dimension","String",dim->getNewName());
616 }
617 }
618 }// if(dim->HaveUnlimitedDim()
619 }// for (vector<Dimension*>::
620 }// for (cvars
621 }// if(true == still_has_unlimited)
622
623 }//if(cvars.size()>0)
624#if 0
625 // The following line will generate the string like "Band1 str1 str2".
626 //if(unlimited_names!="")
627 // // at->append_attr("Unlimited_Dimension","String",unlimited_names);
628#endif
629 }
630}
631
632void gen_gmh5_cfdmr(D4Group* d4_root,const HDF5CF::GMFile *f) {
633
634 BESDEBUG("h5","Coming to GM DDS generation function gen_gmh5_cfdmr() "<<endl);
635
636 const vector<HDF5CF::Var *>& vars = f->getVars();
637 const vector<HDF5CF::GMCVar *>& cvars = f->getCVars();
638 const vector<HDF5CF::GMSPVar *>& spvars = f->getSPVars();
639 const string filename = f->getPath();
640 const hid_t fileid = f->getFileID();
641 const vector<HDF5CF::Group *>& grps = f->getGroups();
642 const vector<HDF5CF::Attribute *>& root_attrs = f->getAttributes();
643
646
647 // Root and low-level group attributes.
648 if (false == root_attrs.empty()) {
649 for (const auto &root_attr:root_attrs)
650 map_cfh5_grp_attr_to_dap4(d4_root,root_attr);
651 }
652
653 // When the DAP4 coverage is turned on, the coordinate variables should be before the variables.
654 if (HDF5RequestHandler::get_add_dap4_coverage() == true) {
655
656 for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
657 BESDEBUG("h5","variable full path= "<< (*it_cv)->getFullPath() <<endl);
658 gen_dap_onegmcvar_dmr(d4_root,*it_cv,fileid, filename);
659 }
660
661 for (it_v = vars.begin(); it_v !=vars.end();++it_v) {
662 BESDEBUG("h5","variable full path= "<< (*it_v)->getFullPath() <<endl);
663 gen_dap_onevar_dmr(d4_root,*it_v,fileid, filename);
664 }
665 }
666 else {
667
668 // Read Variable info.
669 for (it_v = vars.begin(); it_v !=vars.end();++it_v) {
670 BESDEBUG("h5","variable full path= "<< (*it_v)->getFullPath() <<endl);
671 gen_dap_onevar_dmr(d4_root,*it_v,fileid, filename);
672
673 }
674 for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv) {
675 BESDEBUG("h5","variable full path= "<< (*it_cv)->getFullPath() <<endl);
676 gen_dap_onegmcvar_dmr(d4_root,*it_cv,fileid, filename);
677 }
678 }
679
680 // GPM needs to be handled in a special way(mostly _FillValue)
681 if(GPMS_L3 == f->getProductType() || GPMM_L3 == f->getProductType()
682 || GPM_L1 == f->getProductType())
683 update_GPM_special_attrs_cfdmr(d4_root,cvars);
684
685 for (auto it_spv = spvars.begin(); it_spv !=spvars.end();it_spv++) {
686 BESDEBUG("h5","variable full path= "<< (*it_spv)->getFullPath() <<endl);
687 gen_dap_onegmspvar_dmr(d4_root,*it_spv,fileid, filename);
688 }
689
690 // We use the attribute container to store the group attributes.
691 if (false == grps.empty()) {
692
693 for (const auto &grp:grps) {
694
695 auto tmp_grp_unique = make_unique<D4Attribute>();
696 auto tmp_grp = tmp_grp_unique.release();
697 tmp_grp->set_name(grp->getNewName());
698
699 // Make the type as a container
700 tmp_grp->set_type(attr_container_c);
701
702 for (const auto &attr: grp->getAttributes())
703 map_cfh5_attr_container_to_dap4(tmp_grp,attr);
704
705 d4_root->attributes()->add_attribute_nocopy(tmp_grp);
706 }
707 }
708
709 // CHECK ALL UNLIMITED DIMENSIONS from the coordinate variables based on the names.
710 if(f->HaveUnlimitedDim() == true) {
711
712 BESDEBUG("h5","Find unlimited dimension in the GM DMR generation function gen_gmh5_cfdmr() "<<endl);
713
714 // Currently there is no way for DAP to present the unlimited dimension info.
715 // when there are no dimension names. So don't create DODS_EXTRA even if
716 // there is an unlimited dimension in the file. KY 2016-02-18
717 if(cvars.empty()==false ){
718
719 // First check if we do have unlimited dimension in the coordinate variables.
720 // Since unsupported fakedims are removed, we may not have unlimited dimensions.
721 bool still_has_unlimited = false;
722 for (const auto &cvar:cvars) {
723
724 // Check unlimited dimension names.
725 for (const auto &dim:cvar->getDimensions()) {
726
727 // Currently we only check one unlimited dimension, which is the most
728 // common case. When receiving the conventions from JG, will add
729 // the support of multi-unlimited dimension. KY 2016-02-09
730 if(dim->HaveUnlimitedDim() == true) {
731 still_has_unlimited = true;
732 break;
733 }
734 }
735 if(true == still_has_unlimited)
736 break;
737 }
738
739 if(true == still_has_unlimited) {
740
741 string dods_extra = "DODS_EXTRA";
742
743 // If DODS_EXTRA exists, we will not create the unlimited dimensions.
744 if(d4_root->attributes() != nullptr) {
745
746 // TODO: The following lines cause seg. fault in libdap4, needs to investigate
747 //if((d4_root->attributes()->find(dods_extra))==nullptr)
748
749 string unlimited_dim_names;
750
751 for (const auto &cvar:cvars) {
752
753 // Check unlimited dimension names.
754 for (const auto& dim:cvar->getDimensions()) {
755
756 // Currently we only check one unlimited dimension, which is the most
757 // common case. When receiving the conventions from JG, will add
758 // the support of multi-unlimited dimension. KY 2016-02-09
759 if(dim->HaveUnlimitedDim() == true) {
760
761 string unlimited_dim_name = dim->getNewName();
762 if(unlimited_dim_names=="")
763 unlimited_dim_names = unlimited_dim_name;
764 else {
765 if(unlimited_dim_names.rfind(unlimited_dim_name) == string::npos)
766 unlimited_dim_names = unlimited_dim_names+" "+unlimited_dim_name;
767 }
768 }
769 }
770 }
771
772 if(unlimited_dim_names.empty() == false) {
773 auto unlimited_dim_attr_unique = make_unique<D4Attribute>("Unlimited_Dimension",attr_str_c);
774 auto unlimited_dim_attr = unlimited_dim_attr_unique.release();
775 unlimited_dim_attr->add_value(unlimited_dim_names);
776 auto dods_extra_attr_unique = make_unique<D4Attribute>(dods_extra,attr_container_c);
777 auto dods_extra_attr = dods_extra_attr_unique.release();
778 dods_extra_attr->attributes()->add_attribute_nocopy(unlimited_dim_attr);
779 d4_root->attributes()->add_attribute_nocopy(dods_extra_attr);
780
781 }
782 else
783 throw InternalErr(__FILE__, __LINE__, "Unlimited dimension should exist.");
784 }
785
786 }
787 }
788 }
789
790
791 // Add DAP4 Map for coverage
792 if (HDF5RequestHandler::get_add_dap4_coverage() == true) {
793
794 // Obtain the coordinate variable names, these are mapped variables.
795 vector <string> cvar_name;
796 for (it_cv = cvars.begin(); it_cv !=cvars.end();++it_cv)
797 cvar_name.emplace_back((*it_cv)->getNewName());
798
799 add_dap4_coverage(d4_root,cvar_name,f->getIsCOARD());
800 }
801
802}
803
804// Generate the ignored object info. for the CF option of the general products
805void gen_gmh5_cf_ignored_obj_info(DAS &das, HDF5CF::GMFile *f) {
806
807 BESDEBUG("h5","Coming to gen_gmh5_cf_ignored_obj_info() "<<endl);
808 AttrTable *at = das.get_table("Ignored_Object_Info");
809 if (nullptr == at)
810 at = das.add_table("Ignored_Object_Info", obtain_new_attr_table());
811
812 at->append_attr("Message","String",f->Get_Ignored_Msg());
813
814}
815
816// Generate the DDS for a coordinate variable of the General products
817void gen_dap_onegmcvar_dds(DDS &dds,const HDF5CF::GMCVar* cvar, const hid_t file_id, const string & filename) {
818
819 BESDEBUG("h5","Coming to gen_dap_onegmcvar_dds() "<<endl);
820
821 if(cvar->getType() == H5INT64 || cvar->getType() == H5UINT64)
822 return;
823
824 BaseType *bt = nullptr;
825
826 switch(cvar->getType()) {
827#define HANDLE_CASE(tid,type) \
828 case tid: \
829 bt = new (type)(cvar->getNewName(),cvar->getFullPath()); \
830 break;
831
832 HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
833 HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
834 HANDLE_CASE(H5CHAR,HDF5CFInt16)
835 HANDLE_CASE(H5UCHAR, HDF5CFByte)
836 HANDLE_CASE(H5INT16, HDF5CFInt16)
837 HANDLE_CASE(H5UINT16, HDF5CFUInt16)
838 HANDLE_CASE(H5INT32, HDF5CFInt32)
839 HANDLE_CASE(H5UINT32, HDF5CFUInt32)
840 HANDLE_CASE(H5FSTRING, Str)
841 HANDLE_CASE(H5VSTRING, Str)
842
843 default:
844 throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
845#undef HANDLE_CASE
846 }
847
848 if (bt) {
849
850 const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
851 vector <HDF5CF::Dimension*>:: const_iterator it_d;
852 vector <size_t> dimsizes;
853 dimsizes.resize(cvar->getRank());
854 for(int i = 0; i <cvar->getRank();i++)
855 dimsizes[i] = (dims[i])->getSize();
856
857 if (dims.empty()) {
858 delete bt;
859 throw InternalErr(__FILE__, __LINE__, "the coordinate variable cannot be a scalar");
860 }
861 switch(cvar->getCVType()) {
862
863 case CV_EXIST:
864 {
865 HDF5CFArray *ar = nullptr;
866
867 // Need to check if this CV is lat/lon. This is necessary when data memory cache is turned on.
868 bool is_latlon = cvar->isLatLon();
869
870 auto ar_unique = make_unique< HDF5CFArray>
871 (cvar->getRank(),
872 file_id,
873 filename,
874 cvar->getType(),
875 dimsizes,
876 cvar->getFullPath(),
877 cvar->getTotalElems(),
878 CV_EXIST,
879 is_latlon,
880 cvar->getCompRatio(),
881 false,
882 cvar->getNewName(),
883 bt);
884 ar = ar_unique.get();
885
886 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
887 if (((*it_d)->getNewName()).empty())
888 ar->append_dim((int)((*it_d)->getSize()));
889 else
890 ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
891 }
892
893 dds.add_var(ar);
894 }
895 break;
896
897 case CV_LAT_MISS:
898 case CV_LON_MISS:
899 {
900 // Using HDF5GMCFMissLLArray
901 HDF5GMCFMissLLArray *ar = nullptr;
902 auto ar_unique = make_unique<HDF5GMCFMissLLArray>
903 (cvar->getRank(),
904 filename,
905 file_id,
906 cvar->getType(),
907 cvar->getFullPath(),
908 cvar->getPtType(),
909 cvar->getCVType(),
910 cvar->getNewName(),
911 bt);
912 ar = ar_unique.get();
913
914 for (it_d = dims.begin(); it_d != dims.end(); ++it_d) {
915 if (((*it_d)->getNewName()).empty())
916 ar->append_dim((int)((*it_d)->getSize()));
917 else
918 ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
919 }
920 dds.add_var(ar);
921 }
922 break;
923
924 case CV_NONLATLON_MISS:
925 {
926
927 if (cvar->getRank() !=1) {
928 delete bt;
929 throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
930 }
931 auto nelem = (int)((cvar->getDimensions()[0])->getSize());
932
933 HDF5GMCFMissNonLLCVArray *ar = nullptr;
934
935 auto ar_unique = make_unique<HDF5GMCFMissNonLLCVArray>
936 (cvar->getRank(),
937 nelem,
938 cvar->getNewName(),
939 bt);
940 ar = ar_unique.get();
941
942 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
943 if (((*it_d)->getNewName()).empty())
944 ar->append_dim((int)((*it_d)->getSize()));
945 else
946 ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
947 }
948 dds.add_var(ar);
949 }
950 break;
951
952 case CV_FILLINDEX:
953 {
954 if (cvar->getRank() !=1) {
955 delete bt;
956 throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
957 }
958
959 HDF5GMCFFillIndexArray *ar = nullptr;
960
961 auto ar_unique = make_unique<HDF5GMCFFillIndexArray>
962 (cvar->getRank(),
963 cvar->getType(),
964 false,
965 cvar->getNewName(),
966 bt);
967 ar = ar_unique.get();
968
969 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
970 if (((*it_d)->getNewName()).empty())
971 ar->append_dim((int)((*it_d)->getSize()));
972 else
973 ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
974 }
975 dds.add_var(ar);
976 }
977 break;
978
979 case CV_SPECIAL:
980 {
981 // Currently only handle 1-D special CV.
982 if (cvar->getRank() !=1) {
983 delete bt;
984 throw InternalErr(__FILE__, __LINE__, "The rank of special coordinate variable must be 1");
985 }
986 auto nelem = (int)((cvar->getDimensions()[0])->getSize());
987
988 auto ar_unique = make_unique<HDF5GMCFSpecialCVArray>(
989 cvar->getType(),
990 nelem,
991 cvar->getFullPath(),
992 cvar->getPtType(),
993 cvar->getNewName(),
994 bt);
995 auto ar = ar_unique.get();
996
997 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
998 if (((*it_d)->getNewName()).empty())
999 ar->append_dim((int)((*it_d)->getSize()));
1000 else
1001 ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
1002 }
1003
1004 dds.add_var(ar);
1005 }
1006 break;
1007 case CV_MODIFY:
1008 default:
1009 delete bt;
1010 throw InternalErr(__FILE__,__LINE__,"Coordinate variable type is not supported.");
1011 }
1012 }
1013 delete bt;
1014}
1015
1016// Generate DDS for special variable in a general product
1017void gen_dap_onegmspvar_dds(DDS &dds,const HDF5CF::GMSPVar* spvar, const hid_t fileid, const string & filename) {
1018
1019 BESDEBUG("h5","Coming to gen_dap_onegmspvar_dds() "<<endl);
1020 BaseType *bt = nullptr;
1021
1022 switch(spvar->getType()) {
1023#define HANDLE_CASE(tid,type) \
1024 case tid: \
1025 bt = new (type)(spvar->getNewName(),spvar->getFullPath()); \
1026 break;
1027
1028 HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
1029 HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
1030 HANDLE_CASE(H5CHAR,HDF5CFInt16)
1031 HANDLE_CASE(H5UCHAR, HDF5CFByte)
1032 HANDLE_CASE(H5INT16, HDF5CFInt16)
1033 HANDLE_CASE(H5UINT16, HDF5CFUInt16)
1034 HANDLE_CASE(H5INT32, HDF5CFInt32)
1035 HANDLE_CASE(H5UINT32, HDF5CFUInt32)
1036 HANDLE_CASE(H5FSTRING, Str)
1037 HANDLE_CASE(H5VSTRING, Str)
1038 default:
1039 throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
1040#undef HANDLE_CASE
1041 }
1042
1043 if (bt) {
1044
1045 const vector<HDF5CF::Dimension *>& dims = spvar->getDimensions();
1046
1047 if (dims.empty()) {
1048 delete bt;
1049 throw InternalErr(__FILE__, __LINE__, "Currently don't support scalar special variables. ");
1050 }
1051 HDF5GMSPCFArray *ar = nullptr;
1052
1053 auto ar_unique = make_unique<HDF5GMSPCFArray> (
1054 spvar->getRank(),
1055 filename,
1056 fileid,
1057 spvar->getType(),
1058 spvar->getFullPath(),
1059 spvar->getOriginalType(),
1060 spvar->getStartBit(),
1061 spvar->getBitNum(),
1062 spvar->getNewName(),
1063 bt);
1064 ar = ar_unique.get();
1065
1066 for (auto const &dim:dims) {
1067 if ((dim->getNewName()).empty())
1068 ar->append_dim((int)(dim->getSize()));
1069 else
1070 ar->append_dim((int)(dim->getSize()), dim->getNewName());
1071 }
1072
1073 dds.add_var(ar);
1074 delete bt;
1075 }
1076
1077}
1078
1079// When we add floating point fill value at HDF5CF.cc, the value will be changed
1080// a little bit when it changes to string representation.
1081// For example, -9999.9 becomes -9999.9000123. To reduce the misunderstanding,we
1082// just add fillvalue in the string type here. KY 2014-04-02
1083void update_GPM_special_attrs(DAS& das, const HDF5CF::Var *var,bool is_cvar) {
1084
1085 BESDEBUG("h5","Coming to update_GPM_special_attrs() "<<endl);
1086 if(H5FLOAT64 == var->getType() ||
1087 H5FLOAT32 == var->getType() ||
1088 H5INT16 == var->getType() ||
1089 H5CHAR == var->getType()) {
1090
1091 AttrTable *at = das.get_table(var->getNewName());
1092 if (nullptr == at)
1093 at = das.add_table(var->getNewName(), obtain_new_attr_table());
1094 bool has_fillvalue = false;
1095 AttrTable::Attr_iter it = at->attr_begin();
1096 while (it!=at->attr_end() && false==has_fillvalue) {
1097 if (at->get_name(it) =="_FillValue")
1098 {
1099 has_fillvalue = true;
1100 string fillvalue ="";
1101 if(H5FLOAT32 == var->getType()) {
1102 const string cor_fill_value = "-9999.9";
1103 fillvalue = (*at->get_attr_vector(it)->begin());
1104 if((fillvalue.find(cor_fill_value) == 0) && (fillvalue!= cor_fill_value)) {
1105 at->del_attr("_FillValue");
1106 at->append_attr("_FillValue","Float32",cor_fill_value);
1107 }
1108 }
1109 else if(H5FLOAT64 == var->getType()) {
1110 const string cor_fill_value = "-9999.9";
1111 const string exist_fill_value_substr = "-9999.8999";
1112 fillvalue = (*at->get_attr_vector(it)->begin());
1113 if((fillvalue.find(exist_fill_value_substr) == 0) && (fillvalue!= cor_fill_value)) {
1114 at->del_attr("_FillValue");
1115 at->append_attr("_FillValue","Float64",cor_fill_value);
1116 }
1117
1118 }
1119 }
1120 it++;
1121 }
1122
1123 // Add the fill value
1124 if(false == is_cvar ) {
1125
1126 // Current versions of GPM don't add fillvalues. We add the fillvalue according to the document.
1127 if (has_fillvalue != true ) {
1128
1129 if(H5FLOAT32 == var->getType())
1130 at->append_attr("_FillValue","Float32","-9999.9");
1131 else if(H5FLOAT64 == var->getType())
1132 at->append_attr("_FillValue","Float64","-9999.9");
1133 else if (H5INT16 == var->getType())
1134 at->append_attr("_FillValue","Int16","-9999");
1135 else if (H5CHAR == var->getType())// H5CHAR maps to DAP int16
1136 at->append_attr("_FillValue","Int16","-99");
1137
1138 }
1139 }
1140 }
1141}
1142
1143// This routine is following the DAP2 way,except we map HDF5 8-bit integer to DAP4 8-bit integer.
1144// When we add floating point fill value at HDF5CF.cc, the value will be changed
1145// a little bit when it changes to string representation.
1146// For example, -9999.9 becomes -9999.9000123. To reduce the misunderstanding,we
1147// just add fillvalue in the string type here. KY 2014-04-02
1148void update_GPM_special_attrs_cfdmr(libdap::D4Group* d4_root, const vector<HDF5CF::GMCVar *>& cvars) {
1149
1150 BESDEBUG("h5","Coming to update_GPM_special_attrs_cfdmr() "<<endl);
1151
1152 // We need to loop through all the variables.
1153 Constructor::Vars_iter vi = d4_root->var_begin();
1154 Constructor::Vars_iter ve = d4_root->var_end();
1155
1156 for (; vi != ve; vi++) {
1157
1158 // The _FillValue datatype only applies to
1159 // 32-bit and 64-bit floating-point data and
1160 // 8-bit and 16-bit integer.
1161
1162 Type var_type = (*vi)->type();
1163 if ((*vi)->type() == dods_array_c)
1164 var_type = (*vi)->var()->type();
1165 if (dods_float64_c == var_type ||
1166 dods_float32_c == var_type ||
1167 dods_int16_c == var_type ||
1168 dods_int8_c == var_type) {
1169
1170 const D4Attribute *d4_attr = (*vi)->attributes()->find("_FillValue");
1171
1172 // If we don't find the _FillValue, according to DAP2 implementation,
1173 // we need to add the corresponding fill values.
1174 if (!d4_attr) {
1175 bool is_cvar = false;
1176 for (const auto &cvar:cvars) {
1177 if (cvar->getNewName() == (*vi)->name()) {
1178 is_cvar = true;
1179 break;
1180 }
1181 }
1182
1183 // Add fillvalue for real variables not for the coordinate variables.
1184 if(false == is_cvar) {
1185 // Add a DAP4 attribute
1186 D4Attribute *d4_fv = nullptr;
1187 if (dods_float64_c == var_type ) {
1188 auto d4_fv_unique = make_unique<D4Attribute>("_FillValue",attr_float64_c);
1189 d4_fv = d4_fv_unique.release();
1190 d4_fv->add_value("-9999.9");
1191 }
1192 else if (dods_float32_c == var_type) {
1193 auto d4_fv_unique = make_unique<D4Attribute>("_FillValue",attr_float32_c);
1194 d4_fv = d4_fv_unique.release();
1195 d4_fv->add_value("-9999.9");
1196 }
1197 else if (dods_int16_c == var_type) {
1198 auto d4_fv_unique = make_unique<D4Attribute>("_FillValue",attr_int16_c);
1199 d4_fv = d4_fv_unique.release();
1200 d4_fv->add_value("-9999");
1201 }
1202 else if (dods_int8_c == var_type) {
1203 auto d4_fv_unique = make_unique<D4Attribute>("_FillValue",attr_int8_c);
1204 d4_fv = d4_fv_unique.release();
1205 d4_fv->add_value("-99");
1206 }
1207 (*vi)->attributes()->add_attribute_nocopy(d4_fv);
1208 }
1209 }
1210 else {
1211 D4Attribute *d4_fv = nullptr;
1212 if (dods_float64_c == var_type ) {
1213 const string cor_fill_value = "-9999.9";
1214 const string exist_fill_value_substr = "-9999.8999";
1215 string fillvalue = d4_attr->value(0);
1216 if((fillvalue.find(exist_fill_value_substr) == 0) && (fillvalue!= cor_fill_value)) {
1217 (*vi)->attributes()->erase("_FillValue");
1218 auto d4_fv_unique = make_unique<D4Attribute>("_FillValue",attr_float64_c);
1219 d4_fv = d4_fv_unique.release();
1220 d4_fv->add_value(cor_fill_value);
1221 (*vi)->attributes()->add_attribute_nocopy(d4_fv);
1222 }
1223 }
1224 else if (dods_float32_c == var_type) {
1225 const string cor_fill_value = "-9999.9";
1226 string fillvalue = d4_attr->value(0);
1227 // Somehow the fillvalue changes to "-9999.90??", we want to turn it back.
1228 if((fillvalue.find(cor_fill_value) == 0) && (fillvalue!= cor_fill_value)) {
1229 (*vi)->attributes()->erase("_FillValue");
1230 auto d4_fv_unique = make_unique<D4Attribute>("_FillValue",attr_float32_c);
1231 d4_fv = d4_fv_unique.release();
1232 d4_fv->add_value(cor_fill_value);
1233 (*vi)->attributes()->add_attribute_nocopy(d4_fv);
1234 }
1235 }
1236 }
1237 }
1238 }
1239}
1240
1241void gen_dap_onegmcvar_dmr(D4Group*d4_root,const GMCVar* cvar,const hid_t fileid, const string &filename) {
1242
1243 BESDEBUG("h5","Coming to gen_dap_onegmcvar_dds() "<<endl);
1244
1245 BaseType *bt = nullptr;
1246
1247 switch(cvar->getType()) {
1248#define HANDLE_CASE(tid,type) \
1249 case tid: \
1250 bt = new (type)(cvar->getNewName(),cvar->getFullPath()); \
1251 break;
1252
1253 HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
1254 HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
1255 HANDLE_CASE(H5CHAR,HDF5CFInt8)
1256 HANDLE_CASE(H5UCHAR, HDF5CFByte)
1257 HANDLE_CASE(H5INT16, HDF5CFInt16)
1258 HANDLE_CASE(H5UINT16, HDF5CFUInt16)
1259 HANDLE_CASE(H5INT32, HDF5CFInt32)
1260 HANDLE_CASE(H5UINT32, HDF5CFUInt32)
1261 HANDLE_CASE(H5INT64, HDF5CFInt64)
1262 HANDLE_CASE(H5UINT64, HDF5CFUInt64)
1263 HANDLE_CASE(H5FSTRING, Str)
1264 HANDLE_CASE(H5VSTRING, Str)
1265
1266 default:
1267 throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
1268#undef HANDLE_CASE
1269 }
1270
1271 if (bt) {
1272
1273 const vector<HDF5CF::Dimension *>& dims = cvar->getDimensions();
1274 vector <HDF5CF::Dimension*>:: const_iterator it_d;
1275 vector <size_t> dimsizes;
1276 dimsizes.resize(cvar->getRank());
1277
1278 for(int i = 0; i <cvar->getRank();i++)
1279 dimsizes[i] = (dims[i])->getSize();
1280
1281 if(dims.empty()) {
1282 delete bt;
1283 throw InternalErr(__FILE__, __LINE__, "the coordinate variable cannot be a scalar");
1284 }
1285 switch(cvar->getCVType()) {
1286
1287 case CV_EXIST:
1288 {
1289 HDF5CFArray *ar = nullptr;
1290
1291 // Need to check if this CV is lat/lon. This is necessary when data memory cache is turned on.
1292 bool is_latlon = cvar->isLatLon();
1293
1294 bool is_dap4 = true;
1295 auto ar_unique = make_unique<HDF5CFArray> (
1296 cvar->getRank(),
1297 fileid,
1298 filename,
1299 cvar->getType(),
1300 dimsizes,
1301 cvar->getFullPath(),
1302 cvar->getTotalElems(),
1303 CV_EXIST,
1304 is_latlon,
1305 cvar->getCompRatio(),
1306 is_dap4,
1307 cvar->getNewName(),
1308 bt);
1309 ar = ar_unique.get();
1310
1311 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
1312 if (((*it_d)->getNewName()).empty())
1313 ar->append_dim_ll((int)((*it_d)->getSize()));
1314 else
1315 ar->append_dim_ll((int)((*it_d)->getSize()), (*it_d)->getNewName());
1316 }
1317
1318 ar->set_is_dap4(true);
1319 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
1320 map_cfh5_var_attrs_to_dap4(cvar,d4_var);
1321 d4_root->add_var_nocopy(d4_var);
1322 }
1323 break;
1324
1325 case CV_LAT_MISS:
1326 case CV_LON_MISS:
1327 {
1328 // Using HDF5GMCFMissLLArray
1329 HDF5GMCFMissLLArray *ar = nullptr;
1330 auto ar_unique = make_unique<HDF5GMCFMissLLArray> (
1331 cvar->getRank(),
1332 filename,
1333 fileid,
1334 cvar->getType(),
1335 cvar->getFullPath(),
1336 cvar->getPtType(),
1337 cvar->getCVType(),
1338 cvar->getNewName(),
1339 bt);
1340 ar = ar_unique.get();
1341
1342 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
1343 if (((*it_d)->getNewName()).empty())
1344 ar->append_dim_ll((*it_d)->getSize());
1345 else
1346 ar->append_dim_ll((*it_d)->getSize(), (*it_d)->getNewName());
1347 }
1348
1349 ar->set_is_dap4(true);
1350 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
1351 map_cfh5_var_attrs_to_dap4(cvar,d4_var);
1352 d4_root->add_var_nocopy(d4_var);
1353 }
1354 break;
1355
1356 case CV_NONLATLON_MISS:
1357 {
1358
1359 if (cvar->getRank() !=1) {
1360 delete bt;
1361 throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
1362 }
1363 auto nelem = (int)((cvar->getDimensions()[0])->getSize());
1364
1365 HDF5GMCFMissNonLLCVArray *ar = nullptr;
1366
1367 auto ar_unique = make_unique<HDF5GMCFMissNonLLCVArray>(
1368 cvar->getRank(),
1369 nelem,
1370 cvar->getNewName(),
1371 bt);
1372 ar = ar_unique.get();
1373
1374 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
1375 if (((*it_d)->getNewName()).empty())
1376 ar->append_dim_ll((*it_d)->getSize());
1377 else
1378 ar->append_dim_ll((*it_d)->getSize(), (*it_d)->getNewName());
1379 }
1380 ar->set_is_dap4(true);
1381 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
1382 map_cfh5_var_attrs_to_dap4(cvar,d4_var);
1383 d4_root->add_var_nocopy(d4_var);
1384 }
1385 break;
1386
1387 case CV_FILLINDEX:
1388 {
1389
1390 if (cvar->getRank() !=1) {
1391 delete bt;
1392 throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
1393 }
1394
1395 HDF5GMCFFillIndexArray *ar = nullptr;
1396
1397 auto ar_unique = make_unique<HDF5GMCFFillIndexArray>(
1398 cvar->getRank(),
1399 cvar->getType(),
1400 true,
1401 cvar->getNewName(),
1402 bt);
1403 ar = ar_unique.get();
1404
1405 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
1406 if (((*it_d)->getNewName()).empty())
1407 ar->append_dim_ll((*it_d)->getSize());
1408 else
1409 ar->append_dim_ll((*it_d)->getSize(), (*it_d)->getNewName());
1410 }
1411 ar->set_is_dap4(true);
1412 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
1413 map_cfh5_var_attrs_to_dap4(cvar,d4_var);
1414 d4_root->add_var_nocopy(d4_var);
1415 }
1416 break;
1417
1418 case CV_SPECIAL:
1419 {
1420 // Currently only handle 1-D special CV.
1421 if (cvar->getRank() !=1) {
1422 delete bt;
1423 throw InternalErr(__FILE__, __LINE__, "The rank of special coordinate variable must be 1");
1424 }
1425 int nelem = (cvar->getDimensions()[0])->getSize();
1426
1427 auto ar_unique = make_unique<HDF5GMCFSpecialCVArray>(cvar->getType(),
1428 nelem,
1429 cvar->getFullPath(),
1430 cvar->getPtType(),
1431 cvar->getNewName(),
1432 bt);
1433 auto ar = ar_unique.get();
1434 for(it_d = dims.begin(); it_d != dims.end(); ++it_d) {
1435 if (((*it_d)->getNewName()).empty())
1436 ar->append_dim_ll((*it_d)->getSize());
1437 else
1438 ar->append_dim_ll((*it_d)->getSize(), (*it_d)->getNewName());
1439 }
1440
1441 ar->set_is_dap4(true);
1442 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
1443 map_cfh5_var_attrs_to_dap4(cvar,d4_var);
1444 d4_root->add_var_nocopy(d4_var);
1445 }
1446 break;
1447 case CV_MODIFY:
1448 default:
1449 delete bt;
1450 throw InternalErr(__FILE__,__LINE__,"Coordinate variable type is not supported.");
1451 }
1452 }
1453 delete bt;
1454}
1455
1456void gen_dap_onegmspvar_dmr(D4Group*d4_root,const GMSPVar*spvar,const hid_t fileid, const string &filename) {
1457
1458 BESDEBUG("h5","Coming to gen_dap_onegmspvar_dmr() "<<endl);
1459 BaseType *bt = nullptr;
1460
1461 // Note: The special variable is actually an ACOS_OCO2 64-bit integer variable.
1462 // We decompose 64-bit to two integer variables according to the specification.
1463 // This product has been served in this way for years. For backward compatibility,
1464 // we will not change this in the CF DMR implementation. So Int64/UInt64 are not added.
1465 // KY 2021-03-09
1466 switch(spvar->getType()) {
1467#define HANDLE_CASE(tid,type) \
1468 case tid: \
1469 bt = new (type)(spvar->getNewName(),spvar->getFullPath()); \
1470 break;
1471
1472 HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
1473 HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
1474 HANDLE_CASE(H5CHAR,HDF5CFByte)
1475 HANDLE_CASE(H5UCHAR, HDF5CFByte)
1476 HANDLE_CASE(H5INT16, HDF5CFInt16)
1477 HANDLE_CASE(H5UINT16, HDF5CFUInt16)
1478 HANDLE_CASE(H5INT32, HDF5CFInt32)
1479 HANDLE_CASE(H5UINT32, HDF5CFUInt32)
1480 HANDLE_CASE(H5FSTRING, Str)
1481 HANDLE_CASE(H5VSTRING, Str)
1482 default:
1483 throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
1484#undef HANDLE_CASE
1485 }
1486
1487 if (bt) {
1488
1489 const vector<HDF5CF::Dimension *> &dims = spvar->getDimensions();
1490
1491 if (dims.empty()) {
1492 delete bt;
1493 throw InternalErr(__FILE__, __LINE__, "Currently don't support scalar special variables. ");
1494 }
1495
1496 HDF5GMSPCFArray *ar = nullptr;
1497
1498 auto ar_unique = make_unique<HDF5GMSPCFArray>(spvar->getRank(),
1499 filename,
1500 fileid,
1501 spvar->getType(),
1502 spvar->getFullPath(),
1503 spvar->getOriginalType(),
1504 spvar->getStartBit(),
1505 spvar->getBitNum(),
1506 spvar->getNewName(),
1507 bt);
1508 ar = ar_unique.get();
1509
1510 for (const auto &dim:dims) {
1511 if (""==dim->getNewName())
1512 ar->append_dim_ll(dim->getSize());
1513 else
1514 ar->append_dim_ll(dim->getSize(), dim->getNewName());
1515 }
1516
1517 ar->set_is_dap4(true);
1518 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_root);
1519 map_cfh5_var_attrs_to_dap4(spvar,d4_var);
1520 d4_root->add_var_nocopy(d4_var);
1521
1522 delete bt;
1523 }
1524
1525}
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.
This class includes the methods to read data array into DAP buffer from an HDF5 dataset for the CF op...
This class specifies the retrieval of the missing lat/lon values for general HDF5 products.
This class specifies the retrieval of the values of non-lat/lon coordinate variables for general HDF5...
This class specifies the retrieval of the missing lat/lon values for general HDF5 products.
This class specifies the retrieval of data values for special HDF5 products Currently this only appli...
include the entry functions to execute the handlers
CVType getCVType() const
Get the coordinate variable type of this variable.
Definition HDF5CF.h:358
bool HaveUnlimitedDim() const
Has unlimited dimensions.
Definition HDF5CF.h:657
hid_t getFileID() const
Obtain the HDF5 file ID.
Definition HDF5CF.h:627
const std::vector< Attribute * > & getAttributes() const
Public interface to obtain information of all attributes under the root group.
Definition HDF5CF.h:645
const std::vector< Group * > & getGroups() const
Public interface to obtain all the group info.
Definition HDF5CF.h:651
const std::string & getPath() const
Obtain the path of the file.
Definition HDF5CF.h:633
const std::vector< Var * > & getVars() const
Public interface to obtain information of all variables.
Definition HDF5CF.h:639
This class is a derived class of CVar. It represents a coordinate variable for general HDF5 files.
Definition HDF5CF.h:409
H5GCFProduct getPtType() const
Get the data type of this variable.
Definition HDF5CF.h:416
This class is a derived class of File. It includes methods applied to general HDF5 files only.
Definition HDF5CF.h:822
const std::string & Get_Ignored_Msg() override
Get the message that contains the ignored obj. info.
Definition HDF5CF.h:941
This class is a derived class of Var. It represents a special general HDF5 product(currently ACOS and...
Definition HDF5CF.h:378
This class represents one HDF5 dataset(CF variable)
Definition HDF5CF.h:252
float getCompRatio() const
Get the compression ratio of this dataset.
Definition HDF5CF.h:317
int getRank() const
Get the dimension rank of this variable.
Definition HDF5CF.h:294
const std::string & getFullPath() const
Get the full path of this variable.
Definition HDF5CF.h:272
H5DataType getType() const
Get the data type of this variable(Not HDF5 datatype id)
Definition HDF5CF.h:300
const std::vector< Dimension * > & getDimensions() const
Get the list of the dimensions.
Definition HDF5CF.h:311
const std::string & getNewName() const
Get the new name of this variable.
Definition HDF5CF.h:266
STL iterator class.
Helper functions for generating DAS attributes and a function to check BES Key.
Map and generate DDS and DAS for the CF option for generic HDF5 products.
Type
Type of JSON value.
Definition rapidjson.h:664