bes  Updated for version 3.20.5
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 
40 #include <InternalErr.h>
41 #include <BESDebug.h>
42 
43 #include "HDF5RequestHandler.h"
44 #include "h5cfdaputil.h"
45 #include "h5gmcfdap.h"
46 #include "HDF5CFByte.h"
47 #include "HDF5CFUInt16.h"
48 #include "HDF5CFInt16.h"
49 #include "HDF5CFUInt32.h"
50 #include "HDF5CFInt32.h"
51 #include "HDF5CFFloat32.h"
52 #include "HDF5CFFloat64.h"
53 #include "HDF5CFInt64.h"
54 #include "HDF5CFUInt64.h"
55 #include "HDF5CFStr.h"
56 #include "HDF5CFArray.h"
57 #include "HDF5CFGeoCF1D.h"
58 #include "HDF5CFGeoCFProj.h"
59 
60 #include "HDF5Int64.h"
61 
62 using namespace std;
63 using namespace libdap;
64 using namespace HDF5CF;
65 
66 // Generate DDS from one variable
67 void gen_dap_onevar_dds(DDS &dds, const HDF5CF::Var* var, const hid_t file_id, const string & filename)
68 {
69 
70  BESDEBUG("h5", "Coming to gen_dap_onevar_dds() "<<endl);
71  const vector<HDF5CF::Dimension *>& dims = var->getDimensions();
72 
73  if (0 == dims.size()) {
74  // Adding 64-bit integer support for DMR
75  if (H5INT64 == var->getType() || H5UINT64 == var->getType()){
76  DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
77  if(dmr == NULL)
78  return;
79  else {
80  D4Group* root_grp = dmr->root();
81  if(H5INT64 == var->getType()) {
82  HDF5CFInt64 *sca_int64 = NULL;
83  try {
84  sca_int64 = new HDF5CFInt64(var->getNewName(), var->getFullPath(), filename);
85  }
86  catch (...) {
87  string error_message = "Cannot allocate the HDF5CFInt64: " + error_message;
88  throw InternalErr(__FILE__, __LINE__, error_message);
89  }
90  sca_int64->set_is_dap4(true);
91  map_cfh5_attrs_to_dap4(var,sca_int64);
92  root_grp->add_var_nocopy(sca_int64);
93 
94  }
95  else if(H5UINT64 == var->getType()) {
96  HDF5CFUInt64 *sca_uint64 = NULL;
97  try {
98  sca_uint64 = new HDF5CFUInt64(var->getNewName(), var->getFullPath(), filename);
99  }
100  catch (...) {
101  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt64.");
102  }
103  sca_uint64->set_is_dap4(true);
104  map_cfh5_attrs_to_dap4(var,sca_uint64);
105  root_grp->add_var_nocopy(sca_uint64);
106 
107  }
108 
109  }
110  }
111  else if (H5FSTRING == var->getType() || H5VSTRING == var->getType()) {
112  HDF5CFStr *sca_str = NULL;
113  try {
114  sca_str = new HDF5CFStr(var->getNewName(), filename, var->getFullPath());
115  }
116  catch (...) {
117  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFStr.");
118  }
119  dds.add_var(sca_str);
120  delete sca_str;
121  }
122  else {
123  switch (var->getType()) {
124 
125  case H5UCHAR: {
126  HDF5CFByte * sca_uchar = NULL;
127  try {
128  sca_uchar = new HDF5CFByte(var->getNewName(), var->getFullPath(), filename);
129  }
130  catch (...) {
131  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFByte.");
132  }
133  dds.add_var(sca_uchar);
134  delete sca_uchar;
135 
136  }
137  break;
138  case H5CHAR:
139  case H5INT16: {
140  HDF5CFInt16 * sca_int16 = NULL;
141  try {
142  sca_int16 = new HDF5CFInt16(var->getNewName(), var->getFullPath(), filename);
143  }
144  catch (...) {
145  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt16.");
146  }
147  dds.add_var(sca_int16);
148  delete sca_int16;
149  }
150  break;
151  case H5UINT16: {
152  HDF5CFUInt16 * sca_uint16 = NULL;
153  try {
154  sca_uint16 = new HDF5CFUInt16(var->getNewName(), var->getFullPath(), filename);
155  }
156  catch (...) {
157  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt16.");
158  }
159  dds.add_var(sca_uint16);
160  delete sca_uint16;
161  }
162  break;
163  case H5INT32: {
164  HDF5CFInt32 * sca_int32 = NULL;
165  try {
166  sca_int32 = new HDF5CFInt32(var->getNewName(), var->getFullPath(), filename);
167  }
168  catch (...) {
169  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFInt32.");
170  }
171  dds.add_var(sca_int32);
172  delete sca_int32;
173  }
174  break;
175  case H5UINT32: {
176  HDF5CFUInt32 * sca_uint32 = NULL;
177  try {
178  sca_uint32 = new HDF5CFUInt32(var->getNewName(), var->getFullPath(), filename);
179  }
180  catch (...) {
181  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFUInt32.");
182  }
183  dds.add_var(sca_uint32);
184  delete sca_uint32;
185  }
186  break;
187  case H5FLOAT32: {
188  HDF5CFFloat32 * sca_float32 = NULL;
189  try {
190  sca_float32 = new HDF5CFFloat32(var->getNewName(), var->getFullPath(), filename);
191  }
192  catch (...) {
193  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFFloat32.");
194  }
195  dds.add_var(sca_float32);
196  delete sca_float32;
197  }
198  break;
199  case H5FLOAT64: {
200  HDF5CFFloat64 * sca_float64 = NULL;
201  try {
202  sca_float64 = new HDF5CFFloat64(var->getNewName(), var->getFullPath(), filename);
203  }
204  catch (...) {
205  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFFloat64.");
206  }
207  dds.add_var(sca_float64);
208  delete sca_float64;
209 
210  }
211  break;
212  default:
213  throw InternalErr(__FILE__, __LINE__, "unsupported data type.");
214  }
215  }
216  }
217 
218  else {
219 
220  // 64-bit integer support
221  // DMR CHECK
222  bool dap4_int64 = false;
223  if(var->getType() == H5INT64 || var->getType()==H5UINT64) {
224  DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
225  if(dmr == NULL)
226  return;
227  else
228  dap4_int64 = true;
229  }
230 
231 #if 0
232  else {
233  D4Group* root_grp = dmr->root();
234  BaseType *bt = NULL;
235  bt = new(HDF5Int64)(var->getNewName(),var->getFullPath(),filename);
236  bt->transform_to_dap4(root_grp,root_grp);
237  delete bt;
238  return;
239  }
240 #endif
241  BaseType *bt = NULL;
242 
243  if(true == dap4_int64) {
244  if(var->getType() == H5INT64)
245  bt = new(HDF5CFInt64)(var->getNewName(),var->getFullPath());
246  else if(var->getType() == H5UINT64)
247  bt = new(HDF5CFUInt64)(var->getNewName(),var->getFullPath());
248  }
249 
250  else {
251  switch (var->getType()) {
252 #define HANDLE_CASE(tid,type) \
253  case tid: \
254  bt = new (type)(var->getNewName(),var->getFullPath()); \
255  break;
256  HANDLE_CASE(H5FLOAT32, HDF5CFFloat32)
257  ;
258  HANDLE_CASE(H5FLOAT64, HDF5CFFloat64)
259  ;
260  HANDLE_CASE(H5CHAR, HDF5CFInt16)
261  ;
262  HANDLE_CASE(H5UCHAR, HDF5CFByte)
263  ;
264  HANDLE_CASE(H5INT16, HDF5CFInt16)
265  ;
266  HANDLE_CASE(H5UINT16, HDF5CFUInt16)
267  ;
268  HANDLE_CASE(H5INT32, HDF5CFInt32)
269  ;
270  HANDLE_CASE(H5UINT32, HDF5CFUInt32)
271  ;
272  HANDLE_CASE(H5FSTRING, Str)
273  ;
274  HANDLE_CASE(H5VSTRING, Str)
275  ;
276  default:
277  throw InternalErr(__FILE__, __LINE__, "unsupported data type.");
278 #undef HANDLE_CASE
279  }
280  }
281 
282  vector<HDF5CF::Dimension*>::const_iterator it_d;
283  vector<size_t> dimsizes;
284  dimsizes.resize(var->getRank());
285  for (int i = 0; i < var->getRank(); i++)
286  dimsizes[i] = (dims[i])->getSize();
287 
288  HDF5CFArray *ar = NULL;
289  try {
290  ar = new HDF5CFArray(var->getRank(), file_id, filename, var->getType(), dimsizes, var->getFullPath(),
291  var->getTotalElems(), CV_UNSUPPORTED, false, var->getCompRatio(), var->getNewName(), bt);
292  }
293  catch (...) {
294  delete bt;
295  throw InternalErr(__FILE__, __LINE__, "Cannot allocate the HDF5CFStr.");
296  }
297 
298  for (it_d = dims.begin(); it_d != dims.end(); ++it_d) {
299  if ("" == (*it_d)->getNewName())
300  ar->append_dim((*it_d)->getSize());
301  else
302  ar->append_dim((*it_d)->getSize(), (*it_d)->getNewName());
303  }
304 
305  // When handling DAP4 CF, we need to generate dmr for 64-bit integer separately.
306  if(dap4_int64 == true) {
307  DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
308  D4Group* root_grp = dmr->root();
309  // Dimensions need to be translated.
310  BaseType* d4_var = ar->h5cfdims_transform_to_dap4(root_grp);
311  // Attributes.
312  map_cfh5_attrs_to_dap4(var,d4_var);
313  root_grp->add_var_nocopy(d4_var);
314  }
315  else
316  dds.add_var(ar);
317 
318  delete bt;
319  delete ar;
320  }
321 
322  return;
323 
324 }
325 
326 // Currently only when the datatype of fillvalue is not the same as the datatype of the variable,
327 // special attribute handling is needed.
328 bool need_special_attribute_handling(const HDF5CF::Attribute* attr, const HDF5CF::Var* var)
329 {
330  return ((("_FillValue" == attr->getNewName()) && (var->getType() != attr->getType())) ? true : false);
331 }
332 
333 // Currently we only handle the case when the datatype of _FillValue is not the same as the variable datatype.
334 void gen_dap_special_oneobj_das(AttrTable*at, const HDF5CF::Attribute* attr, const HDF5CF::Var* var)
335 {
336 
337  BESDEBUG("h5", "Coming to gen_dap_special_oneobj_das() "<<endl);
338  if (attr->getCount() != 1) throw InternalErr(__FILE__, __LINE__, "FillValue attribute can only have one element.");
339 
340  H5DataType var_dtype = var->getType();
341  if ((true == HDF5RequestHandler::get_fillvalue_check())
342  && (false == is_fvalue_valid(var_dtype, attr))) {
343  string msg = "The attribute value is out of the range.\n";
344  msg += "The variable name: " + var->getNewName() + "\n";
345  msg += "The attribute name: " + attr->getNewName() + "\n";
346  msg += "The error occurs inside the gen_dap_special_oneobj_das function in h5commoncfdap.cc.";
347  throw InternalErr(msg);
348  }
349  string print_rep = HDF5CFDAPUtil::print_attr(attr->getType(), 0, (void*) (&(attr->getValue()[0])));
350  at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(var_dtype), print_rep);
351 }
352 
353 // Check if this fillvalue is in the valid datatype range when the fillvalue datatype is changed to follow the CF
354 bool is_fvalue_valid(H5DataType var_dtype, const HDF5CF::Attribute* attr)
355 {
356 
357  BESDEBUG("h5", "Coming to is_fvalue_valid() "<<endl);
358  bool ret_value = true;
359  // We only check 8-bit and 16-bit integers.
360  switch (attr->getType()) {
361  case H5CHAR: {
362  signed char final_fill_value = *((signed char*) ((void*) (&(attr->getValue()[0]))));
363  if ((var_dtype == H5UCHAR) && (final_fill_value<0))
364  ret_value = false;
365  return ret_value;
366 
367  }
368  case H5INT16: {
369  short final_fill_value = *((short*) ((void*) (&(attr->getValue()[0]))));
370  if ((var_dtype == H5UCHAR) &&(final_fill_value > 255 || final_fill_value < 0))
371  ret_value = false;
372 
373  // No need to check the var_dtype==H5CHAR case since it is mapped to int16.
374  else if ((var_dtype == H5UINT16) && (final_fill_value < 0))
375  ret_value = false;
376  return ret_value;
377  }
378  case H5UINT16: {
379  unsigned short final_fill_value = *((unsigned short*) ((void*) (&(attr->getValue()[0]))));
380  if ((var_dtype == H5UCHAR) &&(final_fill_value > 255)) {
381  ret_value = false;
382  }
383  else if ((var_dtype == H5INT16) && (final_fill_value >32767)){
384  ret_value = false;
385  }
386  return ret_value;
387 
388  }
389  // We are supposed to check the case when the datatype of fillvalue is unsigned char.
390  // However, since the variable type signed char is always mapped to int16, so there
391  // will never be an overflow case(the signed char case is the only possible one).
392  // Still the data producer should not do this. We will not check this in the handler.KY 2016-03-04
393 #if 0
394  case H5UCHAR:
395  {
396  unsigned char final_fill_value = *((unsigned char*)((void*)(&(attr->getValue()[0]))));
397  if(var_dtype == H5CHAR) {
398  if(final_fill_value >127)
399  ret_value = false;
400  }
401  return ret_value;
402  }
403 
404  case H5UCHAR:
405  case H5INT32:
406  case H5UINT32:
407 #endif
408 
409  default:
410  return ret_value;
411  }
412 
413 }
414 // Leave the old code for the time being. KY 2015-05-07
415 #if 0
416 void gen_dap_special_oneobj_das(AttrTable*at, const HDF5CF::Attribute* attr,const HDF5CF::Var* var) {
417 
418  if (attr->getCount() != 1)
419  throw InternalErr(__FILE__,__LINE__,"FillValue attribute can only have one element.");
420 
421  H5DataType var_dtype = var->getType();
422  switch(var_dtype) {
423 
424  case H5UCHAR:
425  {
426  unsigned char final_fill_value = *((unsigned char*)((void*)(&(attr->getValue()[0]))));
427  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
428  }
429  break;
430 
431  case H5CHAR:
432  {
433  // Notice HDF5 native char maps to DAP int16.
434  short final_fill_value = *((short*)((void*)(&(attr->getValue()[0]))));
435  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
436  }
437  break;
438  case H5INT16:
439  {
440  short final_fill_value = *((short*)((void*)(&(attr->getValue()[0]))));
441  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
442  }
443  break;
444  case H5UINT16:
445  {
446  unsigned short final_fill_value = *((unsigned short*)((void*)(&(attr->getValue()[0]))));
447  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
448  }
449  break;
450 
451  case H5INT32:
452  {
453  int final_fill_value = *((int*)((void*)(&(attr->getValue()[0]))));
454  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
455  }
456  break;
457  case H5UINT32:
458  {
459  unsigned int final_fill_value = *((unsigned int*)((void*)(&(attr->getValue()[0]))));
460  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
461  }
462  break;
463  case H5FLOAT32:
464  {
465  float final_fill_value = *((float*)((void*)(&(attr->getValue()[0]))));
466 // memcpy(&(attr->getValue()[0]),(void*)(&final_fill_value),sizeof(float));
467 //cerr<<"final_fill_value is "<<final_fill_value <<endl;
468  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
469  }
470  break;
471  case H5FLOAT64:
472  {
473  double final_fill_value = *((double*)((void*)(&(attr->getValue()[0]))));
474  print_rep = HDF5CFDAPUtil::print_attr(var_dtype,0,(void*)&final_fill_value);
475  }
476  break;
477  default:
478  throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
479  }
480 
481  at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(var_dtype), print_rep);
482 }
483 #endif
484 
485 // Generate DAS from one variable
486 void gen_dap_oneobj_das(AttrTable*at, const HDF5CF::Attribute* attr, const HDF5CF::Var *var)
487 {
488 
489  BESDEBUG("h5", "Coming to gen_dap_oneobj_das() "<<endl);
490  // DMR support for 64-bit integer
491  if (H5INT64 == attr->getType() || H5UINT64 == attr->getType()) {
492  // TODO: Add code to tackle DMR for the variable datatype that is not 64-bit integer.
493  return;
494 
495  }
496  else if ((H5FSTRING == attr->getType()) || (H5VSTRING == attr->getType())) {
497  gen_dap_str_attr(at, attr);
498  }
499  else {
500 
501  if (NULL == var) {
502 
503  // HDF5 Native Char maps to DAP INT16(DAP doesn't have the corresponding datatype), so needs to
504  // obtain the mem datatype.
505  size_t mem_dtype_size = (attr->getBufSize()) / (attr->getCount());
506  H5DataType mem_dtype = HDF5CFDAPUtil::get_mem_dtype(attr->getType(), mem_dtype_size);
507 
508  for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
509  string print_rep = HDF5CFDAPUtil::print_attr(mem_dtype, loc, (void*) &(attr->getValue()[0]));
510  at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(attr->getType()), print_rep);
511  }
512 
513  }
514 
515  else {
516 
517  // The datatype of _FillValue attribute needs to be the same as the variable datatype for an netCDF C file.
518  // To make OPeNDAP's netCDF file out work, we need to change the attribute datatype of _FillValue to be the
519  // same as the variable datatype if they are not the same. An OMI-Aura_L2-OMUVB file has such a case.
520  // The datatype of "TerrainHeight" is int32 but the datatype of the fillvalue is int16.
521  // KY 2012-11-20
522  bool special_attr_handling = need_special_attribute_handling(attr, var);
523  if (true == special_attr_handling) {
524  gen_dap_special_oneobj_das(at, attr, var);
525  }
526 
527  else {
528 
529  // HDF5 Native Char maps to DAP INT16(DAP doesn't have the corresponding datatype), so needs to
530  // obtain the mem datatype.
531  size_t mem_dtype_size = (attr->getBufSize()) / (attr->getCount());
532  H5DataType mem_dtype = HDF5CFDAPUtil::get_mem_dtype(attr->getType(), mem_dtype_size);
533 
534  for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
535  string print_rep = HDF5CFDAPUtil::print_attr(mem_dtype, loc, (void*) &(attr->getValue()[0]));
536  at->append_attr(attr->getNewName(), HDF5CFDAPUtil::print_type(attr->getType()), print_rep);
537  }
538  }
539  }
540  }
541 }
542 
543 void gen_dap_str_attr(AttrTable *at, const HDF5CF::Attribute *attr)
544 {
545 
546  BESDEBUG("h5", "Coming to gen_dap_str_attr() "<<endl);
547  const vector<size_t>& strsize = attr->getStrSize();
548  unsigned int temp_start_pos = 0;
549  bool is_cset_ascii = attr->getCsetType();
550  for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
551  if (strsize[loc] != 0) {
552  string tempstring(attr->getValue().begin() + temp_start_pos,
553  attr->getValue().begin() + temp_start_pos + strsize[loc]);
554  temp_start_pos += strsize[loc];
555 
556  // If the string size is longer than the current netCDF JAVA
557  // string and the "EnableDropLongString" key is turned on,
558  // No string is generated.
559  // The above statement is no longer true. The netCDF Java can handle long string
560  // attributes. The long string can be kept and I do think the
561  // performance penalty should be small. KY 2018-02-26
562  if ((attr->getNewName() != "origname") && (attr->getNewName() != "fullnamepath") && (true == is_cset_ascii))
563  tempstring = HDF5CFDAPUtil::escattr(tempstring);
564  at->append_attr(attr->getNewName(), "String", tempstring);
565  }
566  }
567 }
568 
569 //#if 0
570 // This function adds the 1-D horizontal coordinate variables as well as the dummy projection variable to the grid.
571 //Note: Since we don't add these artifical CF variables to our main engineering at HDFEOS5CF.cc, the information
572 // to handle DAS won't pass to DDS by the file pointer, we need to re-call the routines to check projection
573 // and dimension. The time to retrieve these information is trivial compared with the whole translation.
574 void add_cf_grid_cvs(DDS & dds, EOS5GridPCType cv_proj_code, float cv_point_lower, float cv_point_upper,
575  float cv_point_left, float cv_point_right, const vector<HDF5CF::Dimension*>& dims)
576 {
577 
578  //1. Check the projection information: we first just handled the sinusoidal projection.
579  // We also add the LAMAZ and PS support. These 1-D varaibles are the same as the sinusoidal one.
580  if (HE5_GCTP_SNSOID == cv_proj_code || HE5_GCTP_LAMAZ == cv_proj_code || HE5_GCTP_PS == cv_proj_code) {
581 
582  //2. Obtain the dimension information from latitude and longitude(fieldtype =1 or fieldtype =2)
583  vector<HDF5CF::Dimension*>::const_iterator it_d;
584  string dim0name = dims[0]->getNewName();
585  int dim0size = dims[0]->getSize();
586  string dim1name = dims[1]->getNewName();
587  int dim1size = dims[1]->getSize();
588 
589  //3. Add the 1-D CV variables and the dummy projection variable
590  BaseType *bt_dim0 = NULL;
591  BaseType *bt_dim1 = NULL;
592 
593  HDF5CFGeoCF1D * ar_dim0 = NULL;
594  HDF5CFGeoCF1D * ar_dim1 = NULL;
595 
596  try {
597 
598  bt_dim0 = new (HDF5CFFloat64)(dim0name, dim0name);
599  bt_dim1 = new (HDF5CFFloat64)(dim1name, dim1name);
600 
601  // Note ar_dim0 is y, ar_dim1 is x.
602  ar_dim0 = new HDF5CFGeoCF1D(HE5_GCTP_SNSOID, cv_point_upper, cv_point_lower, dim0size, dim0name, bt_dim0);
603  ar_dim0->append_dim(dim0size, dim0name);
604 
605  ar_dim1 = new HDF5CFGeoCF1D(HE5_GCTP_SNSOID, cv_point_left, cv_point_right, dim1size, dim1name, bt_dim1);
606  ar_dim1->append_dim(dim1size, dim1name);
607  dds.add_var(ar_dim0);
608  dds.add_var(ar_dim1);
609 
610  }
611  catch (...) {
612  if (bt_dim0) delete bt_dim0;
613  if (bt_dim1) delete bt_dim1;
614  if (ar_dim0) delete ar_dim0;
615  if (ar_dim1) delete ar_dim1;
616  throw InternalErr(__FILE__, __LINE__, "Unable to allocate the HDFEOS2GeoCF1D instance.");
617  }
618 
619  if (bt_dim0) delete bt_dim0;
620  if (bt_dim1) delete bt_dim1;
621  if (ar_dim0) delete ar_dim0;
622  if (ar_dim1) delete ar_dim1;
623 
624  }
625 }
626 
627 // This function adds the grid mapping variables.
628 void add_cf_grid_mapinfo_var(DDS & dds, const EOS5GridPCType grid_proj_code, const unsigned short g_suffix)
629 {
630 
631  //Add the dummy projection variable. The attributes of this variable can be used to store the grid mapping info.
632  // To handle multi-grid cases, we need to add suffixes to distinguish them.
633  string cf_projection_base = "eos_cf_projection";
634 
635  HDF5CFGeoCFProj * dummy_proj_cf = NULL;
636  if(HE5_GCTP_SNSOID == grid_proj_code) {
637  // AFAWK, one grid_mapping variable is necessary for multi-grids. So we just leave one grid here.
638  if(g_suffix == 1) {
639  dummy_proj_cf = new HDF5CFGeoCFProj(cf_projection_base, cf_projection_base);
640  dds.add_var(dummy_proj_cf);
641  }
642  }
643  else {
644  stringstream t_suffix_ss;
645  t_suffix_ss << g_suffix;
646  string cf_projection_name = cf_projection_base + "_" + t_suffix_ss.str();
647  dummy_proj_cf = new HDF5CFGeoCFProj(cf_projection_name, cf_projection_name);
648  dds.add_var(dummy_proj_cf);
649  }
650  if (dummy_proj_cf) delete dummy_proj_cf;
651 
652 }
653 
654 // This function adds 1D grid mapping CF attributes to CV and data variables.
655 #if 0
656 void add_cf_grid_cv_attrs(DAS & das, const vector<HDF5CF::Var*>& vars, EOS5GridPCType cv_proj_code,
657  float /*cv_point_lower*/, float /*cv_point_upper*/, float /*cv_point_left*/, float /*cv_point_right*/,
658  const vector<HDF5CF::Dimension*>& dims,const vector<double> &eos5_proj_params,const unsigned short g_suffix)
659 #endif
660 void add_cf_grid_cv_attrs(DAS & das, const vector<HDF5CF::Var*>& vars, EOS5GridPCType cv_proj_code,
661  const vector<HDF5CF::Dimension*>& dims,const vector<double> &eos5_proj_params,const unsigned short g_suffix)
662 {
663 
664 
665  //1. Check the projection information, now, we handle sinusoidal,PS and LAMAZ projections.
666  if (HE5_GCTP_SNSOID == cv_proj_code || HE5_GCTP_PS == cv_proj_code || HE5_GCTP_LAMAZ== cv_proj_code) {
667 
668  string dim0name = (dims[0])->getNewName();
669  int dim0size = dims[0]->getSize();
670  string dim1name = (dims[1])->getNewName();
671  int dim1size = dims[1]->getSize();
672 
673  //2. Add 1D CF attributes to the 1-D CV variables and the dummy grid_mapping variable
674  AttrTable *at = das.get_table(dim0name);
675  if (!at)
676  at = das.add_table(dim0name, new AttrTable);
677  at->append_attr("standard_name", "String", "projection_y_coordinate");
678 
679  string long_name = "y coordinate of projection ";
680  at->append_attr("long_name", "String", long_name);
681 
682  // Change this to meter.
683  at->append_attr("units", "string", "meter");
684 
685  at->append_attr("_CoordinateAxisType", "string", "GeoY");
686 
687  at = das.get_table(dim1name);
688  if (!at) at = das.add_table(dim1name, new AttrTable);
689 
690  at->append_attr("standard_name", "String", "projection_x_coordinate");
691 
692  long_name = "x coordinate of projection ";
693  at->append_attr("long_name", "String", long_name);
694 
695  // change this to meter.
696  at->append_attr("units", "string", "meter");
697 
698  // This is for CDM conventions. Adding doesn't do harm. Same as GeoY.
699  at->append_attr("_CoordinateAxisType", "string", "GeoX");
700 
701  // Add the attributes for the dummy grid_mapping variable.
702  string cf_projection_base = "eos_cf_projection";
703  string cf_projection;
704  if(HE5_GCTP_SNSOID == cv_proj_code)
705  cf_projection = cf_projection_base;
706  else {
707  stringstream t_suffix_ss;
708  t_suffix_ss << g_suffix;
709  cf_projection = cf_projection_base + "_" + t_suffix_ss.str();
710  }
711  add_cf_projection_attrs(das,cv_proj_code,eos5_proj_params,cf_projection);
712 
713  // Fill in the data fields that contains the dim0name and dim1name dimensions with the grid_mapping
714  // We only apply to >=2D data fields.
715  add_cf_grid_mapping_attr(das, vars, cf_projection, dim0name, dim0size, dim1name, dim1size);
716  }
717 
718 }
719 
720 // Add CF projection attribute
721 
722 void add_cf_projection_attrs(DAS &das,EOS5GridPCType cv_proj_code,const vector<double> &eos5_proj_params,const string& cf_projection) {
723 
724  AttrTable* at = das.get_table(cf_projection);
725  if (!at) {// Only append attributes when the table is created.
726  at = das.add_table(cf_projection, new AttrTable);
727 
728  if (HE5_GCTP_SNSOID == cv_proj_code) {
729  at->append_attr("grid_mapping_name", "String", "sinusoidal");
730  at->append_attr("longitude_of_central_meridian", "Float64", "0.0");
731  at->append_attr("earth_radius", "Float64", "6371007.181");
732  at->append_attr("_CoordinateAxisTypes", "string", "GeoX GeoY");
733  }
734  else if (HE5_GCTP_PS == cv_proj_code) {
735 
736  // The following information is added according to the HDF-EOS5 user's guide and
737  // CF 1.7 grid_mapping requirement.
738 
739  // Longitude down below pole of map
740  double vert_lon_pole = HE5_EHconvAng(eos5_proj_params[4],HE5_HDFE_DMS_DEG);
741 
742  // Latitude of true scale
743  double lat_true_scale = HE5_EHconvAng(eos5_proj_params[5],HE5_HDFE_DMS_DEG);
744 
745  // False easting
746  double fe = eos5_proj_params[6];
747 
748  // False northing
749  double fn = eos5_proj_params[7];
750 
751  at->append_attr("grid_mapping_name", "String", "polar_stereographic");
752 
753  ostringstream s_vert_lon_pole;
754  s_vert_lon_pole << vert_lon_pole;
755 
756  // I did this map is based on my best understanding. I cannot be certain about south pole. KY
757  // CF: straight_vertical_longitude_from_pole
758  at->append_attr("straight_vertical_longitude_from_pole", "Float64", s_vert_lon_pole.str());
759  ostringstream s_lat_true_scale;
760  s_lat_true_scale << lat_true_scale;
761 
762  at->append_attr("standard_parallel", "Float64", s_lat_true_scale.str());
763 
764  if(fe == 0.0)
765  at->append_attr("false_easting","Float64","0.0");
766  else {
767  ostringstream s_fe;
768  s_fe << fe;
769  at->append_attr("false_easting","Float64",s_fe.str());
770  }
771 
772 
773  if(fn == 0.0)
774  at->append_attr("false_northing","Float64","0.0");
775  else {
776  ostringstream s_fn;
777  s_fn << fn;
778  at->append_attr("false_northing","Float64",s_fn.str());
779  }
780 
781 
782  if(lat_true_scale >0)
783  at->append_attr("latitude_of_projection_origin","Float64","+90.0");
784  else
785  at->append_attr("latitude_of_projection_origin","Float64","-90.0");
786 
787 
788  at->append_attr("_CoordinateAxisTypes", "string", "GeoX GeoY");
789 
790  // From CF, PS has another parameter,
791  // Either standard_parallel (EPSG 9829) or scale_factor_at_projection_origin (EPSG 9810)
792  // I cannot find the corresponding parameter from the EOS5.
793 
794  }
795  else if(HE5_GCTP_LAMAZ == cv_proj_code) {
796  double lon_proj_origin = HE5_EHconvAng(eos5_proj_params[4],HE5_HDFE_DMS_DEG);
797  double lat_proj_origin = HE5_EHconvAng(eos5_proj_params[5],HE5_HDFE_DMS_DEG);
798  double fe = eos5_proj_params[6];
799  double fn = eos5_proj_params[7];
800 
801  at->append_attr("grid_mapping_name", "String", "lambert_azimuthal_equal_area");
802 
803  ostringstream s_lon_proj_origin;
804  s_lon_proj_origin << lon_proj_origin;
805  at->append_attr("longitude_of_projection_origin", "Float64", s_lon_proj_origin.str());
806 
807  ostringstream s_lat_proj_origin;
808  s_lat_proj_origin << lat_proj_origin;
809 
810  at->append_attr("latitude_of_projection_origin", "Float64", s_lat_proj_origin.str());
811 
812 
813  if(fe == 0.0)
814  at->append_attr("false_easting","Float64","0.0");
815  else {
816  ostringstream s_fe;
817  s_fe << fe;
818  at->append_attr("false_easting","Float64",s_fe.str());
819  }
820 
821 
822  if(fn == 0.0)
823  at->append_attr("false_northing","Float64","0.0");
824  else {
825  ostringstream s_fn;
826  s_fn << fn;
827  at->append_attr("false_northing","Float64",s_fn.str());
828  }
829 
830  at->append_attr("_CoordinateAxisTypes", "string", "GeoX GeoY");
831 
832 
833  }
834  }
835 
836 }
837 
838 
839 // This function adds the 1-D cf grid projection mapping attribute to data variables
840 // it is called by the function add_cf_grid_attrs.
841 void add_cf_grid_mapping_attr(DAS &das, const vector<HDF5CF::Var*>& vars, const string& cf_projection,
842  const string & dim0name, hsize_t dim0size, const string &dim1name, hsize_t dim1size)
843 {
844 
845 #if 0
846  cerr<<"dim0name is "<<dim0name <<endl;
847  cerr<<"dim1name is "<<dim1name <<endl;
848  cerr<<"dim0size is "<<dim0size <<endl;
849  cerr<<"dim1size is "<<dim1size <<endl;
850 #endif
851 
852  // Check >=2-D fields, check if they hold the dim0name,dim0size etc., yes, add the attribute cf_projection.
853  vector<HDF5CF::Var *>::const_iterator it_v;
854  for (it_v = vars.begin(); it_v != vars.end(); ++it_v) {
855 
856  if ((*it_v)->getRank() > 1) {
857  bool has_dim0 = false;
858  bool has_dim1 = false;
859  const vector<HDF5CF::Dimension*>& dims = (*it_v)->getDimensions();
860  for (vector<HDF5CF::Dimension *>::const_iterator j = dims.begin(); j != dims.end(); ++j) {
861  if ((*j)->getNewName() == dim0name && (*j)->getSize() == dim0size)
862  has_dim0 = true;
863  else if ((*j)->getNewName() == dim1name && (*j)->getSize() == dim1size)
864  has_dim1 = true;
865 
866  }
867  if (true == has_dim0 && true == has_dim1) { // Need to add the grid_mapping attribute
868  AttrTable *at = das.get_table((*it_v)->getNewName());
869  if (!at) at = das.add_table((*it_v)->getNewName(), new AttrTable);
870 
871  // The dummy projection name is the value of the grid_mapping attribute
872  at->append_attr("grid_mapping", "String", cf_projection);
873  }
874  }
875  }
876 }
877 // Now this is specially for LAMAZ where the NSIDC EASE-Grid may have points off the earth. So
878 // The calculated lat/lon are set to number out of the normal range. The valid_range attributes
879 // will hopefully constrain the applications not to consider those points.
880 void add_ll_valid_range(AttrTable* at, bool is_lat) {
881  if(true == is_lat) {
882  at->append_attr("valid_min", "Float64","-90.0");
883  at->append_attr("valid_max", "Float64","90.0");
884  }
885  else {
886  at->append_attr("valid_min", "Float64","-180.0");
887  at->append_attr("valid_max", "Float64","180.0");
888  }
889 }
890 
891 // This routine is for 64-bit DAP4 CF support: when var type is 64-bit integer.
892 bool need_attr_values_for_dap4(const HDF5CF::Var *var) {
893  bool ret_value = false;
894  if((HDF5RequestHandler::get_dmr_64bit_int()!=NULL) &&
895  (H5INT64 == var->getType() || H5UINT64 == var->getType()))
896  ret_value = true;
897  return ret_value;
898 }
899 
900 // This routine is for 64-bit DAP4 CF support: map all attributes to DAP4 for 64-bit integers.
901 void map_cfh5_attrs_to_dap4(const HDF5CF::Var *var,BaseType* d4_var) {
902 
903  vector<HDF5CF::Attribute *>::const_iterator it_ra;
904  for (it_ra = var->getAttributes().begin();
905  it_ra != var->getAttributes().end(); ++it_ra) {
906  // HDF5 Native Char maps to DAP INT16(DAP doesn't have the corresponding datatype), so needs to
907  // obtain the mem datatype. Keep this in DAP4 mapping.
908  size_t mem_dtype_size = ((*it_ra)->getBufSize()) / ((*it_ra)->getCount());
909  H5DataType mem_dtype = HDF5CFDAPUtil::get_mem_dtype((*it_ra)->getType(), mem_dtype_size);
910 
911  string dap2_attrtype = HDF5CFDAPUtil::print_type(mem_dtype);
912  D4AttributeType dap4_attrtype = HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype(dap2_attrtype);
913  D4Attribute *d4_attr = new D4Attribute((*it_ra)->getNewName(),dap4_attrtype);
914  if(dap4_attrtype == attr_str_c) {
915  const vector<size_t>& strsize = (*it_ra)->getStrSize();
916  unsigned int temp_start_pos = 0;
917  for (unsigned int loc = 0; loc < (*it_ra)->getCount(); loc++) {
918  if (strsize[loc] != 0) {
919  string tempstring((*it_ra)->getValue().begin() + temp_start_pos,
920  (*it_ra)->getValue().begin() + temp_start_pos + strsize[loc]);
921  temp_start_pos += strsize[loc];
922  if (((*it_ra)->getNewName() != "origname") && ((*it_ra)->getNewName() != "fullnamepath"))
923  tempstring = HDF5CFDAPUtil::escattr(tempstring);
924  d4_attr->add_value(tempstring);
925  }
926  }
927  }
928  else {
929  for (unsigned int loc = 0; loc < (*it_ra)->getCount(); loc++) {
930  string print_rep = HDF5CFDAPUtil::print_attr(mem_dtype, loc, (void*) &((*it_ra)->getValue()[0]));
931  d4_attr->add_value(print_rep);
932  }
933  }
934  d4_var->attributes()->add_attribute_nocopy(d4_attr);
935  }
936 
937 }
938 
939 void check_update_int64_attr(const string & obj_name, const HDF5CF::Attribute * attr) {
940  if(attr->getType() == H5INT64 || attr->getType() == H5UINT64) {
941  DMR * dmr = HDF5RequestHandler::get_dmr_64bit_int();
942  if(dmr != NULL) {
943  string dap2_attrtype = HDF5CFDAPUtil::print_type(attr->getType());
944  D4AttributeType dap4_attrtype = HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype(dap2_attrtype);
945  D4Attribute *d4_attr = new D4Attribute(attr->getNewName(),dap4_attrtype);
946  for (unsigned int loc = 0; loc < attr->getCount(); loc++) {
947  string print_rep = HDF5CFDAPUtil::print_attr(attr->getType(), loc, (void*) &(attr->getValue()[0]));
948  d4_attr->add_value(print_rep);
949  }
950  D4Group * root_grp = dmr->root();
951  D4Attribute *d4_hg_container;
952  if(root_grp->attributes()->empty() == true){
953 #if 0
954  //D4Attribute *d4_hg_container = root_grp->attributes()->find("HDF5_GLOBAL");
955  //if(d4_hg_container == NULL) {
956 #endif
957  d4_hg_container = new D4Attribute;
958  d4_hg_container->set_name("HDF5_GLOBAL_integer_64");
959  d4_hg_container->set_type(attr_container_c);
960  root_grp->attributes()->add_attribute_nocopy(d4_hg_container);
961 #if 0
962  //root_grp->attributes()->add_attribute(d4_hg_container);
963 #endif
964  }
965  //else
966  d4_hg_container = root_grp->attributes()->get("HDF5_GLOBAL_integer_64");
967  if(obj_name != "") {
968  string test_obj_name = "HDF5_GLOBAL_integer_64."+obj_name;
969 #if 0
970  //D4Attribute *d4_container = root_grp->attributes()->find(obj_name);
971  //D4Attribute *d4_container = root_grp->attributes()->get(obj_name);
972 #endif
973  D4Attribute *d4_container = root_grp->attributes()->get(test_obj_name);
974  // ISSUES need to search the attributes
975  //
976 #if 0
977  //D4Attribute *d4_container = d4_hg_container->attributes()->find(obj_name);
978 #endif
979  if(d4_container == NULL) {
980  d4_container = new D4Attribute;
981  d4_container->set_name(obj_name);
982  d4_container->set_type(attr_container_c);
983 
984 #if 0
985  //if(d4_hg_container->attributes()->empty()==true)
986  // cerr<<"global container is empty"<<endl;
987  //d4_hg_container->attributes()->add_attribute_nocopy(d4_container);
988  //cerr<<"end of d4_container "<<endl;
989 #endif
990  }
991  d4_container->attributes()->add_attribute_nocopy(d4_attr);
992 #if 0
993  //root_grp->attributes()->add_attribute_nocopy(d4_container);
994 #endif
995 //#if 0
996  if(d4_hg_container->attributes()->get(obj_name)==NULL)
997  d4_hg_container->attributes()->add_attribute_nocopy(d4_container);
998 //#endif
999  }
1000  else
1001  d4_hg_container->attributes()->add_attribute_nocopy(d4_attr);
1002  }
1003  }
1004 }
This class provides a way to map HDF5 Str to DAP Str for the CF option.
const std::string & getFullPath() const
Get the full path of this variable.
Definition: HDF5CF.h:283
This class represents one HDF5 dataset(CF variable)
Definition: HDF5CF.h:259
const std::string & getNewName() const
Get the new name of this variable.
Definition: HDF5CF.h:277
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 float to DAP float for the CF option.
int getCompRatio() const
Get the compression ratio of this dataset.
Definition: HDF5CF.h:318
int getRank() const
Get the dimension rank of this variable.
Definition: HDF5CF.h:295
This class provides a way to map HDF5 int16 to DAP int16 for the CF option.
Map and generate DDS and DAS for the CF option for generic HDF5 products.
static D4AttributeType daptype_strrep_to_dap4_attrtype(std::string s)
Definition: h5cfdaputil.cc:303
This class provides a way to map HDF5 64-bit floating-point(double) to DAP 64-bit floating-point for ...
include the entry functions to execute the handlers
This class provides a way to map HDF5 Int64 to DAP Int64 for the default option.
This class provides a way to map HDF5 64-bit integer to DAP4 Int64 for the CF option.
const std::vector< Dimension * > & getDimensions() const
Get the list of the dimensions.
Definition: HDF5CF.h:312
This class provides a way to map HDF5 32-bit integer to DAP Int32 for the CF option.
H5DataType getType() const
Get the data type of this variable(Not HDF5 datatype id)
Definition: HDF5CF.h:301
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 64-bit unsigned integer to DAP4 UInt64 for the CF option.
This class represents one attribute.
Definition: HDF5CF.h:189
Helper functions for generating DAS attributes and a function to check BES Key.
static string escattr(string s)
Definition: h5cfdaputil.cc:43
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 byte to DAP byte for the CF option.