bes  Updated for version 3.20.6
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 }
HDF5CFGeoCFProj
Definition: HDF5CFGeoCFProj.h:11
HDF5CFStr.h
This class provides a way to map HDF5 Str to DAP Str for the CF option.
HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype
static D4AttributeType daptype_strrep_to_dap4_attrtype(std::string s)
Definition: h5cfdaputil.cc:303
HDF5CF::Var::getRank
int getRank() const
Get the dimension rank of this variable.
Definition: HDF5CF.h:295
HDF5CFStr
Definition: HDF5CFStr.h:42
HDF5CFInt16.h
This class provides a way to map HDF5 int16 to DAP int16 for the CF option.
HDF5CFUInt32.h
This class provides a way to map HDF5 unsigned 32-bit integer to DAP uint32 for the CF option.
HDF5CF::Var
This class represents one HDF5 dataset(CF variable)
Definition: HDF5CF.h:259
HDF5CFDAPUtil::escattr
static string escattr(string s)
Definition: h5cfdaputil.cc:43
HDF5CFByte
Definition: HDF5CFByte.h:43
HDF5CF::Var::getType
H5DataType getType() const
Get the data type of this variable(Not HDF5 datatype id)
Definition: HDF5CF.h:301
HDF5CFUInt16.h
This class provides a way to map HDF5 unsigned 16-bit integer to DAP uint16 for the CF option.
h5gmcfdap.h
Map and generate DDS and DAS for the CF option for generic HDF5 products.
HDF5CF::Var::getNewName
const std::string & getNewName() const
Get the new name of this variable.
Definition: HDF5CF.h:277
HDF5CFFloat64
Definition: HDF5CFFloat64.h:41
HDF5CFInt16
Definition: HDF5CFInt16.h:40
HDF5CFByte.h
This class provides a way to map HDF5 byte to DAP byte for the CF option.
HDF5CFFloat32
Definition: HDF5CFFloat32.h:42
HDF5CFUInt32
Definition: HDF5CFUInt32.h:42
libdap
Definition: BESDapFunctionResponseCache.h:35
HDF5CFInt64
Definition: HDF5CFInt64.h:41
HDF5RequestHandler.h
include the entry functions to execute the handlers
HDF5CFArray.h
This class includes the methods to read data array into DAP buffer from an HDF5 dataset for the CF op...
HDF5CFInt64.h
This class provides a way to map HDF5 64-bit integer to DAP4 Int64 for the CF option.
HDF5CFInt32
Definition: HDF5CFInt32.h:41
HDF5CFGeoCF1D
Definition: HDF5CFGeoCF1D.h:12
HDF5Int64
Definition: HDF5Int64.h:47
h5cfdaputil.h
Helper functions for generating DAS attributes and a function to check BES Key.
HDF5CF::Var::getCompRatio
int getCompRatio() const
Get the compression ratio of this dataset.
Definition: HDF5CF.h:318
HDF5CFInt32.h
This class provides a way to map HDF5 32-bit integer to DAP Int32 for the CF option.
HDF5CFUInt64
Definition: HDF5CFUInt64.h:41
HDF5CFArray
Definition: HDF5CFArray.h:47
HDF5CFFloat64.h
This class provides a way to map HDF5 64-bit floating-point(double) to DAP 64-bit floating-point for ...
HDF5CFFloat32.h
This class provides a way to map HDF5 float to DAP float for the CF option.
HDF5CF::Attribute
This class represents one attribute.
Definition: HDF5CF.h:189
HDF5CFUInt64.h
This class provides a way to map HDF5 64-bit unsigned integer to DAP4 UInt64 for the CF option.
HDF5CFUInt16
Definition: HDF5CFUInt16.h:40
HDF5CF::Var::getDimensions
const std::vector< Dimension * > & getDimensions() const
Get the list of the dimensions.
Definition: HDF5CF.h:312
HDF5Int64.h
This class provides a way to map HDF5 Int64 to DAP Int64 for the default option.
HDF5CF::Var::getFullPath
const std::string & getFullPath() const
Get the full path of this variable.
Definition: HDF5CF.h:283