bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
HDFEOS2ArrayGridGeoField.h
1
2// This file is part of the hdf4 data handler for the OPeNDAP data server.
3// It retrieves the latitude and longitude of the HDF-EOS2 Grid
4// There are two typical cases:
5// read the lat/lon from the file and calculate lat/lon using the EOS2 library.
6// Several variations are also handled:
7// 1. For geographic and Cylinderic Equal Area projections, condense 2-D to 1-D.
8// 2. For some files, the longitude is within 0-360 range instead of -180 - 180 range.
9// We need to convert 0-360 to -180-180.
10// 3. Some files have fillvalues in the lat. and lon. for the geographic projection.
11// 4. Several MODIS files don't have the correct parameters inside StructMetadata.
12// We can obtain the starting point, the step and replace the fill value.
13// Authors: Kent Yang <myang6@hdfgroup.org> Choonghwan Lee
14// Copyright (c) The HDF Group
16#ifdef USE_HDFEOS2_LIB
17#ifndef HDFEOS2ARRAY_GRIDGEOFIELD_H
18#define HDFEOS2ARRAY_GRIDGEOFIELD_H
19
20#include <cmath>
21
22#include <libdap/Array.h>
23
24#include "mfhdf.h"
25#include "hdf.h"
26#include "HdfEosDef.h"
27
28
29class HDFEOS2ArrayGridGeoField:public libdap::Array
30{
31 public:
32 HDFEOS2ArrayGridGeoField (int rank, int fieldtype, bool llflag, bool ydimmajor, bool condenseddim, bool speciallon, int specialformat, /*short field_cache,*/const std::string &filename, const int gridfd, const std::string & gridname, const std::string & fieldname,const string & n = "", libdap::BaseType * v = nullptr):
33 libdap::Array (n, v),
34 rank (rank),
35 fieldtype (fieldtype),
36 llflag (llflag),
37 ydimmajor (ydimmajor),
38 condenseddim (condenseddim),
39 speciallon (speciallon),
40 specialformat (specialformat),
41 /*field_cache(field_cache),*/
42 filename(filename),
43 gridfd(gridfd),
44 gridname (gridname),
45 fieldname (fieldname)
46 {
47 }
48 ~ HDFEOS2ArrayGridGeoField () override = default;
49
50 int format_constraint (int *cor, int *step, int *edg);
51
52 libdap::BaseType *ptr_duplicate () override
53 {
54 return new HDFEOS2ArrayGridGeoField (*this);
55 }
56
57 bool read () override;
58
59 private:
60
61 // Field array rank
62 int rank;
63
64 // Distinguish coordinate variables from general variables.
65 // For fieldtype values:
66 // 0 the field is a general field
67 // 1 the field is latitude.
68 // 2 the field is longtitude.
69 // 3 the field is a coordinate variable defined as level.
70 // 4 the field is an inserted natural number.
71 // 5 the field is time.
72 int fieldtype;
73
74 // The flag to indicate if lat/lon is an existing field in the file or needs to be calculated.
75 bool llflag;
76
77 // Flag to check if this lat/lon field is YDim major(YDim,XDim). This is necessary to use GDij2ll
78 bool ydimmajor;
79
80 // Flag to check if this 2-D lat/lon can be condensed to 1-D lat/lon
81 bool condenseddim;
82
83 // Flag to check if this file's longitude needs to be handled specially.
84 // Note: longitude values range from 0 to 360 for some fields. We need to map the values to -180 to 180.
85 bool speciallon;
86
87 // Latitude and longitude values of some HDF-EOS2 grids need to be handled in special ways.
88 // There are four cases that we need to calculate lat/lon differently.
89 // This number is used to distinguish them.
90 // 1) specialformat = 1
91 // Projection: Geographic
92 // upleft and lowright coordinates don't follow EOS's DDDMMMSSS conventions.
93 // Instead, they simply represent lat/lon values as -180.0 or -90.0.
94 // Products: mostly MODIS MCD Grid
95
96 // 2) specialformat = 2
97 // Projection: Geographic
98 // upleft and lowright coordinates don't follow EOS's DDDMMMSSS conventions.
99 // Instead, their upleft or lowright are simply represented as default(-1).
100 // Products: mostly TRMM CERES Grid
101
102 // 3) specialformat = 3
103 // One MOD13C2 doesn't provide project code
104 // The upperleft and lowerright coordinates are all -1
105 // We have to calculate lat/lon by ourselves.
106 // Since it doesn't provide the project code, we double check their information
107 // and find that it covers the whole globe with 0.05 degree resolution.
108 // Lat. is from 90 to -90 and Lon is from -180 to 180.
109
110 // 4) specialformat = 4
111 // Projection: Space Oblique Mercator(SOM)
112 // The lat/lon needs to be handled differently for the SOM projection
113 // Products: MISR
114 int specialformat;
115
116 // Temp here: HDF-EOS2 file name
117 std::string filename;
118
119 int gridfd;
120
121 // HDF-EOS2 grid name
122 std::string gridname;
123
124 // HDF-EOS2 field name
125 std::string fieldname;
126 // Calculate Lat and Lon based on HDF-EOS2 library.
127 void CalculateLatLon (int32 gridid, int fieldtype, int specialformat, float64 * outlatlon, float64* latlon_all, const int32 * offset, const int32 * count, const int32 * step, int nelms,bool write_latlon_cache);
128
129 // Calculate Special Latitude and Longitude.
130 //One MOD13C2 file doesn't provide projection code
131 // The upperleft and lowerright coordinates are all -1
132 // We have to calculate lat/lon by ourselves.
133 // Since it doesn't provide the project code, we double check their information
134 // and find that it covers the whole globe with 0.05 degree resolution.
135 // Lat. is from 90 to -90 and Lon is from -180 to 180.
136 void CalculateSpeLatLon (int32 gridid, int fieldtype, float64 * outlatlon, const int32 * offset, const int32 * count, const int32 * step) const;
137
138 // Calculate Latitude and Longtiude for the Geo-projection for very large number of elements per dimension.
139 void CalculateLargeGeoLatLon(int32 gridid, int fieldtype, float64* latlon, float64* latlon_all, const int *start, const int *count, const int *step, int nelms,bool write_latlon_cache) const;
140 // test for undefined values returned by longitude-latitude calculation
141 bool isundef_lat(double value) const
142 {
143 if (std::isinf(value))
144 return true;
145 if (std::isnan(value))
146 return true;
147
148 // GCTP_AMAZ returns "1e+51" for values at the opposite poles
149 if(value < -90.0 || value > 90.0)
150 return true;
151 // This is ok.
152 return false;
153 } // end bool isundef_lat(double value)
154
155 bool isundef_lon(double value) const
156 {
157 if (std::isinf(value))
158 return true;
159 if (std::isnan(value))
160 return true;
161 // GCTP_LAMAZ returns "1e+51" for values at the opposite poles
162 if (value < -180.0 || value > 180.0)
163 return true;
164 return false;
165 } // end bool isundef_lat(double value)
166
167 // Given rol, col address in double array of dimension YDim x XDim
168 // return value of nearest neighbor to (row,col) which is not undefined
169 double nearestNeighborLatVal(double *array, int row, int col, int YDim, int XDim)
170 {
171 // test valid row, col address range
172 if(row < 0 || row > YDim || col < 0 || col > XDim)
173 {
174 cerr << "nearestNeighborLatVal("<<row<<", "<<col<<", "<<YDim<<", "<<XDim;
175 cerr <<"): index out of range"<<endl;
176 return 0.0;
177 }
178 // address (0,0)
179 if(row < YDim/2 && col < XDim/2)
180 { /* search by incrementing both row and col */
181 if(!isundef_lat(array[(row+1)*XDim+col])) return(array[(row+1)*XDim+col]);
182 if(!isundef_lat(array[row*XDim+col+1])) return(array[row*XDim+col+1]);
183 if(!isundef_lat(array[(row+1)*XDim+col+1])) return(array[(row+1)*XDim+col+1]);
184 /* recurse on the diagonal */
185 return(nearestNeighborLatVal(array, row+1, col+1, YDim, XDim));
186 }
187 if(row < YDim/2 && col > XDim/2)
188 { /* search by incrementing row and decrementing col */
189 if(!isundef_lat(array[(row+1)*XDim+col])) return(array[(row+1)*XDim+col]);
190 if(!isundef_lat(array[row*XDim+col-1])) return(array[row*XDim+col-1]);
191 if(!isundef_lat(array[(row+1)*XDim+col-1])) return(array[(row+1)*XDim+col-1]);
192 /* recurse on the diagonal */
193 return(nearestNeighborLatVal(array, row+1, col-1, YDim, XDim));
194 }
195 if(row > YDim/2 && col < XDim/2)
196 { /* search by incrementing col and decrementing row */
197 if(!isundef_lat(array[(row-1)*XDim+col])) return(array[(row-1)*XDim+col]);
198 if(!isundef_lat(array[row*XDim+col+1])) return(array[row*XDim+col+1]);
199 if(!isundef_lat(array[(row-1)*XDim+col+1])) return(array[(row-1)*XDim+col+1]);
200 /* recurse on the diagonal */
201 return(nearestNeighborLatVal(array, row-1, col+1, YDim, XDim));
202 }
203 if(row > YDim/2 && col > XDim/2)
204 { /* search by decrementing both row and col */
205 if(!isundef_lat(array[(row-1)*XDim+col])) return(array[(row-1)*XDim+col]);
206 if(!isundef_lat(array[row*XDim+col-1])) return(array[row*XDim+col-1]);
207 if(!isundef_lat(array[(row-1)*XDim+col-1])) return(array[(row-1)*XDim+col-1]);
208 /* recurse on the diagonal */
209 return(nearestNeighborLatVal(array, row-1, col-1, YDim, XDim));
210 }
211 // dummy return, turn off the compiling warning
212 return 0.0;
213 } // end
214
215 double nearestNeighborLonVal(double *array, int row, int col, int YDim, int XDim)
216 {
217 // test valid row, col address range
218 if(row < 0 || row > YDim || col < 0 || col > XDim)
219 {
220 cerr << "nearestNeighborLonVal("<<row<<", "<<col<<", "<<YDim<<", "<<XDim;
221 cerr <<"): index out of range"<<endl;
222 return 0.0;
223 }
224 // address (0,0)
225 if(row < YDim/2 && col < XDim/2)
226 { /* search by incrementing both row and col */
227 if(!isundef_lon(array[(row+1)*XDim+col])) return(array[(row+1)*XDim+col]);
228 if(!isundef_lon(array[row*XDim+col+1])) return(array[row*XDim+col+1]);
229 if(!isundef_lon(array[(row+1)*XDim+col+1])) return(array[(row+1)*XDim+col+1]);
230 /* recurse on the diagonal */
231 return(nearestNeighborLonVal(array, row+1, col+1, YDim, XDim));
232 }
233 if(row < YDim/2 && col > XDim/2)
234 { /* search by incrementing row and decrementing col */
235 if(!isundef_lon(array[(row+1)*XDim+col])) return(array[(row+1)*XDim+col]);
236 if(!isundef_lon(array[row*XDim+col-1])) return(array[row*XDim+col-1]);
237 if(!isundef_lon(array[(row+1)*XDim+col-1])) return(array[(row+1)*XDim+col-1]);
238 /* recurse on the diagonal */
239 return(nearestNeighborLonVal(array, row+1, col-1, YDim, XDim));
240 }
241 if(row > YDim/2 && col < XDim/2)
242 { /* search by incrementing col and decrementing row */
243 if(!isundef_lon(array[(row-1)*XDim+col])) return(array[(row-1)*XDim+col]);
244 if(!isundef_lon(array[row*XDim+col+1])) return(array[row*XDim+col+1]);
245 if(!isundef_lon(array[(row-1)*XDim+col+1])) return(array[(row-1)*XDim+col+1]);
246 /* recurse on the diagonal */
247 return(nearestNeighborLonVal(array, row-1, col+1, YDim, XDim));
248 }
249 if(row > YDim/2 && col > XDim/2)
250 { /* search by decrementing both row and col */
251 if(!isundef_lon(array[(row-1)*XDim+col])) return(array[(row-1)*XDim+col]);
252 if(!isundef_lon(array[row*XDim+col-1])) return(array[row*XDim+col-1]);
253 if(!isundef_lon(array[(row-1)*XDim+col-1])) return(array[(row-1)*XDim+col-1]);
254 /* recurse on the diagonal */
255 return(nearestNeighborLonVal(array, row-1, col-1, YDim, XDim));
256 }
257
258 // dummy return, turn off the compiling warning
259 return 0.0;
260 } // end
261
262 // Calculate Latitude and Longitude for SOM Projection.
263 // since the latitude and longitude of the SOM projection are 3-D, so we need to handle this projection in a special way.
264 // Based on our current understanding, the third dimension size is always 180.
265 // This is according to the MISR Lat/lon calculation document
266 // at http://eosweb.larc.nasa.gov/PRODOCS/misr/DPS/DPS_v50_RevS.pdf
267 void CalculateSOMLatLon(int32, const int*, const int*, const int*, int,const string &, bool);
268
269 // Calculate Latitude and Longitude for LAMAZ Projection.
270 void CalculateLAMAZLatLon(int32, int, float64*, float64*,const int*, const int*, const int*, bool);
271
272 // Subsetting the latitude and longitude.
273 template <class T> void LatLon2DSubset (T* outlatlon, int ydim, int xdim, T* latlon, const int32 * offset, const int32 * count, const int32 * step) const;
274
275 // Handle latitude and longitude when having fill value for geographic projection
276 //template <class T> void HandleFillLatLon(T* total_latlon, T* latlon,bool ydimmajor,
277 template <class T> void HandleFillLatLon(vector<T> total_latlon, T* latlon,bool ydimmajor, int fieldtype, int32 xdim , int32 ydim, const int32* offset, const int32* count, const int32* step, int fv);
278
279 // Corrected Latitude and longitude when the lat/lon has fill value case.
280 template < class T > bool CorLatLon (T * latlon, int fieldtype, int elms, int fv);
281
282 // Converted longitude from 0-360 to -180-180.
283 template < class T > void CorSpeLon (T * lon, int xdim) const;
284
285 // Lat and Lon for GEO and CEA projections need to be condensed from 2-D to 1-D.
286 // This function does this.
287 void getCorrectSubset (const int *offset, const int *count, const int *step, int32 * offset32, int32 * count32, int32 * step32, bool condenseddim, bool ydimmajor, int fieldtype, int rank) const;
288
289 // Helper function to handle the case that lat. and lon. contain fill value.
290 template < class T > int findfirstfv (T * array, int start, int end, int fillvalue);
291
292};
293#endif
294#endif