OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
l1_safe.cpp
Go to the documentation of this file.
1 /* =============================================================================================== */
2 /* module l1_safe.cpp - functions to read MERIS and OLCI SAFE formatted (coastal color) for MSL12 */
3 /* Written By: Richard Healy (SAIC) July 29, 2015. */
4 /* Modified By: Don Shea (SAIC) April 2, 2022. */
5 /* */
6 /* =============================================================================================== */
7 
8 #include <netcdf.h>
9 
10 #include "l1_safe.h"
11 #include "smile.h"
12 #include "math.h"
13 #include <string>
14 #include <vector>
15 
16 #include <gsl/gsl_spline2d.h>
17 
18 using namespace std;
19 
20 #define NEW_CACHE_SIZE 10000000
21 #define NEW_CACHE_NELEMS 23
22 #define NEW_CACHE_PREEMPTION 1.0
23 
24 #define BANDINFO_FILENAME_MERIS "band_info_meris.txt"
25 #define BANDINFO_FILENAME_OLCI "band_info_olci.txt"
26 
27 #define ANGLE_FILL_VALUE (-999)
28 
29 static int16_t npix;
30 static int64_t *scan_start_tai;
31 static double lastvalidtime;
32 static int lastvalidscan = 0;
33 static vector<string> radFilename;
34 static vector<int32_t> radFileID;
35 static vector<string> radVarname;
36 static string geoCoordinatesFilename, tieGeometriesFilename, instrumentFilename, timeCoordinatesFilename, qualityFlagsFilename;
37 static int32_t geoCoordinatesFileID, tieGeometriesFileID, instrumentFileID, timeCoordinatesFileID, qualityFileID;
38 
39 
40 int openl1_safe(filehandle * l1file) {
41  size_t source_w, source_h, source_b;
42  int32_t nscan;
43  int xid, yid, bid, retval, sds_id;
44  int i;
45  size_t start[3], count[3];
46  unsigned short orbit_number;
47  size_t attrLength;
48 
49  string indirStr;
50  string tmpStr = l1file->name;
51  size_t pos = tmpStr.rfind('/');
52  if(pos != string::npos) {
53  indirStr = tmpStr.substr(0,pos+1);
54  }
55 
56  instrumentFilename = indirStr + "instrument_data.nc";
57  timeCoordinatesFilename = indirStr + "time_coordinates.nc";
58  geoCoordinatesFilename = indirStr + "geo_coordinates.nc";
59  tieGeometriesFilename = indirStr + "tie_geometries.nc";
60  qualityFlagsFilename = indirStr + "qualityFlags.nc";
61 
62  // set vector sizes
63  radFilename.resize(l1file->nbands);
64  radFileID.resize(l1file->nbands);
65  radVarname.resize(l1file->nbands);
66 
67  for (i = 0; i < l1file->nbands; i++) {
68  string numStr = to_string(i+1);
69  if(numStr.size() == 1)
70  numStr = (string) "0" + numStr;
71  if(l1file->sensorID == MERIS)
72  radFilename[i] = indirStr + "M" + numStr + "_radiance.nc";
73  else
74  radFilename[i] = indirStr + "Oa" + numStr + "_radiance.nc";
75 
76  if(want_verbose)
77  printf("SAFE rad=%s\n", radFilename[i].c_str());
78  }
79 
80  // Open the netcdf4 input file
81  if (nc_set_chunk_cache(NEW_CACHE_SIZE, NEW_CACHE_NELEMS,
82  NEW_CACHE_PREEMPTION) != NC_NOERR) {
83  fprintf(stderr, "-E- %s line %d: nc_set_chunk_cache (%s) failed.\n",
84  __FILE__, __LINE__, l1file->name);
85  exit(EXIT_FAILURE);
86  }
87  retval = nc_open(instrumentFilename.c_str(), NC_NOWRITE, &instrumentFileID);
88  if (retval != NC_NOERR) {
89  fprintf(stderr, "-E- %s line %d: nc_open(%s) failed.\n",
90  __FILE__, __LINE__, instrumentFilename.c_str());
91  exit(EXIT_FAILURE);
92  }
93 
94  // Get pixel and scan dimensions
95  DPTB(nc_inq_dimid(instrumentFileID, "rows", &yid));
96  DPTB(nc_inq_dimid(instrumentFileID, "columns", &xid));
97  DPTB(nc_inq_dimid(instrumentFileID, "bands", &bid));
98  DPTB(nc_inq_dimlen(instrumentFileID, xid, &source_w));
99  DPTB(nc_inq_dimlen(instrumentFileID, yid, &source_h));
100  DPTB(nc_inq_dimlen(instrumentFileID, bid, &source_b));
101  if (source_b != (size_t)l1file->nbands) {
102  fprintf(stderr, "-E- %s line %d: num bands (%d) does not match expected SAFE num bands (%d).\n",
103  __FILE__, __LINE__, (int) source_b, l1file->nbands);
104  exit(EXIT_FAILURE);
105  }
106 
107  DPTB(nc_get_att_ushort(instrumentFileID, NC_GLOBAL, "absolute_orbit_number", &orbit_number));
108  DPTB(nc_inq_attlen(instrumentFileID, NC_GLOBAL, "product_name", &attrLength));
109  char* productName = (char*) allocateMemory(attrLength + 1, "product_name");
110  DPTB(nc_get_att_text(instrumentFileID, NC_GLOBAL, "product_name", productName));
111  if (strstr(productName, "ME_1_FRG")) {
112  strcpy(l1file->spatialResolution, "300 m");
113  } else if (strstr(productName, "ME_1_RRG")) {
114  strcpy(l1file->spatialResolution, "1.2 km");
115  } else if (strstr(productName, "OL_1_EFR")) {
116  strcpy(l1file->spatialResolution, "300 m");
117  } else if (strstr(productName, "OL_1_ERR")) {
118  strcpy(l1file->spatialResolution, "1.2 km");
119  } else {
120  fprintf(stderr, "-E- %s line %d: nc_open(%s) illegal product = \"%s\".\n",
121  __FILE__, __LINE__, l1file->name, productName);
122  exit(EXIT_FAILURE);
123  }
124  free(productName);
125 
126  if (want_verbose) {
127  printf("%s L1B SAFE Npix :%d Nscans:%d\n", sensorId2SensorName(l1file->sensorID), (int) source_w,
128  (int) source_h);
129  } // want_verbose
130 
131  npix = (int32_t) source_w;
132  nscan = (int32_t) source_h;
133 
134  l1file->orbit_number = orbit_number;
135  l1file->nbands = source_b;
136  l1file->npix = npix;
137  l1file->nscan = nscan;
138 
139  scan_start_tai = (int64_t *) calloc(nscan, sizeof (int64_t));
140 
141  start[0] = 0;
142  count[0] = nscan;
143 
144  retval = nc_open(timeCoordinatesFilename.c_str(), NC_NOWRITE, &timeCoordinatesFileID);
145  if (retval != NC_NOERR) {
146  fprintf(stderr, "-E- %s line %d: nc_open(%s) failed.\n",
147  __FILE__, __LINE__, timeCoordinatesFilename.c_str());
148  exit(EXIT_FAILURE);
149  }
150 
151  DPTB(nc_inq_varid(timeCoordinatesFileID, "time_stamp", &sds_id)); //microseconds since 1/1/2000
152  DPTB(nc_get_vara_long(timeCoordinatesFileID, sds_id, start, count, (long*) scan_start_tai));
153 
154  retval = nc_open(geoCoordinatesFilename.c_str(), NC_NOWRITE, &geoCoordinatesFileID);
155  if (retval != NC_NOERR) {
156  fprintf(stderr, "-E- %s line %d: nc_open(%s) failed.\n",
157  __FILE__, __LINE__, geoCoordinatesFilename.c_str());
158  exit(EXIT_FAILURE);
159  }
160 
161  retval = nc_open(tieGeometriesFilename.c_str(), NC_NOWRITE, &tieGeometriesFileID);
162  if (retval != NC_NOERR) {
163  fprintf(stderr, "-E- %s line %d: nc_open(%s) failed.\n",
164  __FILE__, __LINE__, tieGeometriesFilename.c_str());
165  exit(EXIT_FAILURE);
166  }
167 
168  retval = nc_open(qualityFlagsFilename.c_str(), NC_NOWRITE, &qualityFileID);
169  if (retval != NC_NOERR) {
170  fprintf(stderr, "-E- %s line %d: nc_open(%s) failed.\n",
171  __FILE__, __LINE__, qualityFlagsFilename.c_str());
172  return (1);
173  }
174 
175  for (i = 0; i < l1file->nbands; i++) {
176  // Open each of the netcdf4 Lt files for each band
177  retval = nc_open(radFilename[i].c_str(), NC_NOWRITE, &radFileID[i]);
178  if (retval != NC_NOERR) {
179  fprintf(stderr,
180  "-E- %s line %d: nc_open failed for file, %s.\n",
181  __FILE__, __LINE__, radFilename[i].c_str());
182  exit(EXIT_FAILURE);
183  }
184  string numStr = to_string(i+1);
185  if(numStr.size() == 1)
186  numStr = (string) "0" + numStr;
187  if(l1file->sensorID == MERIS)
188  radVarname[i] = (string) "M" + numStr + "_radiance";
189  else
190  radVarname[i] = (string) "Oa" + numStr + "_radiance";
191  }
192 
193  return (LIFE_IS_GOOD);
194 }
195 
196 int readl1_safe(filehandle *file, int32_t scan, l1str *l1rec) {
197  static int firstCall = 1;
198  static double time_interval;
199  static double tai93at2000;
200  static int32_t *lon, *lat;
201  static int32_t lonFillValue, latFillValue;
202  static int longitudeVarID, latitudeVarID;
203  static int solaVarID, solzVarID, senaVarID, senzVarID;
204  static double scale_lon, scale_lat;
205  static double scale_solz, scale_sola, scale_senz, scale_sena;
206  static int detectorIndexVarID;
207  static int16_t *detector_index;
208  static uint32_t *qualityFlags;
209  static vector<int> radVarID;
210  static vector<float> radScale;
211  static vector<float> radOffset;
212  static vector<uint16_t> radFillValue;
213 
214  static float *lambda0, *solar_flux;
215  static size_t detectors;
216  static uint16_t *rad_data;
217  static size_t num_tie_cols, num_tie_rows;
218  static uint16_t tie_row_subsample, tie_col_subsample;
219 
220  static double *solz_xa, *solz_ya, *solz_za;
221  static double *sola_x_xa, *sola_x_ya, *sola_x_za;
222  static double *sola_y_xa, *sola_y_ya, *sola_y_za;
223  static double *senz_xa, *senz_ya, *senz_za;
224  static double *sena_x_xa, *sena_x_ya, *sena_x_za;
225  static double *sena_y_xa, *sena_y_ya, *sena_y_za;
226  static gsl_spline2d *solz_spline;
227  static gsl_spline2d *sola_x_spline;
228  static gsl_spline2d *sola_y_spline;
229  static gsl_spline2d *senz_spline;
230  static gsl_spline2d *sena_x_spline;
231  static gsl_spline2d *sena_y_spline;
232  static gsl_interp_accel *solz_xacc, *solz_yacc;
233  static gsl_interp_accel *sola_x_xacc, *sola_x_yacc;
234  static gsl_interp_accel *sola_y_xacc, *sola_y_yacc;
235  static gsl_interp_accel *senz_xacc, *senz_yacc;
236  static gsl_interp_accel *sena_x_xacc, *sena_x_yacc;
237  static gsl_interp_accel *sena_y_xacc, *sena_y_yacc;
238 
239  float *detectorTmpFloat;
240 
241  int retval;
242 
243  int32_t ip, ib, ipb;
244  int32_t nbands = l1rec->l1file->nbands;
245  size_t start[3], count[3];
246 
247  int xid, yid;
248 
249  if (firstCall) {
250  firstCall = 0;
251  if (want_verbose)
252  printf("file->nbands = %d, l1rec->nbands = %d\n",
253  (int) file->nbands, (int) l1rec->l1file->nbands);
254 
255  // set the size of the vectors
256  radVarID.resize(nbands);
257  radScale.resize(nbands);
258  radOffset.resize(nbands);
259  radFillValue.resize(nbands);
260 
261  // This is the time offset between what the time utilities need (1/1/1970) and what
262  // the SAFE netcdf provides (1/1/2000)
263  tai93at2000 = yds2tai93(2000, 1, 0.0);
264 
265  DPTB(nc_inq_dimid(tieGeometriesFileID, "tie_columns", &xid));
266  DPTB(nc_inq_dimlen(tieGeometriesFileID, xid, &num_tie_cols));
267  DPTB(nc_inq_dimid(tieGeometriesFileID, "tie_rows", &yid));
268  DPTB(nc_inq_dimlen(tieGeometriesFileID, yid, &num_tie_rows));
269  DPTB(nc_get_att_ushort(tieGeometriesFileID, NC_GLOBAL, "ac_subsampling_factor", &tie_col_subsample));
270  DPTB(nc_get_att_ushort(tieGeometriesFileID, NC_GLOBAL, "al_subsampling_factor", &tie_row_subsample));
271 
272  if (((num_tie_rows-1) * tie_row_subsample + 1) != (size_t)file->nscan) {
273  printf("-E- %s line %d: Sanity check failed - tie_rows (%d) x tie_row_pts (%d) < nscan (%d) in file %s\n",
274  __FILE__, __LINE__, (int) num_tie_rows, tie_row_subsample, file->nscan, tieGeometriesFilename.c_str());
275  exit(EXIT_FAILURE);
276  }
277  if (((num_tie_cols - 1) * tie_col_subsample + 1) != (size_t)file->npix) {
278  printf("-E- %s line %d: Sanity check failed - tie_cols (%d) x tie_col_pts (%d) != npix (%d) in file %s\n",
279  __FILE__, __LINE__, (int) num_tie_cols, tie_col_subsample, file->nscan, tieGeometriesFilename.c_str());
280  exit(EXIT_FAILURE);
281  }
282 
283  lon = (int32_t *) calloc(npix, sizeof (int32_t));
284  lat = (int32_t *) calloc(npix, sizeof (int32_t));
285 
286  detector_index = (int16_t*) calloc(npix, sizeof (int16_t));
287  qualityFlags = (uint32_t*) calloc(npix, sizeof (uint32_t));
288 
289  DPTB(nc_inq_dimid(instrumentFileID, "detectors", &xid));
290  DPTB(nc_inq_dimlen(instrumentFileID, xid, &detectors));
291 
292  detectorTmpFloat = (float*) allocateMemory(nbands * detectors * sizeof (float), "detectorTmpFloat");
293  lambda0 = (float*) allocateMemory(nbands * detectors * sizeof (float), "lambda0");
294  solar_flux = (float*) allocateMemory(nbands * detectors * sizeof (float), "solar_flux");
295 
296  rad_data = (unsigned short *) calloc(npix, sizeof (unsigned short)); //BYSCAN
297 
298  start[0] = 0;
299  start[1] = 0;
300  start[2] = 0;
301  count[0] = nbands;
302  count[1] = detectors;
303  count[2] = 0;
304 
305  if (l1_input->rad_opt != 0) {
306  retval = nc_inq_varid(instrumentFileID, "lambda0", &xid);
307  if (retval != NC_NOERR) {
308  fprintf(stderr,
309  "-E- %s line %d: nc_get_varid failed for file, %s field, %s.\n",
310  __FILE__, __LINE__, instrumentFilename.c_str(), "lambda0");
311  exit(EXIT_FAILURE);
312  }
313  retval = nc_get_vara_float(instrumentFileID, xid, start, count, detectorTmpFloat);
314  if (retval != NC_NOERR) {
315  fprintf(stderr,
316  "-E- %s line %d: nc_get_vara_float failed for file, %s field, %s.\n",
317  __FILE__, __LINE__, instrumentFilename.c_str(), "lambda0");
318  exit(EXIT_FAILURE);
319  }
320  // swap axis of the array
321  for (int32_t i = 0; i < nbands; i++)
322  for (size_t j = 0; j < detectors; j++)
323  lambda0[j * nbands + i] = detectorTmpFloat[i * detectors + j];
324 
325  retval = nc_inq_varid(instrumentFileID, "solar_flux", &xid);
326  if (retval != NC_NOERR) {
327  fprintf(stderr,
328  "-E- %s line %d: nc_get_vara_float failed for file, %s field, %s.\n",
329  __FILE__, __LINE__, instrumentFilename.c_str(), "solar_flux");
330  exit(EXIT_FAILURE);
331  }
332  retval = nc_get_vara_float(instrumentFileID, xid, start, count, detectorTmpFloat);
333  if (retval != NC_NOERR) {
334  fprintf(stderr,
335  "-E- %s line %d: nc_get_vara_float failed for file, %s field, %s.\n",
336  __FILE__, __LINE__, instrumentFilename.c_str(), "solar_flux");
337  exit(EXIT_FAILURE);
338  }
339  // swap axis of the array
340  for (int32_t i = 0; i < nbands; i++)
341  for (size_t j = 0; j < detectors; j++)
342  solar_flux[j * nbands + i] = detectorTmpFloat[i * detectors + j];
343  free(detectorTmpFloat);
344 
345  char *tmp_str;
346  char filename[FILENAME_MAX];
347  if ((tmp_str = getenv("OCDATAROOT")) == NULL) {
348  printf("OCDATAROOT environment variable is not defined.\n");
349  exit(EXIT_FAILURE);
350  }
351  strcpy(filename, tmp_str);
352  strcat(filename, "/");
353  strcat(filename, sensorId2SensorDir(l1rec->l1file->sensorID));
354  if(l1rec->l1file->sensorID == MERIS) {
355  strcat(filename, "/cal/");
357  } else {
358  strcat(filename, "/");
359  strcat(filename, subsensorId2SubsensorDir(l1rec->l1file->subsensorID));
360  strcat(filename, "/cal/");
362  }
363 
364  smile_init(nbands, detectors, filename, lambda0, solar_flux);
365  } // if rad_opt
366 
367  DPTB(nc_inq_varid(geoCoordinatesFileID, "longitude", &longitudeVarID));
368  DPTB(nc_get_att_double(geoCoordinatesFileID, longitudeVarID, "scale_factor", &scale_lon));
369  lonFillValue = -2147483648;
370  retval = nc_get_att_int(geoCoordinatesFileID, longitudeVarID, "_FillValue", &lonFillValue);
371  DPTB(nc_inq_varid(geoCoordinatesFileID, "latitude", &latitudeVarID));
372  DPTB(nc_get_att_double(geoCoordinatesFileID, latitudeVarID, "scale_factor", &scale_lat));
373  latFillValue = -2147483648;
374  retval = nc_get_att_int(geoCoordinatesFileID, latitudeVarID, "_FillValue", &latFillValue);
375 
376  DPTB(nc_inq_varid(tieGeometriesFileID, "SAA", &solaVarID));
377  DPTB(nc_get_att_double(tieGeometriesFileID, solaVarID, "scale_factor", &scale_sola));
378  DPTB(nc_inq_varid(tieGeometriesFileID, "SZA", &solzVarID));
379  DPTB(nc_get_att_double(tieGeometriesFileID, solzVarID, "scale_factor", &scale_solz));
380 
381  DPTB(nc_inq_varid(tieGeometriesFileID, "OAA", &senaVarID));
382  DPTB(nc_get_att_double(tieGeometriesFileID, senaVarID, "scale_factor", &scale_sena));
383  DPTB(nc_inq_varid(tieGeometriesFileID, "OZA", &senzVarID));
384  DPTB(nc_get_att_double(tieGeometriesFileID, senzVarID, "scale_factor", &scale_senz));
385 
386  DPTB(nc_inq_varid(instrumentFileID, "detector_index", &detectorIndexVarID));
387 
388  for (ib = 0; ib < nbands; ib++) {
389  retval = nc_inq_varid(radFileID[ib], radVarname[ib].c_str(), &radVarID[ib]);
390  if (retval != NC_NOERR) {
391  fprintf(stderr,
392  "-E- %s line %d: nc_inq_varid failed for file=%s, field=%s.\n",
393  __FILE__, __LINE__, radFilename[ib].c_str(), radVarname[ib].c_str());
394  exit(EXIT_FAILURE);
395  }
396  retval = nc_get_att_float(radFileID[ib], radVarID[ib], "scale_factor", &radScale[ib]);
397  if (retval != NC_NOERR) {
398  fprintf(stderr,
399  "-E- %s line %d: nc_get_att_float failed for file=%s, field=%s, attribute=scale_factor.\n",
400  __FILE__, __LINE__, radFilename[ib].c_str(), radVarname[ib].c_str());
401  exit(EXIT_FAILURE);
402  }
403  retval = nc_get_att_float(radFileID[ib], radVarID[ib], "add_offset", &radOffset[ib]);
404  if (retval != NC_NOERR) {
405  fprintf(stderr,
406  "-E- %s line %d: nc_get_att_float failed for file=%s, field=%s, attribute=add_offset.\n",
407  __FILE__, __LINE__, radFilename[ib].c_str(), radVarname[ib].c_str());
408  exit(EXIT_FAILURE);
409  }
410  retval = nc_get_att_ushort(radFileID[ib], radVarID[ib], "_FillValue", &radFillValue[ib]);
411  if (retval != NC_NOERR) {
412  fprintf(stderr,
413  "-E- %s line %d: nc_get_att_float failed for file=%s, field=%s, attribute=_FillValue.\n",
414  __FILE__, __LINE__, radFilename[ib].c_str(), radVarname[ib].c_str());
415  exit(EXIT_FAILURE);
416  }
417 
418  }
419 
420  int num_tie_points = num_tie_cols * num_tie_rows;
421  int32_t *tmp_int = (int32_t*) allocateMemory(num_tie_points * sizeof(int32_t), "tmp_int array for sol and sen");
422  uint32_t *tmp_uint = (uint32_t*) tmp_int;
423 
424  solz_xa = (double*) allocateMemory(num_tie_cols * sizeof(double), "solz_xa");
425  solz_ya = (double*) allocateMemory(num_tie_rows * sizeof(double), "solz_ya");
426  solz_za = (double*) allocateMemory(num_tie_points * sizeof(double), "solz_za");
427  sola_x_xa = (double*) allocateMemory(num_tie_cols * sizeof(double), "sola_pos_xa");
428  sola_x_ya = (double*) allocateMemory(num_tie_rows * sizeof(double), "sola_pos_ya");
429  sola_x_za = (double*) allocateMemory(num_tie_points * sizeof(double), "sola_pos_za");
430  sola_y_xa = (double*) allocateMemory(num_tie_cols * sizeof(double), "sola_neg_xa");
431  sola_y_ya = (double*) allocateMemory(num_tie_rows * sizeof(double), "sola_neg_ya");
432  sola_y_za = (double*) allocateMemory(num_tie_points * sizeof(double), "sola_neg_za");
433  senz_xa = (double*) allocateMemory(num_tie_cols * sizeof(double), "senz_xa");
434  senz_ya = (double*) allocateMemory(num_tie_rows * sizeof(double), "senz_ya");
435  senz_za = (double*) allocateMemory(num_tie_points * sizeof(double), "senz_za");
436  sena_x_xa = (double*) allocateMemory(num_tie_cols * sizeof(double), "sena_pos_xa");
437  sena_x_ya = (double*) allocateMemory(num_tie_rows * sizeof(double), "sena_pos_ya");
438  sena_x_za = (double*) allocateMemory(num_tie_points * sizeof(double), "sena_pos_za");
439  sena_y_xa = (double*) allocateMemory(num_tie_cols * sizeof(double), "sena_neg_xa");
440  sena_y_ya = (double*) allocateMemory(num_tie_rows * sizeof(double), "sena_neg_ya");
441  sena_y_za = (double*) allocateMemory(num_tie_points * sizeof(double), "sena_neg_za");
442  int index = 0;
443  for(size_t i=0; i<num_tie_cols; i++) {
444  solz_xa[i] = index;
445  sola_x_xa[i] = index;
446  sola_y_xa[i] = index;
447  senz_xa[i] = index;
448  sena_x_xa[i] = index;
449  sena_y_xa[i] = index;
450  index += tie_col_subsample;
451  }
452  index = 0;
453  for(size_t i=0; i<num_tie_rows; i++) {
454  solz_ya[i] = index;
455  sola_x_ya[i] = index;
456  sola_y_ya[i] = index;
457  senz_ya[i] = index;
458  sena_x_ya[i] = index;
459  sena_y_ya[i] = index;
460  index += tie_row_subsample;
461  }
462  DPTB(nc_get_var_uint(tieGeometriesFileID, solzVarID, tmp_uint));
463  for(int i=0; i<num_tie_points; i++) {
464  solz_za[i] = tmp_uint[i] * scale_solz;
465  }
466  DPTB(nc_get_var_int(tieGeometriesFileID, solaVarID, tmp_int));
467  for(int i=0; i<num_tie_points; i++) {
468  double angle = tmp_int[i] * scale_sola / RADEG;
469  sola_x_za[i] = cos(angle);
470  sola_y_za[i] = sin(angle);
471  }
472  DPTB(nc_get_var_uint(tieGeometriesFileID, senzVarID, tmp_uint));
473  for(int i=0; i<num_tie_points; i++) {
474  senz_za[i] = tmp_uint[i] * scale_senz;
475  }
476  DPTB(nc_get_var_int(tieGeometriesFileID, senaVarID, tmp_int));
477  for(int i=0; i<num_tie_points; i++) {
478  double angle = tmp_int[i] * scale_sena / RADEG;
479  sena_x_za[i] = cos(angle);
480  sena_y_za[i] = sin(angle);
481  }
482  const gsl_interp2d_type *splineType = gsl_interp2d_bilinear;
483  //const gsl_interp2d_type *splineType = gsl_interp2d_bicubic;
484  solz_spline = gsl_spline2d_alloc(splineType, num_tie_cols, num_tie_rows);
485  sola_x_spline = gsl_spline2d_alloc(splineType, num_tie_cols, num_tie_rows);
486  sola_y_spline = gsl_spline2d_alloc(splineType, num_tie_cols, num_tie_rows);
487  senz_spline = gsl_spline2d_alloc(splineType, num_tie_cols, num_tie_rows);
488  sena_x_spline = gsl_spline2d_alloc(splineType, num_tie_cols, num_tie_rows);
489  sena_y_spline = gsl_spline2d_alloc(splineType, num_tie_cols, num_tie_rows);
490  solz_xacc = gsl_interp_accel_alloc();
491  solz_yacc = gsl_interp_accel_alloc();
492  sola_x_xacc = gsl_interp_accel_alloc();
493  sola_x_yacc = gsl_interp_accel_alloc();
494  sola_y_xacc = gsl_interp_accel_alloc();
495  sola_y_yacc = gsl_interp_accel_alloc();
496  senz_xacc = gsl_interp_accel_alloc();
497  senz_yacc = gsl_interp_accel_alloc();
498  sena_x_xacc = gsl_interp_accel_alloc();
499  sena_x_yacc = gsl_interp_accel_alloc();
500  sena_y_xacc = gsl_interp_accel_alloc();
501  sena_y_yacc = gsl_interp_accel_alloc();
502  gsl_spline2d_init(solz_spline, solz_xa, solz_ya, solz_za, num_tie_cols, num_tie_rows);
503  gsl_spline2d_init(sola_x_spline, sola_x_xa, sola_x_ya, sola_x_za, num_tie_cols, num_tie_rows);
504  gsl_spline2d_init(sola_y_spline, sola_y_xa, sola_y_ya, sola_y_za, num_tie_cols, num_tie_rows);
505  gsl_spline2d_init(senz_spline, senz_xa, senz_ya, senz_za, num_tie_cols, num_tie_rows);
506  gsl_spline2d_init(sena_x_spline, sena_x_xa, sena_x_ya, sena_x_za, num_tie_cols, num_tie_rows);
507  gsl_spline2d_init(sena_y_spline, sena_y_xa, sena_y_ya, sena_y_za, num_tie_cols, num_tie_rows);
508 
509  free(tmp_int);
510  } // first call
511 
512 
513  // set time for this scan - if scan_start_time value not properly set, estimate from scene start time.
514  if (scan_start_tai[scan] > 0) {
515  l1rec->scantime = tai93_to_unix(scan_start_tai[scan] / 1000000.0 + tai93at2000);
516  lastvalidtime = l1rec->scantime;
517  if (scan > 0)
518  time_interval = (scan_start_tai[scan] - lastvalidtime) / (scan - lastvalidscan);
519  lastvalidscan = scan;
520  } else {
521  l1rec->scantime = lastvalidtime + (time_interval * (scan - lastvalidscan));
522  lastvalidtime = l1rec->scantime;
523  }
524 
525  // calculate fsol which is needed by radcor
526  int16_t syear, sday;
527  double secs;
528  unix2yds(l1rec->scantime, &syear, &sday, &secs);
529  int32_t yr = syear;
530  int32_t dy = sday;
531  int32_t msec = (int32_t) (secs * 1000.0);
532  double esdist = esdist_(&yr, &dy, &msec);
533  l1rec->fsol = pow(1.0 / esdist, 2);
534 
535  start[0] = scan;
536  start[1] = 0;
537  start[2] = 0;
538  count[0] = 1;
539  count[1] = npix;
540  count[2] = 0;
541 
542  //until geolocation is read, set fill values -
543  for (ip = 0; ip < npix; ip++) {
544  l1rec->navfail[ip] = 0;
545  l1rec->lon[ip] = ANGLE_FILL_VALUE;
546  l1rec->lat[ip] = ANGLE_FILL_VALUE;
547 
548  l1rec->solz[ip] = ANGLE_FILL_VALUE;
549  l1rec->sola[ip] = ANGLE_FILL_VALUE;
550  l1rec->senz[ip] = ANGLE_FILL_VALUE;
551  l1rec->sena[ip] = ANGLE_FILL_VALUE;
552  }
553 
554  retval = nc_get_vara_int(geoCoordinatesFileID, longitudeVarID, start, count, lon);
555  if (retval != NC_NOERR) {
556  fprintf(stderr,
557  "-E- %s line %d: nc_get_vara_float failed for file, %s field, %s.\n",
558  __FILE__, __LINE__, geoCoordinatesFilename.c_str(), "longitude");
559  exit(EXIT_FAILURE);
560  }
561  retval = nc_get_vara_int(geoCoordinatesFileID, latitudeVarID, start, count, lat);
562  if (retval != NC_NOERR) {
563  fprintf(stderr,
564  "-E- %s line %d: nc_get_vara_float failed for file, %s field, %s.\n",
565  __FILE__, __LINE__, geoCoordinatesFilename.c_str(), "lat");
566  exit(EXIT_FAILURE);
567  }
568  retval = nc_get_vara_short(instrumentFileID, detectorIndexVarID, start, count, detector_index);
569  if (retval != NC_NOERR) {
570  fprintf(stderr,
571  "-E- %s line %d: nc_get_vara_short failed for file, %s field, %s.\n",
572  __FILE__, __LINE__, instrumentFilename.c_str(), "detector_index");
573  exit(EXIT_FAILURE);
574  }
575  for (ip = 0; ip < npix; ip++) {
576  l1rec->pixnum[ip] = ip;
577  l1rec->flags[ip] = 0;
578  l1rec->pixdet[ip] = detector_index[ip];
579  if(lon[ip] == lonFillValue || lat[ip] == latFillValue) {
580  l1rec->lon[ip] = l1rec->lat[ip] = ANGLE_FILL_VALUE;
581  l1rec->navfail[ip] = 1;
582  } else {
583  l1rec->lon[ip] = lon[ip] * scale_lon;
584  l1rec->lat[ip] = lat[ip] * scale_lat;
585  }
586  }
587 
588  retval = nc_inq_varid(qualityFileID, "quality_flags", &xid);
589  if (retval != NC_NOERR) {
590  fprintf(stderr,
591  "-E- %s line %d: nc_get_varid failed for file, %s field, %s.\n",
592  __FILE__, __LINE__, qualityFlagsFilename.c_str(), "quality_flags");
593  exit(FATAL_ERROR);
594  }
595  retval = nc_get_vara_uint(qualityFileID, xid, start, count, qualityFlags);
596  if (retval != NC_NOERR) {
597  fprintf(stderr,
598  "-E- %s line %d: nc_get_vara_uint failed for file, %s field, %s.\n",
599  __FILE__, __LINE__, qualityFlagsFilename.c_str(), "quality_flags");
600  exit(FATAL_ERROR);
601  }
602 
603  // read in radiance data
604  for (ib = 0; ib < nbands; ib++) {
605  retval = nc_get_vara_ushort(radFileID[ib], radVarID[ib], start, count, rad_data); //BYSCAN
606  if (retval != NC_NOERR) {
607  fprintf(stderr,
608  "-E- %s line %d: nc_get_vara_float failed for file, %s field, %s.\n",
609  __FILE__, __LINE__, radFilename[ib].c_str(), radVarname[ib].c_str());
610  exit(FATAL_ERROR);
611  }
612  // copy to Lt record.
613  for (ip = 0; ip < npix; ip++) {
614  ipb = ip * nbands + ib;
615  if(rad_data[ip] == radFillValue[ib]) {
616  l1rec->Lt[ipb] = BAD_FLT;
617  l1rec->navfail[ip] = 1;
618  } else {
619  l1rec->Lt[ipb] = (rad_data[ip] * radScale[ib] + radOffset[ib]) / 10.; //BYSCAN
620 
621  // mark negative input data as HILT
622  if (l1rec->Lt[ipb] < 0.0)
623  l1rec->hilt[ip] = 1;
624  }
625  }
626  } // for ib
627 
628  for (ip = 0; ip < npix; ip++) {
629  double x, y;
630  l1rec->solz[ip] = gsl_spline2d_eval(solz_spline, ip, scan, solz_xacc, solz_yacc);
631  x = gsl_spline2d_eval(sola_x_spline, ip, scan, sola_x_xacc, sola_x_yacc);
632  y = gsl_spline2d_eval(sola_y_spline, ip, scan, sola_y_xacc, sola_y_yacc);
633  l1rec->sola[ip] = atan2(y, x) * RADEG;
634  l1rec->senz[ip] = gsl_spline2d_eval(senz_spline, ip, scan, senz_xacc, senz_yacc);
635  x = gsl_spline2d_eval(sena_x_spline, ip, scan, sena_x_xacc, sena_x_yacc);
636  y = gsl_spline2d_eval(sena_y_spline, ip, scan, sena_y_xacc, sena_y_yacc);
637  l1rec->sena[ip] = atan2(y, x) * RADEG;
638 
639  // radcor needs all Lts populated before running so...one more time around the block...
640  if (l1_input->rad_opt != 0) {
641  uint32_t isLand = qualityFlags[ip] & 2147483648;
642  // es corrected f0, so setting 1 as 4 element - seemed silly to make a variable for it
643  radcor(l1rec, ip, isLand, 1);
644  for (ib = 0; ib < nbands; ib++) {
645  if(l1rec->navfail[ip] != 1) {
646  ipb = ip * nbands + ib;
647  l1rec->Lt[ipb] += l1rec->radcor[ipb];
648  }
649  }
650  }
651  }
652 
653  l1rec->npix = file->npix;
654  l1rec->l1file->terrain_corrected = 1;
655 
656  return (LIFE_IS_GOOD);
657 }
658 
659 int closel1_safe(filehandle *file) {
660  int i;
661 
662  free(scan_start_tai);
663 
664  DPTB(nc_close(instrumentFileID));
665  DPTB(nc_close(timeCoordinatesFileID));
666  DPTB(nc_close(geoCoordinatesFileID));
667  DPTB(nc_close(tieGeometriesFileID));
668  DPTB(nc_close(qualityFileID));
669  for (i = 0; i < file->nbands; i++) {
670  DPTB(nc_close(radFileID[i]));
671  }
672 
673  return (LIFE_IS_GOOD);
674 }
675 
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame index(0-based) was previously being used the frame number(1-based) should have been used. There were only a few minor changes to the uncertainty index(maximum of 1 digit). 3. Some inefficient arrays(Sigma_RVS_norm_sq) were eliminated and some code lines in Preprocess_L1A_Data were moved into Process_OBCEng_Emiss. There were no changes to the product. Required RAM was reduced by 20 MB. Now
const char * sensorId2SensorDir(int sensorId)
Definition: sensorInfo.c:240
int closel1_safe(filehandle *file)
Definition: l1_safe.cpp:659
void radcor(l1str *l1rec, int32_t ip, int32_t land, int32_t escorrected)
Definition: smile.c:195
int j
Definition: decode_rs.h:73
#define NEW_CACHE_PREEMPTION
Definition: l1_safe.cpp:22
#define NEW_CACHE_SIZE
Definition: l1_safe.cpp:20
void * allocateMemory(size_t numBytes, const char *name)
Definition: allocateMemory.c:7
#define NULL
Definition: decode_rs.h:63
MOD_PR01 Production producing one five minute granule of output data in each run It can be configured to produce as many as three five minute granules per run Each execution with one construction record and one date file for each dataset In normal these are created by which splits them out of the hour datasets For LANCE they are created by which merges all session MODIS L0 datasets overlapping the requested time and extracts from the merged data those packets which fall within that time period Each scan of data is stored in the L1A granule that covers the start time of that scan
Definition: MOD_PR01_pr.txt:19
read l1rec
double yds2tai93(int16_t iyr, int16_t idy, double sec)
Definition: yds2tai.c:4
#define MERIS
Definition: sensorDefs.h:22
float32 * pos
Definition: l1_czcs_hdf.c:35
float * lat
int32 * msec
Definition: l1_czcs_hdf.c:31
double esdist_(int32_t *year, int32_t *day, int32_t *msec)
int syear
Definition: l1_czcs_hdf.c:15
u5 which has been done in the LOCALGRANULEID metadata should have an extension NRT It is requested to identify the NRT production Changes from v6 which may affect scientific the sector rotation may actually occur during one of the scans earlier than the one where it is first reported As a the b1 values are about the LOCALGRANULEID metadata should have an extension NRT It is requested to identify the NRT to fill pixels affected by dead subframes with a special value Output the metadata of noisy and dead subframe Dead Subframe EV and Detector Quality Flag2 Removed the function call of Fill_Dead_Detector_SI to stop interpolating SI values for dead detectors
Definition: HISTORY.txt:226
int32 nscan
Definition: l1_czcs_hdf.c:19
@ string
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed file
Definition: HISTORY.txt:413
#define LIFE_IS_GOOD
Definition: passthebuck.h:4
int sday
Definition: l1_czcs_hdf.c:15
#define DPTB(function)
Definition: passthebuck.h:24
double tai93_to_unix(double tai93)
Definition: yds2tai.c:16
int openl1_safe(filehandle *l1file)
Definition: l1_safe.cpp:40
l1_input_t * l1_input
Definition: l1_options.c:9
#define FATAL_ERROR
Definition: swl0_parms.h:5
int want_verbose
void smile_init(int num_bands, int num_detectors, const char *bandinfo_filename, float *detectorWLs, float *detectorE0s)
Definition: smile.c:48
void unix2yds(double usec, short *year, short *day, double *secs)
int readl1_safe(filehandle *file, int32_t scan, l1str *l1rec)
Definition: l1_safe.cpp:196
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
int isLand(float lat, float lon)
Definition: l3mapgen.cpp:66
#define RADEG
Definition: czcs_ctl_pt.c:5
#define NEW_CACHE_NELEMS
Definition: l1_safe.cpp:21
#define BAD_FLT
Definition: jplaeriallib.h:19
#define ANGLE_FILL_VALUE
Definition: l1_safe.cpp:27
int32_t nbands
const char * sensorId2SensorName(int sensorId)
Definition: sensorInfo.c:198
float * lon
real *8 function esdist(iyr, iday, msec)
Definition: esdist.f:3
#define BANDINFO_FILENAME_OLCI
Definition: l1_safe.cpp:25
const char * subsensorId2SubsensorDir(int subsensorId)
Definition: sensorInfo.c:254
int i
Definition: decode_rs.h:71
#define BANDINFO_FILENAME_MERIS
Definition: l1_safe.cpp:24
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int npix
Definition: get_cmp.c:27
int count
Definition: decode_rs.h:79