OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
HDFEOS2.cc
Go to the documentation of this file.
1 // This file is part of the hdf4 data handler for the OPeNDAP data server.
3 //
4 // Authors: MuQun Yang <myang6@hdfgroup.org> Choonghwan Lee
5 // Copyright (c) 2009 The HDF Group
7 
8 #ifdef USE_HDFEOS2_LIB
9 
10 //#include <BESDEBUG.h> // Should provide BESDebug info. later
11 #include <sstream>
12 #include <algorithm>
13 #include <functional>
14 #include <vector>
15 #include <map>
16 #include <set>
17 #include<math.h>
18 #include<sys/stat.h>
19 
20 #include "HDFCFUtil.h"
21 #include "HDFEOS2.h"
22 
23 // Names to be searched by
24 // get_geodim_x_name()
25 // get_geodim_y_name()
26 // get_latfield_name()
27 // get_lonfield_name()
28 // get_geogrid_name()
29 
30 // Possible XDim names
31 const char *HDFEOS2::File::_geodim_x_names[] = {"XDim", "LonDim","nlon"};
32 
33 // Possible YDim names.
34 const char *HDFEOS2::File::_geodim_y_names[] = {"YDim", "LatDim","nlat"};
35 
36 // Possible latitude names.
37 const char *HDFEOS2::File::_latfield_names[] = {
38  "Latitude", "Lat","YDim", "LatCenter"
39 };
40 
41 // Possible longitude names.
42 const char *HDFEOS2::File::_lonfield_names[] = {
43  "Longitude", "Lon","XDim", "LonCenter"
44 };
45 
46 // For some grid products, latitude and longitude are put under a special geogrid.
47 // One possible name is "location".
48 const char *HDFEOS2::File::_geogrid_names[] = {"location"};
49 
50 using namespace HDFEOS2;
51 using namespace std;
52 
53 // The following is for generating exception messages.
54 template<typename T, typename U, typename V, typename W, typename X>
55 static void _throw5(const char *fname, int line, int numarg,
56  const T &a1, const U &a2, const V &a3, const W &a4,
57  const X &a5)
58 {
59  ostringstream ss;
60  ss << fname << ":" << line << ":";
61  for (int i = 0; i < numarg; ++i) {
62  ss << " ";
63  switch (i) {
64  case 0: ss << a1; break;
65  case 1: ss << a2; break;
66  case 2: ss << a3; break;
67  case 3: ss << a4; break;
68  case 4: ss << a5; break;
69  }
70  }
71  throw Exception(ss.str());
72 }
73 
75 // number of arguments.
77 #define throw1(a1) _throw5(__FILE__, __LINE__, 1, a1, 0, 0, 0, 0)
78 #define throw2(a1, a2) _throw5(__FILE__, __LINE__, 2, a1, a2, 0, 0, 0)
79 #define throw3(a1, a2, a3) _throw5(__FILE__, __LINE__, 3, a1, a2, a3, 0, 0)
80 #define throw4(a1, a2, a3, a4) _throw5(__FILE__, __LINE__, 4, a1, a2, a3, a4, 0)
81 #define throw5(a1, a2, a3, a4, a5) _throw5(__FILE__, __LINE__, 5, a1, a2, a3, a4, a5)
82 
83 #define assert_throw0(e) do { if (!(e)) throw1("assertion failure"); } while (false)
84 #define assert_range_throw0(e, ge, l) assert_throw0((ge) <= (e) && (e) < (l))
85 
86 // Convenient function used in destructors.
87 struct delete_elem
88 {
89  template<typename T> void operator()(T *ptr)
90  {
91  delete ptr;
92  }
93 };
94 
95 // Destructor for class File.
96 File::~File()
97 {
98  if(gridfd !=-1) {
99  for (vector<GridDataset *>::const_iterator i = grids.begin();
100  i != grids.end(); ++i){
101  delete *i;
102  }
103  // Grid file IDs will be closed in HDF4RequestHandler.cc.
105  }
106 
107  if(swathfd !=-1) {
108  for (vector<SwathDataset *>::const_iterator i = swaths.begin();
109  i != swaths.end(); ++i){
110  delete *i;
111  }
112 
113  //if((SWclose(swathfd))==-1) throw2("swath close",path);
114  }
115 
116  for (vector<PointDataset *>::const_iterator i = points.begin();
117  i != points.end(); ++i){
118  delete *i;
119  }
120 
121 }
122 
124 File * File::Read(const char *path, int32 mygridfd, int32 myswathfd) throw(Exception)
125 {
126 
127  File *file = new File(path);
128 //cerr <<"File is opened" <<endl;
129 
130  file->gridfd = mygridfd;
131  file->swathfd = myswathfd;
132 
133 #if 0
134  // Read information of all Grid objects in this file.
135  if ((file->gridfd = GDopen(const_cast<char *>(file->path.c_str()),
136  DFACC_READ)) == -1) {
137  delete file;
138  throw2("grid open", path);
139  }
140 #endif
141 
142  vector<string> gridlist;
143  if (!Utility::ReadNamelist(file->path.c_str(), GDinqgrid, gridlist)) {
144  delete file;
145  throw2("grid namelist", path);
146  }
147 
148  try {
149  for (vector<string>::const_iterator i = gridlist.begin();
150  i != gridlist.end(); ++i)
151  file->grids.push_back(GridDataset::Read(file->gridfd, *i));
152  }
153  catch(...) {
154  delete file;
155  throw;
156  }
157 
158 #if 0
159  // Read information of all Swath objects in this file
160  if ((file->swathfd = SWopen(const_cast<char *>(file->path.c_str()),
161  DFACC_READ)) == -1){
162  delete file;
163  throw2("swath open", path);
164  }
165 #endif
166 
167  vector<string> swathlist;
168  if (!Utility::ReadNamelist(file->path.c_str(), SWinqswath, swathlist)){
169  delete file;
170  throw2("swath namelist", path);
171  }
172 
173  try {
174  for (vector<string>::const_iterator i = swathlist.begin();
175  i != swathlist.end(); ++i)
176  file->swaths.push_back(SwathDataset::Read(file->swathfd, *i));
177  }
178  catch(...) {
179  delete file;
180  throw;
181  }
182 
183 
184  // We only obtain the name list of point objects but not don't provide
185  // other information of these objects.
186  // The client will only get the name list of point objects.
187  vector<string> pointlist;
188  if (!Utility::ReadNamelist(file->path.c_str(), PTinqpoint, pointlist)){
189  delete file;
190  throw2("point namelist", path);
191  }
192  for (vector<string>::const_iterator i = pointlist.begin();
193  i != pointlist.end(); ++i)
194  file->points.push_back(PointDataset::Read(-1, *i));
195 
196  // If this is not an HDF-EOS2 file, returns exception as false.
197  if(file->grids.size() == 0 && file->swaths.size() == 0
198  && file->points.size() == 0) {
199  Exception e("Not an HDF-EOS2 file");
200  e.setFileType(false);
201  delete file;
202  throw e;
203  }
204  return file;
205 }
206 
207 
208 // A grid's X-dimension can have different names: XDim, LatDim, etc.
209 // This function returns the name of X-dimension which is used in the given file.
210 // For better performance, we check the first grid or swath only.
211 string File::get_geodim_x_name()
212 {
213  if(!_geodim_x_name.empty())
214  return _geodim_x_name;
215  _find_geodim_names();
216  return _geodim_x_name;
217 }
218 
219 // A grid's Y-dimension can have different names: YDim, LonDim, etc.
220 // This function returns the name of Y-dimension which is used in the given file.
221 // For better performance, we check the first grid or swath only.
222 string File::get_geodim_y_name()
223 {
224  if(!_geodim_y_name.empty())
225  return _geodim_y_name;
226  _find_geodim_names();
227  return _geodim_y_name;
228 }
229 
230 // In some cases, values of latitude and longitude are stored in data fields.
231 // Since the latitude field and longitude field do not have unique names
232 // (e.g., latitude field can be "latitude", "Lat", ...),
233 // we need to retrieve the field name.
234 // The following two functions does this job.
235 // For better performance, we check the first grid or swath only.
236 
237 string File::get_latfield_name()
238 {
239  if(!_latfield_name.empty())
240  return _latfield_name;
241  _find_latlonfield_names();
242  return _latfield_name;
243 }
244 
245 string File::get_lonfield_name()
246 {
247  if(!_lonfield_name.empty())
248  return _lonfield_name;
249  _find_latlonfield_names();
250  return _lonfield_name;
251 }
252 
253 // In some cases, a dedicated grid is used to store the values of
254 // latitude and longitude. The following function finds the name
255 // of the geo grid.
256 
257 string File::get_geogrid_name()
258 {
259  if(!_geogrid_name.empty())
260  return _geogrid_name;
261  _find_geogrid_name();
262  return _geogrid_name;
263 }
264 
265 // Internal function used by
266 // get_geodim_x_name and get_geodim_y_name functions.
267 // This function is not intended to be used outside the
268 // get_geodim_x_name and get_geodim_y_name functions.
269 
270 void File::_find_geodim_names()
271 {
272  set<string> geodim_x_name_set;
273  for(size_t i = 0; i<sizeof(_geodim_x_names) / sizeof(const char *); i++)
274  geodim_x_name_set.insert(_geodim_x_names[i]);
275 
276  set<string> geodim_y_name_set;
277  for(size_t i = 0; i<sizeof(_geodim_y_names) / sizeof(const char *); i++)
278  geodim_y_name_set.insert(_geodim_y_names[i]);
279 
280  const size_t gs = grids.size();
281  const size_t ss = swaths.size();
282  for(size_t i=0; ;i++)
283  {
284  Dataset *dataset=NULL;
285  if(i<gs)
286  dataset = static_cast<Dataset*>(grids[i]);
287  else if(i < gs + ss)
288  dataset = static_cast<Dataset*>(swaths[i-gs]);
289  else
290  break;
291 
292  const vector<Dimension *>& dims = dataset->getDimensions();
293  for(vector<Dimension*>::const_iterator it = dims.begin();
294  it != dims.end(); ++it)
295  {
296  if(geodim_x_name_set.find((*it)->getName()) != geodim_x_name_set.end())
297  _geodim_x_name = (*it)->getName();
298  else if(geodim_y_name_set.find((*it)->getName()) != geodim_y_name_set.end())
299  _geodim_y_name = (*it)->getName();
300  }
301  // For performance, we're checking this for the first grid or swath
302  break;
303  }
304  if(_geodim_x_name.empty())
305  _geodim_x_name = _geodim_x_names[0];
306  if(_geodim_y_name.empty())
307  _geodim_y_name = _geodim_y_names[0];
308 }
309 
310 // Internal function used by
311 // get_latfield_name and get_lonfield_name functions.
312 // This function is not intended to be used outside
313 // the get_latfield_name and get_lonfield_name functions.
314 
315 void File::_find_latlonfield_names()
316 {
317  set<string> latfield_name_set;
318  for(size_t i = 0; i<sizeof(_latfield_names) / sizeof(const char *); i++)
319  latfield_name_set.insert(_latfield_names[i]);
320 
321  set<string> lonfield_name_set;
322  for(size_t i = 0; i<sizeof(_lonfield_names) / sizeof(const char *); i++)
323  lonfield_name_set.insert(_lonfield_names[i]);
324 
325  const size_t gs = grids.size();
326  const size_t ss = swaths.size();
327  for(size_t i=0; ;i++)
328  {
329  Dataset *dataset = NULL;
330  SwathDataset *sw = NULL;
331  if(i<gs)
332  dataset = static_cast<Dataset*>(grids[i]);
333  else if(i < gs + ss)
334  {
335  sw = swaths[i-gs];
336  dataset = static_cast<Dataset*>(sw);
337  }
338  else
339  break;
340 
341  const vector<Field *>& fields = dataset->getDataFields();
342  for(vector<Field*>::const_iterator it = fields.begin();
343  it != fields.end(); ++it)
344  {
345  if(latfield_name_set.find((*it)->getName()) != latfield_name_set.end())
346  _latfield_name = (*it)->getName();
347  else if(lonfield_name_set.find((*it)->getName()) != lonfield_name_set.end())
348  _lonfield_name = (*it)->getName();
349  }
350 
351  if(sw)
352  {
353  const vector<Field *>& geofields = dataset->getDataFields();
354  for(vector<Field*>::const_iterator it = geofields.begin();
355  it != geofields.end(); ++it)
356  {
357  if(latfield_name_set.find((*it)->getName()) != latfield_name_set.end())
358  _latfield_name = (*it)->getName();
359  else if(lonfield_name_set.find((*it)->getName()) != lonfield_name_set.end())
360  _lonfield_name = (*it)->getName();
361  }
362  }
363  // For performance, we're checking this for the first grid or swath
364  break;
365  }
366  if(_latfield_name.empty())
367  _latfield_name = _latfield_names[0];
368  if(_lonfield_name.empty())
369  _lonfield_name = _lonfield_names[0];
370 
371 }
372 
373 // Internal function used by
374 // the get_geogrid_name function.
375 // This function is not intended to be used outside the get_geogrid_name function.
376 
377 void File::_find_geogrid_name()
378 {
379  set<string> geogrid_name_set;
380  for(size_t i = 0; i<sizeof(_geogrid_names) / sizeof(const char *); i++)
381  geogrid_name_set.insert(_geogrid_names[i]);
382 
383  const size_t gs = grids.size();
384  const size_t ss = swaths.size();
385  for(size_t i=0; ;i++)
386  {
387  Dataset *dataset;
388  if(i<gs)
389  dataset = static_cast<Dataset*>(grids[i]);
390  else if(i < gs + ss)
391  dataset = static_cast<Dataset*>(swaths[i-gs]);
392  else
393  break;
394 
395  if(geogrid_name_set.find(dataset->getName()) != geogrid_name_set.end())
396  _geogrid_name = dataset->getName();
397  }
398  if(_geogrid_name.empty())
399  _geogrid_name = "location";
400 }
401 
402 // Check if we have the dedicated lat/lon grid.
403 void File::check_onelatlon_grids() {
404 
405  // 0. obtain "Latitude","Longitude" and "location" set.
406  string LATFIELDNAME = this->get_latfield_name();
407  string LONFIELDNAME = this->get_lonfield_name();
408 
409  // Now only there is only one geo grid name "location", so don't call it know.
410  string GEOGRIDNAME = "location";
411 
412  //only one lat/lon and it is under GEOGRIDNAME
413  int onellcount = 0;
414 
415  // Check if lat/lon is found under other grids.
416  int morellcount = 0;
417 
418  // Loop through all grids
419  for(vector<GridDataset *>::const_iterator i = this->grids.begin();
420  i != this->grids.end(); ++i){
421 
422  // Loop through all fields
423  for(vector<Field *>::const_iterator j =
424  (*i)->getDataFields().begin();
425  j != (*i)->getDataFields().end(); ++j) {
426  if((*i)->getName()==GEOGRIDNAME){
427  if((*j)->getName()==LATFIELDNAME){
428  onellcount++;
429  (*i)->latfield = *j;
430  }
431  if((*j)->getName()==LONFIELDNAME){
432  onellcount++;
433  (*i)->lonfield = *j;
434  }
435  if(onellcount == 2)
436  break;//Finish this grid
437  }
438  else {// Here we assume that lat and lon are always in pairs.
439  if(((*j)->getName()==LATFIELDNAME)||((*j)->getName()==LONFIELDNAME)){
440  (*i)->ownllflag = true;
441  morellcount++;
442  break;
443  }
444  }
445  }
446  }
447 
448  if(morellcount ==0 && onellcount ==2)
449  this->onelatlon = true;
450 }
451 
452 // For one grid, need to handle the third-dimension(both existing and missing) coordinate variables
453 void File::handle_one_grid_zdim(GridDataset* gdset) {
454 
455  // Obtain "XDim","YDim"
456  string DIMXNAME = this->get_geodim_x_name();
457  string DIMYNAME = this->get_geodim_y_name();
458 
459  bool missingfield_unlim_flag = false;
460  Field *missingfield_unlim = NULL;
461 
462  // This is a big assumption, it may be wrong since not every 1-D field
463  // with the third dimension(name and size) is a coordinate
464  // variable. We have to watch the products we've supported. KY 2012-6-13
465 
466  // Unique 1-D field's dimension name list.
467  set<string> tempdimlist;
468  pair<set<string>::iterator,bool> tempdimret;
469 
470  for (vector<Field *>::const_iterator j =
471  gdset->getDataFields().begin();
472  j != gdset->getDataFields().end(); ++j) {
473 
474  //We only need to search those 1-D fields
475  if ((*j)->getRank()==1){
476 
477  // DIMXNAME and DIMYNAME correspond to latitude and longitude.
478  // They should NOT be treated as dimension names missing fields. It will be handled differently.
479  if(((*j)->getDimensions())[0]->getName()!=DIMXNAME && ((*j)->getDimensions())[0]->getName()!=DIMYNAME){
480 
481  tempdimret = tempdimlist.insert(((*j)->getDimensions())[0]->getName());
482 
483  // Kent: The following implementation may not be always right. This essentially is the flaw of the
484  // data product if a file encounters this case. Only unique 1-D third-dimension field should be provided.
485  // Only pick up the first 1-D field that the third-dimension
486  if(tempdimret.second == true) {
487 
488  HDFCFUtil::insert_map(gdset->dimcvarlist, ((*j)->getDimensions())[0]->getName(),
489  (*j)->getName());
490 //cerr<<"dimension name "<<((*j)->getDimensions())[0]->getName() <<endl;
491 //cerr<<"variable name "<<(*j)->getName() <<endl;
492  (*j)->fieldtype = 3;
493  if((*j)->getName() == "Time")
494  (*j)->fieldtype = 5;// IDV can handle 4-D fields when the 4th dim is Time.
495  }
496  }
497  }
498  }
499 
500  // Add the missing Z-dimension field.
501  // Some dimension name's corresponding fields are missing,
502  // so add the missing Z-dimension fields based on the dimension names. When the real
503  // data is read, nature number 1,2,3,.... will be filled!
504  // NOTE: The latitude and longitude dim names are not handled yet.
505 
506  // The above handling is also based on a big assumption. This is the best the
507  // handler can do without having the extra information outside the HDF-EOS2 file. KY 2012-6-12
508  // Loop through all dimensions of this grid.
509  for (vector<Dimension *>::const_iterator j =
510  gdset->getDimensions().begin(); j!= gdset->getDimensions().end();++j){
511 
512  // Don't handle DIMXNAME and DIMYNAME yet.
513  if((*j)->getName()!=DIMXNAME && (*j)->getName()!=DIMYNAME){
514 
515  // This dimension needs a field
516  if((tempdimlist.find((*j)->getName())) == tempdimlist.end()){
517 
518  // Need to create a new data field vector element with the name and dimension as above.
519  Field *missingfield = new Field();
520  missingfield->name = (*j)->getName();
521  missingfield->rank = 1;
522 
523  //This is an HDF constant.the data type is always integer.
524  missingfield->type = DFNT_INT32;
525 
526  // Dimension of the missing field
527  Dimension *dim = new Dimension((*j)->getName(),(*j)->getSize());
528 
529  // only 1 dimension
530  missingfield->dims.push_back(dim);
531 
532  // Provide information for the missing data, since we need to calculate the data, so
533  // the information is different than a normal field.
534  //int missingdatarank =1;
535  //int missingdatatypesize = 4;
536  int missingdimsize[1];
537  missingdimsize[0]= (*j)->getSize();
538  if(0 == (*j)->getSize()) {
539 //cerr<<"missing field name is "<<missingfield->getName() << " dimension name is "<< dim->name <<endl;
540  missingfield_unlim_flag = true;
541  missingfield_unlim = missingfield;
542  }
543 
544 
545  // added Z-dimension coordinate variable with nature number
546  missingfield->fieldtype = 4;
547 
548  // input data is empty now. We need to review this approach in the future.
549  // The data will be retrieved in HDFEOS2ArrayMissGeoField.cc. KY 2013-06-14
550 // LightVector<char>inputdata;
551 // missingfield->data = NULL;
552  //missingfield->data = new MissingFieldData(missingdatarank,missingdatatypesize,missingdimsize,inputdata);
553  // The data will be handled separately, we don't need to provide data.
554  gdset->datafields.push_back(missingfield);
555  HDFCFUtil::insert_map(gdset->dimcvarlist, (missingfield->getDimensions())[0]->getName(),
556  missingfield->name);
557 
558  }
559  }
560  }
561 
562  //Correct the unlimited dimension size.
563  if(true == missingfield_unlim_flag) {
564  for (vector<Field *>::const_iterator i =
565  gdset->getDataFields().begin();
566  i != gdset->getDataFields().end(); ++i) {
567 
568  for (vector<Dimension *>::const_iterator j =
569  gdset->getDimensions().begin(); j!= gdset->getDimensions().end();++j){
570 
571  if((*j)->getName() == (missingfield_unlim->getDimensions())[0]->getName()) {
572  if((*j)->getSize()!= 0) {
573  Dimension *dim = missingfield_unlim->getDimensions()[0];
574  dim->dimsize = (*j)->getSize();
575  missingfield_unlim_flag = false;
576  break;
577  }
578  }
579 
580  if(false == missingfield_unlim_flag)
581  break;
582  }
583  if(false == missingfield_unlim_flag)
584  break;
585  }
586  }
587 
588 }
589 
590 // For one grid, need to handle lat/lon(both existing lat/lon and calculated lat/lon from EOS2 APIs)
591 void File::handle_one_grid_latlon(GridDataset* gdset) throw(Exception)
592 {
593 
594  // Obtain "XDim","YDim","Latitude","Longitude"
595  string DIMXNAME = this->get_geodim_x_name();
596  string DIMYNAME = this->get_geodim_y_name();
597 
598  string LATFIELDNAME = this->get_latfield_name();
599  string LONFIELDNAME = this->get_lonfield_name();
600 
601 
602  // This grid has its own latitude/longitude
603  if(gdset->ownllflag) {
604 
605  // Searching the lat/lon field from the grid.
606  for (vector<Field *>::const_iterator j =
607  gdset->getDataFields().begin();
608  j != gdset->getDataFields().end(); ++j) {
609 
610  if((*j)->getName() == LATFIELDNAME) {
611 
612  // set the flag to tell if this is lat or lon.
613  // The unit will be different for lat and lon.
614  (*j)->fieldtype = 1;
615 
616  // Latitude rank should not be greater than 2.
617  // Here I don't check if the rank of latitude is the same as the longitude.
618  // Hopefully it never happens for HDF-EOS2 cases.
619  // We are still investigating if Java clients work
620  // when the rank of latitude and longitude is greater than 2.
621  if((*j)->getRank() > 2)
622  throw3("The rank of latitude is greater than 2",
623  gdset->getName(),(*j)->getName());
624 
625  if((*j)->getRank() != 1) {
626 
627  // Obtain the major dim. For most cases, it is YDim Major.
628  // But still need to watch out the rare cases.
629  (*j)->ydimmajor = gdset->getCalculated().isYDimMajor();
630 
631  // If the 2-D lat/lon can be condensed to 1-D.
632  // For current HDF-EOS2 files, only GEO and CEA can be condensed.
633  // To gain performance,
634  // we don't check the real latitude values.
635  int32 projectioncode = gdset->getProjection().getCode();
636  if(projectioncode == GCTP_GEO || projectioncode ==GCTP_CEA) {
637  (*j)->condenseddim = true;
638  }
639 
640  // Now we want to handle the dim and the var lists.
641  // If the lat/lon can be condensed to 1-D array,
642  // COARD convention needs to be followed.
643  // Since COARD requires that the dimension name of lat/lon is the same as the field name of lat/lon,
644  // we still need to handle this case in the later step(in function handle_grid_coards).
645 
646  // If the 2-D array can be condensed to a 1-D array.
647  if((*j)->condenseddim) {
648 
649  // Regardless of dimension major, always lat->YDim, lon->XDim;
650  // We don't need to adjust the dimension rank.
651  for (vector<Dimension *>::const_iterator k =
652  (*j)->getDimensions().begin(); k!= (*j)->getDimensions().end();++k){
653  if((*k)->getName() == DIMYNAME) {
654  HDFCFUtil::insert_map(gdset->dimcvarlist, (*k)->getName(), (*j)->getName());
655  }
656  }
657  }
658 
659  // 2-D lat/lon case. Since dimension order doesn't matter, so we always assume lon->XDim, lat->YDim.
660  else {
661  for (vector<Dimension *>::const_iterator k =
662  (*j)->getDimensions().begin(); k!= (*j)->getDimensions().end();++k){
663  if((*k)->getName() == DIMYNAME) {
664  HDFCFUtil::insert_map(gdset->dimcvarlist, (*k)->getName(), (*j)->getName());
665  }
666  }
667  }
668  }
669  // This is the 1-D case, just inserting the dimension, field pair.
670  else {
671  HDFCFUtil::insert_map(gdset->dimcvarlist, (((*j)->getDimensions())[0])->getName(),
672  (*j)->getName());
673  }
674  }
675  else if ((*j)->getName() == LONFIELDNAME) {
676 
677  // set the flag to tell if this is lat or lon. The unit will be different for lat and lon.
678  (*j)->fieldtype = 2;
679 
680  // longitude rank should not be greater than 2.
681  // Here I don't check if the rank of latitude and longitude is the same.
682  // Hopefully it never happens for HDF-EOS2 cases.
683  // We are still investigating if Java clients work when the rank of latitude and longitude is greater than 2.
684  if((*j)->getRank() >2)
685  throw3("The rank of Longitude is greater than 2",gdset->getName(),(*j)->getName());
686 
687  if((*j)->getRank() != 1) {
688 
689  // Obtain the major dim. For most cases, it is YDim Major. But still need to check for rare cases.
690  (*j)->ydimmajor = gdset->getCalculated().isYDimMajor();
691 
692  // If the 2-D lat/lon can be condensed to 1-D.
693  //For current HDF-EOS2 files, only GEO and CEA can be condensed. To gain performance,
694  // we don't check with real values.
695  int32 projectioncode = gdset->getProjection().getCode();
696  if(projectioncode == GCTP_GEO || projectioncode ==GCTP_CEA) {
697  (*j)->condenseddim = true;
698  }
699 
700  // Now we want to handle the dim and the var lists.
701  // If the lat/lon can be condensed to 1-D array, COARD convention needs to be followed.
702  // Since COARD requires that the dimension name of lat/lon is the same as the field name of lat/lon,
703  // we still need to handle this case at last.
704 
705  // Can be condensed to 1-D array.
706  if((*j)->condenseddim) {
707 
708  // Regardless of dimension major, the EOS convention is always lat->YDim, lon->XDim;
709  // We don't need to adjust the dimension rank.
710  for (vector<Dimension *>::const_iterator k =
711  (*j)->getDimensions().begin(); k!= (*j)->getDimensions().end();++k){
712  if((*k)->getName() == DIMXNAME) {
713  HDFCFUtil::insert_map(gdset->dimcvarlist, (*k)->getName(), (*j)->getName());
714  }
715  }
716  }
717  // 2-D lat/lon case. Since dimension order doesn't matter, so we always assume lon->XDim, lat->YDim.
718  else {
719  for (vector<Dimension *>::const_iterator k =
720  (*j)->getDimensions().begin(); k!= (*j)->getDimensions().end();++k){
721  if((*k)->getName() == DIMXNAME) {
722  HDFCFUtil::insert_map(gdset->dimcvarlist, (*k)->getName(), (*j)->getName());
723  }
724  }
725  }
726  }
727  // This is the 1-D case, just inserting the dimension, field pair.
728  else {
729  HDFCFUtil::insert_map(gdset->dimcvarlist, (((*j)->getDimensions())[0])->getName(),
730  (*j)->getName());
731  }
732  }
733  }
734  }
735  else { // this grid's lat/lon has to be calculated.
736 
737  // Latitude and Longitude
738  Field *latfield = new Field();
739  Field *lonfield = new Field();
740 
741  latfield->name = LATFIELDNAME;
742  lonfield->name = LONFIELDNAME;
743 
744  // lat/lon is a 2-D array
745  latfield->rank = 2;
746  lonfield->rank = 2;
747 
748  // The data type is always float64. DFNT_FLOAT64 is the equivalent float64 type.
749  latfield->type = DFNT_FLOAT64;
750  lonfield->type = DFNT_FLOAT64;
751 
752  // Latitude's fieldtype is 1
753  latfield->fieldtype = 1;
754 
755  // Longitude's fieldtype is 2
756  lonfield->fieldtype = 2;
757 
758  // Check if YDim is the major order.
759  // Obtain the major dim. For most cases, it is YDim Major. But some cases may be not. Still need to check.
760  latfield->ydimmajor = gdset->getCalculated().isYDimMajor();
761  lonfield->ydimmajor = latfield->ydimmajor;
762 
763  // Obtain XDim and YDim size.
764  int xdimsize = gdset->getInfo().getX();
765  int ydimsize = gdset->getInfo().getY();
766 
767  // Add dimensions. If it is YDim major,the dimension name list is "YDim XDim", otherwise, it is "XDim YDim".
768  // For LAMAZ projection, Y dimension is always supposed to be major for calculating lat/lon,
769  // but for dimension order, it should be consistent with data fields. (LD -2012/01/16
770  bool dmajor=(gdset->getProjection().getCode()==GCTP_LAMAZ)? gdset->getCalculated().DetectFieldMajorDimension()
771  : latfield->ydimmajor;
772  //bool dmajor = latfield->ydimmajor;
773 
774  if(dmajor) {
775  Dimension *dimlaty = new Dimension(DIMYNAME,ydimsize);
776  latfield->dims.push_back(dimlaty);
777  Dimension *dimlony = new Dimension(DIMYNAME,ydimsize);
778  lonfield->dims.push_back(dimlony);
779  Dimension *dimlatx = new Dimension(DIMXNAME,xdimsize);
780  latfield->dims.push_back(dimlatx);
781  Dimension *dimlonx = new Dimension(DIMXNAME,xdimsize);
782  lonfield->dims.push_back(dimlonx);
783  }
784  else {
785  Dimension *dimlatx = new Dimension(DIMXNAME,xdimsize);
786  latfield->dims.push_back(dimlatx);
787  Dimension *dimlonx = new Dimension(DIMXNAME,xdimsize);
788  lonfield->dims.push_back(dimlonx);
789  Dimension *dimlaty = new Dimension(DIMYNAME,ydimsize);
790  latfield->dims.push_back(dimlaty);
791  Dimension *dimlony = new Dimension(DIMYNAME,ydimsize);
792  lonfield->dims.push_back(dimlony);
793  }
794 
795  // Obtain info upleft and lower right for special longitude.
796  float64* upleft;
797  float64* lowright;
798  upleft = const_cast<float64 *>(gdset->getInfo().getUpLeft());
799  lowright = const_cast<float64 *>(gdset->getInfo().getLowRight());
800 
801  // SOme special longitude is from 0 to 360.We need to check this case.
802  int32 projectioncode = gdset->getProjection().getCode();
803  if(((int)lowright[0]>180000000) && ((int)upleft[0]>-1)) {
804  // We can only handle geographic projection now.
805  // This is the only case we can handle.
806  if(projectioncode == GCTP_GEO) // Will handle when data is read.
807  lonfield->speciallon = true;
808  }
809 
810  // Some MODIS MCD files don't follow standard format for lat/lon (DDDMMMSSS);
811  // they simply represent lat/lon as -180.0000000 or -90.000000.
812  // HDF-EOS2 library won't give the correct value based on these value.
813  // These need to be remembered and resumed to the correct format when retrieving the data.
814  // Since so far we haven't found region of satellite files is within 0.1666 degree(1 minute)
815  // so, we divide the corner coordinate by 1000 and see if the integral part is 0.
816  // If it is 0, we know this file uses special lat/lon coordinate.
817 
818  if(((int)(lowright[0]/1000)==0) &&((int)(upleft[0]/1000)==0)
819  && ((int)(upleft[1]/1000)==0) && ((int)(lowright[1]/1000)==0)) {
820  if(projectioncode == GCTP_GEO){
821  lonfield->specialformat = 1;
822  latfield->specialformat = 1;
823  }
824  }
825 
826  // Some TRMM CERES Grid Data have "default" to be set for the corner coordinate,
827  // which they really mean for the whole globe(-180 - 180 lon and -90 - 90 lat).
828  // We will remember the information and change
829  // those values when we read the lat and lon.
830 
831  if(((int)(lowright[0])==0) &&((int)(upleft[0])==0)
832  && ((int)(upleft[1])==0) && ((int)(lowright[1])==0)) {
833  if(projectioncode == GCTP_GEO){
834  lonfield->specialformat = 2;
835  latfield->specialformat = 2;
836  gdset->addfvalueattr = true;
837  }
838  }
839 
840  //One MOD13C2 file doesn't provide projection code
841  // The upperleft and lowerright coordinates are all -1
842  // We have to calculate lat/lon by ourselves.
843  // Since it doesn't provide the project code, we double check their information
844  // and find that it covers the whole globe with 0.05 degree resolution.
845  // Lat. is from 90 to -90 and Lon is from -180 to 180.
846 
847  if(((int)(lowright[0])==-1) &&((int)(upleft[0])==-1)
848  && ((int)(upleft[1])==-1) && ((int)(lowright[1])==-1)) {
849  lonfield->specialformat = 3;
850  latfield->specialformat = 3;
851  lonfield->condenseddim = true;
852  latfield->condenseddim = true;
853  }
854 
855 
856  // We need to handle SOM projection in a different way.
857  if(GCTP_SOM == projectioncode) {
858  lonfield->specialformat = 4;
859  latfield->specialformat = 4;
860  }
861 
862  // Check if the 2-D lat/lon can be condensed to 1-D.
863  //For current HDF-EOS2 files, only GEO and CEA can be condensed. To gain performance,
864  // we just check the projection code, don't check with real values.
865  if(projectioncode == GCTP_GEO || projectioncode ==GCTP_CEA) {
866  lonfield->condenseddim = true;
867  latfield->condenseddim = true;
868  }
869 
870 #if 0
871  // Cache
872  // Check if a BES key H4.EnableEOSGeoCacheFile is true, if yes, we will check
873  // if a lat/lon cache file exists for this lat/lon.
874  string check_eos_geo_cache_key = "H4.EnableEOSGeoCacheFile";
875  bool enable_eos_geo_cache_key = false;
876  enable_eos_geo_cache_key = HDFCFUtil::check_beskeys(check_eos_geo_cache_key);
877  if(true == enable_eos_geo_cache_key) {
878  // Build the cache file name based on the projection parameters.
879  string cache_fname;
880 
881  // Projection code, zone,sphere,pix,origin
882  cache_fname =HDFCFUtil::get_int_str(gdset->getProjection().getCode());
883  cache_fname +=HDFCFUtil::get_int_str(gdset->getProjection().getZone());
884  cache_fname +=HDFCFUtil::get_int_str(gdset->getProjection().getSphere());
885  cache_fname +=HDFCFUtil::get_int_str(gdset->getProjection().getPix());
886  cache_fname +=HDFCFUtil::get_int_str(gdset->getProjection().getOrigin());
887 
888 
889  // Xdim size, ydim size
890  if(dmajor) {
891  cache_fname +=HDFCFUtil::get_int_str(ydimsize);
892  cache_fname +=HDFCFUtil::get_int_str(xdimsize);
893  }
894  else {
895  cache_fname +=HDFCFUtil::get_int_str(xdimsize);
896  cache_fname +=HDFCFUtil::get_int_str(ydimsize);
897  }
898 
899 
900  // upleft,lowright
901  cache_fname +=HDFCFUtil::get_double_str(upleft[0],17,6);
902  cache_fname +=HDFCFUtil::get_double_str(upleft[1],17,6);
903  cache_fname +=HDFCFUtil::get_double_str(lowright[0],17,6);
904  cache_fname +=HDFCFUtil::get_double_str(lowright[1],17,6);
905 
906 
907  // obtain param
908  float64* params;
909  params = const_cast<float64 *>(gdset->getProjection().getParam());
910  // According to HDF-EOS2 document, only 13 parameters are used.
911  //for(int ipar = 0; ipar<16;ipar++)
912  for(int ipar = 0; ipar<13;ipar++)
913  cache_fname+=HDFCFUtil::get_double_str(params[ipar],17,6);
914 //cerr<<"cache_fname is "<<cache_fname <<endl;
915 
916  // Check if this cache file exists and the file size, then set the flag.
917  // 0: The file doesn't exist. 1: The file size is not the same as the lat/lon size.
918  // 2: The file size is the same as the lat/lon size.
919 
920  // Check the status of the file
921  struct stat st;
922  string cache_fpath = "/tmp/"+cache_fname;
923  int result = stat(cache_fpath.c_str(), &st);
924  if(result == 0){
925  int actual_file_size = st.st_size;
926 cerr<<"HDF-EOS2 actual_file_size is "<<actual_file_size <<endl;
927  int expected_file_size = 0;
928  if(gdset->getProjection().getCode() == GCTP_SOM)
929  expected_file_size = xdimsize*ydimsize*2*sizeof(double)*NBLOCK;
930  else if(gdset->getProjection().getCode() == GCTP_CEA ||
931  gdset->getProjection().getCode() == GCTP_GEO)
932  expected_file_size = (xdimsize+ydimsize)*sizeof(double);
933  else
934  expected_file_size = xdimsize*ydimsize*2*sizeof(double);
935 
936 cerr<<"HDF-EOS2 expected_file_size is "<<expected_file_size <<endl;
937  if(actual_file_size != expected_file_size){
938 cerr<<"field_cache is 1 "<<endl;
939  lonfield->field_cache = 1;
940  latfield->field_cache = 1;
941  }
942  else {
943 cerr<<"field cache is 2 "<<endl;
944  lonfield->field_cache = 2;
945  latfield->field_cache = 2;
946  }
947  }
948 
949 
950  //FILE* pFile;
951  //pFile = fopen(cache_fname.c_str(),"rb");
952  // struct stat st;
953  // int result = stat(filename, &st);
954 
955 
956  }
957 #endif
958 
959 
960  // Add latitude and longitude fields to the field list.
961  gdset->datafields.push_back(latfield);
962  gdset->datafields.push_back(lonfield);
963 
964  // Now we want to handle the dim and the var lists.
965  // If the lat/lon can be condensed to 1-D array, COARD convention needs to be followed.
966  // Since COARD requires that the dimension name of lat/lon is the same as the field name of lat/lon,
967  // we still need to handle this case later(function handle_grid_coards).
968 
969  // Can be condensed to 1-D array.
970  if(lonfield->condenseddim) {
971 
972  // lat->YDim, lon->XDim;
973  // We don't need to adjust the dimension rank.
974  for (vector<Dimension *>::const_iterator j =
975  lonfield->getDimensions().begin(); j!= lonfield->getDimensions().end();++j){
976 
977  if((*j)->getName() == DIMXNAME) {
978  HDFCFUtil::insert_map(gdset->dimcvarlist, (*j)->getName(), lonfield->getName());
979  }
980 
981  if((*j)->getName() == DIMYNAME) {
982  HDFCFUtil::insert_map(gdset->dimcvarlist, (*j)->getName(), latfield->getName());
983  }
984  }
985  }
986  else {// 2-D lat/lon case. Since dimension order doesn't matter, so we always assume lon->XDim, lat->YDim.
987  for (vector<Dimension *>::const_iterator j =
988  lonfield->getDimensions().begin(); j!= lonfield->getDimensions().end();++j){
989 
990  if((*j)->getName() == DIMXNAME){
991  HDFCFUtil::insert_map(gdset->dimcvarlist, (*j)->getName(), lonfield->getName());
992  }
993 
994  if((*j)->getName() == DIMYNAME){
995  HDFCFUtil::insert_map(gdset->dimcvarlist, (*j)->getName(), latfield->getName());
996  }
997  }
998  }
999  }
1000 
1001 }
1002 
1003 // For the case of which all grids have one dedicated lat/lon grid,
1004 // this function shows how to handle lat/lon fields.
1005 void File::handle_onelatlon_grids() throw(Exception) {
1006 
1007  // Obtain "XDim","YDim","Latitude","Longitude" and "location" set.
1008  string DIMXNAME = this->get_geodim_x_name();
1009  string DIMYNAME = this->get_geodim_y_name();
1010  string LATFIELDNAME = this->get_latfield_name();
1011  string LONFIELDNAME = this->get_lonfield_name();
1012 
1013  // Now only there is only one geo grid name "location", so don't call it know.
1014  // string GEOGRIDNAME = this->get_geogrid_name();
1015  string GEOGRIDNAME = "location";
1016 
1017  //Dimension name and the corresponding field name when only one lat/lon is used for all grids.
1018  map<string,string>temponelatlondimcvarlist;
1019 
1020  // First we need to obtain dimcvarlist for the grid that contains lat/lon.
1021  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1022  i != this->grids.end(); ++i){
1023 
1024  // Set the horizontal dimension name "dimxname" and "dimyname"
1025  // This will be used to detect the dimension major order.
1026  (*i)->setDimxName(DIMXNAME);
1027  (*i)->setDimyName(DIMYNAME);
1028 
1029  // Handle lat/lon. Note that other grids need to point to this lat/lon.
1030  if((*i)->getName()==GEOGRIDNAME) {
1031 
1032  // Figure out dimension order,2D or 1D for lat/lon
1033  // if lat/lon field's pointed value is changed, the value of the lat/lon field is also changed.
1034  // set the flag to tell if this is lat or lon. The unit will be different for lat and lon.
1035  (*i)->lonfield->fieldtype = 2;
1036  (*i)->latfield->fieldtype = 1;
1037 
1038  // latitude and longitude rank must be equal and should not be greater than 2.
1039  if((*i)->lonfield->rank >2 || (*i)->latfield->rank >2)
1040  throw2("Either the rank of lat or the lon is greater than 2",(*i)->getName());
1041  if((*i)->lonfield->rank !=(*i)->latfield->rank)
1042  throw2("The rank of the latitude is not the same as the rank of the longitude",(*i)->getName());
1043 
1044  // For 2-D lat/lon arrays
1045  if((*i)->lonfield->rank != 1) {
1046 
1047  // Obtain the major dim. For most cases, it is YDim Major.
1048  //But for some cases it is not. So still need to check.
1049  (*i)->lonfield->ydimmajor = (*i)->getCalculated().isYDimMajor();
1050  (*i)->latfield->ydimmajor = (*i)->lonfield->ydimmajor;
1051 
1052  // Check if the 2-D lat/lon can be condensed to 1-D.
1053  //For current HDF-EOS2 files, only GEO and CEA can be condensed. To gain performance,
1054  // we just check the projection code, don't check the real values.
1055  int32 projectioncode = (*i)->getProjection().getCode();
1056  if(projectioncode == GCTP_GEO || projectioncode ==GCTP_CEA) {
1057  (*i)->lonfield->condenseddim = true;
1058  (*i)->latfield->condenseddim = true;
1059  }
1060 
1061  // Now we want to handle the dim and the var lists.
1062  // If the lat/lon can be condensed to 1-D array, COARD convention needs to be followed.
1063  // Since COARD requires that the dimension name of lat/lon is the same as the field name of lat/lon,
1064  // we still need to handle this case later(function handle_grid_coards). Now we do the first step.
1065  if((*i)->lonfield->condenseddim) {
1066 
1067  // can be condensed to 1-D array.
1068  //regardless of YDim major or XDim major,,always lat->YDim, lon->XDim;
1069  // We still need to remember the dimension major when we calculate the data.
1070  // We don't need to adjust the dimension rank.
1071  for (vector<Dimension *>::const_iterator j =
1072  (*i)->lonfield->getDimensions().begin(); j!= (*i)->lonfield->getDimensions().end();++j){
1073  if((*j)->getName() == DIMXNAME) {
1074  HDFCFUtil::insert_map((*i)->dimcvarlist, (*j)->getName(),
1075  (*i)->lonfield->getName());
1076  }
1077  if((*j)->getName() == DIMYNAME) {
1078  HDFCFUtil::insert_map((*i)->dimcvarlist, (*j)->getName(),
1079  (*i)->latfield->getName());
1080  }
1081  }
1082  }
1083 
1084  // 2-D lat/lon case. Since dimension order doesn't matter, so we always assume lon->XDim, lat->YDim.
1085  else {
1086  for (vector<Dimension *>::const_iterator j =
1087  (*i)->lonfield->getDimensions().begin(); j!= (*i)->lonfield->getDimensions().end();++j){
1088  if((*j)->getName() == DIMXNAME) {
1089  HDFCFUtil::insert_map((*i)->dimcvarlist, (*j)->getName(),
1090  (*i)->lonfield->getName());
1091  }
1092  if((*j)->getName() == DIMYNAME) {
1093  HDFCFUtil::insert_map((*i)->dimcvarlist, (*j)->getName(),
1094  (*i)->latfield->getName());
1095  }
1096  }
1097  }
1098 
1099  }
1100  else { // This is the 1-D case, just inserting the dimension, field pair.
1101  HDFCFUtil::insert_map((*i)->dimcvarlist, ((*i)->lonfield->getDimensions())[0]->getName(),
1102  (*i)->lonfield->getName());
1103  HDFCFUtil::insert_map((*i)->dimcvarlist, ((*i)->latfield->getDimensions())[0]->getName(),
1104  (*i)->latfield->getName());
1105  }
1106  temponelatlondimcvarlist = (*i)->dimcvarlist;
1107  break;
1108 
1109  }
1110 
1111  }
1112 
1113  // Now we need to assign the dim->cvar relation for lat/lon(xdim->lon,ydim->lat) to grids that don't contain lat/lon
1114  for(vector<GridDataset *>::const_iterator i = this->grids.begin();
1115  i != this->grids.end(); ++i){
1116 
1117  string templatlonname1;
1118  string templatlonname2;
1119 
1120  if((*i)->getName() != GEOGRIDNAME) {
1121 
1122  map<string,string>::iterator tempmapit;
1123 
1124  // Find DIMXNAME field
1125  tempmapit = temponelatlondimcvarlist.find(DIMXNAME);
1126  if(tempmapit != temponelatlondimcvarlist.end())
1127  templatlonname1= tempmapit->second;
1128  else
1129  throw2("cannot find the dimension field of XDim", (*i)->getName());
1130 
1131  HDFCFUtil::insert_map((*i)->dimcvarlist, DIMXNAME, templatlonname1);
1132 
1133  // Find DIMYNAME field
1134  tempmapit = temponelatlondimcvarlist.find(DIMYNAME);
1135  if(tempmapit != temponelatlondimcvarlist.end())
1136  templatlonname2= tempmapit->second;
1137  else
1138  throw2("cannot find the dimension field of YDim", (*i)->getName());
1139  HDFCFUtil::insert_map((*i)->dimcvarlist, DIMYNAME, templatlonname2);
1140  }
1141  }
1142 
1143 }
1144 
1145 // Handle the dimension name to coordinate variable map for grid.
1146 void File::handle_grid_dim_cvar_maps() throw(Exception) {
1147 
1148  // Obtain "XDim","YDim","Latitude","Longitude" and "location" set.
1149  string DIMXNAME = this->get_geodim_x_name();
1150 
1151  string DIMYNAME = this->get_geodim_y_name();
1152 
1153  string LATFIELDNAME = this->get_latfield_name();
1154 
1155  string LONFIELDNAME = this->get_lonfield_name();
1156 
1157 
1158  // Now only there is only one geo grid name "location", so don't call it know.
1159  // string GEOGRIDNAME = this->get_geogrid_name();
1160  string GEOGRIDNAME = "location";
1161 
1165 
1166  // 1. Handle name clashings
1167  // 1.1 build up a temp. name list
1168  // Note here: we don't include grid and swath names(simply (*j)->name) due to the products we observe
1169  // Adding the grid/swath names makes the names artificially long. Will check user's feedback
1170  // and may change them later. KY 2012-6-25
1171  // The above assumption is purely for practical reason. Field names for all NASA multi-grid/swath products
1172  // (AIRS, AMSR-E, some MODIS, MISR) can all be distinguished regardless of grid/swath names. However,
1173  // this needs to be carefully watched out. KY 2013-07-08
1174  vector <string> tempfieldnamelist;
1175  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1176  i != this->grids.end(); ++i) {
1177  for (vector<Field *>::const_iterator j = (*i)->getDataFields().begin();
1178  j!= (*i)->getDataFields().end(); ++j) {
1179  tempfieldnamelist.push_back(HDFCFUtil::get_CF_string((*j)->name));
1180  }
1181  }
1182  HDFCFUtil::Handle_NameClashing(tempfieldnamelist);
1183 
1184  // 2. Create a map for dimension field name <original field name, corrected field name>
1185  // Also assure the uniqueness of all field names,save the new field names.
1186 
1187  //the original dimension field name to the corrected dimension field name
1188  map<string,string>tempncvarnamelist;
1189  string tempcorrectedlatname, tempcorrectedlonname;
1190 
1191  int total_fcounter = 0;
1192 
1193  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1194  i != this->grids.end(); ++i){
1195 
1196  // Here we can't use getDataFields call since for no lat/lon fields
1197  // are created for one global lat/lon case. We have to use the dimcvarnamelist
1198  // map we just created.
1199  for (vector<Field *>::const_iterator j =
1200  (*i)->getDataFields().begin();
1201  j != (*i)->getDataFields().end(); ++j)
1202  {
1203  (*j)->newname = tempfieldnamelist[total_fcounter];
1204  total_fcounter++;
1205 
1206  // If this field is a dimension field, save the name/new name pair.
1207  if((*j)->fieldtype!=0) {
1208 
1209  tempncvarnamelist.insert(make_pair((*j)->getName(), (*j)->newname));
1210 
1211  // For one latlon case, remember the corrected latitude and longitude field names.
1212  if((this->onelatlon)&&(((*i)->getName())==GEOGRIDNAME)) {
1213  if((*j)->getName()==LATFIELDNAME)
1214  tempcorrectedlatname = (*j)->newname;
1215  if((*j)->getName()==LONFIELDNAME)
1216  tempcorrectedlonname = (*j)->newname;
1217  }
1218  }
1219  }
1220 
1221  (*i)->ncvarnamelist = tempncvarnamelist;
1222  tempncvarnamelist.clear();
1223  }
1224 
1225  // For one lat/lon case, we have to add the lat/lon field name to other grids.
1226  // We know the original lat and lon names. So just retrieve the corrected lat/lon names from
1227  // the geo grid(GEOGRIDNAME).
1228  if(this->onelatlon) {
1229  for(vector<GridDataset *>::const_iterator i = this->grids.begin();
1230  i != this->grids.end(); ++i){
1231  // Lat/lon names must be in this group.
1232  if((*i)->getName()!=GEOGRIDNAME){
1233  HDFCFUtil::insert_map((*i)->ncvarnamelist, LATFIELDNAME, tempcorrectedlatname);
1234  HDFCFUtil::insert_map((*i)->ncvarnamelist, LONFIELDNAME, tempcorrectedlonname);
1235  }
1236  }
1237  }
1238 
1239  // 3. Create a map for dimension name < original dimension name, corrected dimension name>
1240  map<string,string>tempndimnamelist;//the original dimension name to the corrected dimension name
1241 
1243  vector <string>tempalldimnamelist;
1244  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1245  i != this->grids.end(); ++i)
1246  for (map<string,string>::const_iterator j =
1247  (*i)->dimcvarlist.begin(); j!= (*i)->dimcvarlist.end();++j)
1248  tempalldimnamelist.push_back(HDFCFUtil::get_CF_string((*j).first));
1249 
1250  HDFCFUtil::Handle_NameClashing(tempalldimnamelist);
1251 
1252  // Since DIMXNAME and DIMYNAME are not in the original dimension name list, we use the dimension name,field map
1253  // we just formed.
1254  int total_dcounter = 0;
1255  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1256  i != this->grids.end(); ++i){
1257 
1258  for (map<string,string>::const_iterator j =
1259  (*i)->dimcvarlist.begin(); j!= (*i)->dimcvarlist.end();++j){
1260 
1261  // We have to handle DIMXNAME and DIMYNAME separately.
1262  if((DIMXNAME == (*j).first || DIMYNAME == (*j).first) && (true==(this->onelatlon)))
1263  HDFCFUtil::insert_map(tempndimnamelist, (*j).first,(*j).first);
1264  else
1265  HDFCFUtil::insert_map(tempndimnamelist, (*j).first, tempalldimnamelist[total_dcounter]);
1266  total_dcounter++;
1267  }
1268 
1269  (*i)->ndimnamelist = tempndimnamelist;
1270  tempndimnamelist.clear();
1271  }
1272 }
1273 
1274 // Follow COARDS for grids.
1275 void File::handle_grid_coards() throw(Exception) {
1276 
1277  // Obtain "XDim","YDim","Latitude","Longitude" and "location" set.
1278  string DIMXNAME = this->get_geodim_x_name();
1279  string DIMYNAME = this->get_geodim_y_name();
1280  string LATFIELDNAME = this->get_latfield_name();
1281  string LONFIELDNAME = this->get_lonfield_name();
1282 
1283  // Now only there is only one geo grid name "location", so don't call it know.
1284  // string GEOGRIDNAME = this->get_geogrid_name();
1285  string GEOGRIDNAME = "location";
1286 
1287 
1288  // Revisit the lat/lon fields to check if 1-D COARD convention needs to be followed.
1289  vector<Dimension*> correcteddims;
1290  string tempcorrecteddimname;
1291 
1292  // grid name to the corrected latitude field name
1293  map<string,string> tempnewxdimnamelist;
1294 
1295  // grid name to the corrected longitude field name
1296  map<string,string> tempnewydimnamelist;
1297 
1298  // temporary dimension pointer
1299  Dimension *correcteddim;
1300 
1301  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1302  i != this->grids.end(); ++i){
1303  for (vector<Field *>::const_iterator j =
1304  (*i)->getDataFields().begin();
1305  j != (*i)->getDataFields().end(); ++j) {
1306 
1307  // Now handling COARD cases, since latitude/longitude can be either 1-D or 2-D array.
1308  // So we need to correct both cases.
1309  // 2-D lat to 1-D COARD lat
1310  if((*j)->getName()==LATFIELDNAME && (*j)->getRank()==2 &&(*j)->condenseddim) {
1311 
1312  string templatdimname;
1313  map<string,string>::iterator tempmapit;
1314 
1315  // Find the new name of LATFIELDNAME
1316  tempmapit = (*i)->ncvarnamelist.find(LATFIELDNAME);
1317  if(tempmapit != (*i)->ncvarnamelist.end())
1318  templatdimname= tempmapit->second;
1319  else
1320  throw2("cannot find the corrected field of Latitude", (*i)->getName());
1321 
1322  for(vector<Dimension *>::const_iterator k =(*j)->getDimensions().begin();
1323  k!=(*j)->getDimensions().end();++k){
1324 
1325  // Since hhis is the latitude, we create the corrected dimension with the corrected latitude field name
1326  // latitude[YDIM]->latitude[latitude]
1327  if((*k)->getName()==DIMYNAME) {
1328  correcteddim = new Dimension(templatdimname,(*k)->getSize());
1329  correcteddims.push_back(correcteddim);
1330  (*j)->setCorrectedDimensions(correcteddims);
1331  HDFCFUtil::insert_map(tempnewydimnamelist, (*i)->getName(), templatdimname);
1332  }
1333  }
1334  (*j)->iscoard = true;
1335  (*i)->iscoard = true;
1336  if(this->onelatlon)
1337  this->iscoard = true;
1338 
1339  // Clear the local temporary vector
1340  correcteddims.clear();
1341  }
1342 
1343  // 2-D lon to 1-D COARD lon
1344  else if((*j)->getName()==LONFIELDNAME && (*j)->getRank()==2 &&(*j)->condenseddim){
1345 
1346  string templondimname;
1347  map<string,string>::iterator tempmapit;
1348 
1349  // Find the new name of LONFIELDNAME
1350  tempmapit = (*i)->ncvarnamelist.find(LONFIELDNAME);
1351  if(tempmapit != (*i)->ncvarnamelist.end())
1352  templondimname= tempmapit->second;
1353  else
1354  throw2("cannot find the corrected field of Longitude", (*i)->getName());
1355 
1356  for(vector<Dimension *>::const_iterator k =(*j)->getDimensions().begin();
1357  k!=(*j)->getDimensions().end();++k){
1358 
1359  // Since this is the longitude, we create the corrected dimension with the corrected longitude field name
1360  // longitude[XDIM]->longitude[longitude]
1361  if((*k)->getName()==DIMXNAME) {
1362  correcteddim = new Dimension(templondimname,(*k)->getSize());
1363  correcteddims.push_back(correcteddim);
1364  (*j)->setCorrectedDimensions(correcteddims);
1365  HDFCFUtil::insert_map(tempnewxdimnamelist, (*i)->getName(), templondimname);
1366  }
1367  }
1368 
1369  (*j)->iscoard = true;
1370  (*i)->iscoard = true;
1371  if(this->onelatlon)
1372  this->iscoard = true;
1373  correcteddims.clear();
1374  }
1375  // 1-D lon to 1-D COARD lon
1376  // (this code can be combined with the 2-D lon to 1-D lon case, should handle this later, KY 2013-07-10).
1377  else if(((*j)->getRank()==1) &&((*j)->getName()==LONFIELDNAME) ) {
1378 
1379  string templondimname;
1380  map<string,string>::iterator tempmapit;
1381 
1382  // Find the new name of LONFIELDNAME
1383  tempmapit = (*i)->ncvarnamelist.find(LONFIELDNAME);
1384  if(tempmapit != (*i)->ncvarnamelist.end())
1385  templondimname= tempmapit->second;
1386  else
1387  throw2("cannot find the corrected field of Longitude", (*i)->getName());
1388 
1389  correcteddim = new Dimension(templondimname,((*j)->getDimensions())[0]->getSize());
1390  correcteddims.push_back(correcteddim);
1391  (*j)->setCorrectedDimensions(correcteddims);
1392  (*j)->iscoard = true;
1393  (*i)->iscoard = true;
1394  if(this->onelatlon)
1395  this->iscoard = true;
1396  correcteddims.clear();
1397 
1398  if(((((*j)->getDimensions())[0]->getName()!=DIMXNAME))
1399  &&((((*j)->getDimensions())[0]->getName())!=DIMYNAME)){
1400  throw3("the dimension name of longitude should not be ",
1401  ((*j)->getDimensions())[0]->getName(),(*i)->getName());
1402  }
1403  if((((*j)->getDimensions())[0]->getName())==DIMXNAME) {
1404  HDFCFUtil::insert_map(tempnewxdimnamelist, (*i)->getName(), templondimname);
1405  }
1406  else {
1407  HDFCFUtil::insert_map(tempnewydimnamelist, (*i)->getName(), templondimname);
1408  }
1409  }
1410  // 1-D lat to 1-D COARD lat
1411  // (this case can be combined with the 2-D lat to 1-D lat case, should handle this later. KY 2013-7-10).
1412  else if(((*j)->getRank()==1) &&((*j)->getName()==LATFIELDNAME) ) {
1413 
1414  string templatdimname;
1415  map<string,string>::iterator tempmapit;
1416 
1417  // Find the new name of LATFIELDNAME
1418  tempmapit = (*i)->ncvarnamelist.find(LATFIELDNAME);
1419  if(tempmapit != (*i)->ncvarnamelist.end())
1420  templatdimname= tempmapit->second;
1421  else
1422  throw2("cannot find the corrected field of Latitude", (*i)->getName());
1423 
1424  correcteddim = new Dimension(templatdimname,((*j)->getDimensions())[0]->getSize());
1425  correcteddims.push_back(correcteddim);
1426  (*j)->setCorrectedDimensions(correcteddims);
1427 
1428  (*j)->iscoard = true;
1429  (*i)->iscoard = true;
1430  if(this->onelatlon)
1431  this->iscoard = true;
1432  correcteddims.clear();
1433 
1434  if(((((*j)->getDimensions())[0]->getName())!=DIMXNAME)
1435  &&((((*j)->getDimensions())[0]->getName())!=DIMYNAME))
1436  throw3("the dimension name of latitude should not be ",
1437  ((*j)->getDimensions())[0]->getName(),(*i)->getName());
1438  if((((*j)->getDimensions())[0]->getName())==DIMXNAME){
1439  HDFCFUtil::insert_map(tempnewxdimnamelist, (*i)->getName(), templatdimname);
1440  }
1441  else {
1442  HDFCFUtil::insert_map(tempnewydimnamelist, (*i)->getName(), templatdimname);
1443  }
1444  }
1445  else {
1446  ;
1447  }
1448  }
1449  }
1450 
1451  // If COARDS follows, apply the new DIMXNAME and DIMYNAME name to the ndimnamelist
1452  // One lat/lon for all grids.
1453  if(true == this->onelatlon){
1454 
1455  // COARDS is followed.
1456  if(true == this->iscoard){
1457 
1458  // For this case, only one pair of corrected XDim and YDim for all grids.
1459  string tempcorrectedxdimname;
1460  string tempcorrectedydimname;
1461 
1462  if((int)(tempnewxdimnamelist.size())!= 1)
1463  throw1("the corrected dimension name should have only one pair");
1464  if((int)(tempnewydimnamelist.size())!= 1)
1465  throw1("the corrected dimension name should have only one pair");
1466 
1467  map<string,string>::iterator tempdimmapit = tempnewxdimnamelist.begin();
1468  tempcorrectedxdimname = tempdimmapit->second;
1469  tempdimmapit = tempnewydimnamelist.begin();
1470  tempcorrectedydimname = tempdimmapit->second;
1471 
1472  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1473  i != this->grids.end(); ++i){
1474 
1475  // Find the DIMXNAME and DIMYNAME in the dimension name list.
1476  map<string,string>::iterator tempmapit;
1477  tempmapit = (*i)->ndimnamelist.find(DIMXNAME);
1478  if(tempmapit != (*i)->ndimnamelist.end()) {
1479  HDFCFUtil::insert_map((*i)->ndimnamelist, DIMXNAME, tempcorrectedxdimname);
1480  }
1481  else
1482  throw2("cannot find the corrected dimension name", (*i)->getName());
1483  tempmapit = (*i)->ndimnamelist.find(DIMYNAME);
1484  if(tempmapit != (*i)->ndimnamelist.end()) {
1485  HDFCFUtil::insert_map((*i)->ndimnamelist, DIMYNAME, tempcorrectedydimname);
1486  }
1487  else
1488  throw2("cannot find the corrected dimension name", (*i)->getName());
1489  }
1490  }
1491  }
1492  else {// We have to search each grid
1493  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1494  i != this->grids.end(); ++i){
1495  if((*i)->iscoard){
1496 
1497  string tempcorrectedxdimname;
1498  string tempcorrectedydimname;
1499 
1500  // Find the DIMXNAME and DIMYNAME in the dimension name list.
1501  map<string,string>::iterator tempdimmapit;
1502  map<string,string>::iterator tempmapit;
1503  tempdimmapit = tempnewxdimnamelist.find((*i)->getName());
1504  if(tempdimmapit != tempnewxdimnamelist.end())
1505  tempcorrectedxdimname = tempdimmapit->second;
1506  else
1507  throw2("cannot find the corrected COARD XDim dimension name", (*i)->getName());
1508  tempmapit = (*i)->ndimnamelist.find(DIMXNAME);
1509  if(tempmapit != (*i)->ndimnamelist.end()) {
1510  HDFCFUtil::insert_map((*i)->ndimnamelist, DIMXNAME, tempcorrectedxdimname);
1511  }
1512  else
1513  throw2("cannot find the corrected dimension name", (*i)->getName());
1514 
1515  tempdimmapit = tempnewydimnamelist.find((*i)->getName());
1516  if(tempdimmapit != tempnewydimnamelist.end())
1517  tempcorrectedydimname = tempdimmapit->second;
1518  else
1519  throw2("cannot find the corrected COARD YDim dimension name", (*i)->getName());
1520 
1521  tempmapit = (*i)->ndimnamelist.find(DIMYNAME);
1522  if(tempmapit != (*i)->ndimnamelist.end()) {
1523  HDFCFUtil::insert_map((*i)->ndimnamelist, DIMYNAME, tempcorrectedydimname);
1524  }
1525  else
1526  throw2("cannot find the corrected dimension name", (*i)->getName());
1527  }
1528  }
1529  }
1530 
1531 
1532  // For 1-D lat/lon cases, Make the third (other than lat/lon coordinate variable) dimension to follow COARD conventions.
1533 
1534  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1535  i != this->grids.end(); ++i){
1536  for (map<string,string>::const_iterator j =
1537  (*i)->dimcvarlist.begin(); j!= (*i)->dimcvarlist.end();++j){
1538 
1539  // It seems that the condition for onelatlon case is if(this->iscoard) is true instead if
1540  // this->onelatlon is true.So change it. KY 2010-7-4
1541  //if((this->onelatlon||(*i)->iscoard) && (*j).first !=DIMXNAME && (*j).first !=DIMYNAME)
1542  if((this->iscoard||(*i)->iscoard) && (*j).first !=DIMXNAME && (*j).first !=DIMYNAME) {
1543  string tempnewdimname;
1544  map<string,string>::iterator tempmapit;
1545 
1546  // Find the new field name of the corresponding dimennsion name
1547  tempmapit = (*i)->ncvarnamelist.find((*j).second);
1548  if(tempmapit != (*i)->ncvarnamelist.end())
1549  tempnewdimname= tempmapit->second;
1550  else
1551  throw3("cannot find the corrected field of ", (*j).second,(*i)->getName());
1552 
1553  // Make the new field name to the correponding dimension name
1554  tempmapit =(*i)->ndimnamelist.find((*j).first);
1555  if(tempmapit != (*i)->ndimnamelist.end())
1556  HDFCFUtil::insert_map((*i)->ndimnamelist, (*j).first, tempnewdimname);
1557  else
1558  throw3("cannot find the corrected dimension name of ", (*j).first,(*i)->getName());
1559 
1560  }
1561  }
1562  }
1563 #if 0
1564  // Create the corrected dimension vectors.
1565  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1566  i != this->grids.end(); ++i){
1567 
1568  for (vector<Field *>::const_iterator j =
1569  (*i)->getDataFields().begin();
1570  j != (*i)->getDataFields().end(); ++j) {
1571 
1572  // When the corrected dimension name of lat/lon has been updated,
1573  if((*j)->iscoard == false) {
1574 
1575  // Just obtain the corrected dim names and save the corrected dimensions for each field.
1576  for(vector<Dimension *>::const_iterator k=(*j)->getDimensions().begin();k!=(*j)->getDimensions().end();++k){
1577 
1578  //tempcorrecteddimname =(*i)->ndimnamelist((*k)->getName());
1579  map<string,string>::iterator tempmapit;
1580 
1581  // Find the new name of this field
1582  tempmapit = (*i)->ndimnamelist.find((*k)->getName());
1583  if(tempmapit != (*i)->ndimnamelist.end())
1584  tempcorrecteddimname= tempmapit->second;
1585  else
1586  throw4("cannot find the corrected dimension name", (*i)->getName(),(*j)->getName(),(*k)->getName());
1587  correcteddim = new Dimension(tempcorrecteddimname,(*k)->getSize());
1588  correcteddims.push_back(correcteddim);
1589  }
1590  (*j)->setCorrectedDimensions(correcteddims);
1591  correcteddims.clear();
1592  }
1593  }
1594  }
1595 
1596 #endif
1597 }
1598 
1599 // Create the corrected dimension vector for each field when COARDS is not followed.
1600 void File::update_grid_field_corrected_dims() throw(Exception) {
1601 
1602  // Revisit the lat/lon fields to check if 1-D COARD convention needs to be followed.
1603  vector<Dimension*> correcteddims;
1604  string tempcorrecteddimname;
1605  // temporary dimension pointer
1606  Dimension *correcteddim;
1607 
1608 
1609  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1610  i != this->grids.end(); ++i){
1611 
1612  for (vector<Field *>::const_iterator j =
1613  (*i)->getDataFields().begin();
1614  j != (*i)->getDataFields().end(); ++j) {
1615 
1616  // When the corrected dimension name of lat/lon has been updated,
1617  if((*j)->iscoard == false) {
1618 
1619  // Just obtain the corrected dim names and save the corrected dimensions for each field.
1620  for(vector<Dimension *>::const_iterator k=(*j)->getDimensions().begin();k!=(*j)->getDimensions().end();++k){
1621 
1622  //tempcorrecteddimname =(*i)->ndimnamelist((*k)->getName());
1623  map<string,string>::iterator tempmapit;
1624 
1625  // Find the new name of this field
1626  tempmapit = (*i)->ndimnamelist.find((*k)->getName());
1627  if(tempmapit != (*i)->ndimnamelist.end())
1628  tempcorrecteddimname= tempmapit->second;
1629  else
1630  throw4("cannot find the corrected dimension name", (*i)->getName(),(*j)->getName(),(*k)->getName());
1631  correcteddim = new Dimension(tempcorrecteddimname,(*k)->getSize());
1632  correcteddims.push_back(correcteddim);
1633  }
1634  (*j)->setCorrectedDimensions(correcteddims);
1635  correcteddims.clear();
1636  }
1637  }
1638  }
1639 
1640 }
1641 
1642 void File::handle_grid_cf_attrs() throw(Exception) {
1643 
1644  // Create "coordinates" ,"units" attributes. The "units" attributes only apply to latitude and longitude.
1645  // This is the last round of looping through everything,
1646  // we will match dimension name list to the corresponding dimension field name
1647  // list for every field.
1648 
1649  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1650  i != this->grids.end(); ++i){
1651  for (vector<Field *>::const_iterator j =
1652  (*i)->getDataFields().begin();
1653  j != (*i)->getDataFields().end(); ++j) {
1654 
1655  // Real fields: adding coordinate attributesinate attributes
1656  if((*j)->fieldtype == 0) {
1657  string tempcoordinates="";
1658  string tempfieldname="";
1659  string tempcorrectedfieldname="";
1660  int tempcount = 0;
1661  for(vector<Dimension *>::const_iterator k=(*j)->getDimensions().begin();
1662  k!=(*j)->getDimensions().end();++k){
1663 
1664  // Handle coordinates attributes
1665  map<string,string>::iterator tempmapit;
1666  map<string,string>::iterator tempmapit2;
1667 
1668  // Find the dimension field name
1669  tempmapit = ((*i)->dimcvarlist).find((*k)->getName());
1670  if(tempmapit != ((*i)->dimcvarlist).end())
1671  tempfieldname = tempmapit->second;
1672  else
1673  throw4("cannot find the dimension field name",
1674  (*i)->getName(),(*j)->getName(),(*k)->getName());
1675 
1676  // Find the corrected dimension field name
1677  tempmapit2 = ((*i)->ncvarnamelist).find(tempfieldname);
1678  if(tempmapit2 != ((*i)->ncvarnamelist).end())
1679  tempcorrectedfieldname = tempmapit2->second;
1680  else
1681  throw4("cannot find the corrected dimension field name",
1682  (*i)->getName(),(*j)->getName(),(*k)->getName());
1683 
1684  if(tempcount == 0)
1685  tempcoordinates= tempcorrectedfieldname;
1686  else
1687  tempcoordinates = tempcoordinates +" "+tempcorrectedfieldname;
1688  tempcount++;
1689  }
1690  (*j)->setCoordinates(tempcoordinates);
1691  }
1692 
1693  // Add units for latitude and longitude
1694  if((*j)->fieldtype == 1) {// latitude,adding the "units" degrees_north.
1695  string tempunits = "degrees_north";
1696  (*j)->setUnits(tempunits);
1697  }
1698  if((*j)->fieldtype == 2) { // longitude, adding the units degrees_east.
1699  string tempunits = "degrees_east";
1700  (*j)->setUnits(tempunits);
1701  }
1702 
1703  // Add units for Z-dimension, now it is always "level"
1704  // This also needs to be corrected since the Z-dimension may not always be "level".
1705  // KY 2012-6-13
1706  // We decide not to touch "units" when the Z-dimension is an existing field(fieldtype =3).
1707  if((*j)->fieldtype == 4) {
1708  string tempunits ="level";
1709  (*j)->setUnits(tempunits);
1710  }
1711 
1712  // The units of the time is not right. KY 2012-6-13(documented at jira HFRHANDLER-167)
1713  if((*j)->fieldtype == 5) {
1714  string tempunits ="days since 1900-01-01 00:00:00";
1715  (*j)->setUnits(tempunits);
1716  }
1717 
1718  // We meet a really special case for CERES TRMM data. We attribute it to the specialformat 2 case
1719  // since the corner coordinate is set to default in HDF-EOS2 structmetadata. We also find that there are
1720  // values such as 3.4028235E38 that is the maximum single precision floating point value. This value
1721  // is a fill value but the fillvalue attribute is not set. So we add the fillvalue attribute for this case.
1722  // We may find such cases for other products and will tackle them also.
1723  if (true == (*i)->addfvalueattr) {
1724  if((((*j)->getFillValue()).empty()) && ((*j)->getType()==DFNT_FLOAT32 )) {
1725  float tempfillvalue = HUGE;
1726  (*j)->addFillValue(tempfillvalue);
1727  (*j)->setAddedFillValue(true);
1728  }
1729  }
1730  }
1731  }
1732 }
1733 
1734 // Special handling SOM(Space Oblique Mercator) projection files
1735 void File::handle_grid_SOM_projection() throw(Exception) {
1736 
1737  // since the latitude and longitude of the SOM projection are 3-D, so we need to handle this projection in a special way.
1738  // Based on our current understanding, the third dimension size is always 180.
1739  // If the size is not 180, the latitude and longitude will not be calculated correctly.
1740  // This is according to the MISR Lat/lon calculation document
1741  // at http://eosweb.larc.nasa.gov/PRODOCS/misr/DPS/DPS_v50_RevS.pdf
1742  // KY 2012-6-12
1743 
1744  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
1745  i != this->grids.end(); ++i){
1746  if (GCTP_SOM == (*i)->getProjection().getCode()) {
1747 
1748  // 0. Getting the SOM dimension for latitude and longitude.
1749 
1750  // Obtain SOM's dimension name.
1751  string som_dimname;
1752  for(vector<Dimension *>::const_iterator j=(*i)->getDimensions().begin();
1753  j!=(*i)->getDimensions().end();++j){
1754 
1755  // NBLOCK is from misrproj.h. It is the number of block that MISR team support for the SOM projection.
1756  if(NBLOCK == (*j)->getSize()) {
1757 
1758  // To make sure we catch the right dimension, check the first three characters of the dim. name
1759  // It should be SOM
1760  if ((*j)->getName().compare(0,3,"SOM") == 0) {
1761  som_dimname = (*j)->getName();
1762  break;
1763  }
1764  }
1765  }
1766 
1767  if(""== som_dimname)
1768  throw4("Wrong number of block: The number of block of MISR SOM Grid ",
1769  (*i)->getName()," is not ",NBLOCK);
1770 
1771  map<string,string>::iterator tempmapit;
1772 
1773  // Find the corrected (CF) dimension name
1774  string cor_som_dimname;
1775  tempmapit = (*i)->ndimnamelist.find(som_dimname);
1776  if(tempmapit != (*i)->ndimnamelist.end())
1777  cor_som_dimname = tempmapit->second;
1778  else
1779  throw2("cannot find the corrected dimension name for ", som_dimname);
1780 
1781  // Find the corrected(CF) name of this field
1782  string cor_som_cvname;
1783 
1784  // Here we cannot use getDataFields() since the returned elements cannot be modified. KY 2012-6-12
1785  for (vector<Field *>::iterator j = (*i)->datafields.begin();
1786  j != (*i)->datafields.end(); ++j) {
1787 
1788  // Only 6-7 fields, so just loop through
1789  // 1. Set the SOM dimension for latitude and longitude
1790  if (1 == (*j)->fieldtype || 2 == (*j)->fieldtype) {
1791 
1792  Dimension *newdim = new Dimension(som_dimname,NBLOCK);
1793  Dimension *newcor_dim = new Dimension(cor_som_dimname,NBLOCK);
1794  vector<Dimension *>::iterator it_d;
1795 
1796  it_d = (*j)->dims.begin();
1797  (*j)->dims.insert(it_d,newdim);
1798 
1799  it_d = (*j)->correcteddims.begin();
1800  (*j)->correcteddims.insert(it_d,newcor_dim);
1801 
1802  }
1803 
1804  // 2. Remove the added coordinate variable for the SOM dimension
1805  // The added variable is a variable with the nature number
1806  // Why removing it? Since we cannot follow the general rule to create coordinate variables for MISR products.
1807  // The third-dimension belongs to lat/lon rather than a missing coordinate variable.
1808  if ( 4 == (*j)->fieldtype) {
1809  cor_som_cvname = (*j)->newname;
1810  delete (*j);
1811  (*i)->datafields.erase(j);
1812  // When erasing the iterator for the vector, the iterator will automatically go to the next element,
1813  // so we need to go back 1 in order not to miss the next element.
1814  // Again, check stackoverflow and find this is true. So the following operation is valid.
1815  // KY 2014-02-27
1816  j--;
1817  }
1818  }
1819 
1820  // 3. Fix the "coordinates" attribute: remove the SOM CV name from the coordinate attribute.
1821  // Notice this is a little inefficient. Since we only have a few fields and non-SOM projection products
1822  // won't be affected, and more importantly, to keep the SOM projection handling in a central place,
1823  // I handle the adjustment of "coordinates" attribute here. KY 2012-6-12
1824 
1825  // MISR data cannot be visualized by Panoply and IDV. So the coordinates attribute
1826  // created here reflects the coordinates of this variable more accurately. KY 2012-6-13
1827 
1828  for (vector<Field *>::const_iterator j = (*i)->getDataFields().begin();
1829  j != (*i)->getDataFields().end(); ++j) {
1830 
1831  if ( 0 == (*j)->fieldtype) {
1832 
1833  string temp_coordinates = (*j)->coordinates;
1834 
1835  size_t found;
1836  found = temp_coordinates.find(cor_som_cvname);
1837 
1838  if (0 == found) {
1839  // Need also to remove the space after the SOM CV name.
1840  if (temp_coordinates.size() >cor_som_cvname.size())
1841  temp_coordinates.erase(found,cor_som_cvname.size()+1);
1842  else
1843  temp_coordinates.erase(found,cor_som_cvname.size());
1844  }
1845  else if (found != string::npos)
1846  temp_coordinates.erase(found-1,cor_som_cvname.size()+1);
1847  else
1848  throw4("cannot find the coordinate variable ",cor_som_cvname,
1849  "from ",temp_coordinates);
1850 
1851  (*j)->setCoordinates(temp_coordinates);
1852 
1853  }
1854  }
1855  }
1856  }
1857 }
1858 
1859 // Obtain the number of dimension maps in this file. The input parameter is the number of swath.
1860 int File::obtain_dimmap_num(int numswath) throw(Exception) {
1861 
1862  // S(wath)0. Check if there are dimension maps in this case.
1863  int tempnumdm = 0;
1864  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
1865  i != this->swaths.end(); ++i){
1866  tempnumdm += (*i)->get_num_map();
1867  if (tempnumdm >0)
1868  break;
1869  }
1870 
1871  // MODATML2 and MYDATML2 in year 2010 include dimension maps. But the dimension map
1872  // is not used. Furthermore, they provide additional latitude/longtiude
1873  // for 10 KM under the data field. So we have to handle this differently.
1874  // MODATML2 in year 2000 version doesn't include dimension map, so we
1875  // have to consider both with dimension map and without dimension map cases.
1876  // The swath name is atml2.
1877 
1878  bool fakedimmap = false;
1879 
1880  if(numswath == 1) {// Start special atml2-like handling
1881 
1882  if((this->swaths[0]->getName()).find("atml2")!=string::npos){
1883 
1884  if(tempnumdm >0)
1885  fakedimmap = true;
1886  int templlflag = 0;
1887 
1888  for (vector<Field *>::const_iterator j =
1889  this->swaths[0]->getGeoFields().begin();
1890  j != this->swaths[0]->getGeoFields().end(); ++j) {
1891  if((*j)->getName() == "Latitude" || (*j)->getName() == "Longitude") {
1892  if ((*j)->getType() == DFNT_UINT16 ||
1893  (*j)->getType() == DFNT_INT16)
1894  (*j)->type = DFNT_FLOAT32;
1895  templlflag ++;
1896  if(templlflag == 2)
1897  break;
1898  }
1899  }
1900 
1901  templlflag = 0;
1902 
1903  for (vector<Field *>::const_iterator j =
1904  this->swaths[0]->getDataFields().begin();
1905  j != this->swaths[0]->getDataFields().end(); ++j) {
1906 
1907  // We meet a very speical MODIS case.
1908  // The latitude and longitude types are int16.
1909  // The number are in thousand. The scale factor
1910  // attribute is 0.01. This attribute cannot be
1911  // retrieved by EOS2 APIs. So we have to hard code this.
1912  // We can only use the swath name to
1913  // identify this case.
1914  // The swath name is atml2. It has only one swath.
1915  // We have to change lat and lon to float type array;
1916  // since after applying the scale factor, the array becomes
1917  // float data.
1918  // KY-2010-7-12
1919 
1920  if(((*j)->getName()).find("Latitude") != string::npos){
1921 
1922  if ((*j)->getType() == DFNT_UINT16 ||
1923  (*j)->getType() == DFNT_INT16)
1924  (*j)->type = DFNT_FLOAT32;
1925 
1926  (*j)->fieldtype = 1;
1927 
1928  // Also need to link the dimension to the coordinate variable list
1929  if((*j)->getRank() != 2)
1930  throw2("The lat/lon rank must be 2 for Java clients to work",
1931  (*j)->getRank());
1932  HDFCFUtil::insert_map(this->swaths[0]->dimcvarlist,
1933  (((*j)->getDimensions())[0])->getName(),(*j)->getName());
1934  templlflag ++;
1935  }
1936 
1937  if(((*j)->getName()).find("Longitude")!= string::npos) {
1938 
1939  if((*j)->getType() == DFNT_UINT16 ||
1940  (*j)->getType() == DFNT_INT16)
1941  (*j)->type = DFNT_FLOAT32;
1942 
1943  (*j)->fieldtype = 2;
1944  if((*j)->getRank() != 2)
1945  throw2("The lat/lon rank must be 2 for Java clients to work",
1946  (*j)->getRank());
1947  HDFCFUtil::insert_map(this->swaths[0]->dimcvarlist,
1948  (((*j)->getDimensions())[1])->getName(), (*j)->getName());
1949  templlflag ++;
1950  }
1951 
1952  if(templlflag == 2)
1953  break;
1954  }
1955  }
1956  }// End of special atml2 handling
1957 
1958  // Although this file includes dimension map, it doesn't use it at all. So change
1959  // tempnumdm to 0.
1960  if(true == fakedimmap)
1961  tempnumdm = 0;
1962 
1963  return tempnumdm;
1964 
1965 }
1966 
1967 // Create the dimension name to coordinate variable name map for lat/lon.
1968 // The input parameter is the number of dimension maps in this file.
1969 void File::create_swath_latlon_dim_cvar_map(int numdm) throw(Exception){
1970 
1971  // 1. Prepare the right dimension name and the dimension field list for each swath.
1972  // The assumption is that within a swath, the dimension name is unique.
1973  // The dimension field name(even with the added Z-like field) is unique.
1974  // A map <dimension name, dimension field name> will be created.
1975  // The name clashing handling for multiple swaths will not be done in this step.
1976 
1977  // 1.1 Obtain the dimension names corresponding to the latitude and longitude,
1978  // save them to the <dimname, dimfield> map.
1979 
1980  // We found a special MODIS product: the Latitude and Longitude are put under the Data fields
1981  // rather than GeoLocation fields.
1982  // So we need to go to the "Data Fields" to grab the "Latitude and Longitude".
1983 
1984  bool lat_in_geofields = false;
1985  bool lon_in_geofields = false;
1986 
1987  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
1988  i != this->swaths.end(); ++i){
1989 
1990  int tempgeocount = 0;
1991  for (vector<Field *>::const_iterator j =
1992  (*i)->getGeoFields().begin();
1993  j != (*i)->getGeoFields().end(); ++j) {
1994 
1995  // Here we assume it is always lat[f0][f1] and lon [f0][f1]. No lat[f0][f1] and lon[f1][f0] occur.
1996  // So far only "Latitude" and "Longitude" are used as standard names of lat and lon for swath.
1997  if((*j)->getName()=="Latitude" ){
1998  if((*j)->getRank() > 2)
1999  throw2("Currently the lat/lon rank must be 1 or 2 for Java clients to work",
2000  (*j)->getRank());
2001 
2002  lat_in_geofields = true;
2003 
2004  // Since under our assumption, lat/lon are always 2-D for a swath and
2005  // dimension order doesn't matter for Java clients,
2006  // so we always map Latitude to the first dimension and longitude to the second dimension.
2007  // Save this information in the coordinate variable name and field map.
2008  // For rank =1 case, we only handle the cross-section along the same
2009  // longitude line. So Latitude should be the dimension name.
2010  HDFCFUtil::insert_map((*i)->dimcvarlist, (((*j)->getDimensions())[0])->getName(), "Latitude");
2011 
2012  // Have dimension map, we want to remember the dimension and remove it from the list.
2013  if(numdm >0) {
2014 
2015  // We have to loop through the dimension map
2016  for(vector<SwathDataset::DimensionMap *>::const_iterator
2017  l=(*i)->getDimensionMaps().begin(); l!=(*i)->getDimensionMaps().end();++l){
2018 
2019  // This dimension name will be replaced by the mapped dimension name,
2020  // the mapped dimension name can be obtained from the getDataDimension() method.
2021  if(((*j)->getDimensions()[0])->getName() == (*l)->getGeoDimension()) {
2022  HDFCFUtil::insert_map((*i)->dimcvarlist, (*l)->getDataDimension(), "Latitude");
2023  break;
2024  }
2025  }
2026  }
2027  (*j)->fieldtype = 1;
2028  tempgeocount ++;
2029  }
2030 
2031  if((*j)->getName()=="Longitude"){
2032  if((*j)->getRank() > 2)
2033  throw2("Currently the lat/lon rank must be 1 or 2 for Java clients to work",
2034  (*j)->getRank());
2035 
2036  // Only lat-level cross-section(for Panoply)is supported
2037  // when longitude/latitude is 1-D, so ignore the longitude as the dimension field.
2038  lon_in_geofields = true;
2039  if((*j)->getRank() == 1) {
2040  tempgeocount++;
2041  continue;
2042  }
2043 
2044  // Since under our assumption, lat/lon are almost always 2-D for
2045  // a swath and dimension order doesn't matter for Java clients,
2046  // we always map Latitude to the first dimension and longitude to the second dimension.
2047  // Save this information in the dimensiion name and coordinate variable map.
2048  HDFCFUtil::insert_map((*i)->dimcvarlist,
2049  (((*j)->getDimensions())[1])->getName(), "Longitude");
2050  if(numdm >0) {
2051 
2052  // We have to loop through the dimension map
2053  for(vector<SwathDataset::DimensionMap *>::const_iterator
2054  l=(*i)->getDimensionMaps().begin(); l!=(*i)->getDimensionMaps().end();++l){
2055 
2056  // This dimension name will be replaced by the mapped dimension name,
2057  // This name can be obtained by getDataDimension() fuction of
2058  // dimension map class.
2059  if(((*j)->getDimensions()[1])->getName() ==
2060  (*l)->getGeoDimension()) {
2061  HDFCFUtil::insert_map((*i)->dimcvarlist,
2062  (*l)->getDataDimension(), "Longitude");
2063  break;
2064  }
2065  }
2066  }
2067  (*j)->fieldtype = 2;
2068  tempgeocount++;
2069  }
2070  if(tempgeocount == 2)
2071  break;
2072  }
2073  }// end of creating the <dimname,dimfield> map.
2074 
2075  // If lat and lon are not together, throw an error.
2076  if (lat_in_geofields ^ lon_in_geofields)
2077  throw1("Latitude and longitude must be both under Geolocation fields or Data fields");
2078 
2079  // Check if they are under data fields(The code may be combined with the above, see HFRHANDLER-166)
2080  if (!lat_in_geofields && !lon_in_geofields) {
2081 
2082  bool lat_in_datafields = false;
2083  bool lon_in_datafields = false;
2084 
2085  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2086  i != this->swaths.end(); ++i){
2087 
2088  int tempgeocount = 0;
2089  for (vector<Field *>::const_iterator j =
2090  (*i)->getDataFields().begin();
2091  j != (*i)->getDataFields().end(); ++j) {
2092 
2093  // Here we assume it is always lat[f0][f1] and lon [f0][f1].
2094  // No lat[f0][f1] and lon[f1][f0] occur.
2095  // So far only "Latitude" and "Longitude" are used as
2096  // standard names of Lat and lon for swath.
2097  if((*j)->getName()=="Latitude" ){
2098  if((*j)->getRank() > 2) {
2099  throw2("Currently the lat/lon rank must be 1 or 2 for Java clients to work",
2100  (*j)->getRank());
2101  }
2102  lat_in_datafields = true;
2103 
2104  // Since under our assumption, lat/lon are always 2-D
2105  // for a swath and dimension order doesn't matter for Java clients,
2106  // we always map Latitude the first dimension and longitude the second dimension.
2107  // Save this information in the coordinate variable name and field map.
2108  // For rank =1 case, we only handle the cross-section along the same longitude line.
2109  // So Latitude should be the dimension name.
2110  HDFCFUtil::insert_map((*i)->dimcvarlist,
2111  (((*j)->getDimensions())[0])->getName(), "Latitude");
2112 
2113  // Have dimension map, we want to remember the dimension and remove it from the list.
2114  if(numdm >0) {
2115 
2116  // We have to loop through the dimension map
2117  for(vector<SwathDataset::DimensionMap *>::const_iterator
2118  l=(*i)->getDimensionMaps().begin(); l!=(*i)->getDimensionMaps().end();++l){
2119 
2120  // This dimension name will be replaced by the mapped dimension name,
2121  // the mapped dimension name can be obtained from the getDataDimension() method.
2122  if(((*j)->getDimensions()[0])->getName() == (*l)->getGeoDimension()) {
2123  HDFCFUtil::insert_map((*i)->dimcvarlist, (*l)->getDataDimension(), "Latitude");
2124  break;
2125  }
2126  }
2127  }
2128  (*j)->fieldtype = 1;
2129  tempgeocount ++;
2130  }
2131 
2132  if((*j)->getName()=="Longitude"){
2133 
2134  if((*j)->getRank() > 2) {
2135  throw2("Currently the lat/lon rank must be 1 or 2 for Java clients to work",
2136  (*j)->getRank());
2137  }
2138 
2139  // Only lat-level cross-section(for Panoply)is supported when
2140  // longitude/latitude is 1-D, so ignore the longitude as the dimension field.
2141  lon_in_datafields = true;
2142  if((*j)->getRank() == 1) {
2143  tempgeocount++;
2144  continue;
2145  }
2146 
2147  // Since under our assumption,
2148  // lat/lon are almost always 2-D for a swath and dimension order doesn't matter for Java clients,
2149  // we always map Latitude the first dimension and longitude the second dimension.
2150  // Save this information in the dimensiion name and coordinate variable map.
2151  HDFCFUtil::insert_map((*i)->dimcvarlist,
2152  (((*j)->getDimensions())[1])->getName(), "Longitude");
2153  if(numdm >0) {
2154  // We have to loop through the dimension map
2155  for(vector<SwathDataset::DimensionMap *>::const_iterator
2156  l=(*i)->getDimensionMaps().begin(); l!=(*i)->getDimensionMaps().end();++l){
2157  // This dimension name will be replaced by the mapped dimension name,
2158  // This name can be obtained by getDataDimension() fuction of dimension map class.
2159  if(((*j)->getDimensions()[1])->getName() == (*l)->getGeoDimension()) {
2160  HDFCFUtil::insert_map((*i)->dimcvarlist,
2161  (*l)->getDataDimension(), "Longitude");
2162  break;
2163  }
2164  }
2165  }
2166  (*j)->fieldtype = 2;
2167  tempgeocount++;
2168  }
2169  if(tempgeocount == 2)
2170  break;
2171  }
2172  }// end of creating the <dimname,dimfield> map.
2173 
2174  // If lat and lon are not together, throw an error.
2175  if (lat_in_datafields ^ lon_in_datafields)
2176  throw1("Latitude and longitude must be both under Geolocation fields or Data fields");
2177 
2178  // If lat,lon are not found under either "Data fields" or "Geolocation fields",
2179  // we should not generate "coordiantes"
2180  // However, this case should be handled in the future release if resources allow.
2181  // KY 2014-09-24
2182  //**************** INVESTIGATE in the future if resources allow *******************
2183  //if (!lat_in_datafields && !lon_in_datafields)
2184  // throw1("Latitude and longitude don't exist");
2185  //*********************************************************************************/
2186 
2187  }
2188 
2189 }
2190 
2191 // Create the dimension name to coordinate variable name map for lat/lon.
2192 // The input parameter is the number of dimension maps in this file.
2193 void File:: create_swath_nonll_dim_cvar_map() throw(Exception)
2194 {
2195  // Handle existing and missing fields
2196  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2197  i != this->swaths.end(); ++i){
2198 
2199  // Since we find multiple 1-D fields with the same dimension names for some Swath files(AIRS level 1B),
2200  // we currently always treat the third dimension field as a missing field, this may be corrected later.
2201  // Corrections for the above: MODIS data do include the unique existing Z fields, so we have to search
2202  // the existing Z field. KY 2010-8-11
2203  // Our correction is to search all 1-D fields with the same dimension name within one swath,
2204  // if only one field is found, we use this field as the third dimension.
2205  // 1.1 Add the missing Z-dimension field.
2206  // Some dimension name's corresponding fields are missing,
2207  // so add the missing Z-dimension fields based on the dimension name. When the real
2208  // data is read, nature number 1,2,3,.... will be filled!
2209  // NOTE: The latitude and longitude dim names are not handled yet.
2210 
2211  // Build a unique 1-D dimension name list.
2212  // Now the list only includes dimension names of "latitude" and "longitude".
2213 
2214  pair<set<string>::iterator,bool> tempdimret;
2215  for(map<string,string>::const_iterator j = (*i)->dimcvarlist.begin();
2216  j!= (*i)->dimcvarlist.end();++j){
2217  tempdimret = (*i)->nonmisscvdimlist.insert((*j).first);
2218  }
2219 
2220  // Search the geofield group and see if there are any existing 1-D Z dimension data.
2221  // If 1-D field data with the same dimension name is found under GeoField,
2222  // we still search if that 1-D field is the dimension
2223  // field of a dimension name.
2224  for (vector<Field *>::const_iterator j =
2225  (*i)->getGeoFields().begin();
2226  j != (*i)->getGeoFields().end(); ++j) {
2227 
2228  if((*j)->getRank()==1) {
2229  if((*i)->nonmisscvdimlist.find((((*j)->getDimensions())[0])->getName()) == (*i)->nonmisscvdimlist.end()){
2230  tempdimret = (*i)->nonmisscvdimlist.insert((((*j)->getDimensions())[0])->getName());
2231  if((*j)->getName() =="Time")
2232  (*j)->fieldtype = 5;// This is for IDV.
2233 
2234  // This is for temporarily COARD fix.
2235  // For 2-D lat/lon, the third dimension should NOT follow
2236  // COARD conventions. It will cause Panoply and IDV failed.
2237  // KY 2010-7-21
2238  // It turns out that we need to keep the original field name of the third dimension.
2239  // So assign the flag and save the original name.
2240  // KY 2010-9-9
2241 #if 0
2242  if(((((*j)->getDimensions())[0])->getName())==(*j)->getName()){
2243  (*j)->oriname = (*j)->getName();
2244  // netCDF-Java fixes the problem, now goes back to COARDS.
2245  //(*j)->name = (*j)->getName() +"_d";
2246  (*j)->specialcoard = true;
2247  }
2248 #endif
2249  HDFCFUtil::insert_map((*i)->dimcvarlist, (((*j)->getDimensions())[0])->getName(), (*j)->getName());
2250  (*j)->fieldtype = 3;
2251 
2252  }
2253  }
2254  }
2255 
2256  // We will also check the third dimension inside DataFields
2257  // This may cause potential problems for AIRS data
2258  // We will double CHECK KY 2010-6-26
2259  // So far the tests seem okay. KY 2010-8-11
2260  for (vector<Field *>::const_iterator j =
2261  (*i)->getDataFields().begin();
2262  j != (*i)->getDataFields().end(); ++j) {
2263 
2264  if((*j)->getRank()==1) {
2265  if((*i)->nonmisscvdimlist.find((((*j)->getDimensions())[0])->getName()) == (*i)->nonmisscvdimlist.end()){
2266  tempdimret = (*i)->nonmisscvdimlist.insert((((*j)->getDimensions())[0])->getName());
2267  if((*j)->getName() =="Time")
2268  (*j)->fieldtype = 5;// This is for IDV.
2269 
2270  // This is for temporarily COARD fix.
2271  // For 2-D lat/lon, the third dimension should NOT follow
2272  // COARD conventions. It will cause Panoply and IDV failed.
2273  // KY 2010-7-21
2274 #if 0
2275  if(((((*j)->getDimensions())[0])->getName())==(*j)->getName()){
2276  (*j)->oriname = (*j)->getName();
2277  //(*j)->name = (*j)->getName() +"_d";
2278  (*j)->specialcoard = true;
2279  }
2280 #endif
2281  HDFCFUtil::insert_map((*i)->dimcvarlist, (((*j)->getDimensions())[0])->getName(), (*j)->getName());
2282  (*j)->fieldtype = 3;
2283 
2284  }
2285  }
2286  }
2287 
2288 
2289  // S1.2.3 Handle the missing fields
2290  // Loop through all dimensions of this swath to search the missing fields
2291  //
2292  bool missingfield_unlim_flag = false;
2293  Field *missingfield_unlim = NULL;
2294 
2295  for (vector<Dimension *>::const_iterator j =
2296  (*i)->getDimensions().begin(); j!= (*i)->getDimensions().end();++j){
2297 
2298  if(((*i)->nonmisscvdimlist.find((*j)->getName())) == (*i)->nonmisscvdimlist.end()){// This dimension needs a field
2299 
2300  // Need to create a new data field vector element with the name and dimension as above.
2301  Field *missingfield = new Field();
2302 
2303  // This is for temporarily COARD fix.
2304  // For 2-D lat/lon, the third dimension should NOT follow
2305  // COARD conventions. It will cause Panoply and IDV failed.
2306  // Since Swath is always 2-D lat/lon, so we are okay here. Add a "_d" for each field name.
2307  // KY 2010-7-21
2308  // netCDF-Java now first follows COARDS, change back
2309  // missingfield->name = (*j)->getName()+"_d";
2310  missingfield->name = (*j)->getName();
2311  missingfield->rank = 1;
2312  missingfield->type = DFNT_INT32;//This is an HDF constant.the data type is always integer.
2313  Dimension *dim = new Dimension((*j)->getName(),(*j)->getSize());
2314 
2315  // only 1 dimension
2316  missingfield->dims.push_back(dim);
2317 
2318  // Provide information for the missing data, since we need to calculate the data, so
2319  // the information is different than a normal field.
2320  //int missingdatarank =1;
2321  //int missingdatatypesize = 4;
2322  int missingdimsize[1];
2323  missingdimsize[0]= (*j)->getSize();
2324 
2325  if(0 == (*j)->getSize()) {
2326 //cerr<<"missing field name is "<<missingfield->getName() << " dimension name is "<< dim->name <<endl;
2327  missingfield_unlim_flag = true;
2328  missingfield_unlim = missingfield;
2329  }
2330 
2331  //added Z-dimension coordinate variable with nature number
2332  missingfield->fieldtype = 4;
2333 
2334  (*i)->geofields.push_back(missingfield);
2335  HDFCFUtil::insert_map((*i)->dimcvarlist,
2336  (missingfield->getDimensions())[0]->getName(), missingfield->name);
2337  }
2338  }
2339 
2340  //Correct the unlimited dimension size.
2341  if(true == missingfield_unlim_flag) {
2342  for (vector<Field *>::const_iterator j =
2343  (*i)->getDataFields().begin();
2344  j != (*i)->getDataFields().end(); ++j) {
2345 
2346  for (vector<Dimension *>::const_iterator k =
2347  (*j)->getDimensions().begin(); k!= (*j)->getDimensions().end();++k){
2348 
2349  if((*k)->getName() == (missingfield_unlim->getDimensions())[0]->getName()) {
2350  if((*k)->getSize()!= 0) {
2351  Dimension *dim = missingfield_unlim->getDimensions()[0];
2352  dim->dimsize = (*k)->getSize();
2353  missingfield_unlim_flag = false;
2354  break;
2355  }
2356  }
2357 
2358  if(false == missingfield_unlim_flag)
2359  break;
2360  }
2361  if(false == missingfield_unlim_flag)
2362  break;
2363  }
2364  }
2365 
2366  (*i)->nonmisscvdimlist.clear();// clear this set.
2367 
2368  }// End of handling non-latlon cv
2369 
2370 }
2371 
2372 // Handle swath dimension name to coordinate variable name maps.
2373 // The input parameter is the number of dimension maps in this file.
2374 void File::handle_swath_dim_cvar_maps(int tempnumdm) throw(Exception) {
2375 
2376  // Start handling name clashing
2377  vector <string> tempfieldnamelist;
2378  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2379  i != this->swaths.end(); ++i) {
2380 
2381  // First handle geofield, all dimension fields are under the geofield group.
2382  for (vector<Field *>::const_iterator j =
2383  (*i)->getGeoFields().begin();
2384  j != (*i)->getGeoFields().end(); ++j) {
2385  tempfieldnamelist.push_back(HDFCFUtil::get_CF_string((*j)->name));
2386  }
2387 
2388  for (vector<Field *>::const_iterator j = (*i)->getDataFields().begin();
2389  j!= (*i)->getDataFields().end(); ++j) {
2390  tempfieldnamelist.push_back(HDFCFUtil::get_CF_string((*j)->name));
2391  }
2392  }
2393 
2394  HDFCFUtil::Handle_NameClashing(tempfieldnamelist);
2395 
2396  int total_fcounter = 0;
2397 
2398  // Create a map for dimension field name <original field name, corrected field name>
2399  // Also assure the uniqueness of all field names,save the new field names.
2400  //the original dimension field name to the corrected dimension field name
2401  map<string,string>tempncvarnamelist;
2402  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2403  i != this->swaths.end(); ++i){
2404 
2405  // First handle geofield, all dimension fields are under the geofield group.
2406  for (vector<Field *>::const_iterator j =
2407  (*i)->getGeoFields().begin();
2408  j != (*i)->getGeoFields().end(); ++j)
2409  {
2410 
2411  (*j)->newname = tempfieldnamelist[total_fcounter];
2412  total_fcounter++;
2413 
2414  // If this field is a dimension field, save the name/new name pair.
2415  if((*j)->fieldtype!=0) {
2416  HDFCFUtil::insert_map((*i)->ncvarnamelist, (*j)->getName(), (*j)->newname);
2417  }
2418  }
2419 
2420  for (vector<Field *>::const_iterator j =
2421  (*i)->getDataFields().begin();
2422  j != (*i)->getDataFields().end(); ++j)
2423  {
2424  (*j)->newname = tempfieldnamelist[total_fcounter];
2425  total_fcounter++;
2426 
2427  // If this field is a dimension field, save the name/new name pair.
2428  if((*j)->fieldtype!=0) {
2429  HDFCFUtil::insert_map((*i)->ncvarnamelist, (*j)->getName(), (*j)->newname);
2430  }
2431  }
2432  } // end of creating a map for dimension field name <original field name, corrected field name>
2433 
2434  // Create a map for dimension name < original dimension name, corrected dimension name>
2435 
2436  vector <string>tempalldimnamelist;
2437 
2438  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2439  i != this->swaths.end(); ++i)
2440  for (map<string,string>::const_iterator j =
2441  (*i)->dimcvarlist.begin(); j!= (*i)->dimcvarlist.end();++j)
2442  tempalldimnamelist.push_back(HDFCFUtil::get_CF_string((*j).first));
2443 
2444  // Handle name clashing will make the corrected dimension name follow CF
2445  HDFCFUtil::Handle_NameClashing(tempalldimnamelist);
2446 
2447  int total_dcounter = 0;
2448 
2449  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2450  i != this->swaths.end(); ++i){
2451  for (map<string,string>::const_iterator j =
2452  (*i)->dimcvarlist.begin(); j!= (*i)->dimcvarlist.end();++j){
2453  HDFCFUtil::insert_map((*i)->ndimnamelist, (*j).first, tempalldimnamelist[total_dcounter]);
2454  total_dcounter++;
2455  }
2456  }
2457 
2458  // Create corrected dimension vectors.
2459  vector<Dimension*> correcteddims;
2460  string tempcorrecteddimname;
2461  Dimension *correcteddim;
2462 
2463  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2464  i != this->swaths.end(); ++i){
2465 
2466  // First the geofield.
2467  for (vector<Field *>::const_iterator j =
2468  (*i)->getGeoFields().begin();
2469  j != (*i)->getGeoFields().end(); ++j) {
2470 
2471  for(vector<Dimension *>::const_iterator k=(*j)->getDimensions().begin();k!=(*j)->getDimensions().end();++k){
2472 
2473  map<string,string>::iterator tempmapit;
2474 
2475  if(tempnumdm == 0) { // No dimension map, just obtain the new dimension name.
2476 
2477  // Find the new name of this field
2478  tempmapit = (*i)->ndimnamelist.find((*k)->getName());
2479  if(tempmapit != (*i)->ndimnamelist.end())
2480  tempcorrecteddimname= tempmapit->second;
2481  else
2482  throw4("cannot find the corrected dimension name",
2483  (*i)->getName(),(*j)->getName(),(*k)->getName());
2484 
2485  correcteddim = new Dimension(tempcorrecteddimname,(*k)->getSize());
2486  }
2487  else {
2488  // have dimension map, use the datadim and datadim size to replace the geodim and geodim size.
2489  bool isdimmapname = false;
2490 
2491  // We have to loop through the dimension map
2492  for(vector<SwathDataset::DimensionMap *>::const_iterator
2493  l=(*i)->getDimensionMaps().begin(); l!=(*i)->getDimensionMaps().end();++l){
2494  // This dimension name is the geo dimension name in the dimension map,
2495  // replace the name with data dimension name.
2496  if((*k)->getName() == (*l)->getGeoDimension()) {
2497 
2498  isdimmapname = true;
2499  (*j)->dmap = true;
2500  string temprepdimname = (*l)->getDataDimension();
2501 
2502  // Find the new name of this data dimension name
2503  tempmapit = (*i)->ndimnamelist.find(temprepdimname);
2504  if(tempmapit != (*i)->ndimnamelist.end())
2505  tempcorrecteddimname= tempmapit->second;
2506  else
2507  throw4("cannot find the corrected dimension name", (*i)->getName(),
2508  (*j)->getName(),(*k)->getName());
2509 
2510  // Find the size of this data dimension name
2511  // We have to loop through the Dimensions of this swath
2512  bool ddimsflag = false;
2513  for(vector<Dimension *>::const_iterator m=(*i)->getDimensions().begin();
2514  m!=(*i)->getDimensions().end();++m) {
2515  if((*m)->getName() == temprepdimname) {
2516  // Find the dimension size, create the correcteddim
2517  correcteddim = new Dimension(tempcorrecteddimname,(*m)->getSize());
2518  ddimsflag = true;
2519  break;
2520  }
2521  }
2522  if(!ddimsflag)
2523  throw4("cannot find the corrected dimension size", (*i)->getName(),
2524  (*j)->getName(),(*k)->getName());
2525  break;
2526  }
2527  }
2528  if(false == isdimmapname) { // Still need to assign the corrected dimensions.
2529  // Find the new name of this field
2530  tempmapit = (*i)->ndimnamelist.find((*k)->getName());
2531  if(tempmapit != (*i)->ndimnamelist.end())
2532  tempcorrecteddimname= tempmapit->second;
2533  else
2534  throw4("cannot find the corrected dimension name",
2535  (*i)->getName(),(*j)->getName(),(*k)->getName());
2536 
2537  correcteddim = new Dimension(tempcorrecteddimname,(*k)->getSize());
2538 
2539  }
2540  }
2541 
2542  correcteddims.push_back(correcteddim);
2543  }
2544  (*j)->setCorrectedDimensions(correcteddims);
2545  correcteddims.clear();
2546  }// End of creating the corrected dimension vectors for GeoFields.
2547 
2548  // Then the data field.
2549  for (vector<Field *>::const_iterator j =
2550  (*i)->getDataFields().begin();
2551  j != (*i)->getDataFields().end(); ++j) {
2552 
2553  for(vector<Dimension *>::const_iterator k=
2554  (*j)->getDimensions().begin();k!=(*j)->getDimensions().end();++k){
2555 
2556  if(tempnumdm == 0) {
2557 
2558  map<string,string>::iterator tempmapit;
2559  // Find the new name of this field
2560  tempmapit = (*i)->ndimnamelist.find((*k)->getName());
2561  if(tempmapit != (*i)->ndimnamelist.end())
2562  tempcorrecteddimname= tempmapit->second;
2563  else
2564  throw4("cannot find the corrected dimension name", (*i)->getName(),
2565  (*j)->getName(),(*k)->getName());
2566 
2567  correcteddim = new Dimension(tempcorrecteddimname,(*k)->getSize());
2568  }
2569  else {
2570  map<string,string>::iterator tempmapit;
2571  bool isdimmapname = false;
2572  // We have to loop through dimension map
2573  for(vector<SwathDataset::DimensionMap *>::const_iterator l=
2574  (*i)->getDimensionMaps().begin(); l!=(*i)->getDimensionMaps().end();++l){
2575  // This dimension name is the geo dimension name in the dimension map,
2576  // replace the name with data dimension name.
2577  if((*k)->getName() == (*l)->getGeoDimension()) {
2578  isdimmapname = true;
2579  (*j)->dmap = true;
2580  string temprepdimname = (*l)->getDataDimension();
2581 
2582  // Find the new name of this data dimension name
2583  tempmapit = (*i)->ndimnamelist.find(temprepdimname);
2584  if(tempmapit != (*i)->ndimnamelist.end())
2585  tempcorrecteddimname= tempmapit->second;
2586  else
2587  throw4("cannot find the corrected dimension name",
2588  (*i)->getName(),(*j)->getName(),(*k)->getName());
2589 
2590  // Find the size of this data dimension name
2591  // We have to loop through the Dimensions of this swath
2592  bool ddimsflag = false;
2593  for(vector<Dimension *>::const_iterator m=
2594  (*i)->getDimensions().begin();m!=(*i)->getDimensions().end();++m) {
2595 
2596  // Find the dimension size, create the correcteddim
2597  if((*m)->getName() == temprepdimname) {
2598  correcteddim = new Dimension(tempcorrecteddimname,(*m)->getSize());
2599  ddimsflag = true;
2600  break;
2601  }
2602  }
2603  if(!ddimsflag)
2604  throw4("cannot find the corrected dimension size",
2605  (*i)->getName(),(*j)->getName(),(*k)->getName());
2606  break;
2607  }
2608  }
2609  // Not a dimension with dimension map; Still need to assign the corrected dimensions.
2610  if(!isdimmapname) {
2611 
2612  // Find the new name of this field
2613  tempmapit = (*i)->ndimnamelist.find((*k)->getName());
2614  if(tempmapit != (*i)->ndimnamelist.end())
2615  tempcorrecteddimname= tempmapit->second;
2616  else
2617  throw4("cannot find the corrected dimension name",
2618  (*i)->getName(),(*j)->getName(),(*k)->getName());
2619 
2620  correcteddim = new Dimension(tempcorrecteddimname,(*k)->getSize());
2621  }
2622 
2623  }
2624  correcteddims.push_back(correcteddim);
2625  }
2626  (*j)->setCorrectedDimensions(correcteddims);
2627  correcteddims.clear();
2628  }// End of creating the dimensions for data fields.
2629  }
2630 }
2631 
2632 // Handle CF attributes for swaths.
2633 // The CF attributes include "coordinates", "units" for coordinate variables and "_FillValue".
2634 void File::handle_swath_cf_attrs() throw(Exception) {
2635 
2636  // Create "coordinates" ,"units" attributes. The "units" attributes only apply to latitude and longitude.
2637  // This is the last round of looping through everything,
2638  // we will match dimension name list to the corresponding dimension field name
2639  // list for every field.
2640  // Since we find some swath files don't specify fillvalue when -9999.0 is found in the real data,
2641  // we specify fillvalue for those fields. This is entirely
2642  // artifical and we will evaluate this approach. KY 2010-3-3
2643 
2644  for (vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2645  i != this->swaths.end(); ++i){
2646 
2647  // Handle GeoField first.
2648  for (vector<Field *>::const_iterator j =
2649  (*i)->getGeoFields().begin();
2650  j != (*i)->getGeoFields().end(); ++j) {
2651 
2652  // Real fields: adding the coordinate attribute
2653  if((*j)->fieldtype == 0) {// currently it is always true.
2654  string tempcoordinates="";
2655  string tempfieldname="";
2656  string tempcorrectedfieldname="";
2657  int tempcount = 0;
2658  for(vector<Dimension *>::const_iterator
2659  k=(*j)->getDimensions().begin();k!=(*j)->getDimensions().end();++k){
2660 
2661  // handle coordinates attributes
2662  map<string,string>::iterator tempmapit;
2663  map<string,string>::iterator tempmapit2;
2664 
2665  // Find the dimension field name
2666  tempmapit = ((*i)->dimcvarlist).find((*k)->getName());
2667  if(tempmapit != ((*i)->dimcvarlist).end())
2668  tempfieldname = tempmapit->second;
2669  else
2670  throw4("cannot find the dimension field name",(*i)->getName(),
2671  (*j)->getName(),(*k)->getName());
2672 
2673  // Find the corrected dimension field name
2674  tempmapit2 = ((*i)->ncvarnamelist).find(tempfieldname);
2675  if(tempmapit2 != ((*i)->ncvarnamelist).end())
2676  tempcorrectedfieldname = tempmapit2->second;
2677  else
2678  throw4("cannot find the corrected dimension field name",
2679  (*i)->getName(),(*j)->getName(),(*k)->getName());
2680 
2681  if(tempcount == 0)
2682  tempcoordinates= tempcorrectedfieldname;
2683  else
2684  tempcoordinates = tempcoordinates +" "+tempcorrectedfieldname;
2685  tempcount++;
2686  }
2687  (*j)->setCoordinates(tempcoordinates);
2688  }
2689 
2690  // Add units for latitude and longitude
2691  // latitude,adding the CF units degrees_north.
2692  if((*j)->fieldtype == 1) {
2693  string tempunits = "degrees_north";
2694  (*j)->setUnits(tempunits);
2695  }
2696 
2697  // longitude, adding the CF units degrees_east
2698  if((*j)->fieldtype == 2) {
2699  string tempunits = "degrees_east";
2700  (*j)->setUnits(tempunits);
2701  }
2702 
2703  // Add units for Z-dimension, now it is always "level"
2704  // We decide not touch the units if the third-dimension CV exists(fieldtype =3)
2705  // KY 2013-02-15
2706  //if(((*j)->fieldtype == 3)||((*j)->fieldtype == 4))
2707  if((*j)->fieldtype == 4) {
2708  string tempunits ="level";
2709  (*j)->setUnits(tempunits);
2710  }
2711 
2712  // Add units for "Time",
2713  // Be aware that it is always "days since 1900-01-01 00:00:00"(JIRA HFRHANDLER-167)
2714  if((*j)->fieldtype == 5) {
2715  string tempunits = "days since 1900-01-01 00:00:00";
2716  (*j)->setUnits(tempunits);
2717  }
2718  // Set the fill value for floating type data that doesn't have the fill value.
2719  // We found _FillValue attribute is missing from some swath data.
2720  // To cover the most cases, an attribute called _FillValue(the value is -9999.0)
2721  // is added to the data whose type is float32 or float64.
2722  if((((*j)->getFillValue()).empty()) &&
2723  ((*j)->getType()==DFNT_FLOAT32 || (*j)->getType()==DFNT_FLOAT64)) {
2724  float tempfillvalue = -9999.0;
2725  (*j)->addFillValue(tempfillvalue);
2726  (*j)->setAddedFillValue(true);
2727  }
2728  }
2729 
2730  // Data fields
2731  for (vector<Field *>::const_iterator j =
2732  (*i)->getDataFields().begin();
2733  j != (*i)->getDataFields().end(); ++j) {
2734 
2735  // Real fields: adding coordinate attributesinate attributes
2736  if((*j)->fieldtype == 0) {// currently it is always true.
2737  string tempcoordinates="";
2738  string tempfieldname="";
2739  string tempcorrectedfieldname="";
2740  int tempcount = 0;
2741  for(vector<Dimension *>::const_iterator k
2742  =(*j)->getDimensions().begin();k!=(*j)->getDimensions().end();++k){
2743 
2744  // handle coordinates attributes
2745  map<string,string>::iterator tempmapit;
2746  map<string,string>::iterator tempmapit2;
2747 
2748  // Find the dimension field name
2749  tempmapit = ((*i)->dimcvarlist).find((*k)->getName());
2750  if(tempmapit != ((*i)->dimcvarlist).end())
2751  tempfieldname = tempmapit->second;
2752  else
2753  throw4("cannot find the dimension field name",(*i)->getName(),
2754  (*j)->getName(),(*k)->getName());
2755 
2756  // Find the corrected dimension field name
2757  tempmapit2 = ((*i)->ncvarnamelist).find(tempfieldname);
2758  if(tempmapit2 != ((*i)->ncvarnamelist).end())
2759  tempcorrectedfieldname = tempmapit2->second;
2760  else
2761  throw4("cannot find the corrected dimension field name",
2762  (*i)->getName(),(*j)->getName(),(*k)->getName());
2763 
2764  if(tempcount == 0)
2765  tempcoordinates= tempcorrectedfieldname;
2766  else
2767  tempcoordinates = tempcoordinates +" "+tempcorrectedfieldname;
2768  tempcount++;
2769  }
2770  (*j)->setCoordinates(tempcoordinates);
2771  }
2772  // Add units for Z-dimension, now it is always "level"
2773  if(((*j)->fieldtype == 3)||((*j)->fieldtype == 4)) {
2774  string tempunits ="level";
2775  (*j)->setUnits(tempunits);
2776  }
2777 
2778  // Add units for "Time", Be aware that it is always "days since 1900-01-01 00:00:00"
2779  // documented at JIRA (HFRHANDLER-167)
2780  if((*j)->fieldtype == 5) {
2781  string tempunits = "days since 1900-01-01 00:00:00";
2782  (*j)->setUnits(tempunits);
2783  }
2784 
2785  // Set the fill value for floating type data that doesn't have the fill value.
2786  // We found _FillValue attribute is missing from some swath data.
2787  // To cover the most cases, an attribute called _FillValue(the value is -9999.0)
2788  // is added to the data whose type is float32 or float64.
2789  if((((*j)->getFillValue()).empty()) &&
2790  ((*j)->getType()==DFNT_FLOAT32 || (*j)->getType()==DFNT_FLOAT64)) {
2791  float tempfillvalue = -9999.0;
2792  (*j)->addFillValue(tempfillvalue);
2793  (*j)->setAddedFillValue(true);
2794  }
2795  }
2796  }
2797 }
2798 
2802 void File::Prepare(const char *path) throw(Exception)
2803 {
2804 
2805  // check if this is a special HDF-EOS2 grid(MOD08_M3) that have all dimension scales
2806  // added by the HDF4 library but the relation between the dimension scale and the dimension is not
2807  // specified. If the return value is true, we will specify
2808 
2809  // Obtain the number of swaths and the number of grids
2810  int numgrid = this->grids.size();
2811  int numswath = this->swaths.size();
2812 
2813  if(numgrid < 0)
2814  throw2("the number of grid is less than 0", path);
2815 
2816  // First handle grids
2817  if (numgrid > 0) {
2818 
2819  // Obtain "XDim","YDim","Latitude","Longitude" and "location" set.
2820  string DIMXNAME = this->get_geodim_x_name();
2821 
2822  string DIMYNAME = this->get_geodim_y_name();
2823 
2824  string LATFIELDNAME = this->get_latfield_name();
2825 
2826  string LONFIELDNAME = this->get_lonfield_name();
2827 
2828  // Now only there is only one geo grid name "location", so don't call it know.
2829  // string GEOGRIDNAME = this->get_geogrid_name();
2830  string GEOGRIDNAME = "location";
2831 
2832  // Check global lat/lon for multiple grids.
2833  // We want to check if there is a global lat/lon for multiple grids.
2834  // AIRS level 3 data provides lat/lon under the GEOGRIDNAME grid.
2835  check_onelatlon_grids();
2836 
2837  // Handle the third-dimension(both existing and missing) coordinate variables
2838  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
2839  i != this->grids.end(); ++i) {
2840  handle_one_grid_zdim(*i);
2841  }
2842 
2843  // Handle lat/lon fields for the case of which all grids have one dedicated lat/lon grid.
2844  if (true == this->onelatlon)
2845  handle_onelatlon_grids();
2846  else {
2847  for (vector<GridDataset *>::const_iterator i = this->grids.begin();
2848  i != this->grids.end(); ++i) {
2849 
2850  // Set the horizontal dimension name "dimxname" and "dimyname"
2851  // This will be used to detect the dimension major order.
2852  (*i)->setDimxName(DIMXNAME);
2853  (*i)->setDimyName(DIMYNAME);
2854 
2855  // Handle lat/lon(both existing lat/lon and calculated lat/lon from EOS2 APIs)
2856  handle_one_grid_latlon(*i);
2857  }
2858  }
2859 
2860  // Handle the dimension name to coordinate variable map for grid.
2861  handle_grid_dim_cvar_maps();
2862 
2863  // Follow COARDS for grids.
2864  handle_grid_coards();
2865 
2866  // Create the corrected dimension vector for each field when COARDS is not followed.
2867  update_grid_field_corrected_dims();
2868 
2869  // Handle CF attributes for grids.
2870  handle_grid_cf_attrs();
2871 
2872  // Special handling SOM(Space Oblique Mercator) projection files
2873  handle_grid_SOM_projection();
2874 
2875 
2876  }// End of handling grid
2877 
2878  // Check and set the scale type
2879  for(vector<GridDataset *>::const_iterator i = this->grids.begin();
2880  i != this->grids.end(); ++i){
2881  (*i)->SetScaleType((*i)->name);
2882  }
2883 
2884  if(numgrid==0) {
2885 
2886  // Now we handle swath case.
2887  if (numswath > 0) {
2888 
2889  // Obtain the number of dimension maps in this file.
2890  int tempnumdm = obtain_dimmap_num(numswath);
2891 
2892  // Create the dimension name to coordinate variable name map for lat/lon.
2893  create_swath_latlon_dim_cvar_map(tempnumdm);
2894 
2895  // Create the dimension name to coordinate variable name map for non lat/lon coordinate variables.
2896  create_swath_nonll_dim_cvar_map();
2897 
2898  // Handle swath dimension name to coordinate variable name maps.
2899  handle_swath_dim_cvar_maps(tempnumdm);
2900 
2901  // Handle CF attributes for swaths.
2902  // The CF attributes include "coordinates", "units" for coordinate variables and "_FillValue".
2903  handle_swath_cf_attrs();
2904 
2905  // Check and set the scale type
2906  for(vector<SwathDataset *>::const_iterator i = this->swaths.begin();
2907  i != this->swaths.end(); ++i)
2908  (*i)->SetScaleType((*i)->name);
2909  }
2910 
2911  }// End of handling swath
2912 
2913 }
2914 
2915 #if 0
2916 void correct_unlimited_missing_zdim(GridDataset* gdset) throw(Exception) {
2917 
2918  for (vector<Field *>::const_iterator j =
2919  gdset->getDataFields().begin();
2920  j != gdset->getDataFields().end(); ++j) {
2921 
2922  //We only need to search those 1-D fields
2923  if ((*j)->getRank()==1 && (*j)->){
2924 
2925 
2926 
2927  }
2928 
2929  }
2930 }
2931 #endif
2932 
2933 bool File::check_special_1d_grid() throw(Exception) {
2934 
2935  int numgrid = this->grids.size();
2936  int numswath = this->swaths.size();
2937 //cerr<<"coming to check_special_1d_grid "<<endl;
2938 
2939  if (numgrid != 1 || numswath != 0)
2940  return false;
2941 //cerr<<"after checking grid "<<endl;
2942 
2943  // Obtain "XDim","YDim","Latitude","Longitude" and "location" set.
2944  string DIMXNAME = this->get_geodim_x_name();
2945  string DIMYNAME = this->get_geodim_y_name();
2946 
2947  if(DIMXNAME != "XDim" || DIMYNAME != "YDim")
2948  return false;
2949 
2950  int var_dimx_size = 0;
2951  int var_dimy_size = 0;
2952 
2953  GridDataset *mygrid = (this->grids)[0];
2954 
2955  int field_xydim_flag = 0;
2956  for (vector<Field *>::const_iterator i = mygrid->getDataFields().begin();
2957  i!= mygrid->getDataFields().end(); ++i) {
2958  if(1==(*i)->rank) {
2959  if((*i)->name == "XDim"){
2960  field_xydim_flag++;
2961  var_dimx_size = ((*i)->getDimensions())[0]->getSize();
2962  }
2963  if((*i)->name == "YDim"){
2964  field_xydim_flag++;
2965  var_dimy_size = ((*i)->getDimensions())[0]->getSize();
2966  }
2967  }
2968  if(2==field_xydim_flag)
2969  break;
2970  }
2971 
2972  if(field_xydim_flag !=2)
2973  return false;
2974 
2975  // Obtain XDim and YDim size.
2976  int xdimsize = mygrid->getInfo().getX();
2977  int ydimsize = mygrid->getInfo().getY();
2978 
2979  if(var_dimx_size != xdimsize || var_dimy_size != ydimsize)
2980  return false;
2981 
2982  return true;
2983 
2984 }
2985 
2986 
2987 
2988 
2989 
2990 
2991 // Set scale and offset type
2992 // MODIS data has three scale and offset rules.
2993 // They are
2994 // MODIS_EQ_SCALE: raw_data = scale*data + offset
2995 // MODIS_MUL_SCALE: raw_data = scale*(data -offset)
2996 // MODIS_DIV_SCALE: raw_data = (data-offset)/scale
2997 
2998 void Dataset::SetScaleType(const string EOS2ObjName) throw(Exception) {
2999 
3000 
3001  // Group features of MODIS products.
3002  // Using vector of strings instead of the following.
3003  // C++11 may allow the vector of string to be assigned as follows
3004  // string modis_type1[] = {"L1B", "GEO", "BRDF", "0.05Deg", "Reflectance", "MOD17A2", "North","South","MOD_Swath_Sea_Ice","MOD_Grid_MOD15A2","MODIS_NACP_LAI"};
3005 
3006  vector<string> modis_multi_scale_type;
3007  modis_multi_scale_type.push_back("L1B");
3008  modis_multi_scale_type.push_back("GEO");
3009  modis_multi_scale_type.push_back("BRDF");
3010  modis_multi_scale_type.push_back("0.05Deg");
3011  modis_multi_scale_type.push_back("Reflectance");
3012  modis_multi_scale_type.push_back("MOD17A2");
3013  modis_multi_scale_type.push_back("North");
3014  modis_multi_scale_type.push_back("South");
3015  modis_multi_scale_type.push_back("MOD_Swath_Sea_Ice");
3016  modis_multi_scale_type.push_back("MOD_Grid_MOD15A2");
3017  modis_multi_scale_type.push_back("MODIS_NACP_LAI");
3018 
3019  vector<string> modis_div_scale_type;
3020 
3021  // Always start with MOD or mod.
3022  modis_div_scale_type.push_back("VI");
3023  modis_div_scale_type.push_back("1km_2D");
3024  modis_div_scale_type.push_back("L2g_2d");
3025  modis_div_scale_type.push_back("CMG");
3026  modis_div_scale_type.push_back("MODIS SWATH TYPE L2");
3027 
3028  // This one doesn't start with "MOD" or "mod".
3029  //modis_div_scale_type.push_back("VIP_CMG_GRID");
3030 
3031  string modis_eq_scale_type = "LST";
3032  string modis_divequ_scale_group = "MODIS_Grid";
3033  string modis_div_scale_group = "MOD_Grid";
3034 
3035  // The scale-offset rule for the following group may be MULTI but since add_offset is 0. So
3036  // the MULTI rule is equal to the EQU rule. KY 2013-01-25
3037  string modis_equ_scale_group = "MODIS_Grid_1km_2D";
3038 
3039  if(EOS2ObjName=="mod05" || EOS2ObjName=="mod06" || EOS2ObjName=="mod07"
3040  || EOS2ObjName=="mod08" || EOS2ObjName=="atml2")
3041  {
3042  scaletype = MODIS_MUL_SCALE;
3043  return;
3044  }
3045 
3046  // Find one MYD09GA2012.version005 file that
3047  // the grid names change to MODIS_Grid_500m_2D.
3048  // So add this one. KY 2012-11-20
3049 
3050  // Find the grid name in one MCD43C1 file starts with "MCD_CMG_BRDF",
3051  // however, the offset of the data is 0.
3052  // So we may not handle this file here since it follows the CF conventions.
3053  // May need to double check them later. KY 2013-01-24
3054 
3055 
3056  if(EOS2ObjName.find("MOD")==0 || EOS2ObjName.find("mod")==0)
3057  {
3058  size_t pos = EOS2ObjName.rfind(modis_eq_scale_type);
3059  if(pos != string::npos &&
3060  (pos== (EOS2ObjName.length()-modis_eq_scale_type.length())))
3061  {
3062  scaletype = MODIS_EQ_SCALE;
3063  return;
3064  }
3065 
3066  for(unsigned int k=0; k<modis_multi_scale_type.size(); k++)
3067  {
3068  pos = EOS2ObjName.rfind(modis_multi_scale_type[k]);
3069  if (pos !=string::npos &&
3070  (pos== (EOS2ObjName.length()-modis_multi_scale_type[k].length())))
3071  {
3072  scaletype = MODIS_MUL_SCALE;
3073  return;
3074  }
3075  }
3076 
3077  for(unsigned int k=0; k<modis_div_scale_type.size(); k++)
3078  {
3079  pos = EOS2ObjName.rfind(modis_div_scale_type[k]);
3080  if (pos != string::npos &&
3081  (pos==(EOS2ObjName.length()-modis_div_scale_type[k].length()))){
3082  scaletype = MODIS_DIV_SCALE;
3083 
3084  // We have a case that group
3085  // MODIS_Grid_1km_2D should apply the equal scale equation.
3086  // This will be handled after this loop.
3087  if (EOS2ObjName != "MODIS_Grid_1km_2D")
3088  return;
3089  }
3090  }
3091 
3092  // Special handling for MOD_Grid and MODIS_Grid_500m_2D.
3093  // Check if the group name starts with the modis_divequ and modis_div_scale.
3094  pos = EOS2ObjName.find(modis_divequ_scale_group);
3095 
3096  // Find the "MODIS_Grid???" group.
3097  // We have to separate MODIS_Grid_1km_2D(EQ) from other grids(DIV).
3098  if (0 == pos) {
3099  size_t eq_scale_pos = EOS2ObjName.find(modis_equ_scale_group);
3100  if (0 == eq_scale_pos)
3101  scaletype = MODIS_EQ_SCALE;
3102  else
3103  scaletype = MODIS_DIV_SCALE;
3104  }
3105  else {
3106  size_t div_scale_pos = EOS2ObjName.find(modis_div_scale_group);
3107 
3108  // Find the "MOD_Grid???" group.
3109  if ( 0 == div_scale_pos)
3110  scaletype = MODIS_DIV_SCALE;
3111  }
3112  }
3113 
3114  // MEASuRES VIP files have the grid name VIP_CMG_GRID.
3115  // This applies to all VIP version 2 files. KY 2013-01-24
3116  if (EOS2ObjName =="VIP_CMG_GRID")
3117  scaletype = MODIS_DIV_SCALE;
3118 }
3119 
3120 
3121 
3122 // Release resources
3123 Field::~Field()
3124 {
3125  for_each(this->dims.begin(), this->dims.end(), delete_elem());
3126  for_each(this->correcteddims.begin(), this->correcteddims.end(), delete_elem());
3127 }
3128 
3129 // Release resources
3130 Dataset::~Dataset()
3131 {
3132  for_each(this->dims.begin(), this->dims.end(), delete_elem());
3133  for_each(this->datafields.begin(), this->datafields.end(),
3134  delete_elem());
3135  for_each(this->attrs.begin(), this->attrs.end(), delete_elem());
3136 }
3137 
3138 // Retrieve dimensions of grids or swaths
3139 void Dataset::ReadDimensions(int32 (*entries)(int32, int32, int32 *),
3140  int32 (*inq)(int32, char *, int32 *),
3141  vector<Dimension *> &dims) throw(Exception)
3142 {
3143  // Initialize number of dimensions
3144  int32 numdims = 0;
3145 
3146  // Initialize buf size
3147  int32 bufsize = 0;
3148 
3149  // Obtain the number of dimensions and buffer size of holding ","
3150  // separated dimension name list.
3151  if ((numdims = entries(this->datasetid, HDFE_NENTDIM, &bufsize)) == -1)
3152  throw2("dimension entry", this->name);
3153 
3154  // Read all dimension information
3155  if (numdims > 0) {
3156  vector<char> namelist;
3157  vector<int32> dimsize;
3158 
3159  namelist.resize(bufsize + 1);
3160  dimsize.resize(numdims);
3161 
3162  // Inquiry dimension name lists and sizes for all dimensions
3163  if (inq(this->datasetid, &namelist[0], &dimsize[0]) == -1)
3164  throw2("inquire dimension", this->name);
3165 
3166  vector<string> dimnames;
3167 
3168  // Make the "," separated name string to a string list without ",".
3169  // This split is for global dimension of a Swath or a Grid object.
3170  HDFCFUtil::Split(&namelist[0], bufsize, ',', dimnames);
3171  int count = 0;
3172  for (vector<string>::const_iterator i = dimnames.begin();
3173  i != dimnames.end(); ++i) {
3174  Dimension *dim = new Dimension(*i, dimsize[count]);
3175  dims.push_back(dim);
3176  ++count;
3177  }
3178  }
3179 }
3180 
3181 // Retrieve data field info.
3182 void Dataset::ReadFields(int32 (*entries)(int32, int32, int32 *),
3183  int32 (*inq)(int32, char *, int32 *, int32 *),
3184  intn (*fldinfo)
3185  (int32, char *, int32 *, int32 *, int32 *, char *),
3186  intn (*readfld)
3187  (int32, char *, int32 *, int32 *, int32 *, VOIDP),
3188  intn (*getfill)(int32, char *, VOIDP),
3189  bool geofield,
3190  vector<Field *> &fields) throw(Exception)
3191 {
3192 
3193  // Initalize the number of fields
3194  int32 numfields = 0;
3195 
3196  // Initalize the buffer size
3197  int32 bufsize = 0;
3198 
3199  // Obtain the number of fields and buffer size for the current Swath or
3200  // Grid.
3201  if ((numfields = entries(this->datasetid, geofield ?
3202  HDFE_NENTGFLD : HDFE_NENTDFLD, &bufsize)) == -1)
3203  throw2("field entry", this->name);
3204 
3205  // Obtain the information of fields (either data fields or geo-location
3206  // fields of a Swath object)
3207  if (numfields > 0) {
3208  vector<char> namelist;
3209 
3210  namelist.resize(bufsize + 1);
3211 
3212  // Inquiry fieldname list of the current object
3213  if (inq(this->datasetid, &namelist[0], NULL, NULL) == -1)
3214  throw2("inquire field", this->name);
3215 
3216  vector<string> fieldnames;
3217 
3218  // Split the field namelist, make the "," separated name string to a
3219  // string list without ",".
3220  HDFCFUtil::Split(&namelist[0], bufsize, ',', fieldnames);
3221  for (vector<string>::const_iterator i = fieldnames.begin();
3222  i != fieldnames.end(); ++i) {
3223  Field *field = new Field();
3224  field->name = *i;
3225 
3226  // XXX: We assume the maximum number of dimension for an EOS field
3227  // is 16.
3228  int32 dimsize[16];
3229  char dimlist[512]; // XXX: what an HDF-EOS2 developer recommended
3230 
3231  // Obtain most information of a field such as rank, dimension etc.
3232  if ((fldinfo(this->datasetid,
3233  const_cast<char *>(field->name.c_str()),
3234  &field->rank, dimsize, &field->type, dimlist)) == -1){
3235  delete field;
3236  throw3("field info", this->name, field->name);
3237  }
3238  {
3239  vector<string> dimnames;
3240 
3241  // Split the dimension name list for a field
3242  HDFCFUtil::Split(dimlist, ',', dimnames);
3243  if ((int)dimnames.size() != field->rank) {
3244  delete field;
3245  throw4("field rank", dimnames.size(), field->rank,
3246  this->name);
3247  }
3248  for (int k = 0; k < field->rank; ++k) {
3249  Dimension *dim = new Dimension(dimnames[k], dimsize[k]);
3250  field->dims.push_back(dim);
3251  }
3252  }
3253 
3254  // Get fill value of a field
3255  field->filler.resize(DFKNTsize(field->type));
3256  if (getfill(this->datasetid,
3257  const_cast<char *>(field->name.c_str()),
3258  &field->filler[0]) == -1)
3259  field->filler.clear();
3260 
3261  // Append the field into the fields vector.
3262  fields.push_back(field);
3263  }
3264  }
3265 }
3266 
3267 // Retrieve attribute info.
3268 void Dataset::ReadAttributes(int32 (*inq)(int32, char *, int32 *),
3269  intn (*attrinfo)(int32, char *, int32 *, int32 *),
3270  intn (*readattr)(int32, char *, VOIDP),
3271  vector<Attribute *> &attrs) throw(Exception)
3272 {
3273  // Initalize the number of attributes to be 0
3274  int32 numattrs = 0;
3275 
3276  // Initalize the buffer size to be 0
3277  int32 bufsize = 0;
3278 
3279  // Obtain the number of attributes in a Grid or Swath
3280  if ((numattrs = inq(this->datasetid, NULL, &bufsize)) == -1)
3281  throw2("inquire attribute", this->name);
3282 
3283  // Obtain the list of "name, type, value" tuple
3284  if (numattrs > 0) {
3285  vector<char> namelist;
3286 
3287  namelist.resize(bufsize + 1);
3288 
3289  // inquiry namelist and buffer size
3290  if (inq(this->datasetid, &namelist[0], &bufsize) == -1)
3291  throw2("inquire attribute", this->name);
3292 
3293  vector<string> attrnames;
3294 
3295  // Split the attribute namelist, make the "," separated name string to
3296  // a string list without ",".
3297  HDFCFUtil::Split(&namelist[0], bufsize, ',', attrnames);
3298  for (vector<string>::const_iterator i = attrnames.begin();
3299  i != attrnames.end(); ++i) {
3300  Attribute *attr = new Attribute();
3301  attr->name = *i;
3302  attr->newname = HDFCFUtil::get_CF_string(attr->name);
3303 
3304  int32 count = 0;
3305 
3306  // Obtain the datatype and byte count of this attribute
3307  if (attrinfo(this->datasetid, const_cast<char *>
3308  (attr->name.c_str()), &attr->type, &count) == -1) {
3309  delete attr;
3310  throw3("attribute info", this->name, attr->name);
3311  }
3312 
3313  attr->count = count/DFKNTsize(attr->type);
3314  attr->value.resize(count);
3315 
3316 
3317  // Obtain the attribute value. Note that this function just
3318  // provides a copy of all attribute values.
3319  //The client should properly interpret to obtain individual
3320  // attribute value.
3321  if (readattr(this->datasetid,
3322  const_cast<char *>(attr->name.c_str()),
3323  &attr->value[0]) == -1) {
3324  delete attr;
3325  throw3("read attribute", this->name, attr->name);
3326  }
3327 
3328  // Append this attribute to attrs list.
3329  attrs.push_back(attr);
3330  }
3331  }
3332 }
3333 
3334 // Release grid dataset resources
3335 GridDataset::~GridDataset()
3336 {
3337  if (this->datasetid != -1){
3338  GDdetach(this->datasetid);
3339  }
3340 }
3341 
3342 // Retrieve all information of the grid dataset
3343 GridDataset * GridDataset::Read(int32 fd, const string &gridname)
3344  throw(Exception)
3345 {
3346  GridDataset *grid = new GridDataset(gridname);
3347 
3348  // Open this Grid object
3349  if ((grid->datasetid = GDattach(fd, const_cast<char *>(gridname.c_str())))
3350  == -1) {
3351  delete grid;
3352  throw2("attach grid", gridname);
3353  }
3354 
3355  // Obtain the size of XDim and YDim as well as latitude and longitude of
3356  // the upleft corner and the low right corner.
3357  {
3358  Info &info = grid->info;
3359  if (GDgridinfo(grid->datasetid, &info.xdim, &info.ydim, info.upleft,
3360  info.lowright) == -1) {
3361  delete grid;
3362  throw2("grid info", gridname);
3363  }
3364  }
3365 
3366  // Obtain projection information.
3367  {
3368  Projection &proj = grid->proj;
3369  if (GDprojinfo(grid->datasetid, &proj.code, &proj.zone, &proj.sphere,
3370  proj.param) == -1) {
3371  delete grid;
3372  throw2("projection info", gridname);
3373  }
3374  if (GDpixreginfo(grid->datasetid, &proj.pix) == -1) {
3375  delete grid;
3376  throw2("pixreg info", gridname);
3377  }
3378  if (GDorigininfo(grid->datasetid, &proj.origin) == -1){
3379  delete grid;
3380  throw2("origin info", gridname);
3381  }
3382  }
3383 
3384  try {
3385  // Read dimensions
3386  grid->ReadDimensions(GDnentries, GDinqdims, grid->dims);
3387 
3388  // Read all fields of this Grid.
3389  grid->ReadFields(GDnentries, GDinqfields, GDfieldinfo, GDreadfield,
3390  GDgetfillvalue, false, grid->datafields);
3391 
3392  // Read all attributes of this Grid.
3393  grid->ReadAttributes(GDinqattrs, GDattrinfo, GDreadattr, grid->attrs);
3394  }
3395  catch (...) {
3396  delete grid;
3397  throw;
3398  }
3399 
3400  return grid;
3401 }
3402 
3403 GridDataset::Calculated & GridDataset::getCalculated() const
3404 {
3405  if (this->calculated.grid != this)
3406  this->calculated.grid = this;
3407  return this->calculated;
3408 }
3409 
3410 bool GridDataset::Calculated::isYDimMajor() throw(Exception)
3411 {
3412  this->DetectMajorDimension();
3413  return this->ydimmajor;
3414 }
3415 
3416 #if 0
3417 bool GridDataset::Calculated::isOrthogonal() throw(Exception)
3418 {
3419  if (!this->valid)
3420  this->ReadLongitudeLatitude();
3421  return this->orthogonal;
3422 }
3423 #endif
3424 
3425 int GridDataset::Calculated::DetectFieldMajorDimension() throw(Exception)
3426 {
3427  int ym = -1;
3428 
3429  // Traverse all data fields
3430  for (vector<Field *>::const_iterator i =
3431  this->grid->getDataFields().begin();
3432  i != this->grid->getDataFields().end(); ++i) {
3433 
3434  int xdimindex = -1, ydimindex = -1, index = 0;
3435 
3436  // Traverse all dimensions in each data field
3437  for (vector<Dimension *>::const_iterator j =
3438  (*i)->getDimensions().begin();
3439  j != (*i)->getDimensions().end(); ++j) {
3440  if ((*j)->getName() == this->grid->dimxname)
3441  xdimindex = index;
3442  else if ((*j)->getName() == this->grid->dimyname)
3443  ydimindex = index;
3444  ++index;
3445  }
3446  if (xdimindex == -1 || ydimindex == -1)
3447  continue;
3448 
3449  int major = ydimindex < xdimindex ? 1 : 0;
3450 
3451  if (ym == -1)
3452  ym = major;
3453  break;
3454 
3455  // TO gain performance, just check one field.
3456  // The dimension order for all data fields in a grid should be
3457  // consistent.
3458  // Kent adds this if 0 block 2012-09-19
3459 #if 0
3460  else if (ym != major)
3461  throw2("inconsistent XDim, YDim order", this->grid->getName());
3462 #endif
3463 
3464  }
3465  // At least one data field should refer to XDim or YDim
3466  if (ym == -1)
3467  throw2("lack of data fields", this->grid->getName());
3468 
3469  return ym;
3470 }
3471 
3472 void GridDataset::Calculated::DetectMajorDimension() throw(Exception)
3473 {
3474  int ym = -1;
3475  // ydimmajor := true if (YDim, XDim)
3476  // ydimmajor := false if (XDim, YDim)
3477 
3478  // Traverse all data fields
3479 
3480  for (vector<Field *>::const_iterator i =
3481  this->grid->getDataFields().begin();
3482  i != this->grid->getDataFields().end(); ++i) {
3483 
3484  int xdimindex = -1, ydimindex = -1, index = 0;
3485 
3486  // Traverse all dimensions in each data field
3487  for (vector<Dimension *>::const_iterator j =
3488  (*i)->getDimensions().begin();
3489  j != (*i)->getDimensions().end(); ++j) {
3490  if ((*j)->getName() == this->grid->dimxname)
3491  xdimindex = index;
3492  else if ((*j)->getName() == this->grid->dimyname)
3493  ydimindex = index;
3494  ++index;
3495  }
3496  if (xdimindex == -1 || ydimindex == -1)
3497  continue;
3498 
3499  // Change the way of deciding the major dimesion (LD -2012/01/10).
3500  int major;
3501  if(this->grid->getProjection().getCode() == GCTP_LAMAZ)
3502  major = 1;
3503  else
3504  major = ydimindex < xdimindex ? 1 : 0;
3505 
3506  if (ym == -1)
3507  ym = major;
3508  break;
3509 
3510  // TO gain performance, just check one field.
3511  // The dimension order for all data fields in a grid should be
3512  // consistent.
3513  // Kent adds this if 0 block
3514 #if 0
3515  else if (ym != major)
3516  throw2("inconsistent XDim, YDim order", this->grid->getName());
3517 #endif
3518  }
3519  // At least one data field should refer to XDim or YDim
3520  if (ym == -1)
3521  throw2("lack of data fields", this->grid->getName());
3522  this->ydimmajor = ym != 0;
3523 }
3524 
3525 // The following internal utilities are not used currently, will see if
3526 // they are necessary in the future. KY 2012-09-19
3527 // The internal utility method to check if two vectors have overlapped.
3528 // If not, return true.
3529 // Not used. Temporarily comment out to avoid the compiler warnings.
3530 #if 0
3531 static bool IsDisjoint(const vector<Field *> &l,
3532  const vector<Field *> &r)
3533 {
3534  for (vector<Field *>::const_iterator i = l.begin(); i != l.end(); ++i)
3535  {
3536  if (find(r.begin(), r.end(), *i) != r.end())
3537  return false;
3538  }
3539  return true;
3540 }
3541 
3542 // The internal utility method to check if two vectors have overlapped.
3543 // If not, return true.
3544 static bool IsDisjoint(vector<pair<Field *, string> > &l, const vector<Field *> &r)
3545 {
3546  for (vector<pair<Field *, string> >::const_iterator i =
3547  l.begin(); i != l.end(); ++i) {
3548  if (find(r.begin(), r.end(), i->first) != r.end())
3549  return false;
3550  }
3551  return true;
3552 }
3553 
3554 // The internal utility method to check if vector s is a subset of vector b.
3555 static bool IsSubset(const vector<Field *> &s, const vector<Field *> &b)
3556 {
3557  for (vector<Field *>::const_iterator i = s.begin(); i != s.end(); ++i)
3558  {
3559  if (find(b.begin(), b.end(), *i) == b.end())
3560  return false;
3561  }
3562  return true;
3563 }
3564 
3565 // The internal utility method to check if vector s is a subset of vector b.
3566 static bool IsSubset(vector<pair<Field *, string> > &s, const vector<Field *> &b)
3567 {
3568  for (vector<pair<Field *, string> >::const_iterator i
3569  = s.begin(); i != s.end(); ++i) {
3570  if (find(b.begin(), b.end(), i->first) == b.end())
3571  return false;
3572  }
3573  return true;
3574 }
3575 
3576 #endif
3577 // Destructor, release resources
3578 SwathDataset::~SwathDataset()
3579 {
3580  if (this->datasetid != -1) {
3581  SWdetach(this->datasetid);
3582  }
3583 
3584  for_each(this->dimmaps.begin(), this->dimmaps.end(), delete_elem());
3585  for_each(this->indexmaps.begin(), this->indexmaps.end(),
3586  delete_elem());
3587 
3588  for_each(this->geofields.begin(), this->geofields.end(),
3589  delete_elem());
3590  return;
3591 
3592 }
3593 
3594 // Read all information of this swath
3595 SwathDataset * SwathDataset::Read(int32 fd, const string &swathname)
3596  throw(Exception)
3597 {
3598  SwathDataset *swath = new SwathDataset(swathname);
3599 
3600  // Open this Swath object
3601  if ((swath->datasetid = SWattach(fd,
3602  const_cast<char *>(swathname.c_str())))
3603  == -1) {
3604  delete swath;
3605  throw2("attach swath", swathname);
3606  }
3607 
3608  try {
3609 
3610  // Read dimensions of this Swath
3611  swath->ReadDimensions(SWnentries, SWinqdims, swath->dims);
3612 
3613  // Read all information related to data fields of this Swath
3614  swath->ReadFields(SWnentries, SWinqdatafields, SWfieldinfo, SWreadfield,
3615  SWgetfillvalue, false, swath->datafields);
3616 
3617  // Read all information related to geo-location fields of this Swath
3618  swath->ReadFields(SWnentries, SWinqgeofields, SWfieldinfo, SWreadfield,
3619  SWgetfillvalue, true, swath->geofields);
3620 
3621  // Read all attributes of this Swath
3622  swath->ReadAttributes(SWinqattrs, SWattrinfo, SWreadattr, swath->attrs);
3623 
3624  // Read dimension map and save the number of dimension map for dim. subsetting
3625  swath->set_num_map(swath->ReadDimensionMaps(swath->dimmaps));
3626 
3627  // Read index maps, we haven't found any files with the Index Maps.
3628  swath->ReadIndexMaps(swath->indexmaps);
3629  }
3630  catch (...) {
3631  delete swath;
3632  throw;
3633  }
3634 
3635  return swath;
3636 }
3637 
3638 // Read dimension map info.
3639 int SwathDataset::ReadDimensionMaps(vector<DimensionMap *> &dimmaps)
3640  throw(Exception)
3641 {
3642  int32 nummaps, bufsize;
3643 
3644  // Obtain number of dimension maps and the buffer size.
3645  if ((nummaps = SWnentries(this->datasetid, HDFE_NENTMAP, &bufsize)) == -1)
3646  throw2("dimmap entry", this->name);
3647 
3648  // Will use Split utility method to generate a list of dimension map.
3649  // An example of original representation of a swath dimension map:(d1/d2,
3650  // d3/d4,...)
3651  // d1:the name of this dimension of the data field , d2: the name of the
3652  // corresponding dimension of the geo-location field
3653  // The list will be decomposed from (d1/d2,d3/d4,...) to {[d1,d2,0(offset),
3654  // 1(increment)],[d3,d4,0(offset),1(increment)],...}
3655 
3656  if (nummaps > 0) {
3657  vector<char> namelist;
3658  vector<int32> offset, increment;
3659 
3660  namelist.resize(bufsize + 1);
3661  offset.resize(nummaps);
3662  increment.resize(nummaps);
3663  if (SWinqmaps(this->datasetid, &namelist[0], &offset[0], &increment[0])
3664  == -1)
3665  throw2("inquire dimmap", this->name);
3666 
3667  vector<string> mapnames;
3668  HDFCFUtil::Split(&namelist[0], bufsize, ',', mapnames);
3669  int count = 0;
3670  for (vector<string>::const_iterator i = mapnames.begin();
3671  i != mapnames.end(); ++i) {
3672  vector<string> parts;
3673  HDFCFUtil::Split(i->c_str(), '/', parts);
3674  if (parts.size() != 2)
3675  throw3("dimmap part", parts.size(),
3676  this->name);
3677 
3678  DimensionMap *dimmap = new DimensionMap(parts[0], parts[1],
3679  offset[count],
3680  increment[count]);
3681  dimmaps.push_back(dimmap);
3682  ++count;
3683  }
3684  }
3685  return nummaps;
3686 }
3687 
3688 // The following function is nevered tested and probably will never be used.
3689 void SwathDataset::ReadIndexMaps(vector<IndexMap *> &indexmaps)
3690  throw(Exception)
3691 {
3692  int32 numindices, bufsize;
3693 
3694  if ((numindices = SWnentries(this->datasetid, HDFE_NENTIMAP, &bufsize)) ==
3695  -1)
3696  throw2("indexmap entry", this->name);
3697  if (numindices > 0) {
3698  // TODO: I have never seen any EOS2 files that have index map.
3699  vector<char> namelist;
3700 
3701  namelist.resize(bufsize + 1);
3702  if (SWinqidxmaps(this->datasetid, &namelist[0], NULL) == -1)
3703  throw2("inquire indexmap", this->name);
3704 
3705  vector<string> mapnames;
3706  HDFCFUtil::Split(&namelist[0], bufsize, ',', mapnames);
3707  for (vector<string>::const_iterator i = mapnames.begin();
3708  i != mapnames.end(); ++i) {
3709  IndexMap *indexmap = new IndexMap();
3710  vector<string> parts;
3711  HDFCFUtil::Split(i->c_str(), '/', parts);
3712  if (parts.size() != 2)
3713  throw3("indexmap part", parts.size(),
3714  this->name);
3715  indexmap->geo = parts[0];
3716  indexmap->data = parts[1];
3717 
3718  {
3719  int32 dimsize;
3720  if ((dimsize =
3721  SWdiminfo(this->datasetid,
3722  const_cast<char *>(indexmap->geo.c_str())))
3723  == -1)
3724  throw3("dimension info", this->name, indexmap->geo);
3725  indexmap->indices.resize(dimsize);
3726  if (SWidxmapinfo(this->datasetid,
3727  const_cast<char *>(indexmap->geo.c_str()),
3728  const_cast<char *>(indexmap->data.c_str()),
3729  &indexmap->indices[0]) == -1)
3730  throw4("indexmap info", this->name, indexmap->geo,
3731  indexmap->data);
3732  }
3733 
3734  indexmaps.push_back(indexmap);
3735  }
3736  }
3737 }
3738 
3739 
3740 PointDataset::~PointDataset()
3741 {
3742 }
3743 
3744 PointDataset * PointDataset::Read(int32 /*fd*/, const string &pointname)
3745  throw(Exception)
3746 {
3747  PointDataset *point = new PointDataset(pointname);
3748  return point;
3749 }
3750 
3751 
3752 // Read name list from the EOS2 APIs and store names into a vector
3753 bool Utility::ReadNamelist(const char *path,
3754  int32 (*inq)(char *, char *, int32 *),
3755  vector<string> &names)
3756 {
3757  char *fname = const_cast<char *>(path);
3758  int32 bufsize;
3759  int numobjs;
3760 
3761  if ((numobjs = inq(fname, NULL, &bufsize)) == -1) return false;
3762  if (numobjs > 0) {
3763  vector<char> buffer;
3764  buffer.resize(bufsize + 1);
3765  if (inq(fname, &buffer[0], &bufsize) == -1) return false;
3766  HDFCFUtil::Split(&buffer[0], bufsize, ',', names);
3767  }
3768  return true;
3769 }
3770 #endif
3771 
3772 
static bool insert_map(std::map< std::string, std::string > &m, std::string key, std::string val)
This is a safer way to insert and update a c++ map value. Otherwise, the local testsuite at The HDF G...
Definition: HDFCFUtil.cc:64
STL namespace.
#define NBLOCK
Definition: misrproj.h:5
static void Handle_NameClashing(std::vector< std::string > &newobjnamelist)
General routines to handle name clashings.
Definition: HDFCFUtil.cc:176
static std::string get_int_str(int)
Definition: HDFCFUtil.cc:2803
static std::string get_double_str(double, int, int)
Definition: HDFCFUtil.cc:2770
#define NULL
Definition: wcsUtil.h:65
#define throw1(a1)
The followings are convenient functions to throw exceptions with different.
Definition: HDFSP.cc:80
static void Split(const char *s, int len, char sep, std::vector< std::string > &names)
From a string separated by a separator to a list of string, for example, split "ab,c" to {"ab","c"}.
Definition: HDFCFUtil.cc:38
#define throw3(a1, a2, a3)
Definition: HDFSP.cc:82
static std::string get_CF_string(std::string s)
Change special characters to "_".
Definition: HDFCFUtil.cc:80
static bool check_beskeys(const std::string &key)
Check the BES key. This function will check a BES key specified at the file h4.conf.in. If the key's value is either true or yes. The handler claims to find a key and will do some operations. Otherwise, will do different operations. For example, One may find a line H4.EnableCF=true at h4.conf.in. That means, the HDF4 handler will handle the HDF4 files by following CF conventions.
Definition: HDFCFUtil.cc:17
#define throw2(a1, a2)
Definition: HDFSP.cc:81
#define throw4(a1, a2, a3, a4)
Definition: HDFSP.cc:83
#define HUGE
Definition: freeform.h:797
Definition: DODS_Date.h:95