bes Updated for version 3.20.13
h5commoncfdap.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
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <iostream>
38#include <sstream>
39#include <unordered_map>
40
41#include <libdap/InternalErr.h>
42#include <BESDebug.h>
43
44#include "HDF5RequestHandler.h"
45#include "h5cfdaputil.h"
46#include "h5gmcfdap.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 "HDF5CFFloat32.h"
54#include "HDF5CFFloat64.h"
55#include "HDF5CFInt64.h"
56#include "HDF5CFUInt64.h"
57#include "HDF5CFStr.h"
58#include "HDF5CFArray.h"
59#include "HDF5CFGeoCF1D.h"
60#include "HDF5CFGeoCFProj.h"
61
62//#include "HDF5Int64.h"
63#include "HDF5CFUtil.h"
64
65using namespace std;
66using namespace libdap;
67using namespace HDF5CF;
68
69// TODO In the code below, reduce duplication using a template and use unique_ptr
70// to remove memory leak inside catch(...)/throw block. jhrg 3/9/22
71// Generate DDS from one variable
72void gen_dap_onevar_dds(DDS &dds, const HDF5CF::Var* var, const hid_t file_id, const string & filename)
73{
74
75 BESDEBUG("h5", "Coming to gen_dap_onevar_dds() "<<endl);
76 const vector<HDF5CF::Dimension *>& dims = var->getDimensions();
77
78 if (dims.empty()) {
79 // Adding 64-bit integer support for DMR
80 if (H5INT64 == var->getType() || H5UINT64 == var->getType()){
81 DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
82 if(dmr == nullptr)
83 return;
84 else {
85 D4Group* root_grp = dmr->root();
86 if(H5INT64 == var->getType()) {
87 HDF5CFInt64 *sca_int64 = nullptr;
88 try {
89 sca_int64 = new HDF5CFInt64(var->getNewName(), var->getFullPath(), filename);
90 }
91 catch (...) {
92 string error_message = "Cannot allocate the HDF5CFInt64: " + error_message;
93 throw InternalErr(__FILE__, __LINE__, error_message);
94 }
95 sca_int64->set_is_dap4(true);
96 map_cfh5_var_attrs_to_dap4_int64(var,sca_int64);
97 root_grp->add_var_nocopy(sca_int64);
98
99 }
100 else if(H5UINT64 == var->getType()) {
101 HDF5CFUInt64 *sca_uint64 = nullptr;
102 try {
103 sca_uint64 = new HDF5CFUInt64(var->getNewName(), var->getFullPath(), filename);
104 }
105 catch (...) {
106 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt64.");
107 }
108 sca_uint64->set_is_dap4(true);
109 map_cfh5_var_attrs_to_dap4_int64(var,sca_uint64);
110 root_grp->add_var_nocopy(sca_uint64);
111
112 }
113
114 }
115 }
116 else if (H5FSTRING == var->getType() || H5VSTRING == var->getType()) {
117 HDF5CFStr *sca_str = nullptr;
118 try {
119 sca_str = new HDF5CFStr(var->getNewName(), filename, var->getFullPath());
120 }
121 catch (...) {
122 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFStr.");
123 }
124 dds.add_var(sca_str);
125 delete sca_str;
126 }
127 else {
128 switch (var->getType()) {
129
130 case H5UCHAR: {
131 HDF5CFByte * sca_uchar = nullptr;
132 try {
133 sca_uchar = new HDF5CFByte(var->getNewName(), var->getFullPath(), filename);
134 }
135 catch (...) {
136 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFByte.");
137 }
138 dds.add_var(sca_uchar);
139 delete sca_uchar;
140
141 }
142 break;
143 case H5CHAR:
144 case H5INT16: {
145 HDF5CFInt16 * sca_int16 = nullptr;
146 try {
147 sca_int16 = new HDF5CFInt16(var->getNewName(), var->getFullPath(), filename);
148 }
149 catch (...) {
150 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt16.");
151 }
152 dds.add_var(sca_int16);
153 delete sca_int16;
154 }
155 break;
156 case H5UINT16: {
157 HDF5CFUInt16 * sca_uint16 = nullptr;
158 try {
159 sca_uint16 = new HDF5CFUInt16(var->getNewName(), var->getFullPath(), filename);
160 }
161 catch (...) {
162 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt16.");
163 }
164 dds.add_var(sca_uint16);
165 delete sca_uint16;
166 }
167 break;
168 case H5INT32: {
169 HDF5CFInt32 * sca_int32 = nullptr;
170 try {
171 sca_int32 = new HDF5CFInt32(var->getNewName(), var->getFullPath(), filename);
172 }
173 catch (...) {
174 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt32.");
175 }
176 dds.add_var(sca_int32);
177 delete sca_int32;
178 }
179 break;
180 case H5UINT32: {
181 HDF5CFUInt32 * sca_uint32 = nullptr;
182 try {
183 sca_uint32 = new HDF5CFUInt32(var->getNewName(), var->getFullPath(), filename);
184 }
185 catch (...) {
186 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt32.");
187 }
188 dds.add_var(sca_uint32);
189 delete sca_uint32;
190 }
191 break;
192 case H5FLOAT32: {
193 HDF5CFFloat32 * sca_float32 = nullptr;
194 try {
195 sca_float32 = new HDF5CFFloat32(var->getNewName(), var->getFullPath(), filename);
196 }
197 catch (...) {
198 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFFloat32.");
199 }
200 dds.add_var(sca_float32);
201 delete sca_float32;
202 }
203 break;
204 case H5FLOAT64: {
205 HDF5CFFloat64 * sca_float64 = nullptr;
206 try {
207 sca_float64 = new HDF5CFFloat64(var->getNewName(), var->getFullPath(), filename);
208 }
209 catch (...) {
210 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFFloat64.");
211 }
212 dds.add_var(sca_float64);
213 delete sca_float64;
214
215 }
216 break;
217 default:
218 throw InternalErr(__FILE__, __LINE__, "unsupported data type.");
219 }
220 }
221 }
222
223 else {
224
225 // 64-bit integer support
226 // DMR CHECK
227 bool dap4_int64 = false;
228 if(var->getType() == H5INT64 || var->getType()==H5UINT64) {
229 DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
230 if(dmr == nullptr)
231 return;
232 else
233 dap4_int64 = true;
234 }
235
236#if 0
237 else {
238 D4Group* root_grp = dmr->root();
239 BaseType *bt = nullptr;
240 bt = new(HDF5Int64)(var->getNewName(),var->getFullPath(),filename);
241 bt->transform_to_dap4(root_grp,root_grp);
242 delete bt;
243 return;
244 }
245#endif
246 BaseType *bt = nullptr;
247
248 if(true == dap4_int64) {
249 if(var->getType() == H5INT64)
250 bt = new(HDF5CFInt64)(var->getNewName(),var->getFullPath());
251 else if(var->getType() == H5UINT64)
252 bt = new(HDF5CFUInt64)(var->getNewName(),var->getFullPath());
253 }
254
255 else {
256 switch (var->getType()) {
257 // TODO Remove extra ';' jhrg 3/9/22
258#define HANDLE_CASE(tid,type) \
259 case tid: \
260 bt = new (type)(var->getNewName(),var->getFullPath()); \
261 break;
262 HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
263 HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
264 HANDLE_CASE(H5CHAR, HDF5CFInt16)
265 HANDLE_CASE(H5UCHAR, HDF5CFByte)
266 HANDLE_CASE(H5INT16, HDF5CFInt16)
267 HANDLE_CASE(H5UINT16, HDF5CFUInt16)
268 HANDLE_CASE(H5INT32, HDF5CFInt32)
269 HANDLE_CASE(H5UINT32, HDF5CFUInt32)
270 HANDLE_CASE(H5FSTRING, Str)
271 HANDLE_CASE(H5VSTRING, Str)
272 default:
273 throw InternalErr(__FILE__, __LINE__, "unsupported data type.");
274#undef HANDLE_CASE
275 }
276 }
277
278 vector<size_t> dimsizes;
279 dimsizes.resize(var->getRank());
280 for (int i = 0; i < var->getRank(); i++)
281 dimsizes[i] = (dims[i])->getSize();
282
283 HDF5CFArray *ar = nullptr;
284 try {
285 ar = new HDF5CFArray(var->getRank(), file_id, filename, var->getType(), dimsizes, var->getFullPath(),
286 var->getTotalElems(), CV_UNSUPPORTED, false, var->getCompRatio(), false,var->getNewName(), bt);
287 }
288 catch (...) {
289 delete bt;
290 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFStr.");
291 }
292
293 for (auto it_d = dims.begin(); it_d != dims.end(); ++it_d) {
294 if ("" == (*it_d)->getNewName())
295 ar->append_dim((*it_d)->getSize());
296 else
297 ar->append_dim((*it_d)->getSize(), (*it_d)->getNewName());
298 }
299
300 // When handling DAP4 CF, we need to generate dmr for 64-bit integer separately.
301 if(dap4_int64 == true) {
302 DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
303 D4Group* root_grp = dmr->root();
304 // Dimensions need to be translated.
305 BaseType* d4_var = ar->h5cfdims_transform_to_dap4_int64(root_grp);
306 // Attributes.
307 map_cfh5_var_attrs_to_dap4_int64(var,d4_var);
308 root_grp->add_var_nocopy(d4_var);
309 }
310 else
311 dds.add_var(ar);
312
313 delete bt;
314 delete ar;
315 }
316
317 return;
318
319}
320
321// Currently, only when the datatype of fillvalue is not the same as the datatype of the variable,
322// special attribute handling is needed.
323bool need_special_attribute_handling(const HDF5CF::Attribute* attr, const HDF5CF::Var* var)
324{
325 return ((("_FillValue" == attr->getNewName()) && (var->getType() != attr->getType())) ? true : false);
326}
327
328// Currently, we only handle the case when the datatype of _FillValue is not the same as the variable datatype.
329void gen_dap_special_oneobj_das(AttrTable*at, const HDF5CF::Attribute* attr, const HDF5CF::Var* var)
330{
331
332 BESDEBUG("h5", "Coming to gen_dap_special_oneobj_das() "<<endl);
333 if (attr->getCount() != 1) throw InternalErr(__FILE__, __LINE__, "FillValue attribute can only have one element.");
334
335 H5DataType var_dtype = var->getType();
336 if ((true == HDF5RequestHandler::get_fillvalue_check())
337 && (false == is_fvalue_valid(var_dtype, attr))) {
338 string msg = "The attribute value is out of the range.\n";
339 msg += "The variable name: " + var->getNewName() + "\n";
340 msg += "The attribute name: " + attr->getNewName() + "\n";
341 msg += "The error occurs inside the gen_dap_special_oneobj_das function in h5commoncfdap.cc.";
342 throw InternalErr(msg);
343 }
344 string print_rep = HDF5CFDAPUtil::print_attr(attr->getType(), 0, (void*) (&(attr->getValue()[0])));
345 at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(var_dtype), print_rep);
346}
347
348// Check if this fill value is in the valid datatype range when the fillvalue datatype is changed to follow the CF
349bool is_fvalue_valid(H5DataType var_dtype, const HDF5CF::Attribute* attr)
350{
351
352 BESDEBUG("h5", "Coming to is_fvalue_valid() "<<endl);
353 bool ret_value = true;
354 // We only check 8-bit and 16-bit integers.
355 switch (attr->getType()) {
356 case H5CHAR: {
357 signed char final_fill_value = *((signed char*) ((void*) (&(attr->getValue()[0]))));
358 if ((var_dtype == H5UCHAR) && (final_fill_value<0))
359 ret_value = false;
360 return ret_value;
361
362 }
363 case H5INT16: {
364 short final_fill_value = *((short*) ((void*) (&(attr->getValue()[0]))));
365 if ((var_dtype == H5UCHAR) &&(final_fill_value > 255 || final_fill_value < 0))
366 ret_value = false;
367
368 // No need to check the var_dtype==H5CHAR case since it is mapped to int16.
369 else if ((var_dtype == H5UINT16) && (final_fill_value < 0))
370 ret_value = false;
371 return ret_value;
372 }
373 case H5UINT16: {
374 unsigned short final_fill_value = *((unsigned short*) ((void*) (&(attr->getValue()[0]))));
375 if ((var_dtype == H5UCHAR) &&(final_fill_value > 255)) {
376 ret_value = false;
377 }
378 else if ((var_dtype == H5INT16) && (final_fill_value >32767)){
379 ret_value = false;
380 }
381 return ret_value;
382
383 }
384 // We are supposed to check the case when the datatype of fillvalue is unsigned char.
385 // However, since the variable type signed char is always mapped to int16, so there
386 // will never be an overflow case(the signed char case is the only possible one).
387 // Still the data producer should not do this. We will not check this in the handler.KY 2016-03-04
388#if 0
389 case H5UCHAR:
390 {
391 unsigned char final_fill_value = *((unsigned char*)((void*)(&(attr->getValue()[0]))));
392 if(var_dtype == H5CHAR) {
393 if(final_fill_value >127)
394 ret_value = false;
395 }
396 return ret_value;
397 }
398
399 case H5UCHAR:
400 case H5INT32:
401 case H5UINT32:
402#endif
403
404 default:
405 return ret_value;
406 }
407
408}
409// Leave the old code for the time being. KY 2015-05-07
410#if 0
411void gen_dap_special_oneobj_das(AttrTable*at, const HDF5CF::Attribute* attr,const HDF5CF::Var* var) {
412
413 if (attr->getCount() != 1)
414 throw InternalErr(__FILE__,__LINE__,"FillValue attribute can only have one element.");
415
416 H5DataType var_dtype = var->getType();
417 switch(var_dtype) {
418
419 case H5UCHAR:
420 {
421 unsigned char final_fill_value = *((unsigned char*)((void*)(&(attr->getValue()[0]))));
422 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
423 }
424 break;
425
426 case H5CHAR:
427 {
428 // Notice HDF5 native char maps to DAP int16.
429 short final_fill_value = *((short*)((void*)(&(attr->getValue()[0]))));
430 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
431 }
432 break;
433 case H5INT16:
434 {
435 short final_fill_value = *((short*)((void*)(&(attr->getValue()[0]))));
436 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
437 }
438 break;
439 case H5UINT16:
440 {
441 unsigned short final_fill_value = *((unsigned short*)((void*)(&(attr->getValue()[0]))));
442 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
443 }
444 break;
445
446 case H5INT32:
447 {
448 int final_fill_value = *((int*)((void*)(&(attr->getValue()[0]))));
449 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
450 }
451 break;
452 case H5UINT32:
453 {
454 unsigned int final_fill_value = *((unsigned int*)((void*)(&(attr->getValue()[0]))));
455 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
456 }
457 break;
458 case H5FLOAT32:
459 {
460 float final_fill_value = *((float*)((void*)(&(attr->getValue()[0]))));
461// memcpy(&(attr->getValue()[0]),(void*)(&final_fill_value),sizeof(float));
462//cerr<<"final_fill_value is "<<final_fill_value <<endl;
463 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
464 }
465 break;
466 case H5FLOAT64:
467 {
468 double final_fill_value = *((double*)((void*)(&(attr->getValue()[0]))));
469 print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
470 }
471 break;
472 default:
473 throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
474 }
475
476 at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(var_dtype), print_rep);
477}
478#endif
479
480// Generate DAS from one variable
481void gen_dap_oneobj_das(AttrTable*at, const HDF5CF::Attribute* attr, const HDF5CF::Var *var)
482{
483
484 BESDEBUG("h5", "Coming to gen_dap_oneobj_das() "<<endl);
485 // DMR support for 64-bit integer
486 if (H5INT64 == attr->getType() || H5UINT64 == attr->getType()) {
487 // TODO: Add code to tackle DMR for the variable datatype that is not 64-bit integer.
488 return;
489
490 }
491 else if ((H5FSTRING == attr->getType()) || (H5VSTRING == attr->getType())) {
492 gen_dap_str_attr(at, attr);
493 }
494 else {
495
496 if (nullptr == var) {
497
498 // HDF5 Native Char maps to DAP INT16(DAP doesn't have the corresponding datatype), so needs to
499 // obtain the mem datatype.
500 size_t mem_dtype_size = (attr->getBufSize()) / (attr->getCount());
501 H5DataType mem_dtype = HDF5CFDAPUtil::get_mem_dtype(attr->getType(), mem_dtype_size);
502
503 for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
504 string print_rep = HDF5CFDAPUtil::print_attr(mem_dtype, loc, (void*) &(attr->getValue()[0]));
505 at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(attr->getType()), print_rep);
506 }
507
508 }
509
510 else {
511
512 // The datatype of _FillValue attribute needs to be the same as the variable datatype for an netCDF C file.
513 // To make OPeNDAP's netCDF file out work, we need to change the attribute datatype of _FillValue to be the
514 // same as the variable datatype if they are not the same. An OMI-Aura_L2-OMUVB file has such a case.
515 // The datatype of "TerrainHeight" is int32 but the datatype of the fillvalue is int16.
516 // KY 2012-11-20
517 bool special_attr_handling = need_special_attribute_handling(attr, var);
518 if (true == special_attr_handling) {
519 gen_dap_special_oneobj_das(at, attr, var);
520 }
521
522 else {
523
524 // HDF5 Native Char maps to DAP INT16(DAP doesn't have the corresponding datatype), so needs to
525 // obtain the mem datatype.
526 size_t mem_dtype_size = (attr->getBufSize()) / (attr->getCount());
527 H5DataType mem_dtype = HDF5CFDAPUtil::get_mem_dtype(attr->getType(), mem_dtype_size);
528
529 for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
530 string print_rep = HDF5CFDAPUtil::print_attr(mem_dtype, loc, (void*) &(attr->getValue()[0]));
531 at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(attr->getType()), print_rep);
532 }
533 }
534 }
535 }
536}
537
538// TODO Use a template function in the switch() below. jhrg 3/9/22
539// Generate DMR from one variable
540void gen_dap_onevar_dmr(libdap::D4Group* d4_grp, const HDF5CF::Var* var, const hid_t file_id, const string & filename) {
541
542 BESDEBUG("h5", "Coming to gen_dap_onevar_dmr() "<<endl);
543
544 const vector<HDF5CF::Dimension *>& dims = var->getDimensions();
545
546 if (dims.empty()) {
547
548 if (H5FSTRING == var->getType() || H5VSTRING == var->getType()) {
549 HDF5CFStr *sca_str = nullptr;
550 try {
551 sca_str = new HDF5CFStr(var->getNewName(), filename, var->getFullPath());
552 sca_str->set_is_dap4(true);
553 map_cfh5_var_attrs_to_dap4(var,sca_str);
554 }
555 catch (...) {
556 delete sca_str;
557 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFStr.");
558 }
559 d4_grp->add_var_nocopy(sca_str);
560 }
561 else {
562 switch (var->getType()) {
563
564 case H5UCHAR: {
565 HDF5CFByte * sca_uchar = nullptr;
566 try {
567 sca_uchar = new HDF5CFByte(var->getNewName(), var->getFullPath(), filename);
568 sca_uchar->set_is_dap4(true);
569 map_cfh5_var_attrs_to_dap4(var,sca_uchar);
570 }
571 catch (...) {
572 delete sca_uchar;
573 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFByte.");
574 }
575 d4_grp->add_var_nocopy(sca_uchar);
576 }
577 break;
578 case H5CHAR: {
579 HDF5CFInt8 * sca_char = nullptr;
580 try {
581 sca_char = new HDF5CFInt8(var->getNewName(), var->getFullPath(), filename);
582 sca_char->set_is_dap4(true);
583 map_cfh5_var_attrs_to_dap4(var,sca_char);
584 }
585 catch (...) {
586 delete sca_char;
587 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFByte.");
588 }
589 d4_grp->add_var_nocopy(sca_char);
590 }
591 break;
592
593 case H5INT16: {
594 HDF5CFInt16 * sca_int16 = nullptr;
595 try {
596 sca_int16 = new HDF5CFInt16(var->getNewName(), var->getFullPath(), filename);
597 sca_int16->set_is_dap4(true);
598 map_cfh5_var_attrs_to_dap4(var,sca_int16);
599
600 }
601 catch (...) {
602 delete sca_int16;
603 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt16.");
604 }
605 d4_grp->add_var_nocopy(sca_int16);
606 }
607 break;
608 case H5UINT16: {
609 HDF5CFUInt16 * sca_uint16 = nullptr;
610 try {
611 sca_uint16 = new HDF5CFUInt16(var->getNewName(), var->getFullPath(), filename);
612 sca_uint16->set_is_dap4(true);
613 map_cfh5_var_attrs_to_dap4(var,sca_uint16);
614 }
615 catch (...) {
616 delete sca_uint16;
617 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt16.");
618 }
619 d4_grp->add_var_nocopy(sca_uint16);
620 }
621 break;
622 case H5INT32: {
623 HDF5CFInt32 * sca_int32 = nullptr;
624 try {
625 sca_int32 = new HDF5CFInt32(var->getNewName(), var->getFullPath(), filename);
626 sca_int32->set_is_dap4(true);
627 map_cfh5_var_attrs_to_dap4(var,sca_int32);
628 }
629 catch (...) {
630 delete sca_int32;
631 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt32.");
632 }
633 d4_grp->add_var_nocopy(sca_int32);
634 }
635 break;
636 case H5UINT32: {
637 HDF5CFUInt32 * sca_uint32 = nullptr;
638 try {
639 sca_uint32 = new HDF5CFUInt32(var->getNewName(), var->getFullPath(), filename);
640 sca_uint32->set_is_dap4(true);
641 map_cfh5_var_attrs_to_dap4(var,sca_uint32);
642 }
643 catch (...) {
644 delete sca_uint32;
645 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt32.");
646 }
647 d4_grp->add_var_nocopy(sca_uint32);
648 }
649 break;
650 case H5INT64: {
651 HDF5CFInt64 * sca_int64 = nullptr;
652 try {
653 sca_int64 = new HDF5CFInt64(var->getNewName(), var->getFullPath(), filename);
654 sca_int64->set_is_dap4(true);
655 map_cfh5_var_attrs_to_dap4(var,sca_int64);
656 }
657 catch (...) {
658 delete sca_int64;
659 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt64.");
660 }
661 d4_grp->add_var_nocopy(sca_int64);
662 }
663 break;
664 case H5UINT64: {
665 HDF5CFUInt64 * sca_uint64 = nullptr;
666 try {
667 sca_uint64 = new HDF5CFUInt64(var->getNewName(), var->getFullPath(), filename);
668 sca_uint64->set_is_dap4(true);
669 map_cfh5_var_attrs_to_dap4(var,sca_uint64);
670 }
671 catch (...) {
672 delete sca_uint64;
673 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt64.");
674 }
675 d4_grp->add_var_nocopy(sca_uint64);
676 }
677 break;
678 case H5FLOAT32: {
679 HDF5CFFloat32 * sca_float32 = nullptr;
680 try {
681 sca_float32 = new HDF5CFFloat32(var->getNewName(), var->getFullPath(), filename);
682 sca_float32->set_is_dap4(true);
683 map_cfh5_var_attrs_to_dap4(var,sca_float32);
684 }
685 catch (...) {
686 delete sca_float32;
687 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFFloat32.");
688 }
689 d4_grp->add_var_nocopy(sca_float32);
690 }
691 break;
692 case H5FLOAT64: {
693 HDF5CFFloat64 * sca_float64 = nullptr;
694 try {
695 sca_float64 = new HDF5CFFloat64(var->getNewName(), var->getFullPath(), filename);
696 sca_float64->set_is_dap4(true);
697 map_cfh5_var_attrs_to_dap4(var,sca_float64);
698 }
699 catch (...) {
700 delete sca_float64;
701 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFFloat64.");
702 }
703 d4_grp->add_var_nocopy(sca_float64);
704 }
705 break;
706 default:
707 throw InternalErr(__FILE__, __LINE__, "unsupported data type.");
708 }
709 }
710 }
711
712 else {
713
714 BaseType *bt = nullptr;
715
716 switch (var->getType()) {
717#define HANDLE_CASE(tid,type) \
718 case tid: \
719 bt = new (type)(var->getNewName(),var->getFullPath()); \
720 break;
721 HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
722 HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
723 HANDLE_CASE(H5CHAR, HDF5CFInt8)
724 HANDLE_CASE(H5UCHAR, HDF5CFByte)
725 HANDLE_CASE(H5INT16, HDF5CFInt16)
726 HANDLE_CASE(H5UINT16, HDF5CFUInt16)
727 HANDLE_CASE(H5INT32, HDF5CFInt32)
728 HANDLE_CASE(H5UINT32, HDF5CFUInt32)
729 HANDLE_CASE(H5INT64, HDF5CFInt64)
730 HANDLE_CASE(H5UINT64, HDF5CFUInt64)
731 HANDLE_CASE(H5FSTRING, Str)
732 HANDLE_CASE(H5VSTRING, Str)
733 default:
734 throw InternalErr(__FILE__, __LINE__, "unsupported data type.");
735#undef HANDLE_CASE
736 }
737
738 vector<size_t> dimsizes;
739 dimsizes.resize(var->getRank());
740 for (int i = 0; i < var->getRank(); i++)
741 dimsizes[i] = (dims[i])->getSize();
742
743 HDF5CFArray *ar = nullptr;
744 try {
745 ar = new HDF5CFArray(var->getRank(), file_id, filename, var->getType(), dimsizes, var->getFullPath(),
746 var->getTotalElems(), CV_UNSUPPORTED, false, var->getCompRatio(), true,var->getNewName(), bt);
747 }
748 catch (...) {
749 delete bt;
750 throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFStr.");
751 }
752
753 for (auto it_d = dims.begin(); it_d != dims.end(); ++it_d) {
754 if ("" == (*it_d)->getNewName())
755 ar->append_dim((int)((*it_d)->getSize()));
756 else
757 ar->append_dim((int)((*it_d)->getSize()), (*it_d)->getNewName());
758 }
759
760 delete bt;
761 ar->set_is_dap4(true);
762 BaseType* d4_var=ar->h5cfdims_transform_to_dap4(d4_grp);
763 map_cfh5_var_attrs_to_dap4(var,d4_var);
764 d4_grp->add_var_nocopy(d4_var);
765 delete ar;
766
767 }
768
769 return;
770}
771
791void gen_dap_str_attr(AttrTable *at, const HDF5CF::Attribute *attr)
792{
793 BESDEBUG("h5", "Coming to gen_dap_str_attr() " << endl);
794 const vector<size_t>& strsize = attr->getStrSize();
795
796 unsigned int temp_start_pos = 0;
797 for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
798 if (strsize[loc] != 0) {
799 string tempstring(attr->getValue().begin() + temp_start_pos, attr->getValue().begin() + temp_start_pos + strsize[loc]);
800 temp_start_pos += strsize[loc];
801
802 // If the string size is longer than the current netCDF JAVA
803 // string and the "EnableDropLongString" key is turned on,
804 // No string is generated.
805 //
806 // The above statement is no longer true. The netCDF Java can handle long string
807 // attributes. The long string can be kept, and I do think the
808 // performance penalty should be small. KY 2018-02-26
809 //
810 // Here is the logic to determine if the attribute value should be escaped.
811 // Attributes named 'origname' or 'fullnamepath' are never escaped. Attributes
812 // with values that use the UTF-8 character set _are_ encoded unless the
813 // HD.EscapeUTF8Attr is set to false. If the attribute values use ASCII
814 // (i.e., attr->getCsetType() is true), they are always escaped. jhrg 3/9/22
815 if ((attr->getNewName() != "origname") && (attr->getNewName() != "fullnamepath")
816 && (HDF5RequestHandler::get_escape_utf8_attr() || (true == attr->getCsetType()))) {
817 tempstring = HDF5CFDAPUtil::escattr(tempstring);
818 }
819 at->append_attr(attr->getNewName(), "String", tempstring);
820 }
821 }
822}
823
824//#if 0
825// This function adds the 1-D horizontal coordinate variables as well as the dummy projection variable to the grid.
826// Note: Since we don't add these artificial CF variables to our main engineering at HDFEOS5CF.cc, the information
827// to handle DAS won't pass to DDS by the file pointer, we need to re-call the routines to check projection
828// and dimension. The time to retrieve this information is trivial compared with the whole translation.
829void add_cf_grid_cvs(DDS & dds, EOS5GridPCType cv_proj_code, float cv_point_lower, float cv_point_upper,
830 float cv_point_left, float cv_point_right, const vector<HDF5CF::Dimension*>& dims)
831{
832
833 //1. Check the projection information: we first just handled the sinusoidal projection.
834 // We also add the LAMAZ and PS support. These 1-D variables are the same as the sinusoidal one.
835 if (HE5_GCTP_SNSOID == cv_proj_code || HE5_GCTP_LAMAZ == cv_proj_code || HE5_GCTP_PS == cv_proj_code) {
836
837 //2. Obtain the dimension information from latitude and longitude(fieldtype =1 or fieldtype =2)
838 string dim0name = dims[0]->getNewName();
839 auto dim0size = (int)(dims[0]->getSize());
840 string dim1name = dims[1]->getNewName();
841 auto dim1size = (int)(dims[1]->getSize());
842
843 //3. Add the 1-D CV variables and the dummy projection variable
844 BaseType *bt_dim0 = nullptr;
845 BaseType *bt_dim1 = nullptr;
846
847 HDF5CFGeoCF1D * ar_dim0 = nullptr;
848 HDF5CFGeoCF1D * ar_dim1 = nullptr;
849
850 try {
851
852 bt_dim0 = new (HDF5CFFloat64)(dim0name, dim0name);
853 bt_dim1 = new (HDF5CFFloat64)(dim1name, dim1name);
854
855 // Note ar_dim0 is y, ar_dim1 is x.
856 ar_dim0 = new HDF5CFGeoCF1D(HE5_GCTP_SNSOID, cv_point_upper, cv_point_lower, dim0size, dim0name, bt_dim0);
857 ar_dim0->append_dim(dim0size, dim0name);
858
859 ar_dim1 = new HDF5CFGeoCF1D(HE5_GCTP_SNSOID, cv_point_left, cv_point_right, dim1size, dim1name, bt_dim1);
860 ar_dim1->append_dim(dim1size, dim1name);
861 dds.add_var(ar_dim0);
862 dds.add_var(ar_dim1);
863
864 }
865 catch (...) {
866 if (bt_dim0) delete bt_dim0;
867 if (bt_dim1) delete bt_dim1;
868 if (ar_dim0) delete ar_dim0;
869 if (ar_dim1) delete ar_dim1;
870 throw InternalErr(__FILE__, __LINE__, "Unable to allocate the HDFEOS2GeoCF1D instance.");
871 }
872
873 if (bt_dim0) delete bt_dim0;
874 if (bt_dim1) delete bt_dim1;
875 if (ar_dim0) delete ar_dim0;
876 if (ar_dim1) delete ar_dim1;
877
878 }
879}
880
881// This function adds the grid mapping variables.
882void add_cf_grid_mapinfo_var(DDS & dds, const EOS5GridPCType grid_proj_code, const unsigned short g_suffix)
883{
884
885 //Add the dummy projection variable. The attributes of this variable can be used to store the grid mapping info.
886 // To handle multi-grid cases, we need to add suffixes to distinguish them.
887 string cf_projection_base = "eos_cf_projection";
888
889 HDF5CFGeoCFProj * dummy_proj_cf = nullptr;
890 if(HE5_GCTP_SNSOID == grid_proj_code) {
891 // AFAWK, one grid_mapping variable is necessary for multi-grids. So we just leave one grid here.
892 if(g_suffix == 1) {
893 dummy_proj_cf = new HDF5CFGeoCFProj(cf_projection_base, cf_projection_base);
894 dds.add_var(dummy_proj_cf);
895 }
896 }
897 else {
898 stringstream t_suffix_ss;
899 t_suffix_ss << g_suffix;
900 string cf_projection_name = cf_projection_base + "_" + t_suffix_ss.str();
901 dummy_proj_cf = new HDF5CFGeoCFProj(cf_projection_name, cf_projection_name);
902 dds.add_var(dummy_proj_cf);
903 }
904 if (dummy_proj_cf) delete dummy_proj_cf;
905
906}
907
908// This function adds 1D grid mapping CF attributes to CV and data variables.
909#if 0
910void add_cf_grid_cv_attrs(DAS & das, const vector<HDF5CF::Var*>& vars, EOS5GridPCType cv_proj_code,
911 float /*cv_point_lower*/, float /*cv_point_upper*/, float /*cv_point_left*/, float /*cv_point_right*/,
912 const vector<HDF5CF::Dimension*>& dims,const vector<double> &eos5_proj_params,const unsigned short g_suffix)
913#endif
914void add_cf_grid_cv_attrs(DAS & das, const vector<HDF5CF::Var*>& vars, EOS5GridPCType cv_proj_code,
915 const vector<HDF5CF::Dimension*>& dims,const vector<double> &eos5_proj_params,const unsigned short g_suffix)
916{
917
918
919 //1. Check the projection information, now, we handle sinusoidal,PS and LAMAZ projections.
920 if (HE5_GCTP_SNSOID == cv_proj_code || HE5_GCTP_PS == cv_proj_code || HE5_GCTP_LAMAZ== cv_proj_code) {
921
922 string dim0name = (dims[0])->getNewName();
923 auto dim0size = (int)(dims[0]->getSize());
924 string dim1name = (dims[1])->getNewName();
925 auto dim1size = (int)(dims[1]->getSize());
926
927 //2. Add 1D CF attributes to the 1-D CV variables and the dummy grid_mapping variable
928 AttrTable *at = das.get_table(dim0name);
929 if (!at)
930 at = das.add_table(dim0name, new AttrTable);
931 at->append_attr("standard_name", "String", "projection_y_coordinate");
932
933 string long_name = "y coordinate of projection ";
934 at->append_attr("long_name", "String", long_name);
935
936 // Change this to meter.
937 at->append_attr("units", "string", "meter");
938
939 at->append_attr("_CoordinateAxisType", "string", "GeoY");
940
941 at = das.get_table(dim1name);
942 if (!at) at = das.add_table(dim1name, new AttrTable);
943
944 at->append_attr("standard_name", "String", "projection_x_coordinate");
945
946 long_name = "x coordinate of projection ";
947 at->append_attr("long_name", "String", long_name);
948
949 // change this to meter.
950 at->append_attr("units", "string", "meter");
951
952 // This is for CDM conventions. Adding doesn't do harm. Same as GeoY.
953 at->append_attr("_CoordinateAxisType", "string", "GeoX");
954
955 // Add the attributes for the dummy grid_mapping variable.
956 string cf_projection_base = "eos_cf_projection";
957 string cf_projection;
958 if(HE5_GCTP_SNSOID == cv_proj_code)
959 cf_projection = cf_projection_base;
960 else {
961 stringstream t_suffix_ss;
962 t_suffix_ss << g_suffix;
963 cf_projection = cf_projection_base + "_" + t_suffix_ss.str();
964 }
965 add_cf_projection_attrs(das,cv_proj_code,eos5_proj_params,cf_projection);
966
967 // Fill in the data fields that contains the dim0name and dim1name dimensions with the grid_mapping
968 // We only apply to >=2D data fields.
969 add_cf_grid_mapping_attr(das, vars, cf_projection, dim0name, dim0size, dim1name, dim1size);
970 }
971
972}
973
974// Add CF projection attribute
975
976void add_cf_projection_attrs(DAS &das,EOS5GridPCType cv_proj_code,const vector<double> &eos5_proj_params,const string& cf_projection) {
977
978 AttrTable* at = das.get_table(cf_projection);
979 if (!at) {// Only append attributes when the table is created.
980 at = das.add_table(cf_projection, new AttrTable);
981
982 if (HE5_GCTP_SNSOID == cv_proj_code) {
983 at->append_attr("grid_mapping_name", "String", "sinusoidal");
984 at->append_attr("longitude_of_central_meridian", "Float64", "0.0");
985 at->append_attr("earth_radius", "Float64", "6371007.181");
986 at->append_attr("_CoordinateAxisTypes", "string", "GeoX GeoY");
987 }
988 else if (HE5_GCTP_PS == cv_proj_code) {
989
990 // The following information is added according to the HDF-EOS5 user's guide and
991 // CF 1.7 grid_mapping requirement.
992
993 // Longitude down below pole of map
994 double vert_lon_pole = HE5_EHconvAng(eos5_proj_params[4],HE5_HDFE_DMS_DEG);
995
996 // Latitude of true scale
997 double lat_true_scale = HE5_EHconvAng(eos5_proj_params[5],HE5_HDFE_DMS_DEG);
998
999 // False easting
1000 double fe = eos5_proj_params[6];
1001
1002 // False northing
1003 double fn = eos5_proj_params[7];
1004
1005 at->append_attr("grid_mapping_name", "String", "polar_stereographic");
1006
1007 ostringstream s_vert_lon_pole;
1008 s_vert_lon_pole << vert_lon_pole;
1009
1010 // I did this map is based on my best understanding. I cannot be certain about south pole. KY
1011 // CF: straight_vertical_longitude_from_pole
1012 at->append_attr("straight_vertical_longitude_from_pole", "Float64", s_vert_lon_pole.str());
1013 ostringstream s_lat_true_scale;
1014 s_lat_true_scale << lat_true_scale;
1015
1016 at->append_attr("standard_parallel", "Float64", s_lat_true_scale.str());
1017
1018 if(fe == 0.0)
1019 at->append_attr("false_easting","Float64","0.0");
1020 else {
1021 ostringstream s_fe;
1022 s_fe << fe;
1023 at->append_attr("false_easting","Float64",s_fe.str());
1024 }
1025
1026
1027 if(fn == 0.0)
1028 at->append_attr("false_northing","Float64","0.0");
1029 else {
1030 ostringstream s_fn;
1031 s_fn << fn;
1032 at->append_attr("false_northing","Float64",s_fn.str());
1033 }
1034
1035
1036 if(lat_true_scale >0)
1037 at->append_attr("latitude_of_projection_origin","Float64","+90.0");
1038 else
1039 at->append_attr("latitude_of_projection_origin","Float64","-90.0");
1040
1041
1042 at->append_attr("_CoordinateAxisTypes", "string", "GeoX GeoY");
1043
1044 // From CF, PS has another parameter,
1045 // Either standard_parallel (EPSG 9829) or scale_factor_at_projection_origin (EPSG 9810)
1046 // I cannot find the corresponding parameter from the EOS5.
1047
1048 }
1049 else if(HE5_GCTP_LAMAZ == cv_proj_code) {
1050 double lon_proj_origin = HE5_EHconvAng(eos5_proj_params[4],HE5_HDFE_DMS_DEG);
1051 double lat_proj_origin = HE5_EHconvAng(eos5_proj_params[5],HE5_HDFE_DMS_DEG);
1052 double fe = eos5_proj_params[6];
1053 double fn = eos5_proj_params[7];
1054
1055 at->append_attr("grid_mapping_name", "String", "lambert_azimuthal_equal_area");
1056
1057 ostringstream s_lon_proj_origin;
1058 s_lon_proj_origin << lon_proj_origin;
1059 at->append_attr("longitude_of_projection_origin", "Float64", s_lon_proj_origin.str());
1060
1061 ostringstream s_lat_proj_origin;
1062 s_lat_proj_origin << lat_proj_origin;
1063
1064 at->append_attr("latitude_of_projection_origin", "Float64", s_lat_proj_origin.str());
1065
1066
1067 if(fe == 0.0)
1068 at->append_attr("false_easting","Float64","0.0");
1069 else {
1070 ostringstream s_fe;
1071 s_fe << fe;
1072 at->append_attr("false_easting","Float64",s_fe.str());
1073 }
1074
1075
1076 if(fn == 0.0)
1077 at->append_attr("false_northing","Float64","0.0");
1078 else {
1079 ostringstream s_fn;
1080 s_fn << fn;
1081 at->append_attr("false_northing","Float64",s_fn.str());
1082 }
1083
1084 at->append_attr("_CoordinateAxisTypes", "string", "GeoX GeoY");
1085
1086
1087 }
1088 }
1089
1090}
1091
1092
1093// This function adds the 1-D cf grid projection mapping attribute to data variables
1094// it is called by the function add_cf_grid_attrs.
1095void add_cf_grid_mapping_attr(DAS &das, const vector<HDF5CF::Var*>& vars, const string& cf_projection,
1096 const string & dim0name, hsize_t dim0size, const string &dim1name, hsize_t dim1size)
1097{
1098
1099#if 0
1100 cerr<<"dim0name is "<<dim0name <<endl;
1101 cerr<<"dim1name is "<<dim1name <<endl;
1102 cerr<<"dim0size is "<<dim0size <<endl;
1103 cerr<<"dim1size is "<<dim1size <<endl;
1104#endif
1105
1106 // Check >=2-D fields, check if they hold the dim0name,dim0size etc., yes, add the attribute cf_projection.
1107 for (auto it_v = vars.begin(); it_v != vars.end(); ++it_v) {
1108
1109 if ((*it_v)->getRank() > 1) {
1110 bool has_dim0 = false;
1111 bool has_dim1 = false;
1112 const vector<HDF5CF::Dimension*>& dims = (*it_v)->getDimensions();
1113 for (auto j = dims.begin(); j != dims.end(); ++j) {
1114 if ((*j)->getNewName() == dim0name && (*j)->getSize() == dim0size)
1115 has_dim0 = true;
1116 else if ((*j)->getNewName() == dim1name && (*j)->getSize() == dim1size)
1117 has_dim1 = true;
1118
1119 }
1120 if (true == has_dim0 && true == has_dim1) { // Need to add the grid_mapping attribute
1121 AttrTable *at = das.get_table((*it_v)->getNewName());
1122 if (!at) at = das.add_table((*it_v)->getNewName(), new AttrTable);
1123
1124 // The dummy projection name is the value of the grid_mapping attribute
1125 at->append_attr("grid_mapping", "String", cf_projection);
1126 }
1127 }
1128 }
1129}
1130// Now this is specially for LAMAZ where the NSIDC EASE-Grid may have points off the earth. So
1131// The calculated lat/lon are set to number out of the normal range. The valid_range attributes
1132// will hopefully constrain the applications not to consider those points.
1133void add_ll_valid_range(AttrTable* at, bool is_lat) {
1134 if(true == is_lat) {
1135 at->append_attr("valid_min", "Float64","-90.0");
1136 at->append_attr("valid_max", "Float64","90.0");
1137 }
1138 else {
1139 at->append_attr("valid_min", "Float64","-180.0");
1140 at->append_attr("valid_max", "Float64","180.0");
1141 }
1142}
1143
1144// This routine is for 64-bit DAP4 CF support: when var type is 64-bit integer.
1145// Note: the main part of DMR still comes from DDS and DAS.
1146bool need_attr_values_for_dap4(const HDF5CF::Var *var) {
1147 bool ret_value = false;
1148 if((HDF5RequestHandler::get_dmr_64bit_int()!=nullptr) &&
1149 (H5INT64 == var->getType() || H5UINT64 == var->getType()))
1150 ret_value = true;
1151 return ret_value;
1152}
1153
1154// This routine is for 64-bit DAP4 CF support: map all attributes to DAP4 for 64-bit integers.
1155// Note: the main part of DMR still comes from DDS and DAS.
1156void map_cfh5_var_attrs_to_dap4_int64(const HDF5CF::Var *var,BaseType* d4_var) {
1157
1158 for (auto it_ra = var->getAttributes().begin();
1159 it_ra != var->getAttributes().end(); ++it_ra) {
1160 // HDF5 Native Char maps to DAP INT16(DAP doesn't have the corresponding datatype), so needs to
1161 // obtain the mem datatype. Keep this in DAP4 mapping.
1162 size_t mem_dtype_size = ((*it_ra)->getBufSize()) / ((*it_ra)->getCount());
1163 H5DataType mem_dtype = HDF5CFDAPUtil::get_mem_dtype((*it_ra)->getType(), mem_dtype_size);
1164
1165 string dap2_attrtype = HDF5CFDAPUtil::print_type(mem_dtype);
1166 D4AttributeType dap4_attrtype = HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype(dap2_attrtype);
1167 auto d4_attr = new D4Attribute((*it_ra)->getNewName(),dap4_attrtype);
1168 if(dap4_attrtype == attr_str_c) {
1169 if("coordinates" == (*it_ra)->getNewName()) {
1170 bool chg_coor_value = false;
1171 if((true == HDF5RequestHandler::get_enable_coord_attr_add_path())
1172 &&(true == var->getCoorAttrAddPath()))
1173 chg_coor_value = true;
1174 string tempstring;
1175 handle_coor_attr_for_int64_var((*it_ra),var->getFullPath(),tempstring,chg_coor_value);
1176 d4_attr->add_value(tempstring);
1177 }
1178 else {
1179 const vector<size_t>& strsize = (*it_ra)->getStrSize();
1180 unsigned int temp_start_pos = 0;
1181 for (unsigned int loc = 0; loc < (*it_ra)->getCount(); loc++) {
1182 if (strsize[loc] != 0) {
1183 string tempstring((*it_ra)->getValue().begin() + temp_start_pos,
1184 (*it_ra)->getValue().begin() + temp_start_pos + strsize[loc]);
1185 temp_start_pos += strsize[loc];
1186 //The below if is not necessary since the "origname" and "fullnamepath" are not added.KY 2020-02-24
1187#if 0
1188 //if (((*it_ra)->getNewName() != "origname") && ((*it_ra)->getNewName() != "fullnamepath"))
1189#endif
1190 tempstring = HDF5CFDAPUtil::escattr(tempstring);
1191 d4_attr->add_value(tempstring);
1192 }
1193 }
1194 }
1195
1196 }
1197 else {
1198 for (unsigned int loc = 0; loc < (*it_ra)->getCount(); loc++) {
1199 string print_rep = HDF5CFDAPUtil::print_attr(mem_dtype, loc, (void*) &((*it_ra)->getValue()[0]));
1200 d4_attr->add_value(print_rep);
1201 }
1202 }
1203 d4_var->attributes()->add_attribute_nocopy(d4_attr);
1204 }
1205 // Here we add the "origname" and "fullnamepath" attributes since they are crucial to DMRPP generation.
1206 auto d4_attr = new D4Attribute("origname",attr_str_c);
1207 d4_attr->add_value(var->getName());
1208 d4_var->attributes()->add_attribute_nocopy(d4_attr);
1209 d4_attr = new D4Attribute("fullnamepath",attr_str_c);
1210 d4_attr->add_value(var->getFullPath());
1211 d4_var->attributes()->add_attribute_nocopy(d4_attr);
1212}
1213
1214// A helper function for 64-bit DAP4 CF support
1215// Note: the main part of DMR still comes from DDS and DAS.
1216void check_update_int64_attr(const string & obj_name, const HDF5CF::Attribute * attr) {
1217 if(attr->getType() == H5INT64 || attr->getType() == H5UINT64) {
1218
1219 DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
1220 if(dmr != nullptr) {
1221 string dap2_attrtype = HDF5CFDAPUtil::print_type(attr->getType());
1222 D4AttributeType dap4_attrtype = HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype(dap2_attrtype);
1223 D4Attribute *d4_attr = new D4Attribute(attr->getNewName(),dap4_attrtype);
1224 for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
1225 string print_rep = HDF5CFDAPUtil::print_attr(attr->getType(), loc, (void*) &(attr->getValue()[0]));
1226 d4_attr->add_value(print_rep);
1227 }
1228 D4Group * root_grp = dmr->root();
1229 D4Attribute *d4_hg_container;
1230 if(root_grp->attributes()->empty() == true){
1231#if 0
1232 //D4Attribute *d4_hg_container = root_grp->attributes()->find("HDF5_GLOBAL");
1233 //if(d4_hg_container == nullptr) {
1234#endif
1235 d4_hg_container = new D4Attribute;
1236 d4_hg_container->set_name("HDF5_GLOBAL_integer_64");
1237 d4_hg_container->set_type(attr_container_c);
1238 root_grp->attributes()->add_attribute_nocopy(d4_hg_container);
1239#if 0
1240 //root_grp->attributes()->add_attribute(d4_hg_container);
1241#endif
1242 }
1243 //else
1244 d4_hg_container = root_grp->attributes()->get("HDF5_GLOBAL_integer_64");
1245 if(obj_name != "") {
1246 string test_obj_name = "HDF5_GLOBAL_integer_64."+obj_name;
1247#if 0
1248 //D4Attribute *d4_container = root_grp->attributes()->find(obj_name);
1249 //D4Attribute *d4_container = root_grp->attributes()->get(obj_name);
1250#endif
1251 D4Attribute *d4_container = root_grp->attributes()->get(test_obj_name);
1252 // ISSUES need to search the attributes
1253 //
1254#if 0
1255 //D4Attribute *d4_container = d4_hg_container->attributes()->find(obj_name);
1256#endif
1257 if(d4_container == nullptr) {
1258 d4_container = new D4Attribute;
1259 d4_container->set_name(obj_name);
1260 d4_container->set_type(attr_container_c);
1261
1262#if 0
1263 //if(d4_hg_container->attributes()->empty()==true)
1264 // cerr<<"global container is empty"<<endl;
1265 //d4_hg_container->attributes()->add_attribute_nocopy(d4_container);
1266 //cerr<<"end of d4_container "<<endl;
1267#endif
1268 }
1269 d4_container->attributes()->add_attribute_nocopy(d4_attr);
1270#if 0
1271 //root_grp->attributes()->add_attribute_nocopy(d4_container);
1272#endif
1273//#if 0
1274 if(d4_hg_container->attributes()->get(obj_name)==nullptr)
1275 d4_hg_container->attributes()->add_attribute_nocopy(d4_container);
1276//#endif
1277 }
1278 else
1279 d4_hg_container->attributes()->add_attribute_nocopy(d4_attr);
1280 }
1281 }
1282}
1283
1284// Another helper function for 64-bit DAP4 CF support
1285// Note: the main part of DMR still comes from DDS and DAS.
1286void handle_coor_attr_for_int64_var(const HDF5CF::Attribute *attr,const string &var_path,string &tempstring,bool chg_coor_value) {
1287
1288 string tempstring2(attr->getValue().begin(),attr->getValue().end());
1289 if(true == chg_coor_value) {
1290 char sep=' ';
1291 vector<string>cvalue_vec;
1292 HDF5CFUtil::Split_helper(cvalue_vec,tempstring2,sep);
1293 for (int i = 0; i<cvalue_vec.size();i++) {
1294 HDF5CFUtil::cha_co(cvalue_vec[i],var_path);
1295 string t_str = get_cf_string(cvalue_vec[i]);
1296 if(i == 0)
1297 tempstring = t_str;
1298 else
1299 tempstring += sep+t_str;
1300 }
1301 }
1302 else
1303 tempstring = tempstring2;
1304
1305}
1306
1307// This routine is for direct mapping from CF to DAP4. We build DMR not from DDS and DAS.
1308// Hopefully this will be eventually used to build DMR.
1309void map_cfh5_var_attrs_to_dap4(const HDF5CF::Var *var,BaseType* d4_var) {
1310
1311 for (auto it_ra = var->getAttributes().begin();
1312 it_ra != var->getAttributes().end(); ++it_ra) {
1313
1314 D4Attribute *d4_attr = gen_dap4_attr((*it_ra));
1315 d4_var->attributes()->add_attribute_nocopy(d4_attr);
1316 }
1317}
1318
1319// This routine is for direct mapping from CF to DAP4. We build DMR not from DDS and DAS.
1320void map_cfh5_grp_attr_to_dap4(libdap::D4Group *d4_grp,const HDF5CF::Attribute *attr) {
1321
1322 D4Attribute *d4_attr = gen_dap4_attr(attr);
1323 d4_grp->attributes()->add_attribute_nocopy(d4_attr);
1324
1325}
1326
1327// This routine is for direct mapping from CF to DAP4. We build DMR not from DDS and DAS.
1328void map_cfh5_attr_container_to_dap4(libdap::D4Attribute *d4_con,const HDF5CF::Attribute *attr) {
1329
1330 D4Attribute *d4_attr = gen_dap4_attr(attr);
1331 d4_con->attributes()->add_attribute_nocopy(d4_attr);
1332
1333}
1334
1335// Helper function to generate a DAP4 attribute.
1336D4Attribute *gen_dap4_attr(const HDF5CF::Attribute *attr) {
1337
1338 D4AttributeType dap4_attrtype = HDF5CFDAPUtil::print_type_dap4(attr->getType());
1339 auto d4_attr = new D4Attribute(attr->getNewName(),dap4_attrtype);
1340 if(dap4_attrtype == attr_str_c) {
1341
1342 const vector<size_t>& strsize = attr->getStrSize();
1343#if 0
1344 if(strsize.size() == 0)
1345 cerr << "vector string size is 0" << endl;
1346 for(int i = 0; i<strsize.size(); i++)
1347 cerr << "attr size is "<<strsize[i] << endl;
1348#endif
1349 unsigned int temp_start_pos = 0;
1350 for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
1351 if (strsize[loc] != 0) {
1352 string tempstring(attr->getValue().begin() + temp_start_pos,
1353 attr->getValue().begin() + temp_start_pos + strsize[loc]);
1354 temp_start_pos += strsize[loc];
1355 if ((attr->getNewName() != "origname") && (attr->getNewName() != "fullnamepath")
1356 && (HDF5RequestHandler::get_escape_utf8_attr() || (true == attr->getCsetType()))) {
1357 tempstring = HDF5CFDAPUtil::escattr(tempstring);
1358 }
1359 d4_attr->add_value(tempstring);
1360 }
1361 }
1362 }
1363 else {
1364#if 0
1365 cerr << "not a string type " << endl;
1366#endif
1367 for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
1368 string print_rep = HDF5CFDAPUtil::print_attr(attr->getType(), loc, (void*) &(attr->getValue()[0]));
1369 d4_attr->add_value(print_rep);
1370 }
1371 }
1372
1373 return d4_attr;
1374}
1375
1376// Direct CF to DAP4, add CF grid_mapping attributes of the projection variable to DAP4.
1377// we support sinusodial, polar stereographic and lambert azimuthal equal-area(LAMAZ) projections.
1378void add_gm_oneproj_var_dap4_attrs(BaseType *var,EOS5GridPCType cv_proj_code,const vector<double> &eos5_proj_params) {
1379
1380 if (HE5_GCTP_SNSOID == cv_proj_code) {
1381
1382 add_var_dap4_attr(var,"grid_mapping_name",attr_str_c,"sinusoidal");
1383 add_var_dap4_attr(var,"longitude_of_central_meridian",attr_float64_c,"0.0");
1384 add_var_dap4_attr(var,"earth_radius", attr_float64_c, "6371007.181");
1385 add_var_dap4_attr(var,"_CoordinateAxisTypes", attr_str_c, "GeoX GeoY");
1386
1387 }
1388 else if (HE5_GCTP_PS == cv_proj_code) {
1389
1390 // The following information is added according to the HDF-EOS5 user's guide and
1391 // CF 1.7 grid_mapping requirement.
1392
1393 // Longitude down below pole of map
1394 double vert_lon_pole = HE5_EHconvAng(eos5_proj_params[4],HE5_HDFE_DMS_DEG);
1395
1396 // Latitude of true scale
1397 double lat_true_scale = HE5_EHconvAng(eos5_proj_params[5],HE5_HDFE_DMS_DEG);
1398
1399 // False easting
1400 double fe = eos5_proj_params[6];
1401
1402 // False northing
1403 double fn = eos5_proj_params[7];
1404
1405 add_var_dap4_attr(var,"grid_mapping_name",attr_str_c,"polar_stereographic");
1406
1407 ostringstream s_vert_lon_pole;
1408 s_vert_lon_pole << vert_lon_pole;
1409
1410 // I did this map is based on my best understanding. I cannot be certain about south pole. KY
1411 // CF: straight_vertical_longitude_from_pole
1412#if 0
1413 //at->append_attr("straight_vertical_longitude_from_pole", "Float64", s_vert_lon_pole.str());
1414#endif
1415 add_var_dap4_attr(var,"straight_vertical_longitude_from_pole", attr_float64_c, s_vert_lon_pole.str());
1416
1417 ostringstream s_lat_true_scale;
1418 s_lat_true_scale << lat_true_scale;
1419 add_var_dap4_attr(var,"standard_parallel", attr_float64_c, s_lat_true_scale.str());
1420
1421 if(fe == 0.0)
1422 add_var_dap4_attr(var,"false_easting",attr_float64_c,"0.0");
1423 else {
1424 ostringstream s_fe;
1425 s_fe << fe;
1426 add_var_dap4_attr(var,"false_easting",attr_float64_c,s_fe.str());
1427 }
1428
1429 if(fn == 0.0)
1430 add_var_dap4_attr(var,"false_northing",attr_float64_c,"0.0");
1431 else {
1432 ostringstream s_fn;
1433 s_fn << fn;
1434 add_var_dap4_attr(var,"false_northing",attr_float64_c,s_fn.str());
1435 }
1436
1437 if(lat_true_scale >0)
1438 add_var_dap4_attr(var,"latitude_of_projection_origin",attr_float64_c,"+90.0");
1439 else
1440 add_var_dap4_attr(var, "latitude_of_projection_origin",attr_float64_c,"-90.0");
1441
1442 add_var_dap4_attr(var, "_CoordinateAxisTypes", attr_str_c, "GeoX GeoY");
1443
1444 // From CF, PS has another parameter,
1445 // Either standard_parallel (EPSG 9829) or scale_factor_at_projection_origin (EPSG 9810)
1446 // I cannot find the corresponding parameter from the EOS5.
1447
1448 }
1449 else if(HE5_GCTP_LAMAZ == cv_proj_code) {
1450
1451 double lon_proj_origin = HE5_EHconvAng(eos5_proj_params[4],HE5_HDFE_DMS_DEG);
1452 double lat_proj_origin = HE5_EHconvAng(eos5_proj_params[5],HE5_HDFE_DMS_DEG);
1453 double fe = eos5_proj_params[6];
1454 double fn = eos5_proj_params[7];
1455
1456 add_var_dap4_attr(var,"grid_mapping_name", attr_str_c, "lambert_azimuthal_equal_area");
1457
1458 ostringstream s_lon_proj_origin;
1459 s_lon_proj_origin << lon_proj_origin;
1460 add_var_dap4_attr(var,"longitude_of_projection_origin", attr_float64_c, s_lon_proj_origin.str());
1461
1462 ostringstream s_lat_proj_origin;
1463 s_lat_proj_origin << lat_proj_origin;
1464
1465 add_var_dap4_attr(var,"latitude_of_projection_origin", attr_float64_c, s_lat_proj_origin.str());
1466
1467 if(fe == 0.0)
1468 add_var_dap4_attr(var,"false_easting",attr_float64_c,"0.0");
1469 else {
1470 ostringstream s_fe;
1471 s_fe << fe;
1472 add_var_dap4_attr(var,"false_easting",attr_float64_c,s_fe.str());
1473 }
1474
1475 if(fn == 0.0)
1476 add_var_dap4_attr(var,"false_northing",attr_float64_c,"0.0");
1477 else {
1478 ostringstream s_fn;
1479 s_fn << fn;
1480 add_var_dap4_attr(var,"false_northing",attr_float64_c,s_fn.str());
1481 }
1482
1483 add_var_dap4_attr(var,"_CoordinateAxisTypes", attr_str_c, "GeoX GeoY");
1484 }
1485
1486}
1487
1488// Direct CF to DAP4, add the CF "grid_mapping_name" attribute to every variable that uses the grid.
1489void add_cf_grid_cv_dap4_attrs(D4Group *d4_root, const string& cf_projection,
1490 const vector<HDF5CF::Dimension*>& dims, const vector<string> & cvar_name)
1491{
1492 // dims are dimensions for a grid. It is always 2-D for the projections we support.t
1493 string dim0name = (dims[0])->getNewName();
1494 hsize_t dim0size = dims[0]->getSize();
1495 string dim1name = (dims[1])->getNewName();
1496 hsize_t dim1size = dims[1]->getSize();
1497
1498 // We only add the attribute to the variables that match the grid dimensions.
1499 Constructor::Vars_iter vi = d4_root->var_begin();
1500 Constructor::Vars_iter ve = d4_root->var_end();
1501 for (; vi != ve; vi++) {
1502 // Should not add grid_mapping info for the coordinate variables.
1503 if((*vi)->is_vector_type() && (cvar_name.end() == find(cvar_name.begin(), cvar_name.end(),(*vi)->name()))) {
1504 auto t_a = dynamic_cast<Array*>(*vi);
1505 if(t_a->dimensions() >1) {
1506 Array::Dim_iter dim_i = t_a->dim_begin();
1507 Array::Dim_iter dim_e = t_a->dim_end();
1508 bool has_dim0 = false;
1509 bool has_dim1 = false;
1510 for(;dim_i !=dim_e;dim_i++) {
1511 if((*dim_i).name == dim0name && (*dim_i).size == dim0size)
1512 has_dim0 = true;
1513 else if((*dim_i).name == dim1name && (*dim_i).size == dim1size)
1514 has_dim1 = true;
1515 }
1516
1517 if(true == has_dim0 && true == has_dim1)
1518 add_var_dap4_attr((*vi),"grid_mapping",attr_str_c,cf_projection);
1519 }
1520 }
1521 }
1522}
1523
1524
1525// Direct CF to DAP4, add special CF grid_mapping variable to DAP4.
1526// These variables are dimension variables.
1527void add_gm_spcvs(libdap::D4Group *d4_root, EOS5GridPCType cv_proj_code, float cv_point_lower, float cv_point_upper,
1528 float cv_point_left, float cv_point_right, const std::vector<HDF5CF::Dimension*>& dims) {
1529
1530 //1. Check the projection information: we first just handled the sinusoidal projection.
1531 // We also add the LAMAZ and PS support. These 1-D varaibles are the same as the sinusoidal one.
1532 if (HE5_GCTP_SNSOID == cv_proj_code || HE5_GCTP_LAMAZ == cv_proj_code || HE5_GCTP_PS == cv_proj_code) {
1533
1534 //2. Obtain the dimension information from latitude and longitude(fieldtype =1 or fieldtype =2)
1535 string dim0name = dims[0]->getNewName();
1536 auto dim0size = (int)(dims[0]->getSize());
1537 string dim1name = dims[1]->getNewName();
1538 auto dim1size = (int)(dims[1]->getSize());
1539
1540 //3. Add the 1-D CV variables and the dummy projection variable
1541 BaseType *bt_dim0 = nullptr;
1542 BaseType *bt_dim1 = nullptr;
1543
1544 HDF5CFGeoCF1D * ar_dim0 = nullptr;
1545 HDF5CFGeoCF1D * ar_dim1 = nullptr;
1546
1547 try {
1548
1549 bt_dim0 = new (HDF5CFFloat64)(dim0name, dim0name);
1550 bt_dim1 = new (HDF5CFFloat64)(dim1name, dim1name);
1551
1552 // Note ar_dim0 is y, ar_dim1 is x.
1553 ar_dim0 = new HDF5CFGeoCF1D(HE5_GCTP_SNSOID, cv_point_upper, cv_point_lower, dim0size, dim0name, bt_dim0);
1554 ar_dim0->append_dim(dim0size, dim0name);
1555
1556 ar_dim0->set_is_dap4(true);
1557
1558 add_gm_spcvs_attrs(ar_dim0,true);
1559
1560 ar_dim1 = new HDF5CFGeoCF1D(HE5_GCTP_SNSOID, cv_point_left, cv_point_right, dim1size, dim1name, bt_dim1);
1561 ar_dim1->append_dim(dim1size, dim1name);
1562
1563 ar_dim1->set_is_dap4(true);
1564
1565 add_gm_spcvs_attrs(ar_dim1,false);
1566
1567 d4_root->add_var(ar_dim0);
1568 d4_root->add_var(ar_dim1);
1569
1570 }
1571 catch (...) {
1572 if (bt_dim0) delete bt_dim0;
1573 if (bt_dim1) delete bt_dim1;
1574 if (ar_dim0) delete ar_dim0;
1575 if (ar_dim1) delete ar_dim1;
1576 throw InternalErr(__FILE__, __LINE__, "Unable to allocate the HDFEOS2GeoCF1D instance.");
1577 }
1578
1579 if (bt_dim0) delete bt_dim0;
1580 if (bt_dim1) delete bt_dim1;
1581 if (ar_dim0) delete ar_dim0;
1582 if (ar_dim1) delete ar_dim1;
1583 }
1584}
1585
1586// Direct CF to DAP4,
1587// add CF grid_mapping $attributes for the special dimension variables.
1588void add_gm_spcvs_attrs(libdap::BaseType *var,const bool is_dim0) {
1589
1590 string standard_name;
1591 string long_name;
1592 string COORAxisTypes;
1593
1594 if (true == is_dim0) {
1595 standard_name = "projection_y_coordinate";
1596 long_name = "y coordinate of projection ";
1597 COORAxisTypes = "GeoY";
1598 }
1599 else {
1600 standard_name = "projection_x_coordinate";
1601 long_name = "x coordinate of projection ";
1602 COORAxisTypes = "GeoX";
1603 }
1604
1605 add_var_dap4_attr(var,"standard_name", attr_str_c, standard_name);
1606 add_var_dap4_attr(var,"long_name", attr_str_c, long_name);
1607 add_var_dap4_attr(var,"units", attr_str_c, "meter");
1608 add_var_dap4_attr(var,"_CoordinateAxisType", attr_str_c, COORAxisTypes);
1609
1610}
1611
1612// Direct CF to DAP4, helper function to DAP4 group attributes.
1613void add_grp_dap4_attr(D4Group *d4_grp,const string& attr_name, D4AttributeType attr_type, const string& attr_value){
1614
1615 auto d4_attr = new D4Attribute(attr_name,attr_type);
1616 d4_attr->add_value(attr_value);
1617 d4_grp->attributes()->add_attribute_nocopy(d4_attr);
1618
1619}
1620// Direct CF to DAP4, helper function to DAP4 variable attributes.
1621void add_var_dap4_attr(BaseType *var,const string& attr_name, D4AttributeType attr_type, const string& attr_value){
1622
1623 auto d4_attr = new D4Attribute(attr_name,attr_type);
1624 d4_attr->add_value(attr_value);
1625 var->attributes()->add_attribute_nocopy(d4_attr);
1626
1627}
1628
1629// Add DAP4 coverage
1630void add_dap4_coverage(libdap::D4Group* d4_root, const vector<string>& coord_var_names, bool is_coard) {
1631
1632 // We need to construct the var name to Array map,using unordered_map for quick search.
1633 unordered_map<string, Array*> d4map_array_maps;
1634
1635 // This vector holds all variables that can have coverage maps.
1636 vector<Array*> has_map_arrays;
1637
1638 Constructor::Vars_iter vi = d4_root->var_begin();
1639 Constructor::Vars_iter ve = d4_root->var_end();
1640
1641 for (; vi != ve; vi++) {
1642
1643 BaseType *v = *vi;
1644
1645 // Only Array can have maps.
1646 if (libdap::dods_array_c == v->type()) {
1647
1648 auto t_a = static_cast<Array *>(*vi);
1649
1650 // The maps are essentially coordinate variables.
1651 // We've sorted the coordinate variables already, so
1652 // just save them to the vector.
1653 // Note: the coordinate variables we collect here are
1654 // based on the understanding of the handler. We will
1655 // watch if there are complicated cases down the road. KY 04-15-2022
1656 bool is_cv = false;
1657 for ( auto it_cv = coord_var_names.begin(); it_cv !=coord_var_names.end();++it_cv) {
1658 if ((*it_cv) == v->name()) {
1659 is_cv = true;
1660 d4map_array_maps.emplace(v->name(),t_a);
1661 break;
1662 }
1663 }
1664
1665 // If this is not a map variable, it has a good chance to hold maps.
1666 if (is_cv == false) {
1667 has_map_arrays.emplace_back(t_a);
1668 }
1669 }
1670 }
1671
1672 // loop through has_map_arrays to add the maps.
1673 if (is_coard) {// The grid case.
1674 for ( auto it_hm = has_map_arrays.begin(); it_hm != has_map_arrays.end(); ++it_hm) {
1675
1676 Array::Dim_iter dim_i = (*it_hm)->dim_begin();
1677 Array::Dim_iter dim_e = (*it_hm)->dim_end();
1678 for (; dim_i != dim_e; dim_i++) {
1679
1680 // The dimension name is the same as a map name(A Grid case)
1681 // Need to ensure the map array can be found.
1682 unordered_map<string, Array*>::const_iterator it_ma = d4map_array_maps.find(dim_i->name);
1683 if(it_ma != d4map_array_maps.end()) {
1684 auto d4_map = new D4Map((it_ma->second)->FQN(), it_ma->second, *it_hm);
1685 (*it_hm)->maps()->add_map(d4_map);
1686 }
1687 }
1688 // Need to set the has_map_arrays to 0 to avoid calling ~Array() when the vector goes out of loop.
1689 *it_hm = nullptr;
1690 }
1691 }
1692 else { // A Swath case, need to find coordinates and retrieve the values.
1693
1694 for ( auto it_hm = has_map_arrays.begin(); it_hm != has_map_arrays.end(); ++it_hm) {
1695
1696 // If we cannot find the "coordinates",then this var doesn't have a map.
1697 vector<string> coord_names;
1698 D4Attributes *d4_attrs = (*it_hm)->attributes();
1699 const D4Attribute *d4_attr = d4_attrs->find("coordinates");
1700 if (d4_attr != nullptr) {
1701 // For all the coordinates the CF option can handle,
1702 // the attribute is a one-element string.
1703 if(d4_attr->type() == attr_str_c && d4_attr->num_values() == 1) {
1704 string tempstring = d4_attr->value(0);
1705 char sep=' ';
1706 HDF5CFUtil::Split_helper(coord_names,tempstring,sep);
1707 }
1708 }
1709
1710 // Search if these coordiates can be found in the coordinate variable list.
1711 for(auto it_c = coord_names.begin(); it_c != coord_names.end(); ++it_c) {
1712
1713 unordered_map<string, Array*>::const_iterator it_ma = d4map_array_maps.find(*it_c);
1714 if(it_ma != d4map_array_maps.end()) {
1715 auto d4_map = new D4Map((it_ma->second)->FQN(), it_ma->second, *it_hm);
1716 (*it_hm)->maps()->add_map(d4_map);
1717 }
1718
1719 }
1720
1721 // Need to set the has_map_arrays to 0 to avoid calling ~Array() when the vector goes out of loop.
1722 *it_hm = nullptr;
1723 }
1724 }
1725 // We need to set the second element of the d4map_array_maps to 0 to avoid the ~Array() is called
1726 // when this map goes out of loop.
1727 for (auto it_dm = d4map_array_maps.begin(); it_dm != d4map_array_maps.end(); ++it_dm)
1728 it_dm->second = nullptr;
1729
1730
1731}
1732
1733
1734
1735
1736// Mainly copy from HDF5CF::get_CF_string. Should be
1737// removed if we can generate DMR independently.
1738string get_cf_string(string & s) {
1739
1740 if(s[0] !='/')
1741 return get_cf_string_helper(s);
1742 else {
1743 // The leading underscore should be removed
1744 s.erase(0,1);
1745 return get_cf_string_helper(s);
1746 }
1747
1748}
1749string get_cf_string_helper(string & s) {
1750
1751 if ("" == s) return s;
1752 string insertString(1, '_');
1753
1754 // Always start with _ if the first character is not a letter
1755 if (true == isdigit(s[0])) s.insert(0, insertString);
1756
1757 for (unsigned int i = 0; i < s.length(); i++)
1758 if ((false == isalnum(s[i])) && (s[i] != '_')) s[i] = '_';
1759 return s;
1760}
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 file includes several helper functions for translating HDF5 to CF-compliant.
include the entry functions to execute the handlers
static string escattr(string s)
Definition: h5cfdaputil.cc:60
static D4AttributeType daptype_strrep_to_dap4_attrtype(const string &s)
Definition: h5cfdaputil.cc:371
This class represents one attribute.
Definition: HDF5CF.h:189
This class represents one HDF5 dataset(CF variable)
Definition: HDF5CF.h:256
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.
void gen_dap_str_attr(AttrTable *at, const HDF5CF::Attribute *attr)
Transfer string attributes to a DAP2 AttrTable.
Map and generate DDS and DAS for the CF option for generic HDF5 products.