OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
HDFEOS2ArrayGridGeoField.h
Go to the documentation of this file.
1 // 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: MuQun Yang <myang6@hdfgroup.org> Choonghwan Lee
14 // Copyright (c) 2009-2012 The HDF Group
16 #ifdef USE_HDFEOS2_LIB
17 #ifndef HDFEOS2ARRAY_GRIDGEOFIELD_H
18 #define HDFEOS2ARRAY_GRIDGEOFIELD_H
19 
20 #include <Array.h>
21 #include "mfhdf.h"
22 #include "hdf.h"
23 #include "HdfEosDef.h"
24 
25 using namespace libdap;
26 class HDFEOS2ArrayGridGeoField:public Array
27 {
28  public:
29  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 = "", BaseType * v = 0):
30  Array (n, v),
31  rank (rank),
32  fieldtype (fieldtype),
33  llflag (llflag),
34  ydimmajor (ydimmajor),
35  condenseddim (condenseddim),
36  speciallon (speciallon),
37  specialformat (specialformat),
38  /*field_cache(field_cache),*/
39  filename(filename),
40  gridfd(gridfd),
41  gridname (gridname),
42  fieldname (fieldname)
43  {
44  }
45  virtual ~ HDFEOS2ArrayGridGeoField ()
46  {
47  }
48  int format_constraint (int *cor, int *step, int *edg);
49 
50  BaseType *ptr_duplicate ()
51  {
52  return new HDFEOS2ArrayGridGeoField (*this);
53  }
54 
55  virtual bool read ();
56 
57  private:
58 
59  // Field array rank
60  int rank;
61 
62  // Distinguish coordinate variables from general variables.
63  // For fieldtype values:
64  // 0 the field is a general field
65  // 1 the field is latitude.
66  // 2 the field is longtitude.
67  // 3 the field is a coordinate variable defined as level.
68  // 4 the field is an inserted natural number.
69  // 5 the field is time.
70  int fieldtype;
71 
72  // The flag to indicate if lat/lon is an existing field in the file or needs to be calculated.
73  bool llflag;
74 
75  // Flag to check if this lat/lon field is YDim major(YDim,XDim). This is necessary to use GDij2ll
76  bool ydimmajor;
77 
78  // Flag to check if this 2-D lat/lon can be condensed to 1-D lat/lon
79  bool condenseddim;
80 
81  // Flag to check if this file's longitude needs to be handled specially.
82  // Note: longitude values range from 0 to 360 for some fields. We need to map the values to -180 to 180.
83  bool speciallon;
84 
85  // Latitude and longitude values of some HDF-EOS2 grids need to be handled in special ways.
86  // There are four cases that we need to calculate lat/lon differently.
87  // This number is used to distinguish them.
88  // 1) specialformat = 1
89  // Projection: Geographic
90  // upleft and lowright coordinates don't follow EOS's DDDMMMSSS conventions.
91  // Instead, they simply represent lat/lon values as -180.0 or -90.0.
92  // Products: mostly MODIS MCD Grid
93 
94  // 2) specialformat = 2
95  // Projection: Geographic
96  // upleft and lowright coordinates don't follow EOS's DDDMMMSSS conventions.
97  // Instead, their upleft or lowright are simply represented as default(-1).
98  // Products: mostly TRMM CERES Grid
99 
100  // 3) specialformat = 3
101  // One MOD13C2 doesn't provide project code
102  // The upperleft and lowerright coordinates are all -1
103  // We have to calculate lat/lon by ourselves.
104  // Since it doesn't provide the project code, we double check their information
105  // and find that it covers the whole globe with 0.05 degree resolution.
106  // Lat. is from 90 to -90 and Lon is from -180 to 180.
107 
108  // 4) specialformat = 4
109  // Projection: Space Oblique Mercator(SOM)
110  // The lat/lon needs to be handled differently for the SOM projection
111  // Products: MISR
112  int specialformat;
113 
114  //short field_cache;
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, int32 * offset, int32 * count, 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, int32 * offset, int32 * count, int32 * step, int nelms);
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, int *start, int *count, int *step, int nelms,bool write_latlon_cache);
140  // test for undefined values returned by longitude-latitude calculation
141  bool isundef_lat(double value)
142  {
143  if(isinf(value)) return(true);
144  if(isnan(value)) return(true);
145  // GCTP_LAMAZ returns "1e+51" for values at the opposite poles
146  if(value < -90.0 || value > 90.0) return(true);
147  return(false);
148  } // end bool isundef_lat(double value)
149 
150  bool isundef_lon(double value)
151  {
152  if(isinf(value)) return(true);
153  if(isnan(value)) return(true);
154  // GCTP_LAMAZ returns "1e+51" for values at the opposite poles
155  if(value < -180.0 || value > 180.0) return(true);
156  return(false);
157  } // end bool isundef_lat(double value)
158 
159  // Given rol, col address in double array of dimension YDim x XDim
160  // return value of nearest neighbor to (row,col) which is not undefined
161  double nearestNeighborLatVal(double *array, int row, int col, int YDim, int XDim)
162  {
163  // test valid row, col address range
164  if(row < 0 || row > YDim || col < 0 || col > XDim)
165  {
166  cerr << "nearestNeighborLatVal("<<row<<", "<<col<<", "<<YDim<<", "<<XDim;
167  cerr <<"): index out of range"<<endl;
168  return(0.0);
169  }
170  // address (0,0)
171  if(row < YDim/2 && col < XDim/2)
172  { /* search by incrementing both row and col */
173  if(!isundef_lat(array[(row+1)*XDim+col])) return(array[(row+1)*XDim+col]);
174  if(!isundef_lat(array[row*XDim+col+1])) return(array[row*XDim+col+1]);
175  if(!isundef_lat(array[(row+1)*XDim+col+1])) return(array[(row+1)*XDim+col+1]);
176  /* recurse on the diagonal */
177  return(nearestNeighborLatVal(array, row+1, col+1, YDim, XDim));
178  }
179  if(row < YDim/2 && col > XDim/2)
180  { /* search by incrementing row and decrementing 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 col and decrementing row */
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 decrementing both row and col */
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  // dummy return, turn off the compiling warning
204  return 0.0;
205  } // end
206 
207  double nearestNeighborLonVal(double *array, int row, int col, int YDim, int XDim)
208  {
209  // test valid row, col address range
210  if(row < 0 || row > YDim || col < 0 || col > XDim)
211  {
212  cerr << "nearestNeighborLonVal("<<row<<", "<<col<<", "<<YDim<<", "<<XDim;
213  cerr <<"): index out of range"<<endl;
214  return(0.0);
215  }
216  // address (0,0)
217  if(row < YDim/2 && col < XDim/2)
218  { /* search by incrementing both row and col */
219  if(!isundef_lon(array[(row+1)*XDim+col])) return(array[(row+1)*XDim+col]);
220  if(!isundef_lon(array[row*XDim+col+1])) return(array[row*XDim+col+1]);
221  if(!isundef_lon(array[(row+1)*XDim+col+1])) return(array[(row+1)*XDim+col+1]);
222  /* recurse on the diagonal */
223  return(nearestNeighborLonVal(array, row+1, col+1, YDim, XDim));
224  }
225  if(row < YDim/2 && col > XDim/2)
226  { /* search by incrementing row and decrementing 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 col and decrementing row */
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 decrementing both row and col */
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 
250  // dummy return, turn off the compiling warning
251  return 0.0;
252  } // end
253 
254  // Calculate Latitude and Longitude for SOM Projection.
255  // since the latitude and longitude of the SOM projection are 3-D, so we need to handle this projection in a special way.
256  // Based on our current understanding, the third dimension size is always 180.
257  // This is according to the MISR Lat/lon calculation document
258  // at http://eosweb.larc.nasa.gov/PRODOCS/misr/DPS/DPS_v50_RevS.pdf
259  void CalculateSOMLatLon(int32, int*, int*, int*, int,const string &, bool);
260 
261  // Calculate Latitude and Longitude for LAMAZ Projection.
262  void CalculateLAMAZLatLon(int32, int, float64*, float64*,int*, int*, int*, int,bool);
263 
264  // Subsetting the latitude and longitude.
265  template <class T> void LatLon2DSubset (T* outlatlon, int ydim, int xdim, T* latlon, int32 * offset, int32 * count, int32 * step);
266 
267  // Handle latitude and longitude when having fill value for geographic projection
268  //template <class T> void HandleFillLatLon(T* total_latlon, T* latlon,bool ydimmajor,
269  template <class T> void HandleFillLatLon(vector<T> total_latlon, T* latlon,bool ydimmajor, int fieldtype, int32 xdim , int32 ydim, int32* offset, int32* count, int32* step, int fv);
270 
271  // Corrected Latitude and longitude when the lat/lon has fill value case.
272  template < class T > bool CorLatLon (T * latlon, int fieldtype, int elms, int fv);
273 
274  // Converted longitude from 0-360 to -180-180.
275  template < class T > void CorSpeLon (T * lon, int xdim);
276 
277  // Lat and Lon for GEO and CEA projections need to be condensed from 2-D to 1-D.
278  // This function does this.
279  void getCorrectSubset (int *offset, int *count, int *step, int32 * offset32, int32 * count32, int32 * step32, bool condenseddim, bool ydimmajor, int fieldtype, int rank);
280 
281  // Helper function to handle the case that lat. and lon. contain fill value.
282  template < class T > int findfirstfv (T * array, int start, int end, int fillvalue);
283 
284 };
285 #endif
286 #endif
static class NCMLUtil overview