OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
l1c_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 "l1c_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 "l1c_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: openl1c_msi */
478 /* Open msi l1c data with metadata file */
479 /************************************************/
480 extern "C" int openl1c_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: readl1c_msi */
608 /* Get coordinates and convert to lon/lat */
609 /************************************************/
610 extern "C" int readl1c_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: readl1c_msi */
635 /* Read MSI l1c image data line by line */
636 /************************************************/
637 extern "C" int readl1c_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( ( l1_input->geom_per_band == 1 ) && ( l1rec->geom_per_band == NULL ) )
672  {
674  gm_p_b = l1rec->geom_per_band; // store this address so that it can be later destroyed in close()
675  }
676 
677  l_sun_(&iyear, &idoy, &secondOfDay, sunpos, &sunDist); // get position vector for the sun
678 
679  for (i=0; i < 3; i++) {
680  sunpos[i] *= 1.496e8; //convert to km for call to get_zenaz
681  }
682  // Assign viewing angles to l1rec struct
683  for (ib = 0; ib<maxBands; ib++) {
684  int len = strlen(data->jp2[ib])-7;
685  strncpy(bandStrBuffer, data->jp2[ib]+len, 3);
686  bandStrBuffer[3] = '\0';
687  int bandIdx = str2enum(bandStrBuffer);
688  if (bandIdx == B10)
689  continue;
690 // int detector = -1;
691  for (ip=0; ip<file->npix; ip++) {
692  // use boost.within to determine detector number
693  // but only need to do this once - per band differences not significant
694  if (ib == 0) {
695 // detector = inDetector (data , l1rec->lat[ip], l1rec->lon[ip]);
696 
697  // interpolate GPS position vectors to scantime
698  // If we can get more accurate times, we can use this
699  // interpGPSpos method for sensor angles
700  // NOTE: the solar angles are also affected by the incorrect scantime
701  // but less egregiously so...
702 
703 // interpGPSpos(l1rec,pos,detector,ib);
704 
705 // for (i=0; i < 3; i++) {
706 // epos[i] = pos[i] * 1e-6; //values are in mm, convert to km
707 // }
708 // get_zenaz(epos, l1rec->lon[ip], l1rec->lat[ip], &l1rec->senz[ip], &l1rec->sena[ip]);
709 
710  // Assign band independent solar angles to l1rec struct
711  get_zenaz(sunpos, l1rec->lon[ip], l1rec->lat[ip], &l1rec->solz[ip], &l1rec->sola[ip]);
712  // interpolate tiePoint sensor view angles
713  interpViewAngles(data, ip, recnum, ib, &l1rec->senz[ip], &l1rec->sena[ip]);
714 // printf("%f %f\n",l1rec->senz[ip],l1rec->sena[ip]);
715  }
716 
717  if (l1_input->geom_per_band) {
718  int ipb = ip*file->nbands + bandIdx;
719 
720  // re-interpolate GPS position vectors to per band scantime (see note above)
721 // interpGPSpos(l1rec,pos,detector,ib);
722 //
723 // for (i=0; i < 3; i++)
724 // epos[i] = pos[i] * 1e-6; //values are in mm, convert to km
725 //
726 // get_zenaz(epos, l1rec->lon[ip], l1rec->lat[ip], &l1rec->geom_per_band->senz[ipb], &l1rec->geom_per_band->sena[ipb]);
727  // interpolate tiePoint sensor view angles
728  interpViewAngles(data, ip, recnum, ib, &l1rec->geom_per_band->senz[ipb], &l1rec->geom_per_band->sena[ipb]);
729  // per band solar angles are just repetitions of the nominal values
730  l1rec->geom_per_band->solz[ipb] = l1rec->solz[ip];
731  l1rec->geom_per_band->sola[ipb] = l1rec->sola[ip];
732  }
733  }
734  }
735 
736 
737  // Calculate surface reflectance values for each band
738  for(ib = 0; ib < maxBands; ib++) {
739  int len = strlen(data->jp2[ib])-7;
740  strncpy(bandStrBuffer, data->jp2[ib]+len, 3);
741  bandStrBuffer[3] = '\0';
742  int bandIdx = str2enum(bandStrBuffer);
743  if (bandIdx == B10)
744  continue;
745 
746  l1rec->Fo[bandIdx] = Fobar[bandIdx] * fsol;
747 
748  if(decodeMSI(file, bandIdx, recnum)!=0) {
749  printf("-E-: Error decoding MSI jp2 files.\n");
750  fprintf(stderr, "-E- %s line %d: Failed to read Lt, band %d, recnum %d\n",
751  __FILE__,__LINE__, bandIdx, recnum );
752  exit(1);
753  }
754 
755  for (ip=0; ip<file->npix; ip++) {
756  ipb = ip*file->nbands+bandIdx;
757  if(data->buf[ip] == 0) {
758  l1rec->Lt[ipb] = BAD_FLT;
759  l1rec->navfail[ip] = 1;
760  } else{
761  // 10000 is the QUANTIFICATION_VALUE of MSI data to convert DN value to reflectance
762  // This value is listed in the MTD_MSIL1C.xml file, but we're just hardcoding it...bad?
763  float quant = 10000.;
764  float rToa = (float) (data->buf[ip] / quant);
765 
766  l1rec->Lt[ipb] = (rToa * l1rec->Fo[bandIdx] * cos(l1rec->solz[ip]/RADEG)) / PI ;
767  }
768  }
769  }
770 
771  // Calculate rho_cirrus from cirrus band 10
772  if(decodeMSI(file, B10, recnum)!=0) {
773  fprintf(stderr, "-E- %s line %d: Failed to read cirrus band, recnum %d\n",
774  __FILE__,__LINE__, recnum );
775  exit(1);
776  }
777  for (ip=0;ip<file->npix; ip++) {
778  if(data->buf[ip] == 0)
779  l1rec->rho_cirrus[ip] = BAD_FLT;
780  else
781  l1rec->rho_cirrus[ip] = data->buf[ip] / (PI * 10000.0);
782  }
783 
784  // Check lat and lon values
785  for (ip=0; ip<file->npix; ip++) {
786  l1rec->pixnum[ip] = ip;
787  if ( std::isnan(l1rec->lat[ip]) )
788  l1rec->lat[ip] = -999.0;
789  if ( std::isnan(l1rec->lon[ip]) )
790  l1rec->lon[ip] = -999.0;
791 
792  if (l1rec->lon[ip] < -181.0 || l1rec->lon[ip] > 181.0 ||
793  l1rec->lat[ip] < -91.0 || l1rec->lat[ip] > 91.0 )
794  l1rec->navfail[ip] = 1;
795 
796  }
797 
798  return 0;
799 
800 }
801 uint32_t scale_recnum( int32_t bandIdx, int32_t recnum){
802  switch(bandIdx) {
803  case B01:
804  case B09:
805  case B10:
806  return floor(recnum/3);
807  case B02:
808  case B03:
809  case B04:
810  case B08:
811  return recnum*2;
812  default:
813  return recnum;
814  }
815 }
816 /************************************************/
817 /* function: decodeMSI */
818 /* Decode jp2 data */
819 /************************************************/
820 int decodeMSI(filehandle *file, int32_t bandIdx, int32_t recnum){
821 
822  msi_t* data = (msi_t*) file->private_data;
823  static int32_t initFile[13];
824 
825  int32_t fileIdx, tileIdx;
826  int32_t scaledrecnum;
827 
828  for (fileIdx=0; fileIdx<maxBands; fileIdx++){
829  if (strstr(data->jp2[fileIdx], conversion[bandIdx].str) != NULL)
830  break;
831  }
832  char bandPath[FILENAME_MAX];
833  strcpy(bandPath, data->imgDir);
834  strcat(bandPath, data->jp2[fileIdx]);
835 
836  // Set decoding parameters to default values
837  if (!initFile[bandIdx]){
838 // memset(&(data->parameters[bandIdx]), 0, sizeof(opj_decompress_parameters));
839  memset(&(data->parameters[bandIdx]), 0, sizeof(opj_dparameters_t));
840 
841  // Specify default decoding parameters
842 // opj_set_default_decoder_parameters(&(data->parameters[bandIdx].core));
843  opj_set_default_decoder_parameters(&(data->parameters[bandIdx]));
844 
845  data->image[bandIdx] = NULL;
846  data->l_stream[bandIdx] = NULL;
847  data->l_codec[bandIdx] = opj_create_decompress(OPJ_CODEC_JP2);
848  data->cstr_info[bandIdx] = NULL;
849 
850 // opj_set_info_handler(data->l_codec[bandIdx], info_callback,00);
851  opj_set_warning_handler(data->l_codec[bandIdx], warning_callback,00);
852  opj_set_error_handler(data->l_codec[bandIdx], error_callback,00);
853 
854  } else if (scale_recnum(bandIdx,recnum) >= data->parameters[bandIdx].DA_y1) {
855  opj_stream_destroy(data->l_stream[bandIdx]);
856  opj_destroy_codec(data->l_codec[bandIdx]);
857  opj_image_destroy(data->image[bandIdx]);
858  data->l_codec[bandIdx] = opj_create_decompress(OPJ_CODEC_JP2);
859  initFile[bandIdx] = 0;
860  }
861 
862  // Setup the decoder decoding parameters using user parameters
863  if(!initFile[bandIdx]){
864  // Read input file and put it in memory
865  data->l_stream[bandIdx] = opj_stream_create_default_file_stream(bandPath, 1);
866  if (!data->l_stream[bandIdx]){
867  fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", bandPath);
868  free(&(data->parameters[bandIdx]));
869  return EXIT_FAILURE;
870  }
871 
872 // if ( !opj_setup_decoder(data->l_codec[bandIdx], &(data->parameters[bandIdx].core))){
873  if ( !opj_setup_decoder(data->l_codec[bandIdx], &(data->parameters[bandIdx]))){
874  fprintf(stderr, "ERROR -> opj_compress: failed to setup the decoder\n");
875  opj_stream_destroy(data->l_stream[bandIdx]);
876  opj_destroy_codec(data->l_codec[bandIdx]);
877  return EXIT_FAILURE;
878  }
879 
880  // Read the main header of the codestream and if necessary the JP2 boxes
881  if(! opj_read_header(data->l_stream[bandIdx], data->l_codec[bandIdx], &(data->image[bandIdx]))){
882  fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n");
883  opj_stream_destroy(data->l_stream[bandIdx]);
884  opj_destroy_codec(data->l_codec[bandIdx]);
885  opj_image_destroy(data->image[bandIdx]);
886  return EXIT_FAILURE;
887  }
888  data->cstr_info[bandIdx] = opj_get_cstr_info(data->l_codec[bandIdx]);
889  initFile[bandIdx] = 1;
890  }
891 
892  // Set boundaries for decoding MSI data based on different resolutions
893  switch(bandIdx) {
894  // For 60m resolution data: band 1, band 9 and band 10,
895  case B01:
896  case B09:
897  case B10:
898  scaledrecnum = scale_recnum(bandIdx,recnum);
899  tileIdx = floor(scaledrecnum / (int32_t)data->cstr_info[bandIdx]->tdy);
900  data->parameters[bandIdx].DA_x0 = 0;
901  data->parameters[bandIdx].DA_x1 = floor(file->npix/3);
902  data->parameters[bandIdx].DA_y0 = tileIdx*data->cstr_info[bandIdx]->tdy;
903  data->parameters[bandIdx].DA_y1 = std::min((tileIdx+1)*(int32_t)data->cstr_info[bandIdx]->tdy,file->nscan/3);
904  break;
905  // For 10m resolution data: band 2, band 3, band 4 and band 8,
906  case B02:
907  case B03:
908  case B04:
909  case B08:
910  scaledrecnum = scale_recnum(bandIdx,recnum);
911  tileIdx = floor(scaledrecnum / (int32_t)data->cstr_info[bandIdx]->tdy);
912  data->parameters[bandIdx].DA_x0 = 0;
913  data->parameters[bandIdx].DA_x1 = 2 * file->npix;
914  data->parameters[bandIdx].DA_y0 = tileIdx*data->cstr_info[bandIdx]->tdy;
915  data->parameters[bandIdx].DA_y1 = std::min((tileIdx+1)*(int32_t)data->cstr_info[bandIdx]->tdy,file->nscan*2);
916  break;
917  // For 20m resolution data: band 5, band 6, band 7, band 8a, band 11 and band 12
918  default:
919  scaledrecnum = scale_recnum(bandIdx,recnum);
920  tileIdx = floor(scaledrecnum / (int32_t)data->cstr_info[bandIdx]->tdy);
921  data->parameters[bandIdx].DA_x0 = 0;
922  data->parameters[bandIdx].DA_x1 = file->npix;
923  data->parameters[bandIdx].DA_y0 = tileIdx*data->cstr_info[bandIdx]->tdy;
924  data->parameters[bandIdx].DA_y1 = std::min((tileIdx+1)*(int32_t)data->cstr_info[bandIdx]->tdy,file->nscan);
925  break;
926  }
927 
928 
929  // Decode the JPEG2000 stream
930  if (data->image[bandIdx]->comps->data == NULL) {
931  // Decode the image based on boundaries
932  if (!opj_set_decode_area(data->l_codec[bandIdx], data->image[bandIdx], data->parameters[bandIdx].DA_x0,
933  data->parameters[bandIdx].DA_y0, data->parameters[bandIdx].DA_x1, data->parameters[bandIdx].DA_y1)){
934  fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n");
935  opj_stream_destroy(data->l_stream[bandIdx]);
936  opj_destroy_codec(data->l_codec[bandIdx]);
937  opj_image_destroy(data->image[bandIdx]);
938  return EXIT_FAILURE;
939  }
940  if (!opj_decode(data->l_codec[bandIdx], data->l_stream[bandIdx], data->image[bandIdx]) &&
941  opj_end_decompress(data->l_codec[bandIdx], data->l_stream[bandIdx])){
942  fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n");
943  opj_stream_destroy(data->l_stream[bandIdx]);
944  opj_destroy_codec(data->l_codec[bandIdx]);
945  opj_image_destroy(data->image[bandIdx]);
946  return EXIT_FAILURE;
947  }
948  }
949 
950  // Resampling data of each band to 20m
951  int32_t relative_recnum = scaledrecnum - data->parameters[bandIdx].DA_y0;
952 
953  switch(bandIdx)
954  {
955  case B01:
956  case B09:
957  case B10:
958  resample_msi(data->image[bandIdx], file, relative_recnum, 60, 20);
959  break;
960  case B02:
961  case B03:
962  case B04:
963  case B08:
964  resample_msi(data->image[bandIdx], file, relative_recnum, 10, 20);
965  break;
966  default:
967  resample_msi(data->image[bandIdx], file, relative_recnum, 20, 20);
968  break;
969  }
970 
971  return 0;
972 };
973 
974 
975 /************************************************/
976 /* function: freeMSIData */
977 /* Free memory allocated in createPrivateData */
978 /************************************************/
979 void freeMSIData(msi_t* data) {
980  int i;
981  free(data->ULCoord);
982  for (i = 0; i< 3; i++)
983  free(data->position[i]);
984 
985  free(data->gpstime);
986  free(data->buf);
987 
988  for (int i = 0; i < maxBands; i++) {
989  free(data->sensorZenith[i]);
990  free(data->sensorAzimuth[i]);
991  }
992  free(data->sensorZenith);
993  free(data->sensorAzimuth);
994 
995  free(data);
996 }
997 
998 
999 /************************************************/
1000 /* function: closel1c_msi */
1001 /* Close opened files and free mempry */
1002 /************************************************/
1003 extern "C" int closel1c_msi(filehandle *file){
1004 
1005  msi_t* data = (msi_t*) file->private_data;
1006 
1007  freeMSIData(data);
1008  file->private_data = NULL;
1009 
1010  return 0;
1011 }
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
@ B08
Definition: l1c_msi.cpp:30
@ B03
Definition: l1c_msi.cpp:30
int openl1c_msi(filehandle *file)
Definition: l1c_msi.cpp:480
int init_geom_per_band(l1str *l1rec)
Definition: geom_per_band.c:7
int j
Definition: decode_rs.h:73
void info_callback(const char *msg, void *client_data)
Definition: l1c_msi.cpp:181
void get_zenaz(float *pos, float lon, float lat, float *senz, float *sena)
Definition: get_zenaz.c:28
@ B11
Definition: l1c_msi.cpp:30
void freeMSIData(msi_t *data)
Definition: l1c_msi.cpp:979
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
int32_t readTileMeta_msi(filehandle *file)
Definition: l1c_msi.cpp:245
#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
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
void interpViewAngles(l1str *l1rec, int pixel, int scan, int band, float *senz, float *sena)
void resample_msi(opj_image_t *image, filehandle *file, int recnum, int srcRes, int destRes)
Definition: l1c_msi.cpp:210
@ B01
Definition: l1c_msi.cpp:30
float32 * pos
Definition: l1_czcs_hdf.c:35
msiBandIdx str2enum(const char *str)
Definition: l1c_msi.cpp:63
float * lat
int32 * msec
Definition: l1_czcs_hdf.c:31
double esdist_(int32_t *year, int32_t *day, int32_t *msec)
uint32_t scale_recnum(int32_t bandIdx, int32_t recnum)
Definition: l1c_msi.cpp:801
void warning_callback(const char *msg, void *client_data)
Definition: l1c_msi.cpp:174
int32_t readDatastripMeta_msi(filehandle *file)
Definition: l1c_msi.cpp:367
@ string
void interpGPSpos(l1str *l1rec, double *pos, int detector, int band)
Definition: l1c_msi.cpp:98
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
int inDetector(msi_t *data, float lat, float lon)
Definition: l1c_msi.cpp:75
@ B10
Definition: l1c_msi.cpp:30
character(len=1000) if
Definition: names.f90:13
#define PI
Definition: l3_get_org.c:6
int decodeMSI(filehandle *file, int32_t bandIdx, int32_t recnum)
Definition: l1c_msi.cpp:820
@ B12
Definition: l1c_msi.cpp:30
int readl1c_msi_lonlat(filehandle *file, int recnum, l1str *l1rec)
Definition: l1c_msi.cpp:610
read recnum
subroutine lonlat(alon, alat, xlon, ylat)
Definition: lonlat.f:2
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 *)
@ B05
Definition: l1c_msi.cpp:30
bg::model::point< double, 2, bg::cs::spherical_equatorial< bg::degree > > Point_t
Definition: get_dataday.cpp:23
int closel1c_msi(filehandle *file)
Definition: l1c_msi.cpp:1003
l1_input_t * l1_input
Definition: l1_options.c:9
int want_verbose
msi_t * createPrivateData_msi(int numBands)
Definition: l1c_msi.cpp:189
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
void error_callback(const char *msg, void *client_data)
Definition: l1c_msi.cpp:167
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
const char * str
Definition: l1c_msi.cpp:35
#define BAD_FLT
Definition: jplaeriallib.h:19
@ B09
Definition: l1c_msi.cpp:30
@ B07
Definition: l1c_msi.cpp:30
msiBandIdx
Definition: l1c_msi.cpp:28
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)
float * lon
data_t s[NROOTS]
Definition: decode_rs.h:75
int readl1c_msi(filehandle *file, int recnum, l1str *l1rec, int lonlat)
Definition: l1c_msi.cpp:637
real *8 function esdist(iyr, iday, msec)
Definition: esdist.f:3
@ B8A
Definition: l1c_msi.cpp:30
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:227
@ B06
Definition: l1c_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] 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
@ B02
Definition: l1c_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
int i
Definition: decode_rs.h:71
msiBandIdx val
Definition: l1c_msi.cpp:34
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
@ B04
Definition: l1c_msi.cpp:30
#define maxBands
int sunpos(double tjd, double r[3], char **errstr)
void l_sun_(int *iyr, int *iday, double *sec, float *sunr, float *rs)
int32_t readDetectorFootprint_msi(filehandle *file, int band)
Definition: l1c_msi.cpp:437
float p[MODELMAX]
Definition: atrem_corl1.h:131
double isodate2unix(const char *isodate)
Definition: unix2isodate.c:61
#define numDetectors