NASA Logo
Ocean Color Science Software

ocssw V2022
l1_msi.cpp
Go to the documentation of this file.
1 /************************************************************
2 * Sentinel 2A MSI L1C PROCESSING *
3 * By Jiaying He *
4 * With modifications for seamless integration *
5 * in SeaDAS by Sudipta Sarkar SSAI *
6 ************************************************************/
7 
8 /* Include head files */
9 #include "l1_msi.h"
10 
11 #include "l1.h"
12 #include "jplaeriallib.h"
13 
14 #include <libnav.h>
15 #include <gsl/gsl_interp.h>
16 #include <gsl/gsl_math.h>
17 #include <gsl/gsl_interp2d.h>
18 #include <gsl/gsl_spline2d.h>
19 
20 #include "l1_msi_private.h"
21 #include <cmath>
22 #include <algorithm>
23 #include <pugixml.hpp>
24 
25 using namespace std;
26 using namespace pugi;
27 
28 typedef enum msiBandIdx
29 {
31 } msiBandIdx;
32 
33 const static struct {
35  const char *str;
36 } conversion [] = {
37  {B01, "B01"},
38  {B02, "B02"},
39  {B03, "B03"},
40  {B04, "B04"},
41  {B05, "B05"},
42  {B06, "B06"},
43  {B07, "B07"},
44  {B08, "B08"},
45  {B8A, "B8A"},
46  {B09, "B09"},
47  {B11, "B11"},
48  {B12, "B12"},
49  {B10, "B10"}
50 };
51 
52 void resample_msi(opj_image_t* image, filehandle* file, int recnum, int srcRes, int destRes);
53 int decodeMSI(filehandle *file, int32_t bandIdx, int32_t recnum);
54 void interpGPSpos(l1str *l1rec, double* pos, int detector, int band);
55 int inDetector (msi_t *data , float lat, float lon);
56 void interpViewAngles(l1str* l1rec, int pixel, int scan, int band, float *senz, float *sena);
57 
58 void error_callback(const char *msg, void *client_data);
59 void warning_callback(const char *msg, void *client_data);
60 void info_callback(const char *msg, void *client_data);
61 
62 
63 msiBandIdx str2enum (const char *str)
64 {
65  uint32_t j;
66  for (j = 0; j < sizeof (conversion) / sizeof (conversion[0]); ++j)
67  if (!strcmp (str, conversion[j].str))
68  return conversion[j].val;
69 
70  fprintf(stderr,"-E- %s line %d: something is seriously wrong in Denmark...\n",
71  __FILE__,__LINE__);
72  exit(EXIT_FAILURE);
73 }
74 
75 int inDetector (msi_t *data , float lat, float lon) {
76  int detector = 0;
77  PJ_COORD c, c_out;
78 
79  // set default z and t
80  c.xyzt.x = 0.0;
81  c.xyzt.t = HUGE_VAL;
82 
83  c.xy.x = lon;
84  c.xy.y = lat;
85  c_out = proj_trans(data->pj, PJ_INV, c);
86  Point_t p(c_out.xy.x, c_out.xy.y);
87 
88  for (detector = 0; detector < numDetectors; detector++){
89  if (boost::geometry::within(p, data->detectorFootprints[detector]))
90  break;
91  }
92  if (detector == numDetectors)
93  detector = -1;
94 
95  return detector;
96 }
97 
98 void interpGPSpos(l1str* l1rec, double* pos, int detector, int band){
99  msi_t *data = (msi_t*) l1rec->l1file->private_data;
100  int i;
101  int nelem = data->num_gps;
102  // use GSL...why reinvent the wheel
103  double pixelTime = l1rec->scantime;
104  if (detector >= 0)
105  pixelTime += data->detectorDeltaTime[detector][band];
106 
107  for(i = 0; i< 3; i++) {
108  gsl_interp *interpolation = gsl_interp_alloc(gsl_interp_linear, nelem);
109  gsl_interp_init(interpolation, data->gpstime, data->position[i], nelem);
110  gsl_interp_accel *accelerator = gsl_interp_accel_alloc();
111  pos[i]= gsl_interp_eval(interpolation, data->gpstime, data->position[i], l1rec->scantime, accelerator);
112  gsl_interp_free(interpolation);
113  gsl_interp_accel_free (accelerator);
114  }
115 }
116 
117 void interpViewAngles(msi_t* data, int pixel, int scan, int band, float *senz, float *sena) {
118 
119  float angles[2];
120 
121  int nelem = 23;
122  const gsl_interp2d_type *T = gsl_interp2d_bicubic;
123 
124  double *tieZenith = data->sensorZenith[band];
125  double *tieAzimuth = data->sensorAzimuth[band];
126 
127  double tieX[nelem];
128  double tieY[nelem];
129  double incr = 5490. / (nelem -1);
130  for (int i = 0; i < nelem; i++){
131  tieX[i] = i*incr;
132  tieY[i] = i*incr;
133  }
134 
135  size_t nx = sizeof(tieX) / sizeof(tieX[0]);
136  size_t ny = sizeof(tieY) / sizeof(tieY[0]);
137 
138  gsl_spline2d *splineZenith = gsl_spline2d_alloc(T, nx, ny);
139  gsl_spline2d *splineAzimuth = gsl_spline2d_alloc(T, nx, ny);
140  gsl_interp_accel *xacc = gsl_interp_accel_alloc();
141  gsl_interp_accel *yacc = gsl_interp_accel_alloc();
142 
143  gsl_spline2d_init(splineZenith, tieX, tieY, tieZenith, nx, ny);
144  gsl_spline2d_init(splineAzimuth, tieX, tieY, tieAzimuth, nx, ny);
145 
146  angles[0] = (float) gsl_spline2d_eval(splineZenith,pixel,scan,xacc, yacc);
147  angles[1] = (float) gsl_spline2d_eval(splineAzimuth,pixel,scan,xacc, yacc);
148  *senz = angles[0];
149  *sena = angles[1];
150 
151  gsl_spline2d_free(splineZenith);
152  gsl_spline2d_free(splineAzimuth);
153  gsl_interp_accel_free(xacc);
154  gsl_interp_accel_free(yacc);
155 
156 }
157 
158 static float *Fobar;
159 
160 static geom_struc *gm_p_b = NULL;
161 
162 //TODO: Replace the following callbacks with olog implementation
163 
167 void error_callback(const char *msg, void *client_data) {
168  (void)client_data;
169  fprintf(stdout, "[ERROR] %s", msg);
170 }
174 void warning_callback(const char *msg, void *client_data) {
175  (void)client_data;
176  fprintf(stdout, "[WARNING] %s", msg);
177 }
181 void info_callback(const char *msg, void *client_data) {
182  (void)client_data;
183  fprintf(stdout, "[INFO] %s", msg);
184 }
185 /************************************************/
186 /* function createPrivateData: */
187 /* create private data for Sentinel 2 MSI data */
188 /************************************************/
189 msi_t* createPrivateData_msi(int numBands){
190  // Allocate memory for msi_t data struct
191  msi_t* data = (msi_t*)calloc(1, sizeof(msi_t));
192  if(data == NULL){
193  fprintf(stderr,"-E- %s line %d: unable to allocate private data for MSI\n",
194  __FILE__,__LINE__);
195  exit(1);
196  }
197 
198  // Allocate memory for storing upper left coordinates
199  data->ULCoord = (int32_t*) malloc(2*sizeof(int32_t));
200 
201  return data;
202 }
203 
204 
205 /*************************************************/
206 /* function resample_msi: */
207 /* Resamples 10m and 60m resolution bands to 20m */
208 
209 /*************************************************/
210 void resample_msi(opj_image_t* image, filehandle* file, int recnum, int srcRes, int destRes) {
211 
212  int width;
213  int i, i0;
214  msi_t* data = (msi_t*) file->private_data;
215 
216  if (!data->buf) {
217  data->buf = (uint32_t*) malloc(file->npix * sizeof (uint32_t));
218  }
219  // Set resizing scale
220  float scale = (float) srcRes / (float) destRes;
221  if (scale <= 0) {
222  fprintf(stderr, "-E- %f scale is not calculated correctly\n", scale);
223  exit(EXIT_FAILURE);
224  }
225 
226  width = image->comps[0].w;
227 
228  // Resample the image
229  for (i = 0; i < scale * width; i++) {
230  if (scale > 1) {
231  i0 = floor(i / scale);
232  data->buf[i] = image->comps[0].data[recnum * width + i0];
233  } else if (scale == 1) {
234  data->buf[i] = image->comps[0].data[recnum * width + i];
235  } else {
236  i0 = floor(i / scale);
237  data->buf[i] = (image->comps[0].data[recnum * width + i0]
238  + image->comps[0].data[recnum * width + (i0 + 1)]
239  + image->comps[0].data[(recnum + 1) * width + i0]
240  + image->comps[0].data[(recnum + 1) * width + (i0 + 1)]) / 4;
241  }
242  }
243 }
244 
245 int32_t readTileMeta_msi(filehandle *file) {
246  xml_document rootNode;
247  xml_node dataNode;
248  xml_node zenithNode;
249  xml_node azimuthNode;
250  xml_node valuesNode;
251  char *delim = " "; // input separated by spaces
252  char *token = NULL;
253  msi_t *data = (msi_t*) file->private_data;
254  char* tmpBuff;
255  const char *xmlBuffer;
256  if(!rootNode.load_file(data->granuleMetadataFile)) {
257  return 0;
258  }
259 
260  // fix orbit altitude
261  data->alt = 786.;
262  // Get geocoding information
263  dataNode = rootNode.first_element_by_path("n1:Level-1C_Tile_ID/n1:Geometric_Info/Tile_Geocoding");
264  // Get coordinate system EPSG code
265  xmlBuffer = dataNode.first_element_by_path("HORIZONTAL_CS_CODE").first_child().value();
266  std::string s = xmlBuffer;
267  std::string delimiter = ":";
268  s.erase(0, s.find(delimiter) + delimiter.length());
269  data->CSCode = atoi(s.c_str());
270 
271  // Get coordinate system UTM zone
272  xmlBuffer = dataNode.first_element_by_path("HORIZONTAL_CS_NAME").first_child().value();
273  s = xmlBuffer;
274  delimiter = "zone ";
275  s.erase(0, s.find(delimiter) + delimiter.length());
276  if(s.back() == 'S') {
277  s.pop_back();
278  s.append(" +south");
279  } else if(s.back() == 'N') {
280  s.pop_back();
281  }
282  data->UTMZone = strdup(s.c_str());
283 
284  xmlBuffer = dataNode.find_child_by_attribute("Size","resolution","20").child_value("NCOLS");
285  file->npix = atoi(xmlBuffer);
286  xmlBuffer = dataNode.find_child_by_attribute("Size","resolution","20").child_value("NROWS");
287  file->nscan = atoi(xmlBuffer);
288  xmlBuffer = dataNode.find_child_by_attribute("Geoposition","resolution","20").child_value("ULX");
289  data->ULCoord[0] = atoi(xmlBuffer);
290  xmlBuffer = dataNode.find_child_by_attribute("Geoposition","resolution","20").child_value("ULY");
291  data->ULCoord[1] = atoi(xmlBuffer);
292 
293  // Set projection string
294  char pjStr[FILENAME_MAX];
295  sprintf(pjStr, "+proj=utm +ellps=WGS84 +datum=WGS84 +zone=%s +units=m", data->UTMZone);
296 
297  // init the proj4 projections
298  PJ *pj = proj_create_crs_to_crs(PJ_DEFAULT_CTX,
299  pjStr,
300  "+proj=longlat +ellps=WGS84 +datum=WGS84",
301  NULL);
302  if(pj == NULL) {
303  printf("Error - MSI first PROJ projection failed to init\n");
304  exit(1);
305  }
306  data->pj = proj_normalize_for_visualization(PJ_DEFAULT_CTX, pj);
307  if(data->pj == NULL) {
308  printf("Error - MSI visualization PROJ projection failed to init\n");
309  exit(1);
310  }
311  proj_destroy(pj);
312 
313  // Read tie-point sensor view angles
314  dataNode = rootNode.first_element_by_path("n1:Level-1C_Tile_ID/n1:Geometric_Info/Tile_Angles/Viewing_Incidence_Angles_Grids");
315  // Set up tie point array sizes ([numDetectors][maxBands][HEIGHT][WIDTH])
316  int tiepoint_height = 23;
317  int tiepoint_width = 23;
318  data->sensorZenith = (double **) malloc(maxBands * sizeof (double *));
319  data->sensorAzimuth = (double **) malloc(maxBands * sizeof (double *));
320  for (int i = 0; i < maxBands; i++) {
321  data->sensorZenith[i] = (double *) calloc(tiepoint_width * tiepoint_height, sizeof (double ));
322  data->sensorAzimuth[i] = (double *) calloc(tiepoint_width * tiepoint_height, sizeof (double ));
323  }
324  while (dataNode) {
325  xmlBuffer = dataNode.attribute("bandId").value();
326  int bandIdx = atoi(xmlBuffer);
327  xmlBuffer = dataNode.attribute("detectorId").value();
328  zenithNode = dataNode.first_element_by_path("Zenith/Values_List");
329  valuesNode = zenithNode.first_element_by_path("VALUES");
330  int i = 0;
331  while (valuesNode){
332  tmpBuff = strdup(valuesNode.first_child().value());
333  int j = 0;
334  for (token = strtok((char *) tmpBuff, delim); token != NULL; token = strtok(NULL, delim)) {
335  char *unconverted;
336  double value = strtof(token, &unconverted);
337  if (!std::isnan(value))
338  data->sensorZenith[bandIdx][i*tiepoint_width + j] = value;
339  j++;
340  }
341  free(tmpBuff);
342  i++;
343  valuesNode = valuesNode.next_sibling("VALUES");
344  }
345  azimuthNode = dataNode.first_element_by_path("Azimuth/Values_List");
346  valuesNode = azimuthNode.first_element_by_path("VALUES");
347  i = 0;
348  while (valuesNode){
349  tmpBuff = strdup(valuesNode.first_child().value());
350  int j = 0;
351  for (token = strtok((char *) tmpBuff, delim); token != NULL; token = strtok(NULL, delim)) {
352  char *unconverted;
353  double value = strtod(token, &unconverted);
354  if (!std::isnan(value))
355  data->sensorAzimuth[bandIdx][i*tiepoint_width + j] = value;
356  j++;
357  }
358  free(tmpBuff);
359  i++;
360  valuesNode = valuesNode.next_sibling("VALUES");
361  }
362  dataNode = dataNode.next_sibling("Viewing_Incidence_Angles_Grids");
363  }
364  return 1;
365 }
366 
367 int32_t readDatastripMeta_msi(filehandle *file) {
368  xml_document rootNode;
369  xml_node dataNode;
370  xml_node subDataNode;
371  xml_node_iterator it;
372  double unixseconds;
373  char *delim = " "; // input separated by spaces
374  char *token = NULL;
375  msi_t *data = (msi_t*) file->private_data;
376  char* tmpBuff;
377  const char *xmlBuffer;
378  if (!rootNode.load_file(data->datastripMetadataFile)) {
379  return 0;
380  }
381  // Get start time
382  dataNode = rootNode.first_element_by_path("n1:Level-1C_DataStrip_ID/n1:General_Info/Datastrip_Time_Info");
383  xmlBuffer = rootNode.first_element_by_path("n1:Level-1C_DataStrip_ID/n1:General_Info/Datastrip_Time_Info/DATASTRIP_SENSING_START").first_child().value();
384  data->scene_start_time = isodate2unix((char*) xmlBuffer);
385  // Get detector line period
386  dataNode = rootNode.first_element_by_path("n1:Level-1C_DataStrip_ID/n1:Image_Data_Info/Sensor_Configuration/Time_Stamp");
387  xmlBuffer = dataNode.first_element_by_path("LINE_PERIOD").first_child().value();
388  data->lineTimeDelta = atof(xmlBuffer) * 2e-3; //convert to seconds, for 20m band
389 
390  // Get detector relative startimes
391  dataNode = rootNode.first_element_by_path("n1:Level-1C_DataStrip_ID/n1:Image_Data_Info/Sensor_Configuration/Time_Stamp/Band_Time_Stamp");
392  while (dataNode) {
393  xmlBuffer = dataNode.attribute("bandId").value();
394  int bandIdx = atoi(xmlBuffer);
395  subDataNode = dataNode.first_element_by_path("Detector");
396  while (subDataNode) {
397  xmlBuffer = subDataNode.attribute("detectorId").value();
398  int detectorIdx = atoi(xmlBuffer) - 1;
399  xmlBuffer = subDataNode.child_value("GPS_TIME");
400  unixseconds = isodate2unix((char*) xmlBuffer);
401  data->detectorDeltaTime[detectorIdx][bandIdx] = data->scene_start_time - unixseconds;
402  subDataNode = subDataNode.next_sibling("Detector");
403  }
404 
405  dataNode = dataNode.next_sibling("Band_Time_Stamp");
406  }
407 
408  // Get number of GPS entries
409  dataNode = rootNode.first_element_by_path("n1:Level-1C_DataStrip_ID/n1:Satellite_Ancillary_Data_Info/Ephemeris/GPS_Points_List");
410  data->num_gps = 0;
411  for (it = dataNode.begin(); it != dataNode.end(); it++) {
412  data->num_gps++;
413  }
414  data->gpstime = (double *) malloc(data->num_gps * sizeof(double));
415  for (int i = 0; i<3; i++)
416  data->position[i] = (double *) malloc(data->num_gps * sizeof(double));
417  // read GPS
418  int i = 0;
419  dataNode = rootNode.first_element_by_path("n1:Level-1C_DataStrip_ID/n1:Satellite_Ancillary_Data_Info/Ephemeris/GPS_Points_List/GPS_Point");
420  while (dataNode) {
421  tmpBuff = strdup(dataNode.child_value("POSITION_VALUES"));
422  int j = 0;
423  for (token = strtok((char *)tmpBuff, delim); token != NULL; token = strtok(NULL, delim)) {
424  char *unconverted;
425  data->position[j][i] = strtod(token, &unconverted);
426  j++;
427  }
428  free(tmpBuff);
429  xmlBuffer = dataNode.child_value("GPS_TIME");
430  data->gpstime[i] = isodate2unix((char*) xmlBuffer);
431  i++;
432  dataNode = dataNode.next_sibling("GPS_Point");
433  }
434  return 1;
435 }
436 
437 int32_t readDetectorFootprint_msi(filehandle *file, int band) {
438  xml_document rootNode;
439  xml_node dataNode;
440  xml_node polyNode;
441  msi_t *data = (msi_t*) file->private_data;
442  std::vector<std::string> detstrs;
443  std::vector<std::string> polypointstrs;
444  std::vector<std::string>::iterator sit;
445  const char *detectorName, *polygon;
446  if (!rootNode.load_file(data->detectorFootprintFiles[band])) {
447  return 0;
448  }
449  dataNode = rootNode.first_element_by_path("eop:Mask/eop:maskMembers/eop:MaskFeature");
450  while (dataNode) {
451  detectorName = dataNode.attribute("gml:id").value();
452  //detector_footprint-B05-03-0
453  boost::split(detstrs, detectorName, boost::is_any_of("-"));
454  int detidx = std::atoi(detstrs[2].c_str()) - 1;
455  polyNode = dataNode.first_element_by_path("eop:extentOf/gml:Polygon/gml:exterior/gml:LinearRing/gml:posList");
456  polygon = polyNode.first_child().value();
457  boost::split(polypointstrs, polygon, boost::is_any_of(" "));
458  std::string polyWKT = "POLYGON((";
459  int i = 1;
460  for(sit=polypointstrs.begin() ; sit < polypointstrs.end(); sit++,i++ ) {
461  // skip every third element
462  if(i % 3)
463  polyWKT = polyWKT + *sit + " ";
464  else
465  polyWKT = polyWKT + ",";
466  }
467  polyWKT = polyWKT + "))";
468  boost::geometry::read_wkt(polyWKT, data->detectorFootprints[detidx]);
469  dataNode = dataNode.next_sibling("eop:MaskFeature");
470  }
471 
472  return 1;
473 }
474 
475 
476 /************************************************/
477 /* function: openl1_msi */
478 /* Open msi l1c data with metadata file */
479 /************************************************/
480 extern "C" int openl1_msi(filehandle *file){
481 
482  int i;
483  xml_document rootNode;
484  xml_node dataNode, metaNode;
485  const char *productName, *dataName;
486  msi_t *data;
487 
488  // fill up the private data
489  file->private_data = data = createPrivateData_msi(maxBands);
490 
491  if(!rootNode.load_file(file->name)) {
492  printf("Could not open MSI file: %s\n", file->name);
493  exit(EXIT_FAILURE);
494  }
495 
496  if(want_verbose)
497  printf("Input file: MSI Level-1C %s\n", file->name);
498 
499  metaNode = rootNode.first_element_by_path("xfdu:XFDU/metadataSection");
500 
501  // orbit direction
502  dataNode = metaNode.find_child_by_attribute("metadataObject", "ID", "measurementOrbitReference");
503  dataName = dataNode.first_element_by_path("metadataWrap/xmlData/safe:orbitReference/safe:orbitNumber").attribute("groundTrackDirection").value();
504  data->orbit_direction = strdup(dataName);
505 
506  // Band image paths
507  int nbandsImg = 0;
508  int nbandsDetFoot = 0;
509  int pickMe = 0;
510 
511  dataNode = rootNode.first_element_by_path("xfdu:XFDU/dataObjectSection/dataObject") ;
512  string indir = file->name;
513  size_t index = indir.find_last_of('/');
514  if(index != string::npos)
515  indir.erase(index);
516  else
517  indir.clear();
518  string fileName;
519 
520  while (dataNode) {
521  dataName = dataNode.attribute("ID").value();
522  productName = dataNode.first_element_by_path("byteStream/fileLocation").attribute("href").value();
523  if(indir.empty())
524  fileName = productName;
525  else
526  fileName = indir + "/" + productName;
527  index = fileName.find("./");
528  if(index != string::npos)
529  fileName.erase(index, 2);
530  if (strstr(dataName, "S2_Level-1C_Tile1_Metadata")){
531  data->granuleMetadataFile = strdup(fileName.c_str());
532  }
533  if (strstr(dataName, "S2_Level-1C_Datastrip1_Metadata")){
534  data->datastripMetadataFile = strdup(fileName.c_str());
535  }
536  if (strstr(dataName, "IMG_DATA_Band") && !(strstr(dataName, "TCI"))) {
537  if (nbandsImg > maxBands) {
538  printf("%s, %d - E - Maximum number of radiance values (%d) reached\n",
539  __FILE__, __LINE__, maxBands);
540  exit(EXIT_FAILURE);
541  }
542  data->jp2[nbandsImg] = strdup(fileName.c_str());
543  if (!data->jp2[nbandsImg]) {
544  printf("%s, %d - E - unable to set path for band %d\n",
545  __FILE__, __LINE__, nbandsImg);
546  exit(EXIT_FAILURE);
547  }
548  nbandsImg++;
549  }
550  if (strstr(dataName, "DetectorFootprint")) {
551  if (nbandsDetFoot > maxBands) {
552  printf("%s, %d - E - Maximum number of radiance values (%d) reached\n",
553  __FILE__, __LINE__, maxBands);
554  exit(EXIT_FAILURE);
555  }
556  data->detectorFootprintFiles[nbandsDetFoot] = strdup(fileName.c_str());
557  if (!data->detectorFootprintFiles[nbandsDetFoot]) {
558  printf("%s, %d - E - unable to set path for band %d\n",
559  __FILE__, __LINE__, nbandsDetFoot);
560  exit(EXIT_FAILURE);
561  }
562  if (strstr(data->detectorFootprintFiles[nbandsDetFoot], "B07")) {
563  pickMe = nbandsDetFoot;
564  }
565  nbandsDetFoot++;
566  }
567  dataNode = dataNode.next_sibling("dataObject");
568  }
569 
570  /* Read tile metadata file */
571  if(!readTileMeta_msi(file))
572  fprintf(stderr, "-E- %s line %d: unable read tile metadata file for MSI dataset %s\n",
573  __FILE__,__LINE__,data->granuleMetadataFile);
574 
575  /* Read datastrip metadata file */
577  fprintf(stderr, "-E- %s line %d: unable read datastrip metadata file for MSI dataset %s\n",
578  __FILE__,__LINE__,data->datastripMetadataFile);
579 
580  /* Read detector footprint file
581  for simplicity, read just one for a 20m band
582  */
583  if(!readDetectorFootprint_msi(file, pickMe))
584  fprintf(stderr, "-E- %s line %d: unable read detector footprint file for MSI dataset %s\n",
585  __FILE__,__LINE__,data->detectorFootprintFiles[pickMe]);
586 
587  strcpy(file->spatialResolution, "20 m");
588  if(want_verbose){
589 
590  // Print out all MSI jp2 images
591  for (i = 0; i<maxBands; i++){
592  printf("MSI file %d: %s\n",i, data->jp2[i]);
593  }
594  }
595 
596  /*
597  * get the Fobar here to set up Fo
598  */
599  rdsensorinfo(file->sensorID, l1_input->evalmask, "Fobar", (void **) &Fobar);
600  file->terrain_corrected = 1;
601 
602  return 0;
603 }
604 
605 
606 /************************************************/
607 /* function: readl1_msi */
608 /* Get coordinates and convert to lon/lat */
609 /************************************************/
610 extern "C" int readl1_msi_lonlat(filehandle *file, int recnum, l1str *l1rec)
611 {
612 
613  int ip;
614  msi_t* data = (msi_t*) file->private_data;
615 
616  // Convert lon and lon results of current scanline from radian to degree values
617  PJ_COORD c, c_out;
618 
619  // set default z and t
620  c.xyzt.z = 0.0;
621  c.xyzt.t = HUGE_VAL;
622  for (ip=0; ip<file->npix; ip++) {
623  c.xy.x = data->ULCoord[0] + 10 + ip * 20;
624  c.xy.y = data->ULCoord[1] - 10 - recnum * 20;
625  c_out = proj_trans(data->pj, PJ_FWD, c);
626  l1rec->lon[ip] = c_out.xy.x;
627  l1rec->lat[ip] = c_out.xy.y;
628  }
629 
630  return 0;
631 }
632 
633 /************************************************/
634 /* function: readl1_msi */
635 /* Read MSI l1c image data line by line */
636 /************************************************/
637 extern "C" int readl1_msi(filehandle *file, int recnum, l1str *l1rec, int lonlat)
638 {
639  int i, ip, ib, ipb;
640  msi_t* data = (msi_t*) file->private_data;
641  int16_t year, doy;
642  float sunpos[3];
643  double secondOfDay;
644  float sunDist;
645  char bandStrBuffer[4];
646  l1rec->scantime = data->scene_start_time + recnum * data->lineTimeDelta; //may want to to some math with recnum here
647 
648  // Get lat lon
650  fprintf(stderr,"-E- %s line %d: unable to allocate lat/lon data for MSI\n",
651  __FILE__,__LINE__);
652  exit(1);
653  }
654 
655  // Set information about data
656  l1rec->npix = file->npix;
657  l1rec->l1file->sensorID = file->sensorID;
658 
659  unix2yds(l1rec->scantime, &year, &doy, &secondOfDay);
660 
661  int32_t iyear, idoy, msec;
662  iyear = (int32_t) year;
663  idoy = (int32_t) doy;
664  msec = (int32_t) secondOfDay*1e3;
665  double esdist = esdist_(&iyear, &idoy, &msec);
666  double fsol = pow(1.0 / esdist, 2);
667 
668  /*
669  * if required for that record, set up the geom_per_band storage
670  */
671  if (!lonlat) {
672  if((l1_input->geom_per_band == 1 ) && ( l1rec->geom_per_band == NULL ) ) {
674  gm_p_b = l1rec->geom_per_band; // store this address so that it can be later destroyed in close()
675  }
676  }
677 
678  l_sun_(&iyear, &idoy, &secondOfDay, sunpos, &sunDist); // get position vector for the sun
679 
680  for (i=0; i < 3; i++) {
681  sunpos[i] *= 1.496e8; //convert to km for call to get_zenaz
682  }
683  // Assign viewing angles to l1rec struct
684  for (ib = 0; ib<maxBands; ib++) {
685  int len = strlen(data->jp2[ib])-7;
686  strncpy(bandStrBuffer, data->jp2[ib]+len, 3);
687  bandStrBuffer[3] = '\0';
688  int bandIdx = str2enum(bandStrBuffer);
689  if (bandIdx == B10)
690  continue;
691 // int detector = -1;
692  for (ip=0; ip<file->npix; ip++) {
693  // use boost.within to determine detector number
694  // but only need to do this once - per band differences not significant
695  if (ib == 0) {
696 // detector = inDetector (data , l1rec->lat[ip], l1rec->lon[ip]);
697 
698  // interpolate GPS position vectors to scantime
699  // If we can get more accurate times, we can use this
700  // interpGPSpos method for sensor angles
701  // NOTE: the solar angles are also affected by the incorrect scantime
702  // but less egregiously so...
703 
704 // interpGPSpos(l1rec,pos,detector,ib);
705 
706 // for (i=0; i < 3; i++) {
707 // epos[i] = pos[i] * 1e-6; //values are in mm, convert to km
708 // }
709 // get_zenaz(epos, l1rec->lon[ip], l1rec->lat[ip], &l1rec->senz[ip], &l1rec->sena[ip]);
710 
711  // Assign band independent solar angles to l1rec struct
712  get_zenaz(sunpos, l1rec->lon[ip], l1rec->lat[ip], &l1rec->solz[ip], &l1rec->sola[ip]);
713  if (!lonlat) {
714  // interpolate tiePoint sensor view angles
715  interpViewAngles(data, ip, recnum, ib, &l1rec->senz[ip], &l1rec->sena[ip]);
716  }
717  }
718 
719  // if getting only lonlat stuff, skip everything below and go to the next iteration
720  if (lonlat)
721  continue;
722 
723  if (l1_input->geom_per_band) {
724  int ipb = ip*file->nbands + bandIdx;
725 
726  // re-interpolate GPS position vectors to per band scantime (see note above)
727 // interpGPSpos(l1rec,pos,detector,ib);
728 //
729 // for (i=0; i < 3; i++)
730 // epos[i] = pos[i] * 1e-6; //values are in mm, convert to km
731 //
732 // get_zenaz(epos, l1rec->lon[ip], l1rec->lat[ip], &l1rec->geom_per_band->senz[ipb], &l1rec->geom_per_band->sena[ipb]);
733  // interpolate tiePoint sensor view angles
734  interpViewAngles(data, ip, recnum, ib, &l1rec->geom_per_band->senz[ipb], &l1rec->geom_per_band->sena[ipb]);
735  // per band solar angles are just repetitions of the nominal values
736  l1rec->geom_per_band->solz[ipb] = l1rec->solz[ip];
737  l1rec->geom_per_band->sola[ipb] = l1rec->sola[ip];
738  }
739  }
740 
741  // lonlat mode, only care about when ib = 0, which gets the sensor view angles
742  if (lonlat)
743  break;
744  }
745 
746  // Calculate surface reflectance values for each band
747  for(ib = 0; ib < maxBands; ib++) {
748  int len = strlen(data->jp2[ib])-7;
749  strncpy(bandStrBuffer, data->jp2[ib]+len, 3);
750  bandStrBuffer[3] = '\0';
751  int bandIdx = str2enum(bandStrBuffer);
752  if (bandIdx == B10)
753  continue;
754 
755  l1rec->Fo[bandIdx] = Fobar[bandIdx] * fsol;
756 
757  if(decodeMSI(file, bandIdx, recnum)!=0) {
758  printf("-E-: Error decoding MSI jp2 files.\n");
759  fprintf(stderr, "-E- %s line %d: Failed to read Lt, band %d, recnum %d\n",
760  __FILE__,__LINE__, bandIdx, recnum );
761  exit(1);
762  }
763 
764  for (ip=0; ip<file->npix; ip++) {
765  ipb = ip*file->nbands+bandIdx;
766  if(data->buf[ip] == 0) {
767  l1rec->Lt[ipb] = BAD_FLT;
768  l1rec->navfail[ip] = 1;
769  } else{
770  // 10000 is the QUANTIFICATION_VALUE of MSI data to convert DN value to reflectance
771  // This value is listed in the MTD_MSIL1C.xml file, but we're just hardcoding it...bad?
772  float quant = 10000.;
773  float rToa = (float) (data->buf[ip] / quant);
774 
775  l1rec->Lt[ipb] = (rToa * l1rec->Fo[bandIdx] * cos(l1rec->solz[ip]/RADEG)) / PI ;
776  }
777  }
778  }
779 
780  // Skip everything else if lonlat
781  // Surface reflectance should give a good start pixel for l1info
782  if (lonlat)
783  return 0;
784 
785  // Calculate rho_cirrus from cirrus band 10
786  if(decodeMSI(file, B10, recnum)!=0) {
787  fprintf(stderr, "-E- %s line %d: Failed to read cirrus band, recnum %d\n",
788  __FILE__,__LINE__, recnum );
789  exit(1);
790  }
791  for (ip=0;ip<file->npix; ip++) {
792  if(data->buf[ip] == 0)
793  l1rec->rho_cirrus[ip] = BAD_FLT;
794  else
795  l1rec->rho_cirrus[ip] = data->buf[ip] / (PI * 10000.0);
796  }
797 
798  // Check lat and lon values
799  for (ip=0; ip<file->npix; ip++) {
800  l1rec->pixnum[ip] = ip;
801  if ( std::isnan(l1rec->lat[ip]) )
802  l1rec->lat[ip] = -999.0;
803  if ( std::isnan(l1rec->lon[ip]) )
804  l1rec->lon[ip] = -999.0;
805 
806  if (l1rec->lon[ip] < -181.0 || l1rec->lon[ip] > 181.0 ||
807  l1rec->lat[ip] < -91.0 || l1rec->lat[ip] > 91.0 )
808  l1rec->navfail[ip] = 1;
809 
810  }
811  return 0;
812 }
813 
814 uint32_t scale_recnum( int32_t bandIdx, int32_t recnum){
815  switch(bandIdx) {
816  case B01:
817  case B09:
818  case B10:
819  return floor(recnum/3);
820  case B02:
821  case B03:
822  case B04:
823  case B08:
824  return recnum*2;
825  default:
826  return recnum;
827  }
828 }
829 /************************************************/
830 /* function: decodeMSI */
831 /* Decode jp2 data */
832 /************************************************/
833 int decodeMSI(filehandle *file, int32_t bandIdx, int32_t recnum){
834 
835  msi_t* data = (msi_t*) file->private_data;
836  static int32_t initFile[13];
837 
838  int32_t fileIdx, tileIdx;
839  int32_t scaledrecnum;
840 
841  for (fileIdx=0; fileIdx<maxBands; fileIdx++){
842  if (strstr(data->jp2[fileIdx], conversion[bandIdx].str) != NULL)
843  break;
844  }
845  char bandPath[FILENAME_MAX];
846  strcpy(bandPath, data->imgDir);
847  strcat(bandPath, data->jp2[fileIdx]);
848 
849  // Set decoding parameters to default values
850  if (!initFile[bandIdx]){
851 // memset(&(data->parameters[bandIdx]), 0, sizeof(opj_decompress_parameters));
852  memset(&(data->parameters[bandIdx]), 0, sizeof(opj_dparameters_t));
853 
854  // Specify default decoding parameters
855 // opj_set_default_decoder_parameters(&(data->parameters[bandIdx].core));
856  opj_set_default_decoder_parameters(&(data->parameters[bandIdx]));
857 
858  data->image[bandIdx] = NULL;
859  data->l_stream[bandIdx] = NULL;
860  data->l_codec[bandIdx] = opj_create_decompress(OPJ_CODEC_JP2);
861  data->cstr_info[bandIdx] = NULL;
862 
863 // opj_set_info_handler(data->l_codec[bandIdx], info_callback,00);
864  opj_set_warning_handler(data->l_codec[bandIdx], warning_callback,00);
865  opj_set_error_handler(data->l_codec[bandIdx], error_callback,00);
866 
867  } else if (scale_recnum(bandIdx,recnum) >= data->parameters[bandIdx].DA_y1) {
868  opj_stream_destroy(data->l_stream[bandIdx]);
869  opj_destroy_codec(data->l_codec[bandIdx]);
870  opj_image_destroy(data->image[bandIdx]);
871  data->l_codec[bandIdx] = opj_create_decompress(OPJ_CODEC_JP2);
872  initFile[bandIdx] = 0;
873  }
874 
875  // Setup the decoder decoding parameters using user parameters
876  if(!initFile[bandIdx]){
877  // Read input file and put it in memory
878  data->l_stream[bandIdx] = opj_stream_create_default_file_stream(bandPath, 1);
879  if (!data->l_stream[bandIdx]){
880  fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", bandPath);
881  free(&(data->parameters[bandIdx]));
882  return EXIT_FAILURE;
883  }
884 
885 // if ( !opj_setup_decoder(data->l_codec[bandIdx], &(data->parameters[bandIdx].core))){
886  if ( !opj_setup_decoder(data->l_codec[bandIdx], &(data->parameters[bandIdx]))){
887  fprintf(stderr, "ERROR -> opj_compress: failed to setup the decoder\n");
888  opj_stream_destroy(data->l_stream[bandIdx]);
889  opj_destroy_codec(data->l_codec[bandIdx]);
890  return EXIT_FAILURE;
891  }
892 
893  // Read the main header of the codestream and if necessary the JP2 boxes
894  if(! opj_read_header(data->l_stream[bandIdx], data->l_codec[bandIdx], &(data->image[bandIdx]))){
895  fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n");
896  opj_stream_destroy(data->l_stream[bandIdx]);
897  opj_destroy_codec(data->l_codec[bandIdx]);
898  opj_image_destroy(data->image[bandIdx]);
899  return EXIT_FAILURE;
900  }
901  data->cstr_info[bandIdx] = opj_get_cstr_info(data->l_codec[bandIdx]);
902  initFile[bandIdx] = 1;
903  }
904 
905  // Set boundaries for decoding MSI data based on different resolutions
906  switch(bandIdx) {
907  // For 60m resolution data: band 1, band 9 and band 10,
908  case B01:
909  case B09:
910  case B10:
911  scaledrecnum = scale_recnum(bandIdx,recnum);
912  tileIdx = floor(scaledrecnum / (int32_t)data->cstr_info[bandIdx]->tdy);
913  data->parameters[bandIdx].DA_x0 = 0;
914  data->parameters[bandIdx].DA_x1 = floor(file->npix/3);
915  data->parameters[bandIdx].DA_y0 = tileIdx*data->cstr_info[bandIdx]->tdy;
916  data->parameters[bandIdx].DA_y1 = std::min((tileIdx+1)*(int32_t)data->cstr_info[bandIdx]->tdy,file->nscan/3);
917  break;
918  // For 10m resolution data: band 2, band 3, band 4 and band 8,
919  case B02:
920  case B03:
921  case B04:
922  case B08:
923  scaledrecnum = scale_recnum(bandIdx,recnum);
924  tileIdx = floor(scaledrecnum / (int32_t)data->cstr_info[bandIdx]->tdy);
925  data->parameters[bandIdx].DA_x0 = 0;
926  data->parameters[bandIdx].DA_x1 = 2 * file->npix;
927  data->parameters[bandIdx].DA_y0 = tileIdx*data->cstr_info[bandIdx]->tdy;
928  data->parameters[bandIdx].DA_y1 = std::min((tileIdx+1)*(int32_t)data->cstr_info[bandIdx]->tdy,file->nscan*2);
929  break;
930  // For 20m resolution data: band 5, band 6, band 7, band 8a, band 11 and band 12
931  default:
932  scaledrecnum = scale_recnum(bandIdx,recnum);
933  tileIdx = floor(scaledrecnum / (int32_t)data->cstr_info[bandIdx]->tdy);
934  data->parameters[bandIdx].DA_x0 = 0;
935  data->parameters[bandIdx].DA_x1 = file->npix;
936  data->parameters[bandIdx].DA_y0 = tileIdx*data->cstr_info[bandIdx]->tdy;
937  data->parameters[bandIdx].DA_y1 = std::min((tileIdx+1)*(int32_t)data->cstr_info[bandIdx]->tdy,file->nscan);
938  break;
939  }
940 
941 
942  // Decode the JPEG2000 stream
943  if (data->image[bandIdx]->comps->data == NULL) {
944  // Decode the image based on boundaries
945  if (!opj_set_decode_area(data->l_codec[bandIdx], data->image[bandIdx], data->parameters[bandIdx].DA_x0,
946  data->parameters[bandIdx].DA_y0, data->parameters[bandIdx].DA_x1, data->parameters[bandIdx].DA_y1)){
947  fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n");
948  opj_stream_destroy(data->l_stream[bandIdx]);
949  opj_destroy_codec(data->l_codec[bandIdx]);
950  opj_image_destroy(data->image[bandIdx]);
951  return EXIT_FAILURE;
952  }
953  if (!opj_decode(data->l_codec[bandIdx], data->l_stream[bandIdx], data->image[bandIdx]) &&
954  opj_end_decompress(data->l_codec[bandIdx], data->l_stream[bandIdx])){
955  fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n");
956  opj_stream_destroy(data->l_stream[bandIdx]);
957  opj_destroy_codec(data->l_codec[bandIdx]);
958  opj_image_destroy(data->image[bandIdx]);
959  return EXIT_FAILURE;
960  }
961  }
962 
963  // Resampling data of each band to 20m
964  int32_t relative_recnum = scaledrecnum - data->parameters[bandIdx].DA_y0;
965 
966  switch(bandIdx)
967  {
968  case B01:
969  case B09:
970  case B10:
971  resample_msi(data->image[bandIdx], file, relative_recnum, 60, 20);
972  break;
973  case B02:
974  case B03:
975  case B04:
976  case B08:
977  resample_msi(data->image[bandIdx], file, relative_recnum, 10, 20);
978  break;
979  default:
980  resample_msi(data->image[bandIdx], file, relative_recnum, 20, 20);
981  break;
982  }
983 
984  return 0;
985 };
986 
987 
988 /************************************************/
989 /* function: freeMSIData */
990 /* Free memory allocated in createPrivateData */
991 /************************************************/
992 void freeMSIData(msi_t* data) {
993  int i;
994  free(data->ULCoord);
995  for (i = 0; i< 3; i++)
996  free(data->position[i]);
997 
998  free(data->gpstime);
999  free(data->buf);
1000 
1001  for (int i = 0; i < maxBands; i++) {
1002  free(data->sensorZenith[i]);
1003  free(data->sensorAzimuth[i]);
1004  }
1005  free(data->sensorZenith);
1006  free(data->sensorAzimuth);
1007 
1008  free(data);
1009 }
1010 
1011 
1012 /************************************************/
1013 /* function: closel1_msi */
1014 /* Close opened files and free mempry */
1015 /************************************************/
1016 extern "C" int closel1_msi(filehandle *file){
1017 
1018  msi_t* data = (msi_t*) file->private_data;
1019 
1020  freeMSIData(data);
1021  file->private_data = NULL;
1022 
1023  return 0;
1024 }
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
int32 value
Definition: Granule.c:1235
int init_geom_per_band(l1str *l1rec)
Definition: geom_per_band.c:7
int j
Definition: decode_rs.h:73
void get_zenaz(float *pos, float lon, float lat, float *senz, float *sena)
Definition: get_zenaz.c:28
@ B07
Definition: l1_msi.cpp:30
These are used to scale the SD before writing it to the HDF4 file The default is and which means the product is not scaled at all Since the product is usually stored as a float inside of this is a way to write the float out as a integer l2prod min
@ B11
Definition: l1_msi.cpp:30
#define NULL
Definition: decode_rs.h:63
int closel1_msi(filehandle *file)
Definition: l1_msi.cpp:1016
const char * str
Definition: l1_msi.cpp:35
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
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second band
msiBandIdx val
Definition: l1_msi.cpp:34
void interpViewAngles(l1str *l1rec, int pixel, int scan, int band, float *senz, float *sena)
float32 * pos
Definition: l1_czcs_hdf.c:35
int32 * msec
Definition: l1_czcs_hdf.c:31
msiBandIdx str2enum(const char *str)
Definition: l1_msi.cpp:63
double esdist_(int32_t *year, int32_t *day, int32_t *msec)
int openl1_msi(filehandle *file)
Definition: l1_msi.cpp:480
@ string
msi_t * createPrivateData_msi(int numBands)
Definition: l1_msi.cpp:189
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
character(len=1000) if
Definition: names.f90:13
#define PI
Definition: l3_get_org.c:6
int32_t readDetectorFootprint_msi(filehandle *file, int band)
Definition: l1_msi.cpp:437
int32_t readDatastripMeta_msi(filehandle *file)
Definition: l1_msi.cpp:367
@ B12
Definition: l1_msi.cpp:30
void warning_callback(const char *msg, void *client_data)
Definition: l1_msi.cpp:174
int readl1_msi(filehandle *file, int recnum, l1str *l1rec, int lonlat)
Definition: l1_msi.cpp:637
void freeMSIData(msi_t *data)
Definition: l1_msi.cpp:992
read recnum
subroutine lonlat(alon, alat, xlon, ylat)
Definition: lonlat.f:2
int readl1_msi_lonlat(filehandle *file, int recnum, l1str *l1rec)
Definition: l1_msi.cpp:610
void interpGPSpos(l1str *l1rec, double *pos, int detector, int band)
Definition: l1_msi.cpp:98
make_L3 README txt Compiling set environment variables for HDBLIB and HDFINC to the appropriate HDF4 lib and include directories make_L3_v1 c o make_L3 LIB lib a I LIB I $HDFINC L $HDFLIB lmfhdf ldf lz ljpeg lm lmalloc Running make_L3 takes input from standard so the SeaWIFS level files should be piped to the program via the command line as in to be allocated by the program to buffer the compositing The the better Ideally it should be to fit the entire global image(with all the layers) at once. Otherwise the process will be buffered on disk. -bufstep
char * strdup(const char *)
int32_t readTileMeta_msi(filehandle *file)
Definition: l1_msi.cpp:245
l1_input_t * l1_input
Definition: l1_options.c:9
bg::model::point< double, 2, bg::cs::spherical_equatorial< bg::degree > > Point_t
Definition: get_dataday.cpp:23
int want_verbose
void unix2yds(double usec, short *year, short *day, double *secs)
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution pixel
Definition: HISTORY.txt:192
#define RADEG
Definition: czcs_ctl_pt.c:5
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
@ B08
Definition: l1_msi.cpp:30
@ B06
Definition: l1_msi.cpp:30
@ B05
Definition: l1_msi.cpp:30
uint32_t scale_recnum(int32_t bandIdx, int32_t recnum)
Definition: l1_msi.cpp:814
#define maxBands
void error_callback(const char *msg, void *client_data)
Definition: l1_msi.cpp:167
#define BAD_FLT
Definition: jplaeriallib.h:19
int inDetector(msi_t *data, float lat, float lon)
Definition: l1_msi.cpp:75
#define numDetectors
@ B09
Definition: l1_msi.cpp:30
@ B02
Definition: l1_msi.cpp:30
def polygon
Definition: run_local.py:70
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second and prod_ix set to PARAM_TYPE_INT name_prefix is compared with the beginning of the product name If name_suffix is not empty the it must match the end of the product name The characters right after the prefix are read as an integer and prod_ix is set to that number strncpy(l2prod->name_prefix, "myprod", UNITLEN)
@ B04
Definition: l1_msi.cpp:30
@ B03
Definition: l1_msi.cpp:30
data_t s[NROOTS]
Definition: decode_rs.h:75
void resample_msi(opj_image_t *image, filehandle *file, int recnum, int srcRes, int destRes)
Definition: l1_msi.cpp:210
real *8 function esdist(iyr, iday, msec)
Definition: esdist.f:3
int decodeMSI(filehandle *file, int32_t bandIdx, int32_t recnum)
Definition: l1_msi.cpp:833
int32_t rdsensorinfo(int32_t, int32_t, const char *, void **)
Definition: rdsensorinfo.c:69
for(i=0;i< NROOTS;i++) s[i]
Definition: decode_rs.h:85
string msg
Definition: mapgen.py:229
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 as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
@ B01
Definition: l1_msi.cpp:30
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] angles
Definition: HISTORY.txt:366
@ B8A
Definition: l1_msi.cpp:30
int i
Definition: decode_rs.h:71
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
void info_callback(const char *msg, void *client_data)
Definition: l1_msi.cpp:181
@ B10
Definition: l1_msi.cpp:30
int sunpos(double tjd, double r[3], char **errstr)
Definition: aerosol.c:136
msiBandIdx
Definition: l1_msi.cpp:28
void l_sun_(int *iyr, int *iday, double *sec, float *sunr, float *rs)
float p[MODELMAX]
Definition: atrem_corl1.h:131
double isodate2unix(const char *isodate)
Definition: unix2isodate.c:61