bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
HDF5CFUtil.cc
Go to the documentation of this file.
1// This file is part of the hdf5_handler implementing for the CF-compliant
2// Copyright (c) 2011-2023 The HDF Group, Inc. and OPeNDAP, Inc.
3//
4// This is free software; you can redistribute it and/or modify it under the
5// terms of the GNU Lesser General Public License as published by the Free
6// Software Foundation; either version 2.1 of the License, or (at your
7// option) any later version.
8//
9// This software is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12// License for more details.
13//
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17//
18// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
19// You can contact The HDF Group, Inc. at 410 E University Ave,
20// Suite 200, Champaign, IL 61820
21
31
32#include "HDF5CFUtil.h"
33#include "HDF5RequestHandler.h"
34#include <set>
35#include <sstream>
36#include <algorithm>
37#include <stdlib.h>
38#include <unistd.h>
39#include <math.h>
40#include<InternalErr.h>
41
42using namespace std;
43using namespace libdap;
44// For using GCTP to calculate the lat/lon
45extern "C" {
46int hinv_init(int insys, int inzone, double *inparm, int indatum, char *fn27, char *fn83, int *iflg, int (*hinv_trans[])(double, double, double*, double*));
47
48int hfor_init(int outsys, int outzone, double *outparm, int outdatum, char *fn27, char *fn83, int *iflg, int (*hfor_trans[])(double, double, double *, double *));
49
50}
51
52H5DataType
54{
55 size_t size = 0;
56 int sign = -2;
57
58 switch (H5Tget_class(h5_type_id)) {
59
60 case H5T_INTEGER:
61 size = H5Tget_size(h5_type_id);
62 sign = H5Tget_sign(h5_type_id);
63
64 if (size == 1) { // Either signed char or unsigned char
65 if (sign == H5T_SGN_2)
66 return H5CHAR;
67 else
68 return H5UCHAR;
69 }
70 else if (size == 2) {
71 if (sign == H5T_SGN_2)
72 return H5INT16;
73 else
74 return H5UINT16;
75 }
76 else if (size == 4) {
77 if (sign == H5T_SGN_2)
78 return H5INT32;
79 else
80 return H5UINT32;
81 }
82 else if (size == 8) {
83 if (sign == H5T_SGN_2)
84 return H5INT64;
85 else
86 return H5UINT64;
87 }
88 else return H5UNSUPTYPE;
89
90 case H5T_FLOAT:
91 size = H5Tget_size(h5_type_id);
92
93 if (size == 4) return H5FLOAT32;
94 else if (size == 8) return H5FLOAT64;
95 else return H5UNSUPTYPE;
96
97 case H5T_STRING:
98 if (H5Tis_variable_str(h5_type_id))
99 return H5VSTRING;
100 else return H5FSTRING;
101
102 case H5T_REFERENCE:
103 return H5REFERENCE;
104
105
106 case H5T_COMPOUND:
107 return H5COMPOUND;
108
109 case H5T_ARRAY:
110 return H5ARRAY;
111
112 default:
113 return H5UNSUPTYPE;
114
115 }
116}
117
118size_t HDF5CFUtil::H5_numeric_atomic_type_size(H5DataType h5type) {
119
120 switch(h5type) {
121 case H5CHAR:
122 case H5UCHAR:
123 return 1;
124 case H5INT16:
125 case H5UINT16:
126 return 2;
127 case H5INT32:
128 case H5UINT32:
129 case H5FLOAT32:
130 return 4;
131 case H5FLOAT64:
132 case H5INT64:
133 case H5UINT64:
134 return 8;
135 default:
136 throw InternalErr(__FILE__,__LINE__,"This routine doesn't support to return the size of this datatype");
137 }
138
139}
140
141#if 0
142bool HDF5CFUtil::use_lrdata_mem_cache(H5DataType h5type, CVType cvtype, bool islatlon ) {
143 if(h5type != H5CHAR && h5type !=H5UCHAR && h5type!=H5INT16 && h5type !=H5UINT16 &&
144 h5type != H5INT32 && h5type !=H5UINT32 && h5type !=H5FLOAT32 && h5type!=H5FLOAT64 &&
145 h5type != H5INT64 && h5type !=H5UINT64)
146 return false;
147 else {
148 if(cvtype != CV_UNSUPPORTED)
149 return true;
150 // TODO; if varpath is specified by the user, this should return true!
151 else if(varpath == "")
152 return false;
153 else
154 return false;
155
156 }
157
158}
159#endif
160
161// Check if we cna use data memory cache
162// TODO: This functio is not used, we will check it in the next release.
163bool HDF5CFUtil::use_data_mem_cache(H5DataType h5type, CVType cvtype, const string &varpath) {
164 if(h5type != H5CHAR && h5type !=H5UCHAR && h5type!=H5INT16 && h5type !=H5UINT16 &&
165 h5type != H5INT32 && h5type !=H5UINT32 && h5type !=H5FLOAT32 && h5type!=H5FLOAT64 &&
166 h5type != H5INT64 && h5type !=H5UINT64)
167 return false;
168 else {
169 if(cvtype != CV_UNSUPPORTED)
170 return true;
171 // TODO; if varpath is specified by the user, this should return true!
172 else if(varpath == "")
173 return false;
174 else
175 return false;
176
177 }
178
179}
180
181bool HDF5CFUtil::cf_strict_support_type(H5DataType dtype, bool is_dap4) {
182 if ((H5UNSUPTYPE == dtype)||(H5REFERENCE == dtype)
183 || (H5COMPOUND == dtype) || (H5ARRAY == dtype))
184 // Important comments for the future work.
185 // Try to suport 64-bit integer for DAP4 CF, check the starting code at get_dmr_64bit_int()
186 //"|| (H5INT64 == dtype) ||(H5UINT64 == dtype))"
187 return false;
188 else if ((H5INT64 == dtype) || (H5UINT64 == dtype)) {
189 if (true == is_dap4 || HDF5RequestHandler::get_dmr_long_int()==true)
190 return true;
191 else
192 return false;
193 }
194 else
195 return true;
196}
197
198bool HDF5CFUtil::cf_dap2_support_numeric_type(H5DataType dtype,bool is_dap4) {
199 if ((H5UNSUPTYPE == dtype)||(H5REFERENCE == dtype)
200 || (H5COMPOUND == dtype) || (H5ARRAY == dtype)
201 || (H5INT64 == dtype) ||(H5UINT64 == dtype)
202 || (H5FSTRING == dtype) ||(H5VSTRING == dtype))
203 return false;
204 else if ((H5INT64 == dtype) ||(H5UINT64 == dtype)) {
205 if(true == is_dap4 || true == HDF5RequestHandler::get_dmr_long_int())
206 return true;
207 else
208 return false;
209 }
210 else
211 return true;
212}
213
214string HDF5CFUtil::obtain_string_after_lastslash(const string &s) {
215
216 string ret_str="";
217 size_t last_fslash_pos = s.find_last_of("/");
218 if (string::npos != last_fslash_pos &&
219 last_fslash_pos != (s.size()-1))
220 ret_str=s.substr(last_fslash_pos+1);
221 return ret_str;
222}
223
224string HDF5CFUtil::obtain_string_before_lastslash(const string & s) {
225
226 string ret_str="";
227 size_t last_fslash_pos = s.find_last_of("/");
228 if (string::npos != last_fslash_pos)
229 ret_str=s.substr(0,last_fslash_pos+1);
230 return ret_str;
231
232}
233
234string HDF5CFUtil::trim_string(hid_t ty_id,const string & s, int num_sect, size_t sect_size, vector<size_t>& sect_newsize) {
235
236 string temp_sect_str = "";
237 string temp_sect_newstr = "";
238 string final_str="";
239
240 for (int i = 0; i < num_sect; i++) {
241
242 if (i != (num_sect-1))
243 temp_sect_str = s.substr(i*sect_size,sect_size);
244 else
245 temp_sect_str = s.substr((num_sect-1)*sect_size,s.size()-(num_sect-1)*sect_size);
246
247 size_t temp_pos = 0;
248
249 if (H5T_STR_NULLTERM == H5Tget_strpad(ty_id))
250 temp_pos = temp_sect_str.find_first_of('\0');
251 else if (H5T_STR_SPACEPAD == H5Tget_strpad(ty_id))
252 temp_pos = temp_sect_str.find_last_not_of(' ')+1;
253 else temp_pos = temp_sect_str.find_last_not_of('0')+1;// NULL PAD
254
255 if (temp_pos != string::npos) {
256
257 // Here I only add a space at the end of each section for the SPACEPAD case,
258 // but not for NULL TERM
259 // or NULL PAD. Two reasons: C++ string doesn't need NULL TERM.
260 // We don't know and don't see any NULL PAD applications for NASA data.
261 if (H5T_STR_SPACEPAD == H5Tget_strpad(ty_id)) {
262
263 if (temp_pos == temp_sect_str.size())
264 temp_sect_newstr = temp_sect_str +" ";
265 else
266 temp_sect_newstr = temp_sect_str.substr(0,temp_pos+1);
267
268 sect_newsize[i] = temp_pos +1;
269 }
270 else {
271 temp_sect_newstr = temp_sect_str.substr(0,temp_pos);
272 sect_newsize[i] = temp_pos ;
273 }
274
275 }
276
277 else {// NULL is not found, adding a NULL at the end of this string.
278
279 temp_sect_newstr = temp_sect_str;
280
281 // Here I only add a space for the SPACEPAD, but not for NULL TERM
282 // or NULL PAD. Two reasons: C++ string doesn't need NULL TERM.
283 // We don't know and don't see any NULL PAD applications for NASA data.
284 if (H5T_STR_SPACEPAD == H5Tget_strpad(ty_id)) {
285 temp_sect_newstr.resize(temp_sect_str.size()+1);
286 temp_sect_newstr.append(1,' ');
287 sect_newsize[i] = sect_size + 1;
288 }
289 else
290 sect_newsize[i] = sect_size;
291 }
292 final_str+=temp_sect_newstr;
293 }
294
295 return final_str;
296}
297
298string HDF5CFUtil::remove_substrings(string str,const string &substr) {
299
300 string::size_type i = str.find(substr);
301 while (i != std::string::npos) {
302 str.erase(i, substr.size());
303 i = str.find(substr, i);
304 }
305 return str;
306}
307// Obtain the unique name for the clashed names and save it to set namelist.
308void HDF5CFUtil::gen_unique_name(string &str,set<string>& namelist, int&clash_index) {
309
310 pair<set<string>::iterator,bool> ret;
311 string newstr = "";
312 stringstream sclash_index;
313 sclash_index << clash_index;
314 newstr = str + sclash_index.str();
315
316 ret = namelist.insert(newstr);
317 if (false == ret.second) {
318 clash_index++;
319 gen_unique_name(str,namelist,clash_index);
320 }
321 else
322 str = newstr;
323}
324
325void
326HDF5CFUtil::Split_helper(vector<string> &tokens, const string &text, const char sep)
327{
328 string::size_type start = 0;
329 string::size_type end = 0;
330
331 while ((end = text.find(sep, start)) != string::npos) {
332 tokens.push_back(text.substr(start, end - start));
333 start = end + 1;
334 }
335 tokens.push_back(text.substr(start));
336}
337
338
339// From a string separated by a separator to a list of string,
340// for example, split "ab,c" to {"ab","c"}
341void
342HDF5CFUtil::Split(const char *s, int len, char sep, std::vector<std::string> &names)
343{
344 names.clear();
345 for (int i = 0, j = 0; j <= len; ++j) {
346 if ((j == len && len) || s[j] == sep) {
347 string elem(s + i, j - i);
348 names.push_back(elem);
349 i = j + 1;
350 continue;
351 }
352 }
353}
354
355
356// Assume sz is Null terminated string.
357void
358HDF5CFUtil::Split(const char *sz, char sep, std::vector<std::string> &names)
359{
360 Split(sz, (int)strlen(sz), sep, names);
361}
362
363void HDF5CFUtil::parser_gpm_l3_gridheader(const vector<char>& value,
364 int& latsize, int&lonsize,
365 float& lat_start, float& lon_start,
366 float& lat_res, float& lon_res,
367 bool check_reg_orig ){
368
369 float lat_north = 0.;
370 float lat_south = 0.;
371 float lon_east = 0.;
372 float lon_west = 0.;
373
374 vector<string> ind_elems;
375 char sep='\n';
376 HDF5CFUtil::Split(value.data(),sep,ind_elems);
377
378 // The number of elements in the GridHeader is 9. The string vector will add a leftover. So the size should be 10.
379 // KY: on a CentOS 7 machine, the number of elements is wrongly generated by compiler to 11 instead of 10.
380#if 0
381 //if(ind_elems.size()!=10)
382#endif
383 if(ind_elems.size()<9)
384 throw InternalErr(__FILE__,__LINE__,"The number of elements in the GPM level 3 GridHeader is not right.");
385
386 if(false == check_reg_orig) {
387 if (0 != ind_elems[1].find("Registration=CENTER"))
388 throw InternalErr(__FILE__,__LINE__,"The GPM grid registration is not center.");
389 }
390
391 if (0 == ind_elems[2].find("LatitudeResolution")){
392
393 size_t equal_pos = ind_elems[2].find_first_of('=');
394 if(string::npos == equal_pos)
395 throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for GPM level 3 products");
396
397 size_t scolon_pos = ind_elems[2].find_first_of(';');
398 if(string::npos == scolon_pos)
399 throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for GPM level 3 products");
400 if (equal_pos < scolon_pos){
401
402 string latres_str = ind_elems[2].substr(equal_pos+1,scolon_pos-equal_pos-1);
403 lat_res = strtof(latres_str.c_str(),nullptr);
404 }
405 else
406 throw InternalErr(__FILE__,__LINE__,"latitude resolution is not right for GPM level 3 products");
407 }
408 else
409 throw InternalErr(__FILE__,__LINE__,"The GPM grid LatitudeResolution doesn't exist.");
410
411 if (0 == ind_elems[3].find("LongitudeResolution")){
412
413 size_t equal_pos = ind_elems[3].find_first_of('=');
414 if(string::npos == equal_pos)
415 throw InternalErr(__FILE__,__LINE__,"Cannot find longitude resolution for GPM level 3 products");
416
417 size_t scolon_pos = ind_elems[3].find_first_of(';');
418 if(string::npos == scolon_pos)
419 throw InternalErr(__FILE__,__LINE__,"Cannot find longitude resolution for GPM level 3 products");
420 if (equal_pos < scolon_pos){
421 string lonres_str = ind_elems[3].substr(equal_pos+1,scolon_pos-equal_pos-1);
422 lon_res = strtof(lonres_str.c_str(),nullptr);
423 }
424 else
425 throw InternalErr(__FILE__,__LINE__,"longitude resolution is not right for GPM level 3 products");
426 }
427 else
428 throw InternalErr(__FILE__,__LINE__,"The GPM grid LongitudeResolution doesn't exist.");
429
430 if (0 == ind_elems[4].find("NorthBoundingCoordinate")){
431
432 size_t equal_pos = ind_elems[4].find_first_of('=');
433 if(string::npos == equal_pos)
434 throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for GPM level 3 products");
435
436 size_t scolon_pos = ind_elems[4].find_first_of(';');
437 if(string::npos == scolon_pos)
438 throw InternalErr(__FILE__,__LINE__,"Cannot find latitude resolution for GPM level 3 products");
439 if (equal_pos < scolon_pos){
440 string north_bounding_str = ind_elems[4].substr(equal_pos+1,scolon_pos-equal_pos-1);
441 lat_north = strtof(north_bounding_str.c_str(),nullptr);
442 }
443 else
444 throw InternalErr(__FILE__,__LINE__,"NorthBoundingCoordinate is not right for GPM level 3 products");
445
446 }
447 else
448 throw InternalErr(__FILE__,__LINE__,"The GPM grid NorthBoundingCoordinate doesn't exist.");
449
450 if (0 == ind_elems[5].find("SouthBoundingCoordinate")){
451
452 size_t equal_pos = ind_elems[5].find_first_of('=');
453 if(string::npos == equal_pos)
454 throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for GPM level 3 products");
455
456 size_t scolon_pos = ind_elems[5].find_first_of(';');
457 if(string::npos == scolon_pos)
458 throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for GPM level 3 products");
459 if (equal_pos < scolon_pos){
460 string lat_south_str = ind_elems[5].substr(equal_pos+1,scolon_pos-equal_pos-1);
461 lat_south = strtof(lat_south_str.c_str(),nullptr);
462 }
463 else
464 throw InternalErr(__FILE__,__LINE__,"south bound coordinate is not right for GPM level 3 products");
465
466 }
467 else
468 throw InternalErr(__FILE__,__LINE__,"The GPM grid SouthBoundingCoordinate doesn't exist.");
469
470 if (0 == ind_elems[6].find("EastBoundingCoordinate")){
471
472 size_t equal_pos = ind_elems[6].find_first_of('=');
473 if(string::npos == equal_pos)
474 throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for GPM level 3 products");
475
476 size_t scolon_pos = ind_elems[6].find_first_of(';');
477 if(string::npos == scolon_pos)
478 throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for GPM level 3 products");
479 if (equal_pos < scolon_pos){
480 string lon_east_str = ind_elems[6].substr(equal_pos+1,scolon_pos-equal_pos-1);
481 lon_east = strtof(lon_east_str.c_str(),nullptr);
482 }
483 else
484 throw InternalErr(__FILE__,__LINE__,"south bound coordinate is not right for GPM level 3 products");
485
486 }
487 else
488 throw InternalErr(__FILE__,__LINE__,"The GPM grid EastBoundingCoordinate doesn't exist.");
489
490 if (0 == ind_elems[7].find("WestBoundingCoordinate")){
491
492 size_t equal_pos = ind_elems[7].find_first_of('=');
493 if(string::npos == equal_pos)
494 throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for GPM level 3 products");
495
496 size_t scolon_pos = ind_elems[7].find_first_of(';');
497 if(string::npos == scolon_pos)
498 throw InternalErr(__FILE__,__LINE__,"Cannot find south bound coordinate for GPM level 3 products");
499 if (equal_pos < scolon_pos){
500 string lon_west_str = ind_elems[7].substr(equal_pos+1,scolon_pos-equal_pos-1);
501 lon_west = strtof(lon_west_str.c_str(),nullptr);
502 }
503 else
504 throw InternalErr(__FILE__,__LINE__,"south bound coordinate is not right for GPM level 3 products");
505
506 }
507 else
508 throw InternalErr(__FILE__,__LINE__,"The GPM grid WestBoundingCoordinate doesn't exist.");
509
510 if (false == check_reg_orig) {
511 if (0 != ind_elems[8].find("Origin=SOUTHWEST"))
512 throw InternalErr(__FILE__,__LINE__,"The GPM grid origin is not SOUTHWEST.");
513 }
514
515 // Since we only treat the case when the Registration is center, so the size should be the
516 // regular number size - 1.
517 latsize =(int)((lat_north-lat_south)/lat_res);
518 lonsize =(int)((lon_east-lon_west)/lon_res);
519 lat_start = lat_south;
520 lon_start = lon_west;
521}
522
523void HDF5CFUtil::close_fileid(hid_t file_id,bool pass_fileid) {
524 if((false == pass_fileid) && (file_id !=-1))
525 H5Fclose(file_id);
526}
527
528// Somehow the conversion of double to c++ string with sprintf causes the memory error in
529// the testing code. I used the following code to do the conversion. Most part of the code
530// in reverse, int_to_str and dtoa are adapted from geeksforgeeks.org
531
532// reverses a string 'str' of length 'len'
533void HDF5CFUtil::rev_str(char *str, int len)
534{
535 int i=0;
536 int j=len-1;
537 int temp = 0;
538 while (i<j)
539 {
540 temp = str[i];
541 str[i] = str[j];
542 str[j] = temp;
543 i++;
544 j--;
545 }
546}
547
548// Converts a given integer x to string str[]. d is the number
549// of digits required in output. If d is more than the number
550// of digits in x, then 0s are added at the beginning.
551int HDF5CFUtil::int_to_str(int x, char str[], int d)
552{
553 int i = 0;
554 while (x)
555 {
556 str[i++] = (x%10) + '0';
557 x = x/10;
558 }
559
560 // If number of digits required is more, then
561 // add 0s at the beginning
562 while (i < d)
563 str[i++] = '0';
564
565 rev_str(str, i);
566 str[i] = '\0';
567 return i;
568}
569
570// Converts a double floating point number to string.
571void HDF5CFUtil::dtoa(double n, char *res, int afterpoint)
572{
573 // Extract integer part
574 auto ipart = (int)n;
575
576 // Extract the double part
577 double fpart = n - (double)ipart;
578
579 // convert integer part to string
580 int i = int_to_str(ipart, res, 0);
581
582 // check for display option after point
583 if (afterpoint != 0)
584 {
585 res[i] = '.'; // add dot
586
587 // Get the value of fraction part upto given no.
588 // of points after dot. The third parameter is needed
589 // to handle cases like 233.007
590 fpart = fpart * pow(10, afterpoint);
591
592 // A round-error of 1 is found when casting to the integer for some numbers.
593 // We need to correct it.
594 auto final_fpart = (int)fpart;
595 if(fpart -(int)fpart >0.5)
596 final_fpart = (int)fpart +1;
597 int_to_str(final_fpart, res + i + 1, afterpoint);
598 }
599}
600
601
602// Used to generate EOS geolocation cache name
603string HDF5CFUtil::get_int_str(int x) {
604
605 string str;
606 if(x > 0 && x <10)
607 str.push_back(x+'0');
608
609 else if (x >10 && x<100) {
610 str.push_back(x/10+'0');
611 str.push_back(x%10+'0');
612 }
613 else {
614 int num_digit = 0;
615 int abs_x = (x<0)?-x:x;
616 while(abs_x/=10)
617 num_digit++;
618 if(x<=0)
619 num_digit++;
620 vector<char> buf;
621 buf.resize(num_digit);
622 snprintf(buf.data(),num_digit,"%d",x);
623 str.assign(buf.data());
624
625 }
626
627 return str;
628
629}
630
631//Used to generate EOS5 lat/lon cache name
632string HDF5CFUtil::get_double_str(double x,int total_digit,int after_point) {
633
634 string str;
635 if(x!=0) {
636 vector<char> res;
637 res.resize(total_digit);
638 for(int i = 0; i<total_digit;i++)
639 res[i] = '\0';
640 if (x<0) {
641 str.push_back('-');
642 dtoa(-x,res.data(),after_point);
643 for(int i = 0; i<total_digit;i++) {
644 if(res[i] != '\0')
645 str.push_back(res[i]);
646 }
647 }
648 else {
649 dtoa(x, res.data(), after_point);
650 for(int i = 0; i<total_digit;i++) {
651 if(res[i] != '\0')
652 str.push_back(res[i]);
653 }
654 }
655
656 }
657 else
658 str.push_back('0');
659
660 return str;
661
662}
663
664
665// This function is adapted from the HDF-EOS library.
666int GDij2ll(int projcode, int zonecode, double projparm[],
667 int spherecode, int xdimsize, int ydimsize,
668 double upleftpt[], double lowrightpt[],
669 int npnts, int row[], int col[],
670 double longitude[], double latitude[], EOS5GridPRType pixcen, EOS5GridOriginType pixcnr)
671{
672
673 int errorcode = 0;
674 // In the original GCTP library, the function pointer names should be inv_trans and for_trans.
675 // However, since Hyrax supports both GDAL(including the HDF-EOS2 driver) and HDF handlers,
676 // on some machines, the functions inside the HDF-EOS2 driver will be called in run-time and wrong lat/lon
677 // values may be generated. To avoid, we change the function pointer names inside the GCTP library.
678 int(*hinv_trans[100]) (double,double,double*,double*);
679 int(*hfor_trans[100]) (double,double,double*,double*); /* GCTP function pointer */
680 double arg1;
681 double arg2;
682 double pixadjX = 0.; /* Pixel adjustment (x) */
683 double pixadjY = 0.; /* Pixel adjustment (y) */
684 double lonrad0 = 0.; /* Longitude in radians of upleft point */
685 double latrad0 = 0.; /* Latitude in radians of upleft point */
686 double scaleX = 0.; /* X scale factor */
687 double scaleY = 0.; /* Y scale factor */
688 double lonrad = 0.; /* Longitude in radians of point */
689 double latrad = 0.; /* Latitude in radians of point */
690 double xMtr0;
691 double yMtr0;
692 double xMtr1;
693 double yMtr1;
694
695
696
697 /* Compute adjustment of position within pixel */
698 /* ------------------------------------------- */
699 if (pixcen == HE5_HDFE_CENTER)
700 {
701 /* Pixel defined at center */
702 /* ----------------------- */
703 pixadjX = 0.5;
704 pixadjY = 0.5;
705 }
706 else
707 {
708 switch (pixcnr)
709 {
710
711 case HE5_HDFE_GD_UL:
712 {
713 /* Pixel defined at upper left corner */
714 /* ---------------------------------- */
715 pixadjX = 0.0;
716 pixadjY = 0.0;
717 break;
718 }
719
720 case HE5_HDFE_GD_UR:
721 {
722 /* Pixel defined at upper right corner */
723 /* ----------------------------------- */
724 pixadjX = 1.0;
725 pixadjY = 0.0;
726 break;
727 }
728
729 case HE5_HDFE_GD_LL:
730 {
731 /* Pixel defined at lower left corner */
732 /* ---------------------------------- */
733 pixadjX = 0.0;
734 pixadjY = 1.0;
735 break;
736 }
737
738 case HE5_HDFE_GD_LR:
739 {
740
741 /* Pixel defined at lower right corner */
742 /* ----------------------------------- */
743 pixadjX = 1.0;
744 pixadjY = 1.0;
745 break;
746 }
747
748 default:
749 {
750 throw InternalErr(__FILE__,__LINE__,"Unknown pixel corner to retrieve lat/lon from a grid.");
751 }
752 }
753 }
754
755
756
757 // If projection not GEO or BCEA call GCTP initialization routine
758 if (projcode != HE5_GCTP_GEO && projcode != HE5_GCTP_BCEA)
759 {
760
761 scaleX = (lowrightpt[0] - upleftpt[0]) / xdimsize;
762 scaleY = (lowrightpt[1] - upleftpt[1]) / ydimsize;
763 string eastFile = HDF5RequestHandler::get_stp_east_filename();
764 string northFile = HDF5RequestHandler::get_stp_north_filename();
765
766 hinv_init(projcode, zonecode, projparm, spherecode, (char*)eastFile.c_str(), (char*)northFile.c_str(),
767 &errorcode, hinv_trans);
768
769
770 /* Report error if any */
771 /* ------------------- */
772 if (errorcode != 0)
773 {
774 throw InternalErr(__FILE__,__LINE__,"GCTP hinv_init Error to retrieve lat/lon from a grid.");
775
776 }
777 else
778 {
779 /* For each point ... */
780 /* ------------------ */
781 for (int i = 0; i < npnts; i++)
782 {
783 /* Convert from meters to lon/lat (radians) using GCTP */
784 /* --------------------------------------------------- */
785#if 0
786 /*errorcode = hinv_trans[projcode] ((col[i] + pixadjX) * scaleX + upleftpt[0], (row[i] + pixadjY) * scaleY + upleftpt[1], &lonrad, &latrad);*/
787#endif
788
789 /* modified previous line to the following for the linux64 with -fPIC in cmpilation.
790 Whithout the change col[] and row[] values are ridiclous numbers, resulting a strange
791 number (very big) for arg1 and arg2. But with (int) typecast they become normal integers,
792 resulting in a acceptable values for arg1 and arg2. The problem was discovered during the
793 lat/lon geolocating of an hdfeos5 file with 64-bit hadview plug-in, developped for linux64.
794 */
795 arg1 = ((col[i] + pixadjX) * scaleX + upleftpt[0]);
796 arg2 = ((row[i] + pixadjY) * scaleY + upleftpt[1]);
797 errorcode = hinv_trans[projcode] (arg1, arg2, &lonrad, &latrad);
798
799 /* Report error if any */
800 /* ------------------- */
801 if (errorcode != 0)
802 {
803
804 if(projcode == HE5_GCTP_LAMAZ) {
805 longitude[i] = 1.0e51;
806 latitude[i] = 1.0e51;
807 }
808 else
809 throw InternalErr(__FILE__,__LINE__,"GCTP hinv_trans Error to retrieve lat/lon from a grid.");
810
811 }
812 else
813 {
814
815 /* Convert from radians to decimal degrees */
816 /* --------------------------------------- */
817 longitude[i] = HE5_EHconvAng(lonrad, HE5_HDFE_RAD_DEG);
818 latitude[i] = HE5_EHconvAng(latrad, HE5_HDFE_RAD_DEG);
819
820 }
821 }
822 }
823 }
824 else if (projcode == HE5_GCTP_BCEA)
825 {
826 /* BCEA projection */
827 /* -------------- */
828
829 /* Note: upleftpt and lowrightpt are in packed degrees, so they
830 must be converted to meters for this projection */
831
832 /* Initialize forward transformation */
833 /* --------------------------------- */
834 hfor_init(projcode, zonecode, projparm, spherecode, nullptr, nullptr,&errorcode, hfor_trans);
835
836 /* Report error if any */
837 /* ------------------- */
838 if (errorcode != 0)
839 {
840 throw InternalErr(__FILE__,__LINE__,"GCTP hfor_init Error to retrieve lat/lon from a grid.");
841 }
842
843 /* Convert upleft and lowright X coords from DMS to radians */
844 /* -------------------------------------------------------- */
845 lonrad0 =HE5_EHconvAng(upleftpt[0], HE5_HDFE_DMS_RAD);
846 lonrad = HE5_EHconvAng(lowrightpt[0], HE5_HDFE_DMS_RAD);
847
848 /* Convert upleft and lowright Y coords from DMS to radians */
849 /* -------------------------------------------------------- */
850 latrad0 = HE5_EHconvAng(upleftpt[1], HE5_HDFE_DMS_RAD);
851 latrad = HE5_EHconvAng(lowrightpt[1], HE5_HDFE_DMS_RAD);
852
853 /* Convert form lon/lat to meters(or whatever unit is, i.e unit
854 of r_major and r_minor) using GCTP */
855 /* ----------------------------------------- */
856 errorcode = hfor_trans[projcode] (lonrad0, latrad0, &xMtr0, &yMtr0);
857
858 /* Report error if any */
859 if (errorcode != 0)
860 {
861 throw InternalErr(__FILE__,__LINE__,"GCTP hfor_trans Error to retrieve lat/lon from a grid.");
862
863 }
864
865 /* Convert from lon/lat to meters or whatever unit is, i.e unit
866 of r_major and r_minor) using GCTP */
867 /* ----------------------------------------- */
868 errorcode = hfor_trans[projcode] (lonrad, latrad, &xMtr1, &yMtr1);
869
870 /* Report error if any */
871 if (errorcode != 0)
872 {
873 throw InternalErr(__FILE__,__LINE__,"GCTP hfor_trans Error to retrieve lat/lon from a grid.");
874 }
875
876 /* Compute x scale factor */
877 /* ---------------------- */
878 scaleX = (xMtr1 - xMtr0) / xdimsize;
879
880 /* Compute y scale factor */
881 /* ---------------------- */
882 scaleY = (yMtr1 - yMtr0) / ydimsize;
883
884 /* Initialize inverse transformation */
885 /* --------------------------------- */
886 hinv_init(projcode, zonecode, projparm, spherecode, nullptr, nullptr, &errorcode, hinv_trans);
887 /* Report error if any */
888 /* ------------------- */
889 if (errorcode != 0)
890 {
891 throw InternalErr(__FILE__,__LINE__,"GCTP hinv_init Error to retrieve lat/lon from a grid.");
892 }
893 /* For each point ... */
894 /* ------------------ */
895 for (int i = 0; i < npnts; i++)
896 {
897 /* Convert from meters (or any units that r_major and
898 r_minor has) to lon/lat (radians) using GCTP */
899 /* --------------------------------------------------- */
900 errorcode = hinv_trans[projcode] (
901 (col[i] + pixadjX) * scaleX + xMtr0,
902 (row[i] + pixadjY) * scaleY + yMtr0,
903 &lonrad, &latrad);
904
905 /* Report error if any */
906 /* ------------------- */
907 if (errorcode != 0)
908 {
909#if 0
910 /* status = -1;
911 sprintf(errbuf, "GCTP Error: %li\n", errorcode);
912 H5Epush(__FILE__, "HE5_GDij2ll", __LINE__, H5E_ARGS, H5E_BADVALUE , errbuf);
913 HE5_EHprint(errbuf, __FILE__, __LINE__);
914 return (status); */
915#endif
916 longitude[i] = 1.0e51; /* PGSd_GCT_IN_ERROR */
917 latitude[i] = 1.0e51; /* PGSd_GCT_IN_ERROR */
918 }
919
920 /* Convert from radians to decimal degrees */
921 /* --------------------------------------- */
922 longitude[i] = HE5_EHconvAng(lonrad, HE5_HDFE_RAD_DEG);
923 latitude[i] = HE5_EHconvAng(latrad, HE5_HDFE_RAD_DEG);
924 }
925 }
926
927 else if (projcode == HE5_GCTP_GEO)
928 {
929 /* GEO projection */
930 /* -------------- */
931
932 /*
933 * Note: lonrad, lonrad0, latrad, latrad0 are actually in degrees for
934 * the GEO projection case.
935 */
936
937
938 /* Convert upleft and lowright X coords from DMS to degrees */
939 /* -------------------------------------------------------- */
940 lonrad0 = HE5_EHconvAng(upleftpt[0], HE5_HDFE_DMS_DEG);
941 lonrad = HE5_EHconvAng(lowrightpt[0], HE5_HDFE_DMS_DEG);
942
943 /* Compute x scale factor */
944 /* ---------------------- */
945 scaleX = (lonrad - lonrad0) / xdimsize;
946
947 /* Convert upleft and lowright Y coords from DMS to degrees */
948 /* -------------------------------------------------------- */
949 latrad0 = HE5_EHconvAng(upleftpt[1], HE5_HDFE_DMS_DEG);
950 latrad = HE5_EHconvAng(lowrightpt[1], HE5_HDFE_DMS_DEG);
951
952 /* Compute y scale factor */
953 /* ---------------------- */
954 scaleY = (latrad - latrad0) / ydimsize;
955
956 /* For each point ... */
957 /* ------------------ */
958 for (int i = 0; i < npnts; i++)
959 {
960 /* Convert to lon/lat (decimal degrees) */
961 /* ------------------------------------ */
962 longitude[i] = (col[i] + pixadjX) * scaleX + lonrad0;
963 latitude[i] = (row[i] + pixadjY) * scaleY + latrad0;
964 }
965 }
966
967
968#if 0
969 hinv_init(projcode, zonecode, projparm, spherecode, eastFile, northFile,
970 (int *)&errorcode, hinv_trans);
971
972 for (int i = 0; i < npnts; i++)
973 {
974 /* Convert from meters (or any units that r_major and
975 * r_minor has) to lon/lat (radians) using GCTP */
976 /* --------------------------------------------------- */
977 errorcode =
978 hinv_trans[projcode] (
979 upleftpt[0],
980 upleftpt[1],
981 &lonrad, &latrad);
982
983 }
984#endif
985
986 return 0;
987
988}
989
990
991// convert angle degree to radian.
992double
993HE5_EHconvAng(double inAngle, int code)
994{
995 long min = 0; /* Truncated Minutes */
996 long deg = 0; /* Truncated Degrees */
997
998 double sec = 0.; /* Seconds */
999 double outAngle = 0.; /* Angle in desired units */
1000 double pi = 3.14159265358979324;/* Pi */
1001 double r2d = 180 / pi; /* Rad-deg conversion */
1002 double d2r = 1 / r2d; /* Deg-rad conversion */
1003
1004 switch (code)
1005 {
1006
1007 /* Convert radians to degrees */
1008 /* -------------------------- */
1009 case HE5_HDFE_RAD_DEG:
1010 outAngle = inAngle * r2d;
1011 break;
1012
1013 /* Convert degrees to radians */
1014 /* -------------------------- */
1015 case HE5_HDFE_DEG_RAD:
1016 outAngle = inAngle * d2r;
1017 break;
1018
1019
1020 /* Convert packed degrees to degrees */
1021 /* --------------------------------- */
1022 case HE5_HDFE_DMS_DEG:
1023 deg = (long)(inAngle / 1000000);
1024 min = (long)((inAngle - deg * 1000000) / 1000);
1025 sec = (inAngle - deg * 1000000 - min * 1000);
1026 outAngle = deg + min / 60.0 + sec / 3600.0;
1027 break;
1028
1029
1030 /* Convert degrees to packed degrees */
1031 /* --------------------------------- */
1032 case HE5_HDFE_DEG_DMS:
1033 {
1034 deg = (long)inAngle;
1035 min = (long)((inAngle - deg) * 60);
1036 sec = (inAngle - deg - min / 60.0) * 3600;
1037#if 0
1038/*
1039 if ((int)sec == 60)
1040 {
1041 sec = sec - 60;
1042 min = min + 1;
1043 }
1044*/
1045#endif
1046 if ( fabs(sec - 0.0) < 1.e-7 )
1047 {
1048 sec = 0.0;
1049 }
1050
1051 if ( (fabs(sec - 60) < 1.e-7 ) || ( sec > 60.0 ))
1052 {
1053 sec = sec - 60;
1054 min = min + 1;
1055 if(sec < 0.0)
1056 {
1057 sec = 0.0;
1058 }
1059 }
1060 if (min == 60)
1061 {
1062 min = min - 60;
1063 deg = deg + 1;
1064 }
1065 outAngle = deg * 1000000 + min * 1000 + sec;
1066 }
1067 break;
1068
1069
1070 /* Convert radians to packed degrees */
1071 /* --------------------------------- */
1072 case HE5_HDFE_RAD_DMS:
1073 {
1074 inAngle = inAngle * r2d;
1075 deg = (long)inAngle;
1076 min = (long)((inAngle - deg) * 60);
1077 sec = ((inAngle - deg - min / 60.0) * 3600);
1078#if 0
1079/*
1080 if ((int)sec == 60)
1081 {
1082 sec = sec - 60;
1083 min = min + 1;
1084 }
1085*/
1086#endif
1087 if ( fabs(sec - 0.0) < 1.e-7 )
1088 {
1089 sec = 0.0;
1090 }
1091
1092 if ( (fabs(sec - 60) < 1.e-7 ) || ( sec > 60.0 ))
1093 {
1094 sec = sec - 60;
1095 min = min + 1;
1096 if(sec < 0.0)
1097 {
1098 sec = 0.0;
1099 }
1100 }
1101 if (min == 60)
1102 {
1103 min = min - 60;
1104 deg = deg + 1;
1105 }
1106 outAngle = deg * 1000000 + min * 1000 + sec;
1107 }
1108 break;
1109
1110
1111 /* Convert packed degrees to radians */
1112 /* --------------------------------- */
1113 case HE5_HDFE_DMS_RAD:
1114 deg = (long)(inAngle / 1000000);
1115 min = (long)((inAngle - deg * 1000000) / 1000);
1116 sec = (inAngle - deg * 1000000 - min * 1000);
1117 outAngle = deg + min / 60.0 + sec / 3600.0;
1118 outAngle = outAngle * d2r;
1119 break;
1120 default:
1121 break;
1122 }
1123 return outAngle;
1124}
1125
1126
1127
1128
1129
1130#if 0
1132inline size_t
1133HDF5CFUtil::INDEX_nD_TO_1D (const std::vector <size_t > &dims,
1134 const std::vector < size_t > &pos)
1135{
1136 //
1137 // int a[10][20][30]; // & a[1][2][3] == a + (20*30+1 + 30*2 + 1 *3);
1138 // int b[10][2]; // &b[1][2] == b + (20*1 + 2);
1139 //
1140 if(dims.size () != pos.size ())
1141 throw InternalErr(__FILE__,__LINE__,"dimension error in INDEX_nD_TO_1D routine.");
1142 size_t sum = 0;
1143 size_t start = 1;
1144
1145 for (size_t p = 0; p < pos.size (); p++) {
1146 size_t m = 1;
1147
1148 for (size_t j = start; j < dims.size (); j++)
1149 m *= dims[j];
1150 sum += m * pos[p];
1151 start++;
1152 }
1153 return sum;
1154}
1155#endif
1156
1158//
1159// \param input Input variable
1160// \param dim dimension info of the input
1161// \param start start indexes of each dim
1162// \param stride stride of each dim
1163// \param edge count of each dim
1164// \param poutput output variable
1165// \parrm index dimension index
1166// \return 0 if successful. -1 otherwise.
1167//
1168//
1169#if 0
1170template<typename T>
1171int HDF5CFUtil::subset(
1172 const T input[],
1173 int rank,
1174 vector<int> & dim,
1175 int start[],
1176 int stride[],
1177 int edge[],
1178 std::vector<T> *poutput,
1179 vector<int>& pos,
1180 int index)
1181{
1182 for(int k=0; k<edge[index]; k++)
1183 {
1184 pos[index] = start[index] + k*stride[index];
1185 if(index+1<rank)
1186 subset(input, rank, dim, start, stride, edge, poutput,pos,index+1);
1187 if(index==rank-1)
1188 {
1189 poutput->push_back(input[INDEX_nD_TO_1D( dim, pos)]);
1190 }
1191 } // end of for
1192 return 0;
1193} // end of template<typename T> static int
1194#endif
1195
1196// Need to wrap a 'read buffer' from a pure file call here since read() is also a DAP function to read DAP data.
1197ssize_t HDF5CFUtil::read_buffer_from_file(int fd, void*buf, size_t total_read) {
1198
1199 ssize_t ret_val = read(fd,buf,total_read);
1200 return ret_val;
1201}
1202
1203// Obtain the cache name. The clashing is rare given that fname is unique.The "_" may cause clashing in theory.
1204string HDF5CFUtil::obtain_cache_fname(const string & fprefix, const string &fname, const string &vname) {
1205
1206 string cache_fname = fprefix;
1207
1208 string correct_fname = fname;
1209 std::replace(correct_fname.begin(),correct_fname.end(),'/','_');
1210
1211 string correct_vname = vname;
1212
1213 // Replace the '/' to '_'
1214 std::replace(correct_vname.begin(),correct_vname.end(),'/','_');
1215
1216 // Replace the ' ' to to '_" since space is not good for a file name
1217 std::replace(correct_vname.begin(),correct_vname.end(),' ','_');
1218
1219
1220 cache_fname = cache_fname +correct_fname +correct_vname;
1221
1222 return cache_fname;
1223}
1224size_t INDEX_nD_TO_1D (const std::vector < size_t > &dims,
1225 const std::vector < size_t > &pos){
1226 //
1227 // "int a[10][20][30] // & a[1][2][3] == a + (20*30+1 + 30*2 + 1 *3)"
1228 // "int b[10][2] // &b[1][2] == b + (20*1 + 2)"
1229 //
1230 if(dims.size () != pos.size ())
1231 throw InternalErr(__FILE__,__LINE__,"dimension error in INDEX_nD_TO_1D routine.");
1232 size_t sum = 0;
1233 size_t start = 1;
1234
1235 for (const auto &pos_ele:pos) {
1236 size_t m = 1;
1237
1238 for (size_t j = start; j < dims.size (); j++)
1239 m *= dims[j];
1240 sum += m * pos_ele;
1241 start++;
1242 }
1243 return sum;
1244}
1245
1246// Supposed string temp_str contains several relpath, Obtain all the positions of relpath in temp_str.
1247// The positions are stored in a vector of size_t and returns.
1248void HDF5CFUtil::get_relpath_pos(const string& temp_str, const string& relpath, vector<size_t>&s_pos) {
1249
1250
1251 //s_pos holds all the positions that relpath appears within the temp_str
1252
1253 size_t pos = temp_str.find(relpath, 0);
1254 while(pos != string::npos)
1255 {
1256 s_pos.push_back(pos);
1257#if 0
1258//cout<<"pos is "<<pos <<endl;
1259#endif
1260 pos = temp_str.find(relpath,pos+1);
1261 }
1262#if 0
1263//cout<<"pos.size() is "<<s_pos.size() <<endl;
1264#endif
1265
1266}
1267
1268
1269void HDF5CFUtil::cha_co(string &co,const string & vpath) {
1270
1271 string sep="/";
1272 string rp_sep="../";
1273 if(vpath.find(sep,1)!=string::npos) {
1274 if(co.find(sep)!=string::npos) {
1275 // if finding '../', reduce the path.
1276 if(co.find(rp_sep)!=string::npos) {
1277 vector<size_t>var_sep_pos;
1278 get_relpath_pos(vpath,sep,var_sep_pos);
1279 vector<size_t>co_rp_sep_pos;
1280 get_relpath_pos(co,rp_sep,co_rp_sep_pos);
1281 // We only support when "../" is at position 0.
1282 if(co_rp_sep_pos[0]==0) {
1283 // Obtain the '../' position at co
1284 if(co_rp_sep_pos.size() <var_sep_pos.size()) {
1285 // We obtain the suffix of CO and the path from vpath.
1286 size_t var_prefix_pos=var_sep_pos[var_sep_pos.size()-co_rp_sep_pos.size()-1];
1287 string var_prefix=vpath.substr(1,var_prefix_pos);
1288 string co_suffix = co.substr(co_rp_sep_pos[co_rp_sep_pos.size()-1]+rp_sep.size());
1289 co = var_prefix+co_suffix;
1290#if 0
1291//cout<<"var_prefix_pos is "<<var_prefix_pos <<endl;
1292//cout<<"var_prefix is "<<var_prefix <<endl;
1293//cout<<"co_suffix is "<<co_suffix <<endl;
1294//cout<<"co is "<<co<<endl;;
1295#endif
1296 }
1297 }
1298 }
1299
1300 }
1301 else {// co no path, add fullpath
1302 string var_prefix = obtain_string_before_lastslash(vpath).substr(1);
1303 co = var_prefix +co;
1304#if 0
1305//cout<<"co full is " <<co <<endl;
1306#endif
1307 }
1308 }
1309}
1310
This file includes several helper functions for translating HDF5 to CF-compliant.
include the entry functions to execute the handlers
static void Split(const char *s, int len, char sep, std::vector< std::string > &names)
static H5DataType H5type_to_H5DAPtype(hid_t h5_type_id)
Map HDF5 Datatype to the intermediate H5DAPtype for the future use.
Definition HDF5CFUtil.cc:53
static std::string trim_string(hid_t dtypeid, const std::string &s, int num_sect, size_t section_size, std::vector< size_t > &sect_newsize)
static ssize_t read_buffer_from_file(int fd, void *buf, size_t)
Getting a subset of a variable.