OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
l1_hmodis_hdf.c
Go to the documentation of this file.
1 /* ============================================================================ */
2 /* module l1_hmodis_hdf.c - functions to read MODIS HIRES L1B for MSL12 */
3 /* */
4 /* Written By: B. Franz, NASA/SIMBIOS, January 2003. */
5 /* Modified By: J. Gales, NASA/OBPG, August 2005. */
6 /* Conversion for 16-band MODIS: B. Franz, J. Gales, 2006. */
7 /* Completely restructured by G. Fireman in 2014. */
8 /* */
9 /* ============================================================================ */
10 
11 #define _XOPEN_SOURCE_EXTENDED /* for strdup() */
12 #include "libnav.h"
13 #include "hdf4utils.h"
14 #include "l1.h"
15 #include <libgen.h>
16 #include <hdf.h>
17 #include <mfhdf.h>
18 #undef _XOPEN_SOURCE_EXTENDED
19 
20 #define SCAN_TIME_INTERVAL 1.4771
21 
22 /***********************************************************************/
23 #define TRYMEM(file,line,memstat) { \
24  if (memstat == NULL) { \
25  fprintf(stderr, \
26  "-E- %s line %d: Memory allocation error.\n", \
27  file, line); \
28  exit(1); } \
29  }
30 /***********************************************************************/
31 
32 /* SDSs of interest in each type of input file */
33 typedef struct {
34  int32_t index;
35  int32_t scandim;
36  char *name;
37 } sdslist;
38 
39 /* Positioning info to preload from MODIS Geolocation file */
40 enum REF_SDS {
46 };
47 static const sdslist SDSLIST_REF[] = {
48  { GEO_TAISEC, 0, "EV start time"},
49  { GEO_MSIDE, 0, "Mirror side"},
50  { GEO_ANGLES, 0, "attitude_angles"},
51  { GEO_MNORM, 0, "T_inst2ECR"},
52  { 0, 0, NULL}
53 };
54 
55 /* MODIS Geolocation swath SDSs */
56 enum GEO_SDS {
65 };
66 static const sdslist SDSLIST_GEO[] = {
67  { GEO_LON, 0, "Longitude"}, /* float32 */
68  { GEO_LAT, 0, "Latitude"}, /* float32 */
69  { GEO_HGT, 0, "Height"}, /* int16 */
70  { GEO_SOLZ, 0, "SolarZenith"}, /* int16 */
71  { GEO_SOLA, 0, "SolarAzimuth"}, /* int16 */
72  { GEO_SENZ, 0, "SensorZenith"}, /* int16 */
73  { GEO_SENA, 0, "SensorAzimuth"}, /* int16 */
74  { 0, 0, NULL}
75 };
76 
77 enum GEO_COEFFS {
80 };
81 static const char* geo_coeff[] = {/* index with enum GEO_COEFFS */
82  "scale_factor"
83 };
84 
85 /* MODIS L1B Band groupings */
86 enum L1B_SDS {
93 };
94 static sdslist SDSLIST_1KM[] = {// 1KM file contents
95  { RSB_250, 1, "EV_250_Aggr1km_RefSB"},
96  { RSB_500, 1, "EV_500_Aggr1km_RefSB"},
97  { RSB_1KM, 1, "EV_1KM_RefSB"},
98  { CIR_1KM, 0, "EV_Band26"}, // 1st dim=scan, not band
99  { TEB_1KM, 1, "EV_1KM_Emissive"},
100  { 0, 0, NULL}
101 };
102 static sdslist SDSLIST_HKM[] = {// HKM file contents
103  { RSB_250, 1, "EV_250_Aggr500_RefSB"},
104  { RSB_500, 1, "EV_500_RefSB"},
105  { 0, 0, NULL}
106 };
107 static sdslist SDSLIST_QKM[] = {// QKM file
108  { RSB_250, 1, "EV_250_RefSB"},
109  { 0, 0, NULL}
110 };
111 
118 };
119 static const char* l1b_coeff[] = {/* index with enum L1B_COEFFS */
120  "reflectance_scales",
121  "reflectance_offsets",
122  "radiance_scales",
123  "radiance_offsets"
124 };
125 
126 /***********************************************************************/
127 
128 /* Structure holding info for each MODIS input file */
129 typedef struct {
130  int32_t id;
131  char file[FILENAME_MAX];
132  char shortname[FILENAME_MAX];
133  double starttime;
134  int16_t resolution;
135  int32_t nlines;
136  int32_t npixls;
137  int32_t n_sds;
138  sds_struct *sds;
139 } modis_file;
140 
141 /***********************************************************************/
142 
143 /* Structure holding info needed for each swath-based SDS */
144 typedef struct {
145  sds_struct sds;
146  int16_t resolution;
147  int32_t nbands;
148  int32_t nscans;
149  int32_t ndets;
150  int32_t nframes;
151  int32_t nsf;
152  int32_t scandim;
153 } modis_sds;
154 
155 /*
156  Notes:
157  All GEO arrays are dimensioned [nscans*ndets, nframes]
158  Most L1B arrays are dimensioned [nbands, nscans*ndets, nframes*nsf]
159  where:
160  nscans and nframes are at 1KM resolution
161  nsf = #subframes = 1000/resolution
162  ndets = 10*nsubframes
163 
164  Band 26 drops the 1st dimension.
165  Geolocation is inherently 1KM resolution: nbands==1, ndets==10, nsf==1.
166 
167  ndets and scandim are needed for reading data one scan at a time.
168 
169  There is some redundancy between resolution, ndets, and nsf,
170  but it's helpful to have them all defined.
171  */
172 
173 /***********************************************************************/
174 /* Global variables */
175 
176 static modis_file file_geo, file_1km, file_hkm, file_qkm;
177 static modis_sds ref[REF_NUM_SDS], geo[GEO_NUM_SDS], l1b[L1B_NUM_SDS];
178 
179 /***********************************************************************/
180 
181 /* Substitute provided string for LAC/1KM part of filename */
182 int modpath_1km(const char *oldpath, const char* newchars, char* newpath) {
183  int32_t status;
184  char *ptr = NULL;
185  char *tmpbuf = NULL;
186  char *filename = NULL;
187 
188  /* directory name */
189  tmpbuf = strdup(oldpath);
190  strcpy(newpath, dirname(tmpbuf));
191  strcat(newpath, "/");
192 
193  /* filename up to substring */
194  tmpbuf = strdup(oldpath);
195  filename = basename(tmpbuf);
196  status = ((ptr = strstr(filename, "_MODIS.")) == NULL);
197  if (status) {
198  status = (((ptr = strstr(filename, "LAC")) == NULL) &&
199  ((ptr = strstr(filename, "1KM")) == NULL));
200 
201  if (status) {
202  fprintf(stderr,
203  "Input file %s does not follow the standard name convention;"
204  " can't find \"%s\" file.\n",
205  oldpath, newchars);
206  newpath[0] = '\0';
207  return status;
208  }
209 
210  strncat(newpath, filename, ptr - filename);
211 
212  /* add new substring and the rest of the filename */
213  strcat(newpath, newchars);
214  strcat(newpath, ptr + strlen(newchars));
215  } else {
216  strncat(newpath, filename, ptr - filename + 6);
217 
218  /* add new substring and the rest of the filename */
219  strcat(newpath, "_");
220  strcat(newpath, newchars);
221  strcat(newpath, ptr + strlen(newchars) + 3);
222  }
223  free(tmpbuf);
224 
225  return status;
226 }
227 
228 /***********************************************************************/
229 
231  int32_t status = FAIL;
232  int32_t i;
233  char result[FILENAME_MAX];
234  sdslist *file_content;
235 
236  /* Open input file */
237  status = ((l1bfile->id = SDstart(l1bfile->file, DFACC_RDONLY)) == FAIL);
238  if (status) {
239  fopen_warn(l1bfile->file, __FILE__, __LINE__);
240  return status;
241  }
242 
243  /*----- Read Global Attributes to determine file type -----*/
244  get_hdfeos_meta(l1bfile->id, "CoreMetadata.0", "SHORTNAME", result);
245  if ((strcmp(result, "MYD021KM") == 0) ||
246  (strcmp(result, "MOD021KM") == 0)) { // 1KM
247  l1bfile->resolution = 1000;
248  file_content = SDSLIST_1KM;
249  } else if ((strcmp(result, "MYD02HKM") == 0) ||
250  (strcmp(result, "MOD02HKM") == 0)) { // HKM
251  l1bfile->resolution = 500;
252  file_content = SDSLIST_HKM;
253  } else if ((strcmp(result, "MYD02QKM") == 0) ||
254  (strcmp(result, "MOD02QKM") == 0)) { // QKM
255  l1bfile->resolution = 250;
256  file_content = SDSLIST_QKM;
257  } else {
258  fprintf(stderr,
259  "Input file %s has type %s; "
260  "does not contain MODIS calibrated radiances.\n",
261  l1bfile->file, result);
262  return FAIL;
263  }
264  strcpy(l1bfile->shortname, result);
265 
266  /*----- Data set info -----*/
267  l1bfile->n_sds = 0;
268  while (file_content[l1bfile->n_sds].name)
269  l1bfile->n_sds++;
270  TRYMEM(__FILE__, __LINE__,
271  (l1bfile->sds = calloc(l1bfile->n_sds, sizeof (sds_struct))));
272  for (i = 0; i < l1bfile->n_sds; i++)
273  init_sds_byname(l1bfile->id, file_content[i].name, &(l1bfile->sds[i]));
274 
275  /*----- Native dimensions -----*/
276  l1bfile->nlines = l1bfile->sds[RSB_250].dimlen[1]; //(bands,NSCANS*NDETS,nframes*nsf)
277  l1bfile->npixls = l1bfile->sds[RSB_250].dimlen[2]; //(bands,nscans*ndets,NFRAMES*NSF)
278 
279  /* Note: Every MODIS L1B file contains a 250m-band SDS, aggregated for
280  coarser resolutions, so we can use [RSB_250] to reference native
281  dimensions for every file. Later we'll use [RSB_250] to index the
282  highest-resolution SDS, to specify output dimensions. */
283 
284  return SUCCESS;
285 }
286 
287 int init_l1b(const char filename[FILENAME_MAX], int32_t *max_resolution) {
288  int32_t i, j;
289  int32_t status = FAIL;
290 
291  /* Start fresh */
292  memset(&file_1km, 0, sizeof (modis_file));
293  memset(&file_hkm, 0, sizeof (modis_file));
294  memset(&file_qkm, 0, sizeof (modis_file));
295 
296  /* Initialize L1B 1KM file info */
297  strcpy(file_1km.file, filename);
298  status = open_modis_l1bfile(&file_1km);
299  if (status) {
300  fprintf(stderr,
301  "Error reading %s; please specify a valid Level 1B file.\n",
302  filename);
303  return status;
304  }
305 
306  /* Input L1B file must have 1KM resolution */
307  status = (file_1km.resolution != 1000);
308  if (status) {
309  fprintf(stderr,
310  "Input file %s has %dm resolution; "
311  "please specify a 1km-resolution Level 1B file.\n",
312  filename, file_1km.resolution);
313  return status;
314  }
315 
316  /* Open other L1B files as needed for specified resolution */
317  switch (*max_resolution) {
318 
319  case 250: // QKM
320  status = modpath_1km(filename, "QKM", file_qkm.file);
321  if (status)
322  return status;
323  status = open_modis_l1bfile(&file_qkm);
324  if (status) {
325  fprintf(stderr, "File not found: %s\n", file_qkm.file);
326  fprintf(stderr,
327  "Processing at %im resolution requires a QKM file to be "
328  "present in the same directory as the 1KM L1B file.\n",
329  *max_resolution);
330  return status;
331  }
332  /* no break: also load HKM */
333 
334  case 500: // HKM
335  status = modpath_1km(filename, "HKM", file_hkm.file);
336  if (status)
337  return status;
338  status = open_modis_l1bfile(&file_hkm);
339  if (status) {
340  fprintf(stderr, "File not found: %s\n", file_hkm.file);
341  fprintf(stderr,
342  "Processing at %im resolution requires a HKM file to be "
343  "present in the same directory as the 1KM L1B file.\n",
344  *max_resolution);
345  return status;
346  }
347  break;
348 
349  case -1: // default to 1KM
350  *max_resolution = 1000;
351  /* no break: proceed as for 1KM */
352 
353  case 1000: // 1KM
354  /* file_1km has already been initialized */
355  break;
356 
357  default:
358  fprintf(stderr, "Invalid resolution %i; ", *max_resolution);
359  fprintf(stderr, "must be 1000, 500 or 250 m.\n");
360  status = FAIL;
361  exit(status);
362  break;
363  }
364 
365  /* Populate global info for each L1B SDS */
366  for (i = 0; i < L1B_NUM_SDS; i++) {
367  l1b[i].sds = file_1km.sds[i]; // initialize to 1KM inputs
368  l1b[i].resolution = file_1km.resolution;
369  l1b[i].nscans = file_1km.nlines / 10;
370  l1b[i].nframes = file_1km.npixls;
371  l1b[i].scandim = SDSLIST_1KM[i].scandim;
372  }
373  if (*max_resolution < 1000) {
374  l1b[RSB_500].sds = file_hkm.sds[RSB_500]; // HKM or QKM
375  l1b[RSB_500].resolution = file_hkm.resolution;
376 
377  l1b[RSB_250].sds = file_hkm.sds[RSB_250]; // HKM only
378  l1b[RSB_250].resolution = file_hkm.resolution;
379  }
380  if (*max_resolution < 500) {
381  l1b[RSB_250].sds = file_qkm.sds[RSB_250]; // QKM only
382  l1b[RSB_250].resolution = file_qkm.resolution;
383  }
384 
385  /* Derived values */
386  for (i = 0; i < L1B_NUM_SDS; i++) {
387  l1b[i].nbands =
388  (l1b[i].scandim == 0) ? 1 // Band 26 only
389  : l1b[i].sds.dimlen[0];
390  l1b[i].nsf = 1000 / l1b[i].resolution;
391  l1b[i].ndets = 10 * l1b[i].nsf;
392 
393  /* Load scaling coefficient attribute(s) */
394  TRYMEM(__FILE__, __LINE__,
395  (l1b[i].sds.atts = calloc(L1B_NUM_COEFFS, sizeof (att_struct))));
396  l1b[i].sds.natts = L1B_NUM_COEFFS;
397  for (j = 0; j < L1B_NUM_COEFFS; j++)
398  load_att_byname(l1b[i].sds.id, l1b_coeff[j], &l1b[i].sds.atts[j]);
399  }
400 
401  return status;
402 }
403 
404 /***********************************************************************/
405 
407  int32_t status = FAIL;
408  int32_t i;
409  char result[FILENAME_MAX];
410 
411  /* Open input file */
412  status = ((geofile->id = SDstart(geofile->file, DFACC_RDONLY)) == FAIL);
413  if (status) {
414  fopen_warn(geofile->file, __FILE__, __LINE__);
415  return status;
416  }
417 
418  /*----- Read Global Attributes to determine file type -----*/
419  get_hdfeos_meta(geofile->id, "CoreMetadata.0", "SHORTNAME", result);
420  if ((strcmp(result, "MYD03") == 0) ||
421  (strcmp(result, "MOD03") == 0)) { // GEO
422  } else {
423  fprintf(stderr, "Input file %s has type %s; "
424  "does not contain MODIS geolocation.\n",
425  geofile->file, result);
426  return FAIL;
427  }
428  strcpy(geofile->shortname, result);
429 
430  /*----- Data set info -----*/
431  geofile->n_sds = GEO_NUM_SDS;
432  TRYMEM(__FILE__, __LINE__,
433  (geofile->sds = calloc(GEO_NUM_SDS, sizeof (sds_struct))));
434  for (i = 0; i < GEO_NUM_SDS; i++)
435  init_sds_byname(geofile->id, SDSLIST_GEO[i].name, &(geofile->sds[i]));
436 
437  /*----- Native dimensions -----*/
438  geofile->nlines = geofile->sds[GEO_LAT].dimlen[0];
439  geofile->npixls = geofile->sds[GEO_LAT].dimlen[1];
440 
441  return SUCCESS;
442 }
443 
444 int init_geo(const char filename[FILENAME_MAX]) {
445  int32_t i, j;
446  int32_t status = FAIL;
447 
448  /* Start fresh */
449  memset(&file_geo, 0, sizeof (modis_file));
450 
451  /* Initialize GEO file info */
452  strcpy(file_geo.file, filename);
453  status = open_modis_geofile(&file_geo);
454  if (status) {
455  fprintf(stderr,
456  "Error reading %s; please specify a valid geolocation file.\n",
457  filename);
458  return status;
459  }
460 
461  /* Populate global info for each GEO SDS */
462  for (i = 0; i < GEO_NUM_SDS; i++) {
463  geo[i].sds = file_geo.sds[i];
464  geo[i].resolution = 1000;
465  geo[i].nbands = 1;
466  geo[i].nscans = file_geo.nlines / 10;
467  geo[i].ndets = 10;
468  geo[i].nframes = file_geo.npixls;
469  geo[i].nsf = 1;
470  geo[i].scandim = SDSLIST_GEO[i].scandim;
471 
472  /* Load scaling coefficient attribute(s) */
473  TRYMEM(__FILE__, __LINE__,
474  (geo[i].sds.atts = calloc(GEO_NUM_COEFFS, sizeof (att_struct))));
475  geo[i].sds.natts = GEO_NUM_COEFFS;
476  for (j = 0; j < GEO_NUM_COEFFS; j++)
477  load_att_byname(geo[i].sds.id, geo_coeff[j], &geo[i].sds.atts[j]);
478  }
479 
480  /*----- Read preloaded variables -----*/
481  for (i = 0; i < REF_NUM_SDS; i++) {
482  init_sds_byname(file_geo.id, SDSLIST_REF[i].name, &(ref[i].sds));
483  readall_sds(&(ref[i].sds));
484  }
485 
486  return status;
487 }
488 
489 int read_sds_1scan(sds_struct *sds,
490  int32_t iscan,
491  int32_t scandim,
492  int32_t per_scan) {
493  int32_t i;
494  int32_t status = FAIL;
495  int32_t nvals = 1;
496  int32_t *start, *edges;
497 
498  /* don't bother if SDS handle is invalid */
499  if (sds->id != FAIL) {
500 
501  /* set array indices */
502  TRYMEM(__FILE__, __LINE__,
503  (start = malloc(sds->ndims * sizeof (int32_t))));
504  TRYMEM(__FILE__, __LINE__,
505  (edges = malloc(sds->ndims * sizeof (int32_t))));
506  for (i = 0; i < sds->ndims; i++) {
507  if (i == scandim) {
508  start[i] = iscan * per_scan;
509  edges[i] = per_scan;
510  } else {
511  start[i] = 0;
512  edges[i] = sds->dimlen[i];
513  }
514  nvals *= edges[i];
515  }
516 
517  /* allocate one scan as needed (first call) */
518  if (sds->data == NULL)
519  TRYMEM(__FILE__, __LINE__,
520  (sds->data = malloc(nvals * DFKNTsize(sds->ntype))));
521 
522  /* read data */
523  status = SDreaddata(sds->id, start, NULL, edges, sds->data);
524  free(start);
525  free(edges);
526  }
527  if (status != FAIL)
528  return nvals;
529  else
530  return status;
531 }
532 
533 /***********************************************************************/
534 /* Everything below this line is specific to OCSSW implementation. */
535 /***********************************************************************/
536 #define MIN_BAD_SI 65500
537 #define MAX_ATTERR 0.017453293 /* radians, ~= 1 degree */
538 #define LOOPI for (i = 0; i < nvals; i++)
539 
540 /* Global variables from l1_hmodis_hdf.c */
541 static int32_t spixl = 0; /* first valid pixel of extracted granule */
542 static float *Fobar;
543 
544 /* RSMAS corrections to Terra IR radiances (20,22,23,27,28,29,31,32) */
545 /* latband v6 sst coefficients were estimated from Bt's from which these */
546 /* corrections have been applied, so we have to keep using them. */
547 static float radoff[][10] = {
548  {-0.000972, 0.014200, 0.000022, 0.000238, -0.000003,
549  0.003760, 0.002337, 0.000084, 0.008848, 0.005050},
550  {-0.002300, 0.000600, 0.000236, -0.000280, -0.000003,
551  0.002798, 0.003496, 0.018035, 0.002942, 0.001787},
552  {-0.003833, 0.003657, 0.002118, 0.000798, -0.000003,
553  0.000208, 0.000399, 0.000553, 0.000258, 0.021128},
554  {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
555  {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
556  {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
557  {-0.000423, -0.000242, -0.000330, -0.000065, -0.000001,
558  -0.000006, 0.000064, 0.000398, 0.000362, 0.000322},
559  {-0.000433, -0.000246, -0.000222, -0.000148, -0.000001,
560  0.000068, 0.000221, 0.000221, 0.000437, 0.000303}
561 };
562 static float mfact[] = {0.0, 0.0, 0.0005, 0.0, 0.0, 0.0, 0.0028, 0.00278};
563 
567 typedef struct {
568  int16_t sdsindex;
569  int16_t bandindex;
570  int16_t flagindex;
571  int16_t wavelength;
572  char *bandname;
573 } bandinfo;
574 
575 /* Bands used by l2gen, in expected order */
576 static const bandinfo BANDLIST[] = {
577  /*** Reflective Solar Bands ***/
578  { RSB_1KM, 0, 180, 412, "8"}, // 0
579  { RSB_1KM, 1, 190, 443, "9"}, // 1
580  { RSB_500, 0, 80, 469, "3"}, // 2
581  { RSB_1KM, 2, 200, 488, "10"}, // 3
582  { RSB_1KM, 3, 210, 531, "11"}, // 4
583  { RSB_1KM, 4, 220, 547, "12"}, // 5
584  { RSB_500, 1, 100, 555, "4"}, // 6
585  { RSB_250, 0, 0, 645, "1"}, // 7
586  { RSB_1KM, 5, 230, 667, "13lo"}, // 8
587  { RSB_1KM, 7, 250, 678, "14lo"}, // 9
588  { RSB_1KM, 9, 270, 748, "15"}, // 10
589  { RSB_250, 1, 40, 859, "2"}, // 11
590  { RSB_1KM, 10, 280, 869, "16"}, // 12
591  { RSB_500, 2, 120, 1240, "5"}, // 13
592  { RSB_500, 3, 140, 1640, "6"}, // 14
593  { RSB_500, 4, 160, 2130, "7"}, // 15
594  /*** Thermal Emissive Bands ***/
595  { TEB_1KM, 0, 330, 3750, "20"}, // 16
596  { TEB_1KM, 2, 350, 3959, "22"}, // 17
597  { TEB_1KM, 3, 360, 4050, "23"}, // 18
598  { TEB_1KM, 6, 390, 6715, "27"}, // 19
599  { TEB_1KM, 7, 400, 7325, "28"}, // 20
600  { TEB_1KM, 8, 410, 8550, "29"}, // 21
601  { TEB_1KM, 10, 430, 11000, "31"}, // 22
602  { TEB_1KM, 11, 440, 12000, "32"}, // 23
603  /*** Cirrus Band ***/
604  { CIR_1KM, 0, 320, 1375, "26"} // 24
605 };
606 
607 /***********************************************************************/
608 
614 int openl1_hmodis_hdf(filehandle *l1file) {
615  char geometa[EOSMETALEN] = "";
616  char result[EOSMETALEN] = "";
617  char datetime[32] = "";
618  int32_t resolution;
619  int32_t intval;
620  uint32_t gflags[8];
621 
622  /*----- Initialize L1B and GEO info -----*/
623  if (init_l1b(l1file->name, &l1_input->resolution))
624  exit(EXIT_FAILURE);
625  if (init_geo(l1file->geofile))
626  exit(EXIT_FAILURE);
627 
628  /* Make sure this is not an ocean-band subsetted L1A file */
629  int i;
630  for (i = 0; i < file_1km.n_sds; i++) {
631  if (strcmp(file_1km.sds[i].name, "EV_250_Aggr1km_RefSB") == 0) {
632  if (SDfindattr(file_1km.sds[i].id, "Rescaled Ocean R") != FAIL) {
633  fprintf(stderr, "\n"
634  "This L1B file contains only the ocean band subset.\n"
635  "Processing is no longer supported; exiting.\n");
636  exit(EXIT_FAILURE);
637  }
638  break;
639  }
640  }
641 
642  /*----- Populate filehandle structure -----*/
643  l1file->ndets = l1b[RSB_250].ndets;
644  l1file->nscan = l1b[RSB_250].nscans * l1b[RSB_250].ndets;
645  l1file->npix = l1b[RSB_250].nframes * l1b[RSB_250].nsf;
646 
647  /* Capture processing resolution */
649  if (resolution == 1000)
650  strcpy(l1file->spatialResolution, "1 km");
651  else
652  sprintf(l1file->spatialResolution, "%d m", resolution);
653 
654  if (want_verbose) {
655  printf("Processing at %d meter resolution.\n", resolution);
656  printf(" 1000-meter file: %s\n", file_1km.file);
657  if (resolution < 1000) {
658  printf(" 500-meter file: %s\n", file_hkm.file);
659  if (resolution < 500)
660  printf(" 250-meter file: %s\n", file_qkm.file);
661  }
662  printf("\n");
663  }
664 
665  /*----- Read Level 1B metadata -----*/
666  get_hdfeos_meta(file_1km.id, "CoreMetadata.0", "INPUTPOINTER", result);
667  strcpy(l1_input->calfile, result);
668 
669  /*----- Read Geolocation metadata -----*/
670  if (read_att(file_geo.id, "CoreMetadata.0", geometa)) {
671  fprintf(stderr,
672  "-E- %s line %d: Error reading CoreMetadata.0 from %s.\n",
673  __FILE__, __LINE__, file_geo.file);
674  exit(EXIT_FAILURE);
675  }
676 
677  /* Orbit info */
678  parse_odl(geometa, "ORBITNUMBER", result);
679  if (strlen(result) > 0)
680  l1file->orbit_number = (int32_t) atoi(result);
681  parse_odl(geometa, "EQUATORCROSSINGLONGITUDE", result);
682  if (strlen(result) > 0)
683  l1file->orbit_node_lon = atof(result);
684 
685  parse_odl(geometa, "EQUATORCROSSINGDATE", result);
686  strcpy(datetime, result);
687  strcat(datetime, "T");
688  parse_odl(geometa, "EQUATORCROSSINGTIME", result);
689  strcat(datetime, result);
690  l1file->node_crossing_time = isodate2unix(datetime);
691 
692  /* Granule start time */
693  parse_odl(geometa, "RANGEBEGINNINGDATE", result);
694  strcpy(datetime, result);
695  strcat(datetime, "T");
696  parse_odl(geometa, "RANGEBEGINNINGTIME", result);
697  strcat(datetime, result);
698  file_geo.starttime = isodate2unix(datetime);
699 
700  /* Terrain height */
701  if (read_att(file_geo.id, "Cumulated gflags", gflags))
702  fprintf(stderr, "-W- %s line %d: Error reading gflags from %s.\n",
703  __FILE__, __LINE__, file_geo.file);
704  else
705  l1file->terrain_corrected = (((int32_t*) gflags)[5] == 0);
706 
707  /*** Adjust dimensions for extracted granules ***/
708  /*
709  When Level 1 MODIS granules are extracted, the full scan
710  width is retained but pixels outside the ROI are set to fill
711  value. We must keep track of pixel offset and count in
712  order to load the ROI correctly. Line offset and count are
713  handled in the main() loop.
714  */
715  if (read_att(file_1km.id, "Extract Pixel Count", &intval) == 0
716  && intval > 0) {
717  int32_t sline, nline, npixl;
718  npixl = intval * l1b[RSB_250].nsf;
719  read_att(file_1km.id, "Extract Pixel Offset", &intval);
720  spixl = intval * l1b[RSB_250].nsf;
721  read_att(file_1km.id, "Extract Line Offset", &intval);
722  sline = intval * l1b[RSB_250].ndets;
723  if (want_verbose) {
724  nline = l1file->nscan;
725  fprintf(stdout,
726  "File was generated from L1A extract of size %d x %d\n",
727  npixl, nline);
728  fprintf(stdout, " Pixels %d - %d\n", spixl + 1, spixl + npixl);
729  fprintf(stdout, " Lines %d - %d\n", sline + 1, sline + nline);
730  }
731  l1file->npix = npixl;
732  }
733 
734  /* Read reflectance to radiance conversion factors */
735  rdsensorinfo(l1file->sensorID, l1_input->evalmask, "Fobar", (void **) &Fobar);
736 
737  return SUCCESS;
738 }
739 
740 /***********************************************************************/
741 
744 static struct {
745  int32_t iscan;
746  int32_t nvals;
747  int32_t npix;
748  int32_t nbands;
750  /* read from input files */
751  double taisec;
752  int32_t mside;
753  double angles[3];
754  double mnorm[3];
755  float *lon;
756  float *lat;
757  float *hgt;
758  float *solz;
759  float *sola;
760  float *senz;
761  float *sena;
762  float *allbands;
763 } scan;
764 
770 int alloc_scan(const int32_t nvals) {
771 
772  /* set stack variables */
773  memset(&scan, 0, sizeof (scan));
774  scan.mside = -1;
775  scan.nvals = nvals;
776  scan.npix = nvals / l1b[RSB_250].ndets;
777  scan.nbands = sizeof (BANDLIST) / sizeof (BANDLIST[0]); // works on stack vars only
778 
779  /* allocate memory for dynamic variables */
780  TRYMEM(__FILE__, __LINE__, (scan.lon = malloc(nvals * sizeof (*scan.lon))));
781  TRYMEM(__FILE__, __LINE__, (scan.lat = malloc(nvals * sizeof (*scan.lat))));
782  TRYMEM(__FILE__, __LINE__, (scan.hgt = malloc(nvals * sizeof (*scan.hgt))));
783  TRYMEM(__FILE__, __LINE__, (scan.solz = malloc(nvals * sizeof (*scan.solz))));
784  TRYMEM(__FILE__, __LINE__, (scan.sola = malloc(nvals * sizeof (*scan.sola))));
785  TRYMEM(__FILE__, __LINE__, (scan.senz = malloc(nvals * sizeof (*scan.senz))));
786  TRYMEM(__FILE__, __LINE__, (scan.sena = malloc(nvals * sizeof (*scan.sena))));
787  TRYMEM(__FILE__, __LINE__,
788  (scan.allbands = malloc(scan.nbands * nvals * sizeof (*scan.allbands))));
789 
790  return SUCCESS;
791 }
792 
793 /***********************************************************************/
794 
795 typedef struct {
796  int16_t nrad;
797  int16_t nsf;
798  double *SI_val;
799  double *corr;
800 } sfcorr_table;
801 
802 void read_sfcorrtables(sfcorr_table *sfcorr, int32_t sensorID) {
803  char *dataroot;
804  char file[FILENAME_MAX] = "";
805  char sensorName[32];
806  FILE *fp = NULL;
807  char line[81];
808  int32_t iband, isf, nsf, irad, nrad;
809  size_t isds, ical;
810  att_struct *atts;
811  double scale, offset;
812  double radiance, SI, radiance2, SI2, rad_corr[4];
813 
814  /* calibration directory path */
815  if ((dataroot = getenv("OCDATAROOT")) == NULL) {
816  printf("OCDATAROOT environment variable is not defined.\n");
817  exit(1);
818  }
819 
820  /* for each band, */
821  /* get max possible subframes */
822  if (want_verbose)
823  printf("\nLoading subframe correction tables:\n");
824  for (iband = 0; iband < scan.nbands; iband++) {
825  nrad = 0;
826  isds = BANDLIST[iband].sdsindex;
827  if (isds == RSB_250)
828  nsf = 4;
829  else if (isds == RSB_500)
830  nsf = 2;
831  else
832  nsf = 1;
833 
834  /* if a hi-res band, */
835  if (nsf > 1) {
836 
837  /* get radiance factors */
838  atts = l1b[isds].sds.atts;
839  ical = BANDLIST[iband].bandindex;
840  scale = (double) ((float*) atts[RAD_SCALE].data)[ical];
841  offset = (double) ((float*) atts[RAD_OFFSET].data)[ical];
842 
843  strcpy(sensorName, sensorId2SensorName(sensorID));
844  lowcase(sensorName);
845 
846  /* open subframe correction file */
847  sprintf(file, "%s/%s/%s/cal/subframecor_%s_%d.dat",
848  dataroot,
851  sensorName,
852  BANDLIST[iband].wavelength);
853  if (want_verbose)
854  printf(" %s\n", file);
855  if ((fp = fopen(file, "r")) == NULL) {
856  fprintf(stderr,
857  "-E- %s line %d: unable to open %s for reading\n",
858  __FILE__, __LINE__, file);
859  exit(1);
860  }
861 
862  /* find number of radiance levels and allocate space */
863  while (fgets(line, 80, fp))
864  if (strncmp(line, "Number of radiance levels", 25) == 0) {
865  sscanf(line, "Number of radiance levels: %d", &nrad);
866  TRYMEM(__FILE__, __LINE__,
867  (sfcorr[iband].SI_val =
868  malloc(nrad * sizeof (*sfcorr[iband].SI_val))));
869  TRYMEM(__FILE__, __LINE__,
870  (sfcorr[iband].corr =
871  malloc(nrad * 4 * sizeof (*sfcorr[iband].corr))));
872  break;
873  }
874  while (fgets(line, 80, fp)) /* skip over rest of header */
875  if (strncmp(line, "/end_header", 11) == 0)
876  break;
877 
878  /* read radiances and correction factors */
879  for (irad = 0; irad < nrad; irad++) {
880  if (fgets(line, 80, fp) == NULL) {
881  fprintf(stderr,
882  "-E- %s line %d: File %s contains only %d data records\n",
883  __FILE__, __LINE__, file, irad);
884  exit(1);
885  }
886  sscanf(line, "%lf %lf %lf %lf %lf", &radiance,
887  &rad_corr[0], &rad_corr[1], &rad_corr[2], &rad_corr[3]);
888 
889  /* Scale reference radiances and corrections to SI
890  space so we don't have to scale each pixel later.
891  Also invert factor so we later multiply instead of
892  divide.
893  */
894  SI = radiance / scale + offset;
895  sfcorr[iband].SI_val[irad] = SI;
896  for (isf = 0; isf < 4; isf++) {
897  radiance2 = radiance / rad_corr[isf];
898  SI2 = radiance2 / scale + offset;
899  sfcorr[iband].corr[4 * irad + isf] = SI2 / SI;
900  }
901 
902  }
903  fclose(fp);
904 
905  } // hi-res band
906  sfcorr[iband].nrad = nrad;
907  sfcorr[iband].nsf = nsf;
908 
909  } // iband
910 
911  if (want_verbose)
912  printf("Subframe destriping corrections enabled.\n\n");
913 }
914 
915 void subframe_correction(const int32_t sensorID,
916  const int32_t iband,
917  const modis_sds mds,
918  double *data) {
919  /* Applies subframe destriping to an entire full-width scan at once,
920  so we don't need to correct for any extract offset. */
921  sfcorr_table lut;
922  int32_t i;
923  int32_t idet, iframe, isf, ip;
924  double x; // input value (scaled radiance)
925  double y; // interpolated subframe correction
926 
927  static sfcorr_table *sfcorr = NULL;
928 
929  /* Initialize subframe correction tables */
930  if (sfcorr == NULL) {
931  TRYMEM(__FILE__, __LINE__,
932  (sfcorr = malloc(scan.nbands * sizeof (*sfcorr))));
933  read_sfcorrtables(sfcorr, sensorID);
934  }
935  lut = sfcorr[iband];
936 
937  /* Destripe hi-res bands at native resolution only */
938  if ((lut.nsf > 1) && (lut.nrad > 0) && (lut.nsf == mds.nsf)) {
939  for (idet = 0; idet < mds.ndets; idet++)
940  for (iframe = 0; iframe < mds.nframes; iframe++)
941  for (isf = 0; isf < mds.nsf; isf++) {
942  ip = (idet * mds.nframes + iframe) * mds.nsf + isf;
943 
944  if (data[ip] < MIN_BAD_SI) {
945  x = data[ip];
946 
947  /* find closest lookup table indices */
948  /* TO DO: implement more efficient lookup */
949  for (i = 0; i < lut.nrad - 1; i++) {
950  if (x < lut.SI_val[i])
951  break;
952  }
953 
954  /* use end value if out-of-bounds */
955  if (i == 0 || i == (lut.nrad - 1))
956  y = lut.corr[4 * i + isf];
957 
958  /* otherwise, interpolate between two closest values */
959  else {
960  double x0 = lut.SI_val[i - 1];
961  double x1 = lut.SI_val[i];
962  double y0 = lut.corr[4 * (i - 1) + isf];
963  double y1 = lut.corr[4 * i + isf];
964  y = y0 + (x - x0) * (y1 - y0) / (x1 - x0);
965  }
966 
967  /* Apply the destriping correction */
968  data[ip] *= (float) y;
969  }
970  } // isf, iframe, idet loops
971  } // eligible band
972 }
973 
974 /***********************************************************************/
975 
976 typedef struct {
977  int32_t ndets;
978  int32_t *prev;
979  int32_t *next;
980 } fill_table;
981 
983  int32_t ndets; // number of detectors
984  int32_t isds, iband, idet, i0, x0, x1;
985  char dead[EOSMETALEN] = "";
986 
987  /* Read "Dead Detector List" global attribute */
988  if (read_att(file_1km.id, "Dead Detector List", dead)) {
989  fprintf(stderr,
990  "-E- %s line %d: Error reading \"Dead Detector List\" from %s.\n",
991  __FILE__, __LINE__, file_1km.file);
992  exit(EXIT_FAILURE);
993  }
994 
995  /* Load values into dead detector table */
996  for (iband = 0; iband < scan.nbands; iband++) {
997  i0 = BANDLIST[iband].flagindex;
998 
999  /* Find number of detectors at native resolution */
1000  isds = BANDLIST[iband].sdsindex;
1001  if (isds == RSB_250)
1002  ndets = 40;
1003  else if (isds == RSB_500)
1004  ndets = 20;
1005  else
1006  ndets = 10;
1007  fill[iband].ndets = ndets;
1008 
1009  /* Allocate space for arrays */
1010  TRYMEM(__FILE__, __LINE__,
1011  (fill[iband].prev = malloc(ndets * sizeof (*fill->prev))));
1012  TRYMEM(__FILE__, __LINE__,
1013  (fill[iband].next = malloc(ndets * sizeof (*fill->next))));
1014 
1015  /* Find previous and next good detectors */
1016  /*
1017  These arrays hold indices for the nearest previous and next
1018  valid detector for each detector. Since detector arrays are
1019  small, opt for code clarity over efficiency.
1020 
1021  Special values:
1022  prev=idet=next: detector is alive
1023  prev = -1 : no previous good detector
1024  next = ndets: no next good detector
1025  */
1026  for (idet = 0; idet < ndets; idet++) {
1027  x0 = idet; // previous
1028  while ((x0 > -1) && dead[i0 + x0]) x0--;
1029  fill[iband].prev[idet] = x0;
1030  x1 = idet; // next
1031  while ((x1 < ndets) && dead[i0 + x1]) x1++;
1032  fill[iband].next[idet] = x1;
1033  }
1034 
1035  } // iband loop
1036 }
1037 
1038 void fill_dead_detectors(const int32_t iband, const modis_sds mds, double *data) {
1039 
1040  int32_t idet, ndets, ipix, npix;
1041  size_t nbytes; // bytes per line (detector)
1042 
1043  int32_t *prev, *next; // previous and next valid detector for each det
1044  int32_t x, x0, x1; // index into data array for current, prev, next det
1045  double y0, y1; // previous and next valid value for current detector
1046  double dx, dy; // change in det, value over valid interval
1047 
1048  static fill_table *fill = NULL;
1049 
1050  /* Initialize previous and next valid detector array table */
1051  if (fill == NULL) {
1052  TRYMEM(__FILE__, __LINE__, (fill = malloc(scan.nbands * sizeof (*fill))));
1053  init_detfill(fill);
1054  }
1055 
1056  /* Fill dead detectors at native resolution only */
1057  ndets = fill[iband].ndets;
1058  if (ndets == mds.ndets) {
1059 
1060  prev = fill[iband].prev;
1061  next = fill[iband].next;
1062  npix = mds.nframes * mds.nsf; // # values per line (detector)
1063  nbytes = npix * sizeof (*data);
1064 
1065  /* Substitute data values as appropriate for each detector: */
1066  for (idet = 0; idet < ndets; idet++) {
1067  if (prev[idet] != next[idet]) { // continue for bad dets only
1068 
1069  /* Between two good detectors: interpolate */
1070  if ((prev[idet] > -1) && (next[idet] < ndets)) {
1071  dx = next[idet] - prev[idet];
1072 
1073  for (ipix = 0; ipix < npix; ipix++) {
1074  x = idet * npix + ipix;
1075  x0 = prev[idet] * npix + ipix;
1076  x1 = next[idet] * npix + ipix;
1077  y0 = data[x0];
1078  y1 = data[x1];
1079 
1080  /* if both values are valid, interpolate */
1081  if ((y0 < MIN_BAD_SI) && (y1 < MIN_BAD_SI)) {
1082  dy = y1 - y0;
1083  data[x] = y0 + (idet - prev[idet]) * (dy / dx);
1084  }
1085  /* otherwise copy adjacent valid value */
1086  else if (y0 < MIN_BAD_SI) data[x] = data[x0];
1087  else if (y1 < MIN_BAD_SI) data[x] = data[x1];
1088 
1089  /* if none, copy maximum adjacent flag */
1090  else
1091  data[x] = MAX(data[x0], data[x1]);
1092  }
1093  }
1094  /* No previous good detector: copy next value or flag */
1095  else if ((prev[idet] == -1) && (next[idet] < ndets))
1096  memcpy(&data[idet * npix], &data[next[idet] * npix], nbytes);
1097 
1098  /* No next good detector: copy previous value or flag */
1099  else if ((prev[idet] > -1) && (next[idet] == ndets))
1100  memcpy(&data[idet * npix], &data[prev[idet] * npix], nbytes);
1101 
1102  /* Default case: no good detectors = no change. */
1103 
1104  } // dead detector
1105  } // idet loop
1106  } // band is at native resolution
1107 }
1108 
1109 /***********************************************************************/
1110 
1111 double interp_bilin(double val[4], double dx, double dy) {
1112  return (1 - dy) * (val[0] * (1 - dx) + val[1] * dx)
1113  + dy * (val[2] * (1 - dx) + val[3] * dx);
1114 }
1115 
1116 double interp_modis_EVdata(double val[4], double dx, double dy) {
1117  int32_t i, ngood = 0;
1118  double sum_val = 0;
1119  double max_val = 0;
1120  double result;
1121 
1122  /* interpolation: account for flagged values */
1123  for (i = 0; i < 4; i++) {
1124  if (val[i] < MIN_BAD_SI) {
1125  sum_val = sum_val + val[i];
1126  ngood++;
1127  }
1128  if (val[i] > max_val)
1129  max_val = val[i];
1130  }
1131 
1132  /* If we have four non-flagged samples, bilinearly interpolate. */
1133  /* If all samples are flagged, set to the max flag value. */
1134  /* If we have 1-3 samples, use average of unflagged values. */
1135  switch (ngood) {
1136  case 4:
1137  result = interp_bilin(val, dx, dy);
1138  break;
1139  case 0:
1140  result = max_val;
1141  break;
1142  default:
1143  /* TO DO: should be WEIGHTED avg of good values */
1144  result = sum_val / ngood;
1145  break;
1146  }
1147  return result;
1148 }
1149 
1150 double interp_modis_Longitude(double val[4], double dx, double dy) {
1151  int32_t i;
1152  double min_val, max_val;
1153 
1154  /* longitude interpolation: account for dateline */
1155  min_val = max_val = val[0];
1156  for (i = 1; i < 4; i++) {
1157  if (val[i] < min_val)
1158  min_val = val[i];
1159  else if (val[i] > max_val)
1160  max_val = val[i];
1161  }
1162  if (max_val > 180.0 + min_val) {
1163  for (i = 0; i < 4; i++) {
1164  if (val[i] < 0.0)
1165  val[i] += 360.0;
1166  }
1167  }
1168  return interp_bilin(val, dx, dy);
1169 }
1170 
1171 double (*interp_modis_var)(double val[4], double dx, double dy);
1172 
1174  const int32_t sdsband,
1175  const int32_t newres,
1176  double *olddata,
1177  double *newdata) {
1178 
1179  int32_t ny = s.ndets;
1180  int32_t nx = s.nframes * s.nsf;
1181  int32_t nvals = ny * nx;
1182  int32_t oldres = s.resolution;
1183 
1184  int32_t nxnew, nynew;
1185  int32_t ixnew, iynew;
1186 
1187  int32_t x0, y0, x1, y1; // 4 points in old array
1188  double fx, fy;
1189  double dx, dy;
1190  double val[4];
1191  int32_t i;
1192  double factor, xoffset, yoffset;
1193  int32_t maxi = 2; /* 1 duplicates end pixel; 2 extrapolates past end */
1194 
1195  int32_t sdsoffset = nvals * sdsband; // offset within SDS
1196  short alloc_old;
1197 
1198  /* Cast input data to double precision */
1199  alloc_old = (olddata == NULL);
1200  if (alloc_old) {
1201  TRYMEM(__FILE__, __LINE__, (olddata = malloc(nvals * sizeof (*olddata))));
1202 
1203  switch (s.sds.ntype) {
1204  case DFNT_FLOAT32:
1205  LOOPI olddata[i] = (double) ((float*) s.sds.data)[sdsoffset + i];
1206  break;
1207  case DFNT_INT16:
1208  LOOPI olddata[i] = (double) ((int16_t*) s.sds.data)[sdsoffset + i];
1209  break;
1210  case DFNT_UINT16:
1211  LOOPI olddata[i] = (double) ((uint16_t*) s.sds.data)[sdsoffset + i];
1212  break;
1213  default:
1214  fprintf(stderr,
1215  "-E- %s line %d: Cannot interpolate type code: %d\n",
1216  __FILE__, __LINE__, s.sds.ntype);
1217  exit(EXIT_FAILURE);
1218  break;
1219  }
1220  } // alloc_old
1221 
1222  /* Set interp function pointer according to SDS */
1223  if (strncmp(s.sds.name, "EV_", 3) == 0)
1225  else if (strcmp(s.sds.name, "Longitude") == 0)
1227  else
1229 
1230  /* Calculate offset between different pixel resolutions */
1231  factor = (double) newres / (double) oldres;
1232  xoffset = 0; // frame centers are aligned
1233  yoffset = 0.5 * (1.0 - factor); // detector edges are aligned
1234  /* yoffset = 0; // for testing only */
1235 
1236  /* Size of new array */
1237  nxnew = nx * oldres / newres;
1238  nynew = ny * oldres / newres;
1239 
1240  /* Calculate index into original data */
1241  for (iynew = 0; iynew < nynew; iynew++) {
1242  fy = factor * iynew - yoffset;
1243  y0 = MIN(MAX((int32_t) floor(fy), 0), ny - maxi);
1244  y1 = MIN(y0 + 1, ny - 1);
1245  dy = fy - (double) y0;
1246 
1247  for (ixnew = 0; ixnew < nxnew; ixnew++) {
1248  fx = factor * ixnew - xoffset;
1249  x0 = MIN(MAX((int32_t) floor(fx), 0), nx - maxi);
1250  x1 = MIN(x0 + 1, nx - 1);
1251  dx = fx - (double) x0;
1252 
1253  /* Do bilinear interpolation */
1254  val[0] = olddata[nx * y0 + x0];
1255  val[1] = olddata[nx * y0 + x1];
1256  val[2] = olddata[nx * y1 + x0];
1257  val[3] = olddata[nx * y1 + x1];
1258  newdata[nxnew * iynew + ixnew] = interp_modis_var(val, dx, dy);
1259  }
1260  }
1261 
1262  if (alloc_old)
1263  free(olddata);
1264 
1265  return SUCCESS;
1266 }
1267 
1268 /***********************************************************************/
1269 
1275 int load_modis_scan(const int32_t iscan,
1276  const int32_t resolution,
1277  int32_t sensorID) {
1278  modis_sds s;
1279  int32_t isds, iband;
1280  int32_t i, i1, i2, nold;
1281  static int32_t nvals = 0; /* pixels per variable at output resolution */
1282  double *olddata = NULL; /* at native resolution */
1283  double *newdata = NULL; /* at output resolution */
1284 
1285  /* Allocate space to hold all data for one scan */
1286  if (nvals == 0) {
1287  nvals = l1b[RSB_250].ndets * l1b[RSB_250].nframes * l1b[RSB_250].nsf;
1288  alloc_scan(nvals);
1289  }
1290 
1291  /* Allocate space to hold interpolation buffer for one variable */
1292  TRYMEM(__FILE__, __LINE__, (newdata = malloc(nvals * sizeof (*newdata))));
1293 
1294  /* ----- Geolocation values ----- */
1295  for (isds = 0; isds < GEO_NUM_SDS; isds++)
1296  read_sds_1scan(&geo[isds].sds,
1297  iscan,
1298  geo[isds].scandim,
1299  geo[isds].ndets);
1300 
1301  if (geo[GEO_LON].resolution == resolution) { /* native resolution */
1302  /* memcpy works only when src and dst have same data type */
1303  memcpy(scan.lon, geo[GEO_LON].sds.data, nvals * sizeof (float));
1304  memcpy(scan.lat, geo[GEO_LAT].sds.data, nvals * sizeof (float));
1305 
1306  /* must copy each element when datatypes differ */
1307  LOOPI{
1308  scan.hgt[i] = (float) ((int16_t *) geo[GEO_HGT].sds.data)[i];
1309  scan.solz[i] = (float) ((int16_t *) geo[GEO_SOLZ].sds.data)[i] * 0.01;
1310  scan.sola[i] = (float) ((int16_t *) geo[GEO_SOLA].sds.data)[i] * 0.01;
1311  scan.senz[i] = (float) ((int16_t *) geo[GEO_SENZ].sds.data)[i] * 0.01;
1312  scan.sena[i] = (float) ((int16_t *) geo[GEO_SENA].sds.data)[i] * 0.01;}
1313 
1314  } else { /* must interpolate */
1315  modis_interp(geo[GEO_LON], 0, resolution, NULL, newdata);
1316  LOOPI scan.lon[i] = (float) newdata[i];
1317  modis_interp(geo[GEO_LAT], 0, resolution, NULL, newdata);
1318  LOOPI scan.lat[i] = (float) newdata[i];
1319  modis_interp(geo[GEO_HGT], 0, resolution, NULL, newdata);
1320  LOOPI scan.hgt[i] = (float) newdata[i];
1321  modis_interp(geo[GEO_SOLZ], 0, resolution, NULL, newdata);
1322  LOOPI scan.solz[i] = (float) newdata[i] * 0.01;
1323  modis_interp(geo[GEO_SOLA], 0, resolution, NULL, newdata);
1324  LOOPI scan.sola[i] = (float) newdata[i] * 0.01;
1325  modis_interp(geo[GEO_SENZ], 0, resolution, NULL, newdata);
1326  LOOPI scan.senz[i] = (float) newdata[i] * 0.01;
1327  modis_interp(geo[GEO_SENA], 0, resolution, NULL, newdata);
1328  LOOPI scan.sena[i] = (float) newdata[i] * 0.01;
1329  }
1330 
1331  /* ----- Radiometric values ----- */
1332  for (isds = 0; isds < L1B_NUM_SDS; isds++)
1333  read_sds_1scan(&l1b[isds].sds,
1334  iscan,
1335  l1b[isds].scandim,
1336  l1b[isds].ndets);
1337 
1338  for (iband = 0; iband < scan.nbands; iband++) {
1339  s = l1b[BANDLIST[iband].sdsindex];
1340  nold = s.ndets * s.nframes * s.nsf;
1341  i1 = nold * BANDLIST[iband].bandindex; // offset within SDS
1342  i2 = nvals * iband; // offset within scan.allbands
1343 
1344  /* Cast SI values to double precision, in native spatial resolution */
1345  TRYMEM(__FILE__, __LINE__, (olddata = malloc(nold * sizeof (*olddata))));
1346  for (i = 0; i < nold; i++)
1347  olddata[i] = (double) ((uint16_t*) s.sds.data)[i1 + i];
1348 
1349  /* Apply subframe correction to destripe BEFORE interpolation */
1350  if ((sensorID == MODISA) && (resolution < 1000))
1351  subframe_correction(sensorID, iband, s, olddata);
1352 
1353  /* Fill any dead detectors with neighboring values */
1354  fill_dead_detectors(iband, s, olddata);
1355 
1356  /* Interpolate to higher resolution, as needed */
1357  if (s.resolution != resolution) {
1358  modis_interp(l1b[BANDLIST[iband].sdsindex],
1359  BANDLIST[iband].bandindex,
1360  resolution, olddata, newdata);
1361 
1362  /* Copy adjusted data into scan structure */
1363  LOOPI scan.allbands[i2++] = (float) newdata[i]; // interpolated
1364  } else
1365  LOOPI scan.allbands[i2++] = (float) olddata[i]; // native resolution
1366 
1367  free(olddata);
1368  }
1369 
1370  /* ----- Store preloaded values for later ----- */
1371  scan.iscan = iscan;
1372  scan.taisec = ((double*) ref[GEO_TAISEC].sds.data)[iscan];
1373  scan.mside = (int32_t) ((int16_t*) ref[GEO_MSIDE].sds.data)[iscan];
1374  for (i = 0; i < 3; i++) {
1375  scan.angles[i] = ((double*) ref[GEO_ANGLES].sds.data)[3 * iscan + i];
1376  scan.mnorm[i] = ((double*) ref[GEO_MNORM].sds.data)[3 * (3 * iscan + i)];
1377  }
1378  free(newdata);
1379  return SUCCESS;
1380 }
1381 
1388 int set_l1rec_scanvals(const int32_t iscan, l1str *l1rec) {
1389  double esdist;
1390  static double lastTAIsec = -1;
1391  int16_t badatt, badmside;
1392  double TAIsec, dsec;
1393  int16_t year, day;
1394  int32_t i;
1395 
1396  /* Mirror Side */
1397  l1rec->mside = scan.mside;
1398  badmside = (l1rec->mside < 0);
1399  if (badmside) /* Fix mirror side if set to -1 */
1400  l1rec->mside = 0;
1401 
1402  /* Check for non-nominal roll, pitch, or yaw */
1403  badatt =
1404  (fabs(scan.angles[0]) > MAX_ATTERR) ||
1405  (fabs(scan.angles[1]) > MAX_ATTERR) ||
1406  (fabs(scan.angles[2]) > MAX_ATTERR);
1407 
1408  /* Flag each pixel of scan for geolocation errors */
1409  for (i = 0; i < l1rec->npix; i++) {
1410  l1rec->pixnum[i] = spixl + i;
1411  l1rec->navfail[i] = badmside;
1412  l1rec->navwarn[i] = badatt;
1413  }
1414 
1415  /* Scan Start Time */
1416  TAIsec = scan.taisec;
1417  if (TAIsec < 0) { /* Workaround for scan time errors */
1418  fprintf(stderr, "-W- %s: Bad time for scan %d; ", __FILE__, iscan);
1419  if (iscan == 0) {
1420  fprintf(stderr, "using granule start time.\n");
1421  TAIsec = unix_to_tai93(file_geo.starttime);
1422  } else {
1423  fprintf(stderr, "extrapolating from last good scan.\n");
1424  TAIsec = lastTAIsec + SCAN_TIME_INTERVAL;
1425  }
1426  }
1427  l1rec->scantime = tai93_to_unix(TAIsec);
1428  lastTAIsec = TAIsec;
1429 
1430  /* Earth-sun distance correction for this scan */
1431  unix2yds(l1rec->scantime, &year, &day, &dsec);
1432  int32_t msec = (int32_t) (dsec * 1000.0);
1433  int32_t yr = (int32_t) year;
1434  int32_t dy = (int32_t) day;
1435  esdist = esdist_(&yr, &dy, &msec);
1436  l1rec->fsol = pow(1.0 / esdist, 2);
1437 
1438  return SUCCESS;
1439 }
1440 
1448 int readl1_hmodis_hdf(filehandle *l1file,
1449  const int32_t line,
1450  l1str *l1rec) {
1451  static int32_t prev_scan = -1;
1452  int32_t iband, iscan, idet, ndets;
1453  size_t ip, ipb;
1454  size_t detoffset, dataptr;
1455  size_t nbytes;
1456  size_t irsb, iteb, ical;
1457  att_struct *atts;
1458  float scale, offset, SI_val, value;
1459 
1460  /* Scan and detector numbers for this line */
1461  ndets = l1b[RSB_250].ndets;
1462  iscan = line / ndets;
1463  idet = line % ndets;
1464 
1465  /* Load all values for next scan as needed */
1466  if (iscan != prev_scan) {
1467  prev_scan = iscan;
1468  load_modis_scan(iscan, l1_input->resolution, l1file->sensorID);
1469  }
1470 
1471  /* The l1rec structure is reinitialized */
1472  /* each line, so always reload basic info. */
1473  l1rec->npix = l1file->npix;
1474  l1rec->detnum = (int32_t) idet;
1476  unix_to_tai93(file_geo.starttime);
1477 
1478  /* "scan" structure data pointer offset due */
1479  /* to line number and extract start pixel */
1480  detoffset = idet * scan.npix + spixl;
1481 
1482  /* ----- Geolocation values ----- */
1483  nbytes = l1rec->npix * sizeof (float);
1484  memcpy(l1rec->lon, &scan.lon[detoffset], nbytes);
1485  memcpy(l1rec->lat, &scan.lat[detoffset], nbytes);
1486  memcpy(l1rec->height, &scan.hgt[detoffset], nbytes);
1487  memcpy(l1rec->solz, &scan.solz[detoffset], nbytes);
1488  memcpy(l1rec->sola, &scan.sola[detoffset], nbytes);
1489  memcpy(l1rec->senz, &scan.senz[detoffset], nbytes);
1490  memcpy(l1rec->sena, &scan.sena[detoffset], nbytes);
1491 
1492  /* Don't need to check for navigation errors
1493  - it's done by readl1() */
1494 
1495  /* Compute polarization frame rotation angles */
1496  compute_alpha(l1rec->lon, l1rec->lat,
1497  l1rec->senz, l1rec->sena,
1498  scan.mnorm, l1rec->npix, l1rec->alpha);
1499 
1500  /* ----- Radiometric values ----- */
1501  irsb = iteb = 0;
1502  for (iband = 0; iband < scan.nbands; iband++) {
1503 
1504  /* calibration info */
1505  atts = l1b[BANDLIST[iband].sdsindex].sds.atts;
1506  ical = BANDLIST[iband].bandindex;
1507 
1508  /* offset within scan.allbands */
1509  dataptr = iband * scan.nvals + detoffset;
1510 
1511  /*** Thermal Emissive Bands ***/
1512  if (BANDLIST[iband].sdsindex == TEB_1KM) {
1513  scale = ((float*) atts[RAD_SCALE].data)[ical];
1514  offset = ((float*) atts[RAD_OFFSET].data)[ical];
1515 
1516  for (ip = 0; ip < l1rec->npix; ip++) {
1517  value = 0.0; /* init to fill value */
1518 
1519  /* Apply calibration for valid values */
1520  SI_val = scan.allbands[dataptr + ip];
1521  if (SI_val < MIN_BAD_SI) {
1522 
1523  /* Convert radiance from Watts/m^2/micrometer/steradian */
1524  /* to mW/cm2/um/sr, as expected by l2gen */
1525  value = (SI_val - offset) * scale / 10.0;
1526 
1527  /* Terra adjustments */
1528  if (l1rec->l1file->sensorID == MODIST) {
1529  value *= (1.0 - radoff[iteb][idet / (ndets / 10)]);
1530  if (l1rec->mside == 1)
1531  value *= (1.0 + mfact[iteb]);
1532  } /* Aqua adjustments */
1533  else {
1534  /* channel 22 detector balancing */
1535  if (ical == 1)
1536  value /= l1_input->ch22detcor[line % 10];
1537  /* channel 23 detector balancing */
1538  if (ical == 2)
1539  value /= l1_input->ch23detcor[line % 10];
1540  }
1541  }
1542 
1543  /* populate l1rec->Ltir */
1544  ipb = ip * l1rec->l1file->nbandsir + iteb; /* band varies fastest */
1545  l1rec->Ltir[ipb] = value;
1546 
1547  } // ip
1548  iteb++;
1549  }// TEB
1550 
1551  /*** Cirrus Band ***/
1552  else if (BANDLIST[iband].sdsindex == CIR_1KM) {
1553  scale = ((float*) atts[REFL_SCALE].data)[ical];
1554  offset = ((float*) atts[REFL_OFFSET].data)[ical];
1555 
1556  for (ip = 0; ip < l1rec->npix; ip++) {
1557  value = BAD_FLT; /* init to fill value */
1558 
1559  /* Apply calibration for valid values */
1560  SI_val = scan.allbands[dataptr + ip];
1561  if (SI_val < MIN_BAD_SI)
1562 
1563  /* Normalize reflectance by solar zenith angle */
1564  value = (SI_val - offset) * scale
1565  / cos(l1rec->solz[ip] / RADEG);
1566 
1567  /* populate l1rec->rho_cirrus */
1568  l1rec->rho_cirrus[ip] = value;
1569 
1570  } // ip
1571  }// CIR
1572 
1573  /*** Reflective Solar Bands ***/
1574  else {
1575  l1rec->Fo[irsb] = Fobar[irsb] * l1rec->fsol;
1576  scale = ((float*) atts[REFL_SCALE].data)[ical];
1577  offset = ((float*) atts[REFL_OFFSET].data)[ical];
1578 
1579  for (ip = 0; ip < l1rec->npix; ip++) {
1580  value = BAD_FLT; /* init to fill value */
1581 
1582  /* skip night data for visible bands */
1583  if (SOLZNIGHT < l1rec->solz[ip])
1584  continue;
1585 
1586  /* Apply calibration for valid values */
1587  SI_val = scan.allbands[dataptr + ip];
1588  if (SI_val < MIN_BAD_SI)
1589 
1590  /* Convert from reflectance to radiance */
1591  value = (SI_val - offset) * scale * l1rec->Fo[irsb] / PI;
1592 
1593  /* Flag any sentinel values */
1594  else
1595  switch ((int32_t) SI_val) {
1596  case 65527: /* not in earth view: SECTOR_ROTATION_SI */
1597  l1rec->navfail[ip] = 1;
1598  break;
1599  case 65529: /* saturation: TEB_OR_RSB_GT_MAX_SI */
1600  case 65533: /* saturation: SATURATED_DETECTOR_SI */
1601  value = 1000.0;
1602  if (irsb < 13)
1603  l1rec->hilt[ip] = 1;
1604  break;
1605  default: /* all others */
1606  break;
1607  }
1608 
1609  /* populate l1rec->Lt */
1610  ipb = ip * l1rec->l1file->nbands + irsb; /* band varies fastest */
1611  l1rec->Lt[ipb] = value;
1612 
1613  } // ip
1614  irsb++;
1615  } // RSB
1616 
1617  } // iband
1618 
1619  /* Convert IR bands to brightness temperature */
1620  radiance2bt(l1rec, l1_input->resolution);
1621 
1622  return SUCCESS;
1623 }
1624 
1625 /***********************************************************************/
1626 
1632  int32_t i;
1633 
1634  /* Free memory allocated for global variables */
1635  for (i = 0; i < REF_NUM_SDS; i++)
1636  free_sds(&(ref[i].sds));
1637  for (i = 0; i < GEO_NUM_SDS; i++)
1638  free_sds(&(geo[i].sds));
1639  for (i = 0; i < L1B_NUM_SDS; i++)
1640  free_sds(&(l1b[i].sds));
1641 
1642  /* Free any memory allocated for input files */
1643  if (file_geo.sds) {
1644  for (i = 0; i < file_geo.n_sds; i++)
1645  free_sds(&(file_geo.sds[i]));
1646  free(file_geo.sds);
1647  }
1648  if (file_1km.sds) {
1649  for (i = 0; i < file_1km.n_sds; i++)
1650  free_sds(&(file_1km.sds[i]));
1651  free(file_1km.sds);
1652  }
1653  if (file_hkm.sds) {
1654  for (i = 0; i < file_hkm.n_sds; i++)
1655  free_sds(&(file_hkm.sds[i]));
1656  free(file_hkm.sds);
1657  }
1658  if (file_qkm.sds) {
1659  for (i = 0; i < file_qkm.n_sds; i++)
1660  free_sds(&(file_qkm.sds[i]));
1661  free(file_qkm.sds);
1662  }
1663 
1664  /* End HDF access */
1665  if (file_geo.id) SDend(file_geo.id);
1666  if (file_1km.id) SDend(file_1km.id);
1667  if (file_hkm.id) SDend(file_hkm.id);
1668  if (file_qkm.id) SDend(file_qkm.id);
1669  file_geo.id = file_1km.id = file_hkm.id = file_qkm.id = 0;
1670 
1671  /* TO DO: free scan structure */
1672 
1673  return SUCCESS;
1674 }
1675 
1676 /***********************************************************************/
1677 
1678 int readl1_lonlat_hmodis_hdf(filehandle *l1file, int32_t line, l1str *l1rec) {
1679  static float *lonscan = NULL; /* storage buffer arrays */
1680  static float *latscan = NULL; /* (at output resolution) */
1681 
1682  int32_t ndets = l1b[RSB_250].ndets; /* output resolution dimensions*/
1683  int32_t npixl = l1b[RSB_250].nframes * l1b[RSB_250].nsf;
1684  int32_t nvals = ndets * npixl;
1685  int32_t resolution = l1_input->resolution;
1686 
1687  double *newdata = NULL; /* interpolation buffer */
1688  static int32_t prev_scan = -1;
1689  int32_t i, iscan, idet;
1690  size_t detoffset, nbytes;
1691 
1692  /* Allocate space to hold lon/lat data for one scan at output resolution */
1693  if (lonscan == NULL) {
1694  TRYMEM(__FILE__, __LINE__, (lonscan = malloc(nvals * sizeof (*lonscan))));
1695  TRYMEM(__FILE__, __LINE__, (latscan = malloc(nvals * sizeof (*latscan))));
1696  }
1697 
1698  /* Scan and detector indices for this line */
1699  iscan = line / ndets;
1700  idet = line % ndets;
1701 
1702  /* Load next scan as needed */
1703  if (iscan != prev_scan) {
1704  prev_scan = iscan;
1705 
1706  /* Read values */
1707  read_sds_1scan(&geo[GEO_LON].sds,
1708  iscan,
1709  geo[GEO_LON].scandim,
1710  geo[GEO_LON].ndets);
1711  read_sds_1scan(&geo[GEO_LAT].sds,
1712  iscan,
1713  geo[GEO_LAT].scandim,
1714  geo[GEO_LAT].ndets);
1715 
1716  /* If native resolution, copy values into storage buffers */
1717  if (geo[GEO_LON].resolution == resolution) {
1718  memcpy(lonscan, geo[GEO_LON].sds.data, nvals * sizeof (*lonscan));
1719  memcpy(latscan, geo[GEO_LAT].sds.data, nvals * sizeof (*latscan));
1720  }
1721  /* Otherwise, interpolate first */
1722  else {
1723  TRYMEM(__FILE__, __LINE__,
1724  (newdata = malloc(nvals * sizeof (*newdata))));
1725  modis_interp(geo[GEO_LON], 0, resolution, NULL, newdata);
1726  LOOPI lonscan[i] = (float) newdata[i];
1727  modis_interp(geo[GEO_LAT], 0, resolution, NULL, newdata);
1728  LOOPI latscan[i] = (float) newdata[i];
1729  free(newdata);
1730  }
1731 
1732  } // loaded new scan
1733 
1734  /* Copy specified line from storage buffers into l1rec structure */
1735  detoffset = idet * npixl + spixl;
1736  nbytes = l1rec->npix * sizeof (float);
1737  memcpy(l1rec->lon, &lonscan[detoffset], nbytes);
1738  memcpy(l1rec->lat, &latscan[detoffset], nbytes);
1739 
1740  return SUCCESS;
1741 }
GEO_SDS
Definition: l1_hmodis_hdf.c:56
int open_modis_geofile(modis_file *geofile)
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
#define MAX(A, B)
Definition: swl0_utils.h:26
int32 value
Definition: Granule.c:1235
const char * sensorId2SensorDir(int sensorId)
Definition: sensorInfo.c:240
#define MIN(x, y)
Definition: rice.h:169
int32_t nscans
int modpath_1km(const char *oldpath, const char *newchars, char *newpath)
int16_t sdsindex
int16_t resolution
float * hgt
#define SUCCESS
Definition: ObpgReadGrid.h:15
int j
Definition: decode_rs.h:73
float * allbands
int32_t day
int status
Definition: l1_czcs_hdf.c:32
int32_t ndets
int set_l1rec_scanvals(const int32_t iscan, l1str *l1rec)
int32_t * prev
char * lowcase(char *instr)
Definition: lowcase.c:10
double mnorm[3]
void read_sfcorrtables(sfcorr_table *sfcorr, int32_t sensorID)
@ RSB_500
Definition: l1_hmodis_hdf.c:88
@ GEO_SENA
Definition: l1_hmodis_hdf.c:63
@ RAD_SCALE
int16_t resolution
@ L1B_NUM_SDS
Definition: l1_hmodis_hdf.c:92
@ GEO_HGT
Definition: l1_hmodis_hdf.c:59
#define FAIL
Definition: ObpgReadGrid.h:18
#define NULL
Definition: decode_rs.h:63
@ RSB_1KM
Definition: l1_hmodis_hdf.c:89
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
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that resolution
Definition: HISTORY.txt:188
int32_t scandim
@ GEO_LAT
Definition: l1_hmodis_hdf.c:58
int16_t wavelength
int readl1_hmodis_hdf(filehandle *l1file, const int32_t line, l1str *l1rec)
int init_l1b(const char filename[FILENAME_MAX], int32_t *max_resolution)
read l1rec
int32_t nbands
char file[FILENAME_MAX]
@ RSB_250
Definition: l1_hmodis_hdf.c:87
L1B_COEFFS
sds_struct sds
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 wavelength
int init_sds_byname(int32_t fileid, const char *sdsname, sds_struct *sds)
Definition: hdf4_utils.c:92
double angles[3]
float * lat
int32 * msec
Definition: l1_czcs_hdf.c:31
#define MODIST
Definition: sensorDefs.h:18
void init_detfill(fill_table *fill)
double esdist_(int32_t *year, int32_t *day, int32_t *msec)
void subframe_correction(const int32_t sensorID, const int32_t iband, const modis_sds mds, double *data)
float * senz
int open_modis_l1bfile(modis_file *l1bfile)
@ TEB_1KM
Definition: l1_hmodis_hdf.c:91
int32_t npix
@ GEO_SOLA
Definition: l1_hmodis_hdf.c:61
@ GEO_MSIDE
Definition: l1_hmodis_hdf.c:42
int sensorId2SubsensorId(int sensorId)
Definition: sensorInfo.c:322
int32_t n_sds
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
@ GEO_NUM_COEFFS
Definition: l1_hmodis_hdf.c:79
L1B_SDS
Definition: l1_hmodis_hdf.c:86
#define PI
Definition: l3_get_org.c:6
char * bandname
char * name
Definition: l1_hmodis_hdf.c:36
int32_t nsf
int modis_interp(const modis_sds s, const int32_t sdsband, const int32_t newres, double *olddata, double *newdata)
int32_t index
Definition: l1_hmodis_hdf.c:34
void compute_alpha(float lon[], float lat[], float senz[], float sena[], double mnorm[3], int npix, float alpha[])
Definition: compute_alpha.c:8
int readl1_lonlat_hmodis_hdf(filehandle *l1file, int32_t line, l1str *l1rec)
double unix_to_tai93(double unixtime)
Definition: yds2tai.c:11
int32_t mside
float * solz
double(* interp_modis_var)(double val[4], double dx, double dy)
int openl1_hmodis_hdf(filehandle *l1file)
double tai93_to_unix(double tai93)
Definition: yds2tai.c:16
@ GEO_TAISEC
Definition: l1_hmodis_hdf.c:41
double interp_bilin(double val[4], double dx, double dy)
@ GEO_SCALE
Definition: l1_hmodis_hdf.c:78
char * strdup(const char *)
int load_modis_scan(const int32_t iscan, const int32_t resolution, int32_t sensorID)
#define LOOPI
int32_t nbands
int32_t * next
#define MAX_ATTERR
@ GEO_NUM_SDS
Definition: l1_hmodis_hdf.c:64
double * corr
int16_t flagindex
int32_t id
l1_input_t * l1_input
Definition: l1_options.c:9
int want_verbose
void unix2yds(double usec, short *year, short *day, double *secs)
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
double interp_modis_EVdata(double val[4], double dx, double dy)
@ CIR_1KM
Definition: l1_hmodis_hdf.c:90
@ REF_NUM_SDS
Definition: l1_hmodis_hdf.c:45
double interp_modis_Longitude(double val[4], double dx, double dy)
integer, parameter double
HDF4 data type of the output SDS Default is DFNT_FLOAT32 Common types used DFNT_INT16
sds_struct * sds
int get_hdfeos_meta(int32_t sd_id, char *attribute, char *name, char *data)
Definition: hdf4_utils.c:326
#define RADEG
Definition: czcs_ctl_pt.c:5
@ GEO_SOLZ
Definition: l1_hmodis_hdf.c:60
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor and incalculable values of SV or BB averages was moved outside the loop over frames in Emissive_Cal c since none of these quantities are frame dependent Initialization of b1 and XMS values in Preprocess c routine Process_OBCENG_Emiss was moved inside the detector loops The code was altered so that if up to five scans are dropped between the leading middle or middle trailing the leading or trailing granule will still be used in emissive calibration to form a cross granule average QA bits and are set for a gap between the leading middle and middle trailing granules respectively This may in rare instances lead to a change in emissive calibration coefficients for scans at the beginning or end of a granule A small bug in the Band correction algorithm was corrected an uncertainty value was being checked against an upper bound whereas the proper quantity to be checked was the corresponding SI
Definition: HISTORY.txt:595
double starttime
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
int32_t nlines
@ GEO_LON
Definition: l1_hmodis_hdf.c:57
int32_t scandim
Definition: l1_hmodis_hdf.c:35
#define basename(s)
Definition: l0chunk_modis.c:29
#define SCAN_TIME_INTERVAL
Definition: l1_hmodis_hdf.c:20
#define BAD_FLT
Definition: jplaeriallib.h:19
const char * sensorId2SensorName(int sensorId)
Definition: sensorInfo.c:198
void radiance2bt(l1str *l1rec, int resolution)
Definition: brightness.c:170
#define MIN_BAD_SI
#define fabs(a)
Definition: misc.h:93
int32_t iscan
float * sena
void fopen_warn(const char *filename, const char *file, const int32_t line)
Definition: hdf4_utils.c:261
int read_sds_1scan(sds_struct *sds, int32_t iscan, int32_t scandim, int32_t per_scan)
int16_t bandindex
void free_sds(sds_struct *sds)
Definition: hdf4_utils.c:161
int32_t npixls
int32_t nvals
int init_geo(const char filename[FILENAME_MAX])
@ L1B_NUM_COEFFS
float * lon
int readall_sds(sds_struct *sds)
Definition: hdf4_utils.c:138
data_t s[NROOTS]
Definition: decode_rs.h:75
real *8 function esdist(iyr, iday, msec)
Definition: esdist.f:3
double taisec
#define read_att(obj_id, attname, valptr)
Definition: hdf4utils.h:177
int32_t rdsensorinfo(int32_t, int32_t, const char *, void **)
Definition: rdsensorinfo.c:69
@ RAD_OFFSET
const char * subsensorId2SubsensorDir(int subsensorId)
Definition: sensorInfo.c:254
l2prod offset
#define TRYMEM(file, line, memstat)
Definition: l1_hmodis_hdf.c:23
HDF4 data type of the output SDS Default is DFNT_FLOAT32 Common types used DFNT_FLOAT32
int32_t ndets
@ GEO_SENZ
Definition: l1_hmodis_hdf.c:62
@ GEO_MNORM
Definition: l1_hmodis_hdf.c:44
void fill_dead_detectors(const int32_t iband, const modis_sds mds, double *data)
REF_SDS
Definition: l1_hmodis_hdf.c:40
double * SI_val
int i
Definition: decode_rs.h:71
int alloc_scan(const int32_t nvals)
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")
int load_att_byname(int32_t obj_id, const char *attname, att_struct *att)
Definition: hdf4_utils.c:31
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:97
#define MODISA
Definition: sensorDefs.h:19
#define EOSMETALEN
Definition: filetype.c:23
@ REFL_OFFSET
int closel1_hmodis_hdf()
int32_t nframes
@ GEO_ANGLES
Definition: l1_hmodis_hdf.c:43
float * sola
char shortname[FILENAME_MAX]
GEO_COEFFS
Definition: l1_hmodis_hdf.c:77
double isodate2unix(const char *isodate)
Definition: unix2isodate.c:61
@ REFL_SCALE