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