NASA Logo
Ocean Color Science Software

ocssw V2022
l1_l7etm.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <stdio.h>
3 
4 #include "l1.h"
5 #include "l1_l7etm.h"
6 
7 #include <tiffio.h>
8 #include <geotiff.h>
9 #include <xtiffio.h>
10 #include <geo_normalize.h>
11 #include <libgen.h>
12 
13 /* For Landsat 7 ETM */
14 
15 int get_l57tm_nom_angles( char *meta_filename, int32_t npix, int32_t nscan, int32_t iscan,
16  float *solz, float *sola, float *senz, float *sena);
17 
18 static const int itemSize = 500;
19 static const int maxBands = 8;
20 static const int maxReflBands = 7;
21 
22 typedef struct L7ETM_struct {
23  int32_t year, doy, msec;
25  double *lat, *lon;
26  double *scale, *offset;
28  TIFF** tif; // file handle for each band
29  GTIF* gtif; // geotiff handle for the first file
30  GTIFDefn* defn; // geotiff definition structure for first file
31  uint8_t* buf; // buffer used to read one scan line from TIFF file
32 } l7etm_t;
33 
34 
35 l7etm_t* createPrivateData_l7etm(int numBands) {
36  l7etm_t* data = (l7etm_t*)calloc(1, sizeof(l7etm_t));
37  if(data == NULL) {
38  fprintf(stderr,"-E- %s line %d: unable to allocate private data for l7etm\n",
39  __FILE__,__LINE__);
40  exit(1);
41  }
42 
43  data->scale = (double *) malloc(numBands*sizeof(double) );
44  data->offset = (double *) malloc(numBands*sizeof(double) );
45  if(data->scale==NULL || data->offset==NULL) {
46  fprintf(stderr,"-E- %s line %d: unable to allocate scale/offset data for L7ETM\n",
47  __FILE__,__LINE__);
48  exit(1);
49  }
50 
51  data->refl_scale = (double *) malloc(numBands*sizeof(double) );
52  data->refl_offset = (double *) malloc(numBands*sizeof(double) );
53  if(data->refl_scale==NULL || data->refl_offset==NULL) {
54  fprintf(stderr,"-E- %s line %d: unable to allocate reflectance scale/offset data for L7ETM\n",
55  __FILE__,__LINE__);
56  exit(1);
57  }
58 
59  data->tif = (TIFF**) calloc(numBands, sizeof(TIFF*) );
60  if(data->tif==NULL) {
61  fprintf(stderr,"-E- %s line %d: unable to allocate TIFF pointers for L7ETM\n",
62  __FILE__,__LINE__);
63  exit(1);
64  }
65 
66  data->defn = (GTIFDefn*) malloc(sizeof(GTIFDefn) );
67  if(data->defn==NULL) {
68  fprintf(stderr,"-E- %s line %d: unable to allocate GEOTIFF definition structure for L7ETM\n",
69  __FILE__,__LINE__);
70  exit(1);
71  }
72 
73  return data;
74 }
75 
76 void freePrivateData_l7etm(l7etm_t* data) {
77  free(data->scale);
78  free(data->offset);
79  free(data->refl_scale);
80  free(data->refl_offset);
81  free(data->tif);
82  free(data->defn);
83  free(data);
84 }
85 
86 void readNextLine_l7etm(FILE* fp, char* tag, int* i, char* val) {
87  char* result;
88  char line[itemSize];
89  int count;
90 
91  result = fgets(line, itemSize, fp);
92  if(result == NULL) {
93  fprintf(stderr,"-E- %s line %d: unable to read all of the required metadata from L7ETM file\n",
94  __FILE__,__LINE__);
95  exit(1);
96  }
98 
99  count = sscanf(line, "%s = %s", tag, val);
100  if(count != 2) {
101  // not found so return blank line
102  tag[0] = 0;
103  *i = 0;
104  val[0] = 0;
105  return;
106  }
107 
108  // grab index if it exists
109  result = strrchr(tag, '_');
110  if(result) {
111  result++;
112  *i = atoi(result);
113  } else {
114  *i = 0;
115  }
116 
117  // get rid of the quotes from val
118  if(val[0] == '"')
119  val[0] = ' ';
120  count = strlen(val) - 1;
121  if(val[count] == '"')
122  val[count] = 0;
123  trimBlanks(val);
124 }
125 
126 int openl1_l7etm(filehandle *file) {
127  int i;
128  FILE *fp;
129  char tag[itemSize];
130  char val[itemSize];
131  char dateStr[32];
132  char timeStr[32];
133  char fileName[itemSize];
134 
135  l7etm_t* data = file->private_data = createPrivateData_l7etm(maxBands);
136 
137  if(want_verbose)
138  printf("L7ETM Level-1B %s\n", file->name );
139 
140  /* Open file */
141  if ((fp = fopen(file->name, "r")) == NULL) {
142  fprintf(stderr,"-E- %s line %d: unable open %s\n",
143  __FILE__,__LINE__,file->name);
144  exit(1);
145  }
146 
147  int dateNeeded = 1;
148  int timeNeeded = 1;
149  int filesNeeded = 1;
150  int numLinesNeeded = 1;
151  int numSamplesNeeded = 1;
152  int sunAzimuthNeeded = 1;
153  int sunElevationNeeded = 1;
154  int scaleNeeded = 1;
155  int offsetNeeded = 1;
156 // int reflScaleNeeded = 1;
157 // int reflOffsetNeeded = 1;
158 
159  // loop metadata
160  while(dateNeeded ||
161  timeNeeded ||
162  numLinesNeeded ||
163  numSamplesNeeded ||
164  filesNeeded ||
165  sunAzimuthNeeded ||
166  sunElevationNeeded ||
167  /* reflScaleNeeded ||
168  reflOffsetNeeded || */
169  scaleNeeded ||
170  offsetNeeded) {
171 
172  readNextLine_l7etm(fp, tag, &i, val);
173 
174  // skip blank lines
175  if(tag[0] == 0)
176  continue;
177 
178  // get date
179  if(!strcmp(tag, "DATE_ACQUIRED")) {
180  dateNeeded = 0;
181  strcpy(dateStr, val);
182 
183  // get time
184  } else if(!strcmp(tag, "SCENE_CENTER_TIME")) {
185  timeNeeded = 0;
186  strcpy(timeStr, val);
187 
188  // get num lines
189  } else if(!strcmp(tag, "REFLECTIVE_LINES")) {
190  numLinesNeeded = 0;
191  file->nscan = atoi(val);
192 
193  // get num samples
194  } else if(!strcmp(tag, "REFLECTIVE_SAMPLES")) {
195  numSamplesNeeded = 0;
196  file->npix = atoi(val);
197 
198 
199  // get band file names
200  } else if(!strncmp(tag, "FILE_NAME_BAND_", 15)) {
201  if(i == maxBands)
202  filesNeeded = 0;
203  i--;
204  if(i>=0 && i<maxBands)
205  {
206  if (!strncmp(tag, "FILE_NAME_BAND_6_VCID_2", 23))
207  continue;
208 
209  if (!strncmp(tag, "FILE_NAME_BAND_6_VCID_1", 23))
210  i = 5; /* For ETM the BAND_6_VCID_1 format can confuse the index i so reset it here */
211  // dirname might destroy input, so we pass it a copy
212  char dir[FILENAME_MAX];
213  strcpy(dir,file->name);
214  strcpy(fileName, dirname(dir));
215  strcat(fileName, "/");
216  strcat(fileName, val);
217  if(want_verbose)
218  printf("L7ETM Level-1B Band[%d]:%s\n\n", i, fileName );
219  data->tif[i] = XTIFFOpen(fileName, "r");
220  if (!data->tif[i]) {
221  fprintf(stderr,"-E- %s line %d: unable open TIFF file %s\n",
222  __FILE__,__LINE__,fileName);
223  exit(1);
224  }
225  }
226 
227  // get sun azimuth
228  } else if(!strcmp(tag, "SUN_AZIMUTH")) {
229  sunAzimuthNeeded = 0;
230  data->sunAzimuth = atof(val);
231 
232  // get sun elevation
233  } else if(!strcmp(tag, "SUN_ELEVATION")) {
234  sunElevationNeeded = 0;
235  data->sunElevation = atof(val);
236  }
237  // get refl_scale
238  else if(!strncmp(tag, "REFLECTANCE_MULT_BAND_", 22)) {
239 // if(i == maxReflBands)
240 // reflScaleNeeded = 0;
241  i--;
242  if(i>=0 && i<maxReflBands) {
243  data->refl_scale[i] = atof(val);
244  }
245 
246  // get refl_offset
247  } else if(!strncmp(tag, "REFLECTANCE_ADD_BAND_", 21)) {
248 // if(i == maxReflBands)
249 // reflOffsetNeeded = 0;
250  i--;
251  if(i>=0 && i<maxReflBands) {
252  data->refl_offset[i] = atof(val);
253  }
254 
255  }
256  // radiance scale
257  else if(!strncmp(tag, "RADIANCE_MULT_BAND_", 19)) {
258  if(i == maxBands)
259  scaleNeeded = 0;
260  i--;
261  if(i>=0 && i<maxBands) {
262  data->scale[i] = atof(val);
263  }
264 
265  // get offset
266  } else if(!strncmp(tag, "RADIANCE_ADD_BAND_", 18)) {
267  if(i == maxBands)
268  offsetNeeded = 0;
269  i--;
270  if(i>=0 && i<maxBands) {
271  data->offset[i] = atof(val);
272  }
273  }
274 
275  } // while
276 
277  fclose(fp);
278 
279  // allocate lat and lon storage
280  data->lat = (double *) malloc(file->npix*sizeof(double) );
281  data->lon = (double *) malloc(file->npix*sizeof(double) );
282  if(data->lat==NULL || data->lon==NULL) {
283  fprintf(stderr,"-E- %s line %d: unable to allocate lat/lon data for L7ETM\n",
284  __FILE__,__LINE__);
285  exit(1);
286  }
287 
288  // only need the GEO TIFF info from one file
289  data->gtif = GTIFNew(data->tif[0]);
290  if (!data->gtif) {
291  fprintf(stderr,"-E- %s line %d: unable open GEOTIFF file %s\n",
292  __FILE__,__LINE__,fileName);
293  exit(1);
294  }
295 
296  if(!GTIFGetDefn(data->gtif, data->defn)) {
297  fprintf(stderr,"-E- %s line %d: unable populate GEOTIFF defn structure for %s\n",
298  __FILE__,__LINE__,fileName);
299  exit(1);
300  }
301 
302  // allocate buffer to hold one scan line
303  int size = TIFFScanlineSize(data->tif[0]);
304  if(size != file->npix) /* For Landsat 5 TM the data type is Byte */
305  {
306  fprintf(stderr,"-E- %s line %d: unexpected pixel data size in %s\n",
307  __FILE__,__LINE__,fileName);
308  exit(1);
309  }
310  data->buf = (uint8_t*) malloc(size);
311 
312  // get date "2013-07-19"
313  int year, month, day;
314  sscanf(dateStr, "%d-%d-%d", &year, &month, &day);
315 
316  // get time "10:41:59.9930740Z"
317  int hour, minute;
318  double sec;
319  sscanf(timeStr, "%d:%d:%lf", &hour, &minute, &sec);
320 
321  int isec = (int)sec;
322  ymdhms2ydmsec(year, month, day, hour, minute, isec,
323  &data->year, &data->doy, &data->msec);
324  sec -= isec;
325  data->msec += sec * 1000;
326 
327  if(want_verbose) {
328  printf("L7ETM Start Time: %4d-%02d-%02d %03d %02d:%02d:%f\n",
329  year, month, day, data->doy, hour, minute, sec);
330 
331  printf("L7ETM file has %d bands, %d samples, %d lines\n",
332  file->nbands, file->npix, file->nscan );
333  }
334  strcpy(file->spatialResolution,"30 m");
335 
336  return 0;
337 }
338 
339 int readl1_l7etm( filehandle *file, int recnum, l1str *l1rec, int lonlat) {
340  int ip, ib, ipb;
341  l7etm_t* data = (l7etm_t*)file->private_data;
342 
343  // set information about data
344  l1rec->npix = file->npix;
345  l1rec->l1file->sensorID = file->sensorID;
346  l1rec->scantime = yds2unix((int16_t) data->year, (int16_t) data->doy,
347  (double) (data->msec / 1000.0 ));
348 
349  // get lat-lon
350  for (ip=0; ip<file->npix; ip++) {
351  data->lon[ip] = ip;
352  data->lat[ip] = recnum;
353  GTIFImageToPCS(data->gtif, data->lon+ip, data->lat+ip);
354  }
355 
356  if (!GTIFProj4ToLatLong(data->defn, file->npix, data->lon, data->lat) ) {
357  fprintf(stderr,"-E- %s line %d: unable reproject points for scan %d\n",
358  __FILE__,__LINE__,recnum);
359  exit(1);
360  }
361 
362  for (ip=0; ip<file->npix; ip++) {
363 
364  l1rec->pixnum[ip] = ip;
365 
366  if ( isnan(data->lat[ip]) )
367  data->lat[ip] = -999.0;
368  if ( isnan(data->lon[ip]) )
369  data->lon[ip] = -999.0;
370  l1rec->lat[ip] = data->lat[ip];
371  l1rec->lon[ip] = data->lon[ip];
372 
373  /* printf("lat = %f, lon = %f\n", l1rec->lat[ip], l1rec->lon[ip]); */
374 
375  if (l1rec->lon[ip] < -181.0 || l1rec->lon[ip] > 181.0 ||
376  l1rec->lat[ip] < -91.0 || l1rec->lat[ip] > 91.0 )
377  {
378  l1rec->navfail[ip] = 1;
379  printf("ERROR: lat = %f, lon = %f\n", l1rec->lat[ip], l1rec->lon[ip]);
380  }
381 
382  }
383 
384  // read path angles if user supplied, else use best guess
385  if (get_l57tm_nom_angles(file->name,file->npix,file->nscan,recnum,l1rec->solz,l1rec->sola,l1rec->senz,l1rec->sena) == -1) {
386  fprintf(stderr, "-E- %s line %d: missing or incompatible geofile\n",
387  __FILE__,__LINE__);
388  exit(1);
389  }
390 
391  if (lonlat)
392  return(LIFE_IS_GOOD);
393 
394  //printf("in readl1_l7etm file->nbands = %d\n", file->nbands);
395  for(ib = 0; ib < file->nbands; ib++)
396  {
397 
398  /* For Landsat 7 skip band 6 */
399  if (ib == 5)
400  {
401  if(TIFFReadScanline(data->tif[ib+1], (void*)data->buf, recnum, 0) == -1) {
402  fprintf(stderr, "-E- %s line %d: Failed to read Lt, band %d, recnum %d\n",
403  __FILE__,__LINE__, ib, recnum );
404  exit(1);
405  }
406  }
407  else
408  {
409  if(TIFFReadScanline(data->tif[ib], (void*)data->buf, recnum, 0) == -1) {
410  fprintf(stderr, "-E- %s line %d: Failed to read Lt, band %d, recnum %d\n",
411  __FILE__,__LINE__, ib, recnum );
412  exit(1);
413  }
414  }
415 
416  for (ip=0; ip<file->npix; ip++) {
417  ipb = ip*file->nbands+ib;
418  if(data->buf[ip] == 0) {
419  l1rec->Lt[ipb] = BAD_FLT; // I assume this is outside the projected tile
420  l1rec->navfail[ip] = 1; // so set navigation failure
421  } else
422  {
423  /* For Landsat 5 skip band 6 */
424  if (ib == 5)
425  {
426  l1rec->Lt[ipb] = (data->buf[ip] * data->scale[ib+1] + data->offset[ib+1]) / 10.0;
427  /* printf("band = %d, scale = %f, offset = %f\n", ib+1, data->scale[ib+1], data->offset[ib+1]);
428  printf("buf = %d, final = %f\n", data->buf[ip], l1rec->Lt[ipb]); */
429  }
430  else
431  {
432  l1rec->Lt[ipb] = (data->buf[ip] * data->scale[ib] + data->offset[ib]) / 10.0;
433  /* printf("band = %d, scale = %f, offset = %f\n", ib, data->scale[ib], data->offset[ib]);
434  printf("buf = %d, final = %f\n", data->buf[ip], l1rec->Lt[ipb]); */
435  }
436 
437  }
438  }
439  }
440 
441  // read Cirrus Band 9
442 
443  /* ib = 8;
444  if(TIFFReadScanline(data->tif[ib], (void*)data->buf, recnum, 0) == -1) {
445  fprintf(stderr, "-E- %s line %d: Failed to read cirrus band, recnum %d\n",
446  __FILE__,__LINE__, recnum );
447  exit(1);
448  }
449 
450  for (ip=0;ip<file->npix; ip++) {
451  if(data->buf[ip] == 0)
452  l1rec->rho_cirrus[ip] = BAD_FLT;
453  else
454  l1rec->rho_cirrus[ip] = (data->buf[ip] * data->refl_scale[ib] + data->refl_offset[ib])
455  / cos(l1rec->solz[ip]/RADEG);
456 
457  } */
458 
459  return 0;
460 }
461 
462 int closel1_l7etm(filehandle *file) {
463  int ib;
464  l7etm_t* data = (l7etm_t*) file->private_data;
465 
466  // undo what open allocated
467  free(data->lat);
468  free(data->lon);
469  data->lat = data->lon = NULL;
470 
471  free(data->buf);
472  data->buf = NULL;
473 
474  GTIFFree(data->gtif);
475  data->gtif = NULL;
476 
477  for(ib=0; ib<file->nbands; ib++) {
478  XTIFFClose(data->tif[ib]);
479  }
481  file->private_data = NULL;
482 
483  return 0;
484 }
TIFF ** tif
Definition: l1_l7etm.c:28
int32_t day
double sunAzimuth
Definition: l1_l7etm.c:24
int32_t msec
Definition: l1_l7etm.c:23
double yds2unix(int16_t year, int16_t day, double secs)
Definition: yds2unix.c:7
GTIFDefn * defn
Definition: l1_l7etm.c:30
#define NULL
Definition: decode_rs.h:63
read l1rec
double * scale
Definition: l1_l7etm.c:26
void trimBlanks(char *str)
Definition: trimBlanks.c:10
int32_t year
Definition: l1_l7etm.c:23
l7etm_t * createPrivateData_l7etm(int numBands)
Definition: l1_l7etm.c:35
GTIF * gtif
Definition: l1_l7etm.c:29
int openl1_l7etm(filehandle *file)
Definition: l1_l7etm.c:126
void freePrivateData_l7etm(l7etm_t *data)
Definition: l1_l7etm.c:76
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed file
Definition: HISTORY.txt:413
#define LIFE_IS_GOOD
Definition: passthebuck.h:4
void readNextLine_l7etm(FILE *fp, char *tag, int *i, char *val)
Definition: l1_l7etm.c:86
read recnum
subroutine lonlat(alon, alat, xlon, ylat)
Definition: lonlat.f:2
int readl1_l7etm(filehandle *file, int recnum, l1str *l1rec, int lonlat)
Definition: l1_l7etm.c:339
int32_t doy
Definition: l1_l7etm.c:23
double * lon
Definition: l1_l7etm.c:25
int get_l57tm_nom_angles(char *meta_filename, int32_t npix, int32_t nscan, int32_t iscan, float *solz, float *sola, float *senz, float *sena)
int want_verbose
int closel1_l7etm(filehandle *file)
Definition: l1_l7etm.c:462
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
#define maxBands
#define BAD_FLT
Definition: jplaeriallib.h:19
void ymdhms2ydmsec(int yy, int mm, int dd, int hh, int mn, int sc, int32_t *year, int32_t *day, int32_t *msec)
Definition: ydhms2ydmsec.c:3
double sunElevation
Definition: l1_l7etm.c:24
int32_t iscan
double * lat
Definition: l1_l7etm.c:25
uint8_t * buf
Definition: l1_l7etm.c:31
double * refl_scale
Definition: l1_l7etm.c:27
double * refl_offset
Definition: l1_l7etm.c:27
int i
Definition: decode_rs.h:71
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int npix
Definition: get_cmp.c:28
double * offset
Definition: l1_l7etm.c:26
int count
Definition: decode_rs.h:79