OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
get_dataday.cpp
Go to the documentation of this file.
1 /*
2  * Given a L2 file, determine the dataday(s) it contains
3  */
4 
5 #include <cstdio>
6 #include <cstdlib>
7 #include <boost/geometry.hpp>
8 #include <boost/geometry/geometries/point_xy.hpp>
9 #include <boost/geometry/geometries/polygon.hpp>
10 #include <iostream>
11 #include <netcdf>
12 #include <stdlib.h>
13 #include "timeutils.h"
14 #include "version.h"
15 #include "sensorInfo.h"
16 #include "sensorDefs.h"
17 
18 using namespace std;
19 using namespace netCDF;
20 using namespace netCDF::exceptions;
21 namespace bg = boost::geometry;
22 
23 typedef bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree>> Point_t;
24 typedef bg::model::linestring<Point_t> Linestring_t;
25 typedef bg::model::polygon<Point_t> Polygon_t;
26 typedef bg::model::multi_point<Point_t> MultiPoint_t;
27 
28 enum class DL {
29  NOT_CROSSED,
30  CROSSED,
34 
35 Polygon_t gRing_to_gPolygon(float* gRingLats, float* gRingLons, size_t length){
36  Polygon_t gPolygon;
37 
38  for (size_t i = 0; i < length; i++){
39  double lat = boost::lexical_cast<double>(gRingLats[i]);
40  double lon = boost::lexical_cast<double>(gRingLons[i]);
41  gPolygon.outer().push_back(Point_t{lon,lat});
42  }
43  gPolygon.outer().push_back(Point_t{boost::lexical_cast<double>(gRingLons[0]),boost::lexical_cast<double>(gRingLats[0])});
44 
45  return gPolygon;
46 }
47 
48 void printUsage (int32_t exitStatus) {
49  std::string softwareVersion;
50  softwareVersion += std::to_string(VERSION_MAJOR);
51  softwareVersion += ".";
52  softwareVersion += std::to_string(VERSION_MINOR);
53  softwareVersion += ".";
54  softwareVersion += std::to_string(VERSION_PATCH);
55  softwareVersion += "-";
56  softwareVersion += GITSHA;
57 
58  cout << "get_dataday " << softwareVersion << endl;
59  cout << "\nUsage: get_dataday ifile" << endl;
60  cout << "where:\n\tifile is an L2 file generated by l2gen\n" << endl;
61  cout << "Options:\n\t-h, --help: get this clever little usage statement" << endl;
62  exit(exitStatus);
63 }
64 
66  time_t starttime, /* (in) swath start time
67  (seconds since 1-Jan-1970 00:00:00 GMT) */
68  float equatorialCrossingTime, /* (in) sensor's nominal local equator
69  crossing time (expressed in hours) */
70  DL dateLineCrossed, /* (in) indicates whether swath crosses dateline */
71  float west, /* (in) westernmost longitude of swath */
72  float east, /* (in) easternmost longitude of swath */
73  int32_t *dataday0, /* (out) dataday of swath (days since 1-Jan-1970) */
74  int32_t *dataday1 /* (out) 2nd dataday for datline-spanning swaths */
75  ) {
76  time_t referenceTime;
77  int referenceDay;
78  float referenceHour;
79 
80  referenceTime = (time_t) (starttime + (12 - (double) equatorialCrossingTime)*3600);
81  referenceDay = referenceTime / 86400;
82  referenceHour = (referenceTime % 86400) / 3600.0;
83 
84  if (dateLineCrossed == DL::NOT_CROSSED) {
85  *dataday1 = *dataday0 = referenceDay;
86  } else if (referenceHour < 6) {
87  *dataday0 = referenceDay - 1;
88  *dataday1 = referenceDay;
89  } else if (referenceHour > 18) {
90  *dataday0 = referenceDay;
91  *dataday1 = referenceDay + 1;
92  } else if (dateLineCrossed == DL::CROSSED_NORTH_POLE || dateLineCrossed == DL::CROSSED_SOUTH_POLE) {
93  *dataday1 = *dataday0 = referenceDay;
94  } else {
95  float westOfDateline = 180 - west; /* number of degrees west of dateline */
96  float eastOfDateline = east + 180; /* number of degrees east of dateline */
97 
98  if (westOfDateline > eastOfDateline) {
99  *dataday0 = referenceDay - 1;
100  *dataday1 = referenceDay;
101  } else {
102  *dataday0 = referenceDay;
103  *dataday1 = referenceDay + 1;
104  }
105  }
106 }
107 
108 void getEquatorCrossingTime(int32_t sensorID, bool dayNight, time_t starttime,
109  float *equatorialCrossingTime, int32_t *plusDay) {
110 
111  switch (sensorID) {
112  case HICO:
113  *equatorialCrossingTime = 12.0; // Made this up - RJH
114  break;
115  case MODISA:
116  case VIIRSN:
117  case VIIRSJ1:
118  *equatorialCrossingTime = 13.5;
119  break;
120  case MODIST:
121  case MERIS:
122  case OCTS:
123  *equatorialCrossingTime = 10.5;
124  break;
125  case OLCIS3A:
126  case OLCIS3B:
127  *equatorialCrossingTime = 10.0;
128  break;
129  case CZCS:
130  *equatorialCrossingTime = 12.0;
131  break;
132  case SEAWIFS:
133  *equatorialCrossingTime = 12.0;
134  int16_t year;
135  int16_t day;
136  double secs;
137  unix2yds(starttime, &year, &day, &secs);
138  if (year > 2002) {
139  // The constant 10957 makes d the number of days since 1 Jan. 2000
140  int32_t d = starttime / 86400.0 - 10957.0;
141  /*
142  * On 10 July 2010 (d=3843) OrbView-2/SeaWiFS was nearing the
143  * end of its orbit-raising maneuvers. Before these maneuvers
144  * the node-crossing time was drifting further into the afternoon
145  * (first equation below). After the orbit raising, the node-crossing
146  * time was drifting back towards noon (second equation).
147 
148  * Correction equations provided by Fred Patt.
149  */
150  double deg;
151  if (d < 3843) {
152 
153  deg = 7.7517951e-10 * d * d * d
154  - 2.1692192e-06 * d * d
155  + 0.0070669241 * d
156  - 4.1300585;
157  } else {
158  /*
159  * This equation may need to be replaced with a polynomial
160  * once we get more orbit data under our belts. (16-Jul-2010 N.Kuring)
161  * ...note...the above comment was written before the demise of SeaWiFS
162  * on 11-Dec-2010 ...no further modifications necessary...
163  */
164  deg = -0.024285181 * d + 128.86093;
165  }
166 
167  //The above polynomials yield degrees; convert to hours.
168  float hours = (float) (deg / 15.);
169 
170  *equatorialCrossingTime = 12.0 + hours;
171  }
172 
173  break;
174  case HAWKEYE:
175  *equatorialCrossingTime = 12.0;
176  break;
177  default:
178  cerr << "-W- Unknown equator crossing time for sensorID=" << sensorID << endl;
179  cerr << "-W- Assuming local noon crossing" << endl;
180  *equatorialCrossingTime = 12.0;
181  break;
182 
183  }
184  // Shift the equatorial crossing time by 12 hours if doing night time binning
185  // This is done so that if crossing the dateline the reference hour is being used
186  // to move into a dataday in the same direction in function get_datadays
187  if (dayNight) {
188  *equatorialCrossingTime = *equatorialCrossingTime - 12;
189  if (*equatorialCrossingTime < 0) {
190  *equatorialCrossingTime = *equatorialCrossingTime + 24;
191  *plusDay = 1; // if we do this, we're effectively going back
192  // a day, and we so we need to add a day to the
193  // output of get_datadays...
194  }
195  }
196 }
197 
198 std::string dataday_to_isodate(int32_t dataday) {
199  double datatime = dataday * 86400.0;
200  std::string isoDate(unix2isodate(datatime,'G'));
201  return isoDate;
202 }
203 
204 int main(int argc, char** argv) {
205  //double const earth_radius = 6371.229;
206 
207  // Define the dateline, north and south poles
208  Linestring_t dateline;
209  bg::append(dateline, Point_t(180.0, 89.9999));
210  bg::append(dateline, Point_t(180.0, -89.9999));
211  Point_t northPole = {0, 90.0};
212  Point_t southPole = {0, -90.0};
213 
214  if (argc < 2) {
215  printUsage(0);
216  }
217 
218  string inputFile = argv[1];
219  if (inputFile == "-h" || inputFile == "--help" ){
220  printUsage(0);
221  }
222  // Open the file for read access
223 
224  NcFile* nc_input;
225  try {
226  nc_input = new NcFile(inputFile, NcFile::read );
227  }
228  catch( NcException& e) {
229  e.what();
230  cerr << "\nFailure opening input file: " + inputFile + "\n" << endl;
231  printUsage(NC2_ERR);
232  }
233 
234  multimap <string, NcGroupAtt> attributes;
235  // Get global attributes
236  char instrument[255];
237  char platform[255];
238  char day_night_flag[6];
239  float maxEast;
240  float maxWest;
241  char sceneStartTimeISO[30];
242 
243  attributes = nc_input->getAtts();
244  (attributes.find("geospatial_lon_max")->second).getValues(&maxEast);
245  (attributes.find("geospatial_lon_min")->second).getValues(&maxWest);
246  (attributes.find("time_coverage_start")->second).getValues(sceneStartTimeISO);
247  (attributes.find("instrument")->second).getValues(instrument);
248  (attributes.find("platform")->second).getValues(platform);
249  (attributes.find("day_night_flag")->second).getValues(day_night_flag);
250 
252 
253  double sceneStartTime = isodate2unix(sceneStartTimeISO);
254  // Get navigation_data group attributes
255  NcGroup navGroup = nc_input->getGroup("navigation_data");
256 
257  float* gRingLats;
258  float* gRingLons;
259  attributes = navGroup.getAtts();
260  size_t length = (attributes.find("gringpointlatitude")->second).getAttLength();
261 
262  gRingLats = (float*) calloc(length,sizeof(float));
263  gRingLons = (float*) calloc(length,sizeof(float));
264 
265  (attributes.find("gringpointlatitude")->second).getValues(gRingLats);
266  (attributes.find("gringpointlongitude")->second).getValues(gRingLons);
267 
268  DL dateLineCrossed = DL::NOT_CROSSED;
269 
270  Polygon_t gPolygon = gRing_to_gPolygon(gRingLats,gRingLons,length);
271  free(gRingLats);
272  free(gRingLons);
273  nc_input->close();
274  std::vector<Point_t> result;
275  bg::intersection(dateline,gPolygon,result);
276  if (result.size()) {
277  if (bg::within(northPole, gPolygon)) {
278  dateLineCrossed = DL::CROSSED_NORTH_POLE;
279  cout << "# Scene crossed North pole" << endl;
280  } else if (bg::within(southPole, gPolygon)) {
281  cout << "# Scene crossed South pole" << endl;
282  dateLineCrossed = DL::CROSSED_SOUTH_POLE;
283  } else {
284  cout << "# Scene crossed dateline" << endl;
285  dateLineCrossed = DL::CROSSED;
286  }
287  }
288 
289  int32_t dataday0, dataday1;
290  int32_t plusDay = 0;
291  float equatorialCrossingTime;
292  bool nightScene = false;
293  if (std::string(day_night_flag) == "Night"){
294  nightScene = true;
295  }
296  getEquatorCrossingTime(sensorID, nightScene, sceneStartTime, &equatorialCrossingTime, &plusDay);
297 
298  get_datadays(sceneStartTime, equatorialCrossingTime, dateLineCrossed,
299  maxWest, maxEast, &dataday0, &dataday1);
300 
301  std::string startDataDay = dataday_to_isodate(dataday0 + plusDay);
302  std::string stopDataDay = dataday_to_isodate(dataday1 + plusDay);
303  // Print out day/night flag
304  cout << "Day_Night_Flag=" << day_night_flag << endl;
305  // Print out the derived dataday(s)
306  if (dataday0 == dataday1) {
307  cout << "DataDay0=" << startDataDay.substr(0, 10) << endl;
308 
309  } else {
310  cout << "DataDay0=" << startDataDay.substr(0, 10) << "\nDataDay1=" << stopDataDay.substr(0, 10) << endl;
311  }
312 
313  return 0;
314 }
315 
void printUsage(int32_t exitStatus)
Definition: get_dataday.cpp:48
#define OLCIS3A
Definition: sensorDefs.h:32
int32_t day
int instrumentPlatform2SensorId(const char *instrument, const char *platform)
Definition: sensorInfo.c:302
Polygon_t gRing_to_gPolygon(float *gRingLats, float *gRingLons, size_t length)
Definition: get_dataday.cpp:35
#define VERSION_MINOR
Definition: version.h:2
@ CROSSED
int main(int argc, char **argv)
#define VIIRSN
Definition: sensorDefs.h:23
#define MERIS
Definition: sensorDefs.h:22
@ CROSSED_IRREGULAR
#define GITSHA
Definition: version.h:4
float * lat
#define MODIST
Definition: sensorDefs.h:18
#define VERSION_PATCH
Definition: version.h:3
@ CROSSED_SOUTH_POLE
std::string dataday_to_isodate(int32_t dataday)
@ string
#define VERSION_MAJOR
Definition: version.h:1
@ CROSSED_NORTH_POLE
bg::model::linestring< Point_t > Linestring_t
Definition: get_dataday.cpp:24
bg::model::point< double, 2, bg::cs::spherical_equatorial< bg::degree > > Point_t
Definition: get_dataday.cpp:23
#define HAWKEYE
Definition: sensorDefs.h:39
bg::model::multi_point< Point_t > MultiPoint_t
Definition: get_dataday.cpp:26
void unix2yds(double usec, short *year, short *day, double *secs)
void getEquatorCrossingTime(int32_t sensorID, bool dayNight, time_t starttime, float *equatorialCrossingTime, int32_t *plusDay)
@ NOT_CROSSED
#define OCTS
Definition: sensorDefs.h:14
subroutine geometry
void get_datadays(time_t starttime, float equatorialCrossingTime, DL dateLineCrossed, float west, float east, int32_t *dataday0, int32_t *dataday1)
Definition: get_dataday.cpp:65
char * unix2isodate(double dtime, char zone)
Definition: unix2isodate.c:10
#define CZCS
Definition: sensorDefs.h:17
float * lon
#define OLCIS3B
Definition: sensorDefs.h:41
#define HICO
Definition: sensorDefs.h:25
DL
Definition: get_dataday.cpp:28
bg::model::polygon< Point_t > Polygon_t
Definition: get_dataday.cpp:25
#define SEAWIFS
Definition: sensorDefs.h:12
int i
Definition: decode_rs.h:71
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:97
#define MODISA
Definition: sensorDefs.h:19
#define VIIRSJ1
Definition: sensorDefs.h:37
a context in which it is NOT documented to do so subscript which cannot be easily calculated when extracting TONS attitude data from the Terra L0 files Corrected several defects in extraction of entrained ephemeris and and as HDF file attributes
Definition: HISTORY.txt:65
double isodate2unix(const char *isodate)
Definition: unix2isodate.c:61