OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
l1_prism.c
Go to the documentation of this file.
1 /*
2  * l1_prism.c
3  *
4  * Portable Remote Imaging SpectroMeter (PRISM)
5  *
6  * Created on: June 11, 2015
7  * Author: Rick Healy SAIC
8  * NASA-GSFC OBPG
9  */
10 #include "l1.h"
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include "jplaeriallib.h"
16 #include "prism.h"
17 #include <libnav.h>
18 
19 #define SKIP -9999
20 
21 static const int maxBands = 285;
22 static double *lat, *lon;
23 
24 prism_t* createPrivateData_pr(int numBands, int32_t nscan, int32_t npix) {
25 
26  prism_t* data = (prism_t*) calloc(1, sizeof (prism_t));
27  if (data == NULL) {
28  fprintf(stderr, "-E- %s line %d: unable to allocate private data for prism\n",
29  __FILE__, __LINE__);
30  exit(1);
31  }
32 
33  data->wave = (double *) malloc(numBands * sizeof (double));
34  data->fwhm = (double *) malloc(numBands * sizeof (double));
35  data->gain = (double *) malloc(numBands * sizeof (double));
36  if (data->wave == NULL || data->fwhm == NULL || data->gain == NULL) {
37  fprintf(stderr, "-E- %s line %d: unable to allocate scale/offset data for prism\n",
38  __FILE__, __LINE__);
39  exit(1);
40  }
41 
42  return data;
43 }
44 
45 int openl1_prism(filehandle *file) {
46 
47  FILE *ptr;
48  char *val0;
49  char *inbasename, *infile;
50  int i, pos;
51  int numBands;
52  char* result;
53  char line[itemSize];
54  int year, month, day, hour, minute, second;
55  //float knts2mps = 0.51444444444; // knots to meters per second
56  float ft2m = 0.3048; // feet to meters
57 
58  char projStr[1024];
59  static char *dupline;
60  int cnt, linelength;
61 
62  printf("file=%s\n", file->name);
63  inbasename = getinbasename(file->name);
64  printf("Basename=%s\n", inbasename);
65  pos = strlen(inbasename);
66  if (pos <= 0) {
67  fprintf(stderr, "-E- %s line %d: Not a avalid prism file %s\n",
68  __FILE__, __LINE__, file->name);
69  return 1;
70  }
71 
72  sscanf(inbasename, "prm%4d%2d%2dt%2d%2d%2d", &year, &month, &day, &hour, &minute, &second);
73 
74  prism_t* data = file->private_data = createPrivateData_pr(maxBands, file->nscan, file->npix);
75 
76  data->stime = ymds2unix(year, month, day, hour * 3600.0 + minute * 60.0 + second);
77 
78  printf("Date of prism flight: %s\n", unix2isodate(data->stime, 'G'));
79 
80  if ((ptr = fopen(file->name, "r")) == NULL) {
81  fprintf(stderr, "-E- %s line %d: unable to open %s\n",
82  __FILE__, __LINE__, file->name);
83  return 1;
84  }
85 
86  int numLinesNeeded = 1;
87  int numSamplesNeeded = 1;
88  int bandsNeeded = 1;
89  int utmZoneNeeded = 1;
90  int eastingNeeded = 1;
91  int northingNeeded = 1;
92  int pixelSizeNeeded = 1;
93  int interleaveNeeded = 1;
94  int rotationAngNeeded = 1;
95  int EndTimeNeeded = 1;
96  int altNeeded = 1;
97 
98  // loop metadata
99  while (numLinesNeeded ||
100  numSamplesNeeded ||
101  bandsNeeded ||
102  pixelSizeNeeded ||
103  utmZoneNeeded ||
104  eastingNeeded ||
105  northingNeeded ||
106  rotationAngNeeded ||
107  EndTimeNeeded ||
108  altNeeded ||
109  interleaveNeeded) {
110 
111  result = fgets(line, itemSize, ptr);
112  if (result == NULL) {
113  fprintf(stderr, "-E- %s line %d: unable to read all of the required metadata from prism file\n",
114  __FILE__, __LINE__);
115  exit(1);
116  }
117  trimBlanks(line);
118 
119  if ((val0 = checkTagLine(line, "lines"))) {
120  numLinesNeeded = 0;
121  file->nscan = atoi(val0);
122  data->nscan = file->nscan;
123  printf("lines=%d\n", data->nscan);
124  }
125  if ((val0 = checkTagLine(line, "samples"))) {
126  numSamplesNeeded = 0;
127  file->npix = atoi(val0);
128  data->npix = file->npix;
129  printf("samples=%d\n", data->npix);
130  }
131  if ((val0 = checkTagLine(line, "Alt"))) {
132  altNeeded = 0;
133  data->alt = atof(val0) * ft2m;
134  printf("Altitude=%lf\n", data->alt);
135  }
136  if ((val0 = checkTagLine(line, "EndTime"))) {
137  EndTimeNeeded = 0;
138  sscanf(val0, "%2d%2d", &hour, &minute);
139  printf("End hour=%d minute=%d\n", hour, minute);
140  data->etime = ymds2unix(year, month, day, hour * 3600.0 + minute * 60.0);
141  printf("End Time=%s\n", unix2isodate(data->etime, 'G'));
142  }
143  if ((val0 = checkTagLine(line, "bands"))) {
144  bandsNeeded = 0;
145  numBands = atoi(val0);
146  data->numBands = numBands;
147  if (numBands > maxBands) {
148  fprintf(stderr, "-E- %s line %d: number of bands (%d) from prism file > maxBands (%d)\n",
149  __FILE__, __LINE__, numBands, maxBands);
150  exit(1);
151  }
152  printf("numBands=%d\n", data->numBands);
153  }
154  if ((val0 = checkTagLine(line, "interleave"))) {
155  interleaveNeeded = 0;
156  if (strstr(val0, "bip")) {
157  data->interleave = BIP;
158  } else if (strstr(val0, "bil")) {
159  data->interleave = BIL;
160  } else {
161  fprintf(stderr, "Interleave = %s is not supported\n", val0);
162  exit(1);
163  }
164  printf("Interleave=%d\n", data->interleave);
165  }
166  if ((val0 = checkTagLine(line, "map info"))) {
167  cnt = 0;
168  linelength = strlen(line);
169  if (dupline) free(dupline);
170  if ((dupline = (char *) malloc(linelength * sizeof (char))) == NULL) {
171  fprintf(stderr,
172  "-E- %s line %d: Memory allocation failure.\n",
173  __FILE__, __LINE__);
174  return (0);
175  }
176  strcpy(dupline, line);
177  result = strtok(dupline, ",");
178  while (result) {
179  switch (cnt) {
180  case 3:
181  data->easting = atof(result);
182  eastingNeeded = 0;
183  break;
184  case 4:
185  data->northing = atof(result);
186  northingNeeded = 0;
187  break;
188  case 5:
189  data->pixelSize = atof(result);
190  pixelSizeNeeded = 0;
191  break;
192  case 7:
193  data->utmZone = atoi(result);
194  utmZoneNeeded = 0;
195  break;
196  default:
197  break;
198  }
199  printf(">>%d) %s\n", cnt, result);
200  cnt++;
201  result = strtok(NULL, ",");
202  }
203  if ((val0 = checknspTagLine(line, "rotation"))) {
204  rotationAngNeeded = 0;
205  data->rotation = atof(val0);
206  } else {
207  printf("Rotation angle expected in line: %s\n", val0);
208  exit(-1);
209  }
210  printf("Rotation/easting/northing/pixsize/utmzone=%f/%lf/%lf/%lf/%d\n", data->rotation, data->easting, data->northing, data->pixelSize, data->utmZone);
211  }
212  // if((val0=checkTagLine(line,"map info"))) {
213  // sscanf(val0,"%*[^,], %*f, %*f, %lf, %lf, %lf, %lf, %d, %*[^,], %*[^,], %*[^,], %s}",&data->easting,&data->northing,&data->pixelSize,&data->pixelSize,&data->utmZone,val1);
214  // if((val0=checknspTagLine(line,"rotation"))) {
215  // rotationAngNeeded = 0;
216  // rotation = atof(val0);
217  // if (rotation > 45)
218  // data->eastbyscan = -1;
219  // else if (rotation < -45)
220  // data->eastbyscan = 1;
221  // else
222  // data->eastbyscan = 0;
223  // } else {
224  // printf("Rotation angle expected in line: %s\n",val0);
225  // exit(-1);
226  // }
227  // printf("Rotation/easting/northing/pixsize/utmzone=%f/%lf/%lf/%lf/%d\n",rotation,data->easting,data->northing,data->pixelSize,data->utmZone);
228  // pixelSizeNeeded = 0;
229  // northingNeeded = 0;
230  // eastingNeeded = 0;
231  // utmZoneNeeded = 0;
232  //
233  // }
234 
235 
236  }
237 
238  fclose(ptr);
239 
240 
241  // Get the sensor and solar data
242  data->sena = (double **) malloc(data->nscan * sizeof (double*));
243  data->senz = (double **) malloc(data->nscan * sizeof (double*));
244  data->solz = (double **) malloc(data->nscan * sizeof (double*));
245  data->sola = (double **) malloc(data->nscan * sizeof (double*));
246  data->utc = (double **) malloc(data->nscan * sizeof (double*));
247  if (data->sena == NULL || data->senz == NULL || data->sola == NULL || data->solz == NULL) {
248  fprintf(stderr, "-E- %s line %d: unable to allocate sensor and solar angle data for prism\n",
249  __FILE__, __LINE__);
250  exit(1);
251  }
252 
253  for (i = 0; i < data->nscan; i++) {
254  data->sena[i] = (double *) malloc(data->npix * sizeof (double));
255  data->senz[i] = (double *) malloc(data->npix * sizeof (double));
256  data->sola[i] = (double *) malloc(data->npix * sizeof (double));
257  data->solz[i] = (double *) malloc(data->npix * sizeof (double));
258  data->utc[i] = (double *) malloc(data->npix * sizeof (double));
259  if (data->sena[i] == NULL || data->senz[i] == NULL || data->sola[i] == NULL || data->solz[i] == NULL || data->utc[i] == NULL) {
260  fprintf(stderr, "-E- %s line %d: unable to allocate sensor and solar angle data for prism\n",
261  __FILE__, __LINE__);
262  exit(1);
263  }
264  }
265 
266  for (i = 0; i < numBands; i++) {
267  *(data->gain + i) = 1.0;
268  }
269 
270  // free(infile);
271  infile = malloc((pos + strlen("_rdn_ort")) * sizeof (char));
272  strcpy(infile, inbasename);
273  strcat(infile, "_rdn_ort");
274  printf("Opening prism image file %s\n", infile);
275 
276  if ((data->av_fp = fopen(infile, "rb")) == NULL) {
277  fprintf(stderr, "-E- %s line %d: unable to open %s\n",
278  __FILE__, __LINE__, infile);
279  return 1;
280 
281  }
282 
283  PJ *pj;
284  sprintf(projStr, "+proj=utm +zone=%d +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
285  data->utmZone);
286 
287  // init the proj4 projections
288  pj = proj_create_crs_to_crs(PJ_DEFAULT_CTX,
289  projStr,
290  "+proj=longlat +ellps=WGS84 +datum=WGS84",
291  NULL);
292  if(pj == NULL) {
293  printf("Error - prism first PROJ projection failed to init\n");
294  exit(1);
295  }
296  data->pj = proj_normalize_for_visualization(PJ_DEFAULT_CTX, pj);
297  if(data->pj == NULL) {
298  printf("Error - prism visualization PROJ projection failed to init\n");
299  exit(1);
300  }
301  proj_destroy(pj);
302 
303  lat = (double *) malloc(file->npix * sizeof (double));
304  lon = (double *) malloc(file->npix * sizeof (double));
305 
306  return (0);
307 
308 }
309 
310 int readl1_prism(filehandle *file, int recnum, l1str *l1rec, int lonlat)
311 /*
312  * fill standard record with L1B line of data
313  */ {
314  static int firstCall = 1;
315  double pos[3];
316  float epos[3], sunpos[3];
317  int16_t year, doy;
318  double secondOfDay;
319  float longitude, latitude, sunDist;
320  int i;
321  int npix = file->npix, ip;
322  prism_t* data = (prism_t*) file->private_data;
323 
324  if (firstCall) {
325  if (want_verbose)
326  printf("file->nbands = %d\n", (int) file->nbands);
327  firstCall = 0;
328 
329  for (ip = 0; ip < npix; ip++) {
330  l1rec->pixnum[ip] = ip;
331  l1rec->flags[ip] = 0;
332  }
333  }
334 
335  // set information about data
336  npix = file->npix;
337  l1rec->npix = file->npix;
338  l1rec->alt = data->alt;
339 
340  // *(l1rec->year) = data->year;
341  // *(l1rec->day) = data->doy;
342  // *(l1rec->msec) = data->msec + (data->emsec - data->msec)*recnum/(data->nscan-1);
343  l1rec->scantime = data->stime + (data->etime - data->stime) * recnum / (data->nscan - 1);
344 
345  // get lat-lon
346  for (ip = 0; ip < npix; ip++) {
347  //rotate pixel to project onto map
348  lon[ip] = data->easting + ip * cos(deg2rad(data->rotation)) * data->pixelSize + recnum * sin(deg2rad(data->rotation)) * data->pixelSize; // starts in upper left corner
349  lat[ip] = data->northing + ip * sin(deg2rad(data->rotation)) * data->pixelSize - recnum * cos(deg2rad(data->rotation)) * data->pixelSize;
350  }
351 
353 
354  if (lat[npix / 2] > SKIP)
355  latitude = lat[npix / 2];
356  else {
357  fprintf(stderr, "-E- %s line %d: Don't have sensor latitude for geometry calculation\n",
358  __FILE__, __LINE__);
359  exit(1);
360  }
361 
362  if (lon[npix / 2] > SKIP)
363  longitude = lon[npix / 2];
364  else {
365  fprintf(stderr, "-E- %s line %d: Don't have sensor longitude for geometry calculation\n",
366  __FILE__, __LINE__);
367  exit(1);
368  }
369 
370  getPosVec(latitude, longitude, data->alt, pos); // get position vector of sensor
371  unix2yds(l1rec->scantime, &year, &doy, &secondOfDay);
372 
373  int32_t iyear, idoy;
374  iyear = (int32_t) year;
375  idoy = (int32_t) doy;
376  l_sun_(&iyear, &idoy, &secondOfDay, sunpos, &sunDist); // get position vector for the sun
377 
378  for (i = 0; i < 3; i++) {
379  sunpos[i] *= 1.496e8; //convert to km for call to get_zenaz
380  epos[i] = pos[i];
381  }
382 
383  for (ip = 0; ip < npix; ip++) {
384 
385  l1rec->pixnum[ip] = ip;
386 
387  if (isnan(lat[ip])) lat[ip] = SKIP;
388  if (isnan(lon[ip])) lon[ip] = SKIP;
389  l1rec->lat[ip] = lat[ip];
390  l1rec->lon[ip] = lon[ip];
391  //printf("ip=%d scan=%d lat=%f lon=%f\n",ip,recnum,lat[ip],lon[ip]);
392 
393  if (l1rec->lon[ip] < -181.0 || l1rec->lon[ip] > 181.0 ||
394  l1rec->lat[ip] < -91.0 || l1rec->lat[ip] > 91.0)
395  l1rec->navfail[ip] = 1;
396 
397  get_zenaz(epos, lon[ip], lat[ip], &l1rec->senz[ip], &l1rec->sena[ip]);
398  get_zenaz(sunpos, lon[ip], lat[ip], &l1rec->solz[ip], &l1rec->sola[ip]);
399 
400  //printf("RJH: %d %d senz=%f sena=%f solz=%f sola=%f\n",recnum, ip, l1rec->senz[ip],l1rec->sena[ip], l1rec->solz[ip],l1rec->sola[ip]);
401 
402 
403  }
404 
405  readBinScanLine_float(l1rec->Lt, recnum, l1rec->npix, data->gain, l1rec->l1file->nbands, data->numBands, data->interleave, 0, data->av_fp);
406 
407  return (LIFE_IS_GOOD);
408 }
409 
410 void prism_proj4_convert(prism_t *data, int numPoints, double *x, double *y) {
411  int i;
412  PJ_COORD c, c_out;
413 
414  // set default z and t
415  c.xyzt.z = 0.0;
416  c.xyzt.t = HUGE_VAL;
417 
418  for (i = 0; i < numPoints; i++) {
419  c.xy.x = x[i];
420  c.xy.y = y[i];
421  c_out = proj_trans(data->pj, PJ_FWD, c);
422  x[i] = c_out.xy.x;
423  y[i] = c_out.xy.y;
424  }
425 }
426 
427 int closel1_prism(filehandle *file) {
428  prism_t* data = (prism_t*) file->private_data;
429 
430  // undo what open allocated
431 
433  free(file->private_data);
434 
435  return 0;
436 }
437 
438 void freePrivateData_pr(prism_t* data) {
439  int k;
440  free(data->gain);
441  for (k = 0; k < data->nscan; k++) {
442  free(data->sena[k]);
443  free(data->senz[k]);
444  free(data->sola[k]);
445  free(data->solz[k]);
446  free(data->utc[k]);
447  }
448  free(data->sena);
449  free(data->senz);
450  free(data->sola);
451  free(data->solz);
452  free(data->utc);
453  gsl_interp_accel_free(data->spl_acc);
454 
455 }
456 
#define SKIP
Definition: l1_prism.c:19
void get_zenaz(float *pos, float lon, float lat, float *senz, float *sena)
Definition: get_zenaz.c:28
int32_t day
real(single), dimension(:,:), allocatable longitude
int closel1_prism(filehandle *file)
Definition: l1_prism.c:427
#define NULL
Definition: decode_rs.h:63
char * getinbasename(char *file)
Definition: jplaeriallib.c:41
const double deg2rad
read l1rec
void trimBlanks(char *str)
Definition: trimBlanks.c:10
real(single), dimension(:,:), allocatable latitude
int readl1_prism(filehandle *file, int recnum, l1str *l1rec, int lonlat)
Definition: l1_prism.c:310
void getPosVec(float lat, float lon, float alt, double *pos)
Definition: jplaeriallib.c:561
char * checknspTagLine(char *line, char *tag)
Definition: jplaeriallib.c:534
float32 * pos
Definition: l1_czcs_hdf.c:35
float * lat
int32 nscan
Definition: l1_czcs_hdf.c:19
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed file
Definition: HISTORY.txt:413
character(len=1000) if
Definition: names.f90:13
#define LIFE_IS_GOOD
Definition: passthebuck.h:4
#define BIL
read recnum
subroutine lonlat(alon, alat, xlon, ylat)
Definition: lonlat.f:2
#define BIP
prism_t * createPrivateData_pr(int numBands, int32_t nscan, int32_t npix)
Definition: l1_prism.c:24
int want_verbose
void unix2yds(double usec, short *year, short *day, double *secs)
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
int openl1_prism(filehandle *file)
Definition: l1_prism.c:45
void freePrivateData_pr(prism_t *data)
Definition: l1_prism.c:438
char * checkTagLine(char *line, char *tag)
Definition: jplaeriallib.c:433
char * unix2isodate(double dtime, char zone)
Definition: unix2isodate.c:10
void prism_proj4_convert(prism_t *data, int numPoints, double *x, double *y)
Definition: l1_prism.c:410
float * lon
double ymds2unix(short year, short month, short day, double secs)
int readBinScanLine_float(float *Lt, int32_t recnum, int32_t npix, double *gain, int nbands, int numBands, int interleave, int swap, FILE *ptr)
Definition: jplaeriallib.c:371
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
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")
#define maxBands
int sunpos(double tjd, double r[3], char **errstr)
int k
Definition: decode_rs.h:73
int npix
Definition: get_cmp.c:27
void l_sun_(int *iyr, int *iday, double *sec, float *sunr, float *rs)