OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
main_l0merge.c
Go to the documentation of this file.
1 /* ==================================================================== */
2 /* */
3 /* SWl0merge - merges multiple L0 files to one optimal file */
4 /* */
5 /* synopsisl: */
6 /* */
7 /* SWl0merge input-L0-listfile [output-L0-file] */
8 /* */
9 /* Description: */
10 /* */
11 /* Takes as input a list of Level-0 filenames and writes a merged */
12 /* Level-0 file. Frames of common type and time are resolved by */
13 /* quality tests based on bit-error counts. Only the best available */
14 /* frame is retained in the merged output. */
15 /* */
16 /* Currently, the program can merge up to 100 files, but this limit can */
17 /* be easily increased. */
18 /* */
19 /* Written By: */
20 /* */
21 /* Bryan A. Franz */
22 /* General Sciences Corp. */
23 /* 13 Septempber 2002 */
24 /* */
25 /* =====================================================================*/
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <libgen.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <time.h>
37 
38 #include "swl0_proto.h"
39 #define MAXFILES 100
40 #define CMD_ARGS "gt:"
41 
42 /* Function to read a list of filenames from a specified file */
43 INT32 read_file_list(char *filename, char files[][FILENAME_MAX], INT32 maxfiles) {
44  FILE *fp = NULL;
45  int nfiles = 0;
46 
47  if ((fp = fopen(filename, "r")) == NULL) {
48  fprintf(stderr,
49  "-W- %s line %d: unable to open %s for reading\n",
50  __FILE__, __LINE__, filename);
51  return (1);
52  }
53 
54  while (nfiles < maxfiles && (fscanf(fp, "%s\n", files[nfiles]) != EOF))
55  if (strlen(files[nfiles]) > 1)
56  nfiles++;
57 
58  fclose(fp);
59 
60  return (nfiles);
61 }
62 
63 /* qsort comparison function for the merged index */
64 int compmindx(swl0mindx *rec1, swl0mindx *rec2) {
65  int retval = 0;
66 
67  /* frame type */
68  if (rec1->qual->mnftype > rec2->qual->mnftype) retval = 1;
69  if (rec1->qual->mnftype < rec2->qual->mnftype) retval = -1;
70 
71  /* frame time within type (+/- 1/60 sec) */
72  if (retval == 0) {
73  if (rec1->qual->time > (rec2->qual->time + DTLAC / 10)) retval = 1;
74  if (rec1->qual->time < (rec2->qual->time - DTLAC / 10)) retval = -1;
75  }
76 
77  /* quality within time */
78  if (retval == 0) {
79  if (rec1->qual->pixVariance > rec2->qual->pixVariance) retval = 1;
80  if (rec1->qual->pixVariance < rec2->qual->pixVariance) retval = -1;
81  }
82  if (retval == 0) {
83  if (rec1->qual->errBits > rec2->qual->errBits) retval = 1;
84  if (rec1->qual->errBits < rec2->qual->errBits) retval = -1;
85  }
86  if (retval == 0) {
87  if (rec1->qual->sgaError > rec2->qual->sgaError) retval = 1;
88  if (rec1->qual->sgaError < rec2->qual->sgaError) retval = -1;
89  }
90  if (retval == 0) {
91  if (rec1->qual->sacError > rec2->qual->sacError) retval = 1;
92  if (rec1->qual->sacError < rec2->qual->sacError) retval = -1;
93  }
94  if (retval == 0) {
95  if (rec1->qual->saaError > rec2->qual->saaError) retval = 1;
96  if (rec1->qual->saaError < rec2->qual->saaError) retval = -1;
97  }
98 
99  /* filename within quality (LAC files take precedence) */
100  if (retval == 0) {
101  if (strstr(rec1->filename, "LAC") != NULL)
102  retval = -1;
103  else if (strstr(rec2->filename, "LAC") != NULL)
104  retval = 1;
105  else if (strstr(rec1->filename, "HNSG") != NULL)
106  retval = -1;
107  else if (strstr(rec2->filename, "HNSG") != NULL)
108  retval = 1;
109  else if (strstr(rec1->filename, "HDUN") != NULL)
110  retval = -1;
111  else if (strstr(rec2->filename, "HDUN") != NULL)
112  retval = 1;
113  else
114  retval = strcmp(rec1->filename, rec2->filename);
115  }
116 
117  return (retval);
118 }
119 
120 /* builds a seawifs-style filename from time and datatype */
121 char *ml0filename(double time, unsigned char dataType) {
122 
123  static char filename[23]; /* "Syyyydddhhmmss.L0_tttt\0" */
124  struct tm *t;
125  time_t itime;
126  double rint(double);
127  char suffix[5] = "MLAC";
128 
129  if (dataType == GACTYPE) strcpy(suffix, "MGAC");
130 
131  itime = (time_t) rint(time); /* Round to nearest second. */
132  t = gmtime(&itime);
133 
134  sprintf(
135  filename,
136  "S%4d%03d%02d%02d%02d.L0_%.4s",
137  t->tm_year + 1900,
138  t->tm_yday + 1,
139  t->tm_hour,
140  t->tm_min,
141  t->tm_sec,
142  suffix
143  );
144 
145  return (filename);
146 }
147 
148 void usage(char *file) {
149  printf("%s %s (%s %s)\n",
150  file, L01VERSION, __DATE__, __TIME__);
151  if (endianess() == 1)
152  printf(" (byte-swapping on)\n");
153  printf("\nUsage: %s [-%s] input-L0-listfile [output-file-name or dir]\n",
154  file, CMD_ARGS);
155  printf(" -g : force GAC processing (allows mixed frame types).\n");
156  printf(" -t n : limit timetags to +/- n-days around data start time. (GAC)\n");
157 
158  exit(FATAL_ERROR);
159 }
160 
161 
162 /* -------------------------------------------------------------------- */
163 /* main */
164 
165 /* -------------------------------------------------------------------- */
166 int main(int argc, char* argv[]) {
167  char *l0listfile = NULL; /* Input L0 list file */
168  char outpath[FILENAME_MAX]; /* Output file dir or path */
169  char l0files[MAXFILES][FILENAME_MAX]; /* Input L0 files */
170  char *filename; /* Output L0 filename */
171  unsigned char dataType = LACTYPE; /* Flag for file naming */
172  struct stat file_stat; /* File status buffer */
173 
174  INT32 irec; /* Record (frame) number */
175  INT32 nfiles = 0; /* Number of input L0 files */
176  INT32 nframes = 0; /* Number of frames in L0 file */
177  INT32 nrecs = 0; /* Number of merged frames */
178  INT32 ntotal = 0; /* Total frames from all files */
179 
180  INT32 filecnt[MAXFILES]; /* Count select frames by file */
181 
182  swl0ctl l0ctl; /* Control str for L0 indexing */
183  swl0indx indx[MAXFILES]; /* L0 file content and quality */
184  swl0mindx *mindx; /* Merged L0 file index */
185 
186 
187  FILE *ifp = NULL; /* Input L0 file pointer */
188  FILE *ofp = NULL; /* Output merged file pointer */
189 
190  swl0hdr hdr; /* Level-0 file header */
191  BYTE mnf[L0LEN]; /* Raw minor frame */
192  INT32 fileBytePos; /* File position of L0 frame */
193 
194  FLOAT64 lasttime;
195  INT32 lastfilenum;
196  INT32 i, j;
197 
198 
199  /* Parameters for getopt() */
200  extern int opterr;
201  extern int optind;
202  extern char *optarg;
203  int c;
204 
205 
206  /* */
207  /* Enable line buffering for better log-file monitoring */
208  /* */
210 
211 
212  /* */
213  /* Initialize control structure */
214  /* */
215  l0ctl.fileType = HRPT; /* Assume HRPT (ignore non-LAC frames)*/
216  l0ctl.timerangeFactor = 0; /* Get timerange limits from hdr (GAC)*/
217  l0ctl.maxBitErrors = 500; /* No effect on SWl0merge */
218  l0ctl.gainSetting = 0; /* No effect on SWl0merge */
219  l0ctl.stopTimeDelta = 3600; /* Stop-time delta (seconds) */
220 
221 
222  /* */
223  /* Process command-line arguments */
224  /* */
225  while ((c = getopt(argc, argv, CMD_ARGS)) != EOF) {
226  switch (c) {
227  case 't':
228  l0ctl.timerangeFactor = atoi(optarg);
229  break;
230  case 'g':
231  l0ctl.fileType = GAC;
232  dataType = GACTYPE;
233  break;
234  default:
235  usage(argv[0]);
236  break;
237  }
238  }
239  switch (argc - optind + 1) {
240  case 3:
241  l0listfile = argv[optind + 0];
242  strcpy(outpath, argv[optind + 1]);
243  break;
244  case 2:
245  l0listfile = argv[optind + 0];
246  strcpy(outpath, ".");
247  break;
248  default:
249  usage(argv[0]);
250  break;
251  }
252 
253 
254  /* */
255  /* Build L0 file list */
256  /* */
257  nfiles = read_file_list(l0listfile, l0files, MAXFILES);
258  if (nfiles <= 0) {
259  printf("-E- %s: error reading list file %s\n", argv[0], l0listfile);
260  exit(FATAL_ERROR);
261  }
262  printf("\nMerging %d files.\n", nfiles);
263  for (i = 0; i < nfiles; i++) printf("File %d: %s\n", i + 1, l0files[i]);
264  printf("\n");
265 
266 
267  /* */
268  /* Loop over each L0 file and create content and quality index */
269  /* */
270  for (i = 0; i < nfiles; i++) {
271  printf("\nGenerating Level-0 file index for %s\n", l0files[i]);
272  filecnt[i] = 0;
273  nframes = getl0indx(l0files[i], &l0ctl, &indx[i]);
274  if (nframes <= 0) {
275  printf("-E- %s: no frames found in %s\n", argv[0], l0files[i]);
276  exit(FATAL_ERROR);
277  }
278  nrecs += nframes;
279  }
280 
281 
282  /* */
283  /* Allocate space for merged index of all files, all frames */
284  /* */
285  if ((mindx = (swl0mindx *) calloc(nrecs, sizeof (swl0mindx))) == NULL) {
286  fprintf(stderr,
287  "-E- %s line %d: error allocating memory for merge index array\n",
288  __FILE__, __LINE__);
289  return (1);
290  }
291 
292 
293  /* */
294  /* Concatenate frame quality indices into merged index */
295  /* */
296  irec = 0;
297  for (i = 0; i < nfiles; i++) {
298  printindx(&indx[i]);
299  for (j = indx[i].srec; j <= indx[i].erec; j++) {
300  if (indx[i].rec[j].tRanError == 0 &&
301  indx[i].rec[j].tSeqError == 0 &&
302  indx[i].rec[j].tDifError == 0 &&
303  indx[i].rec[j].tShfError == 0 &&
304  indx[i].rec[j].scidError == 0) {
305 
306  strcpy(mindx[irec].filename, l0files[i]);
307  mindx[irec].filenum = i;
308  mindx[irec].framenum = j;
309  mindx[irec].qual = &(indx[i].rec[j]);
310  irec++;
311 
312  }
313  }
314  }
315  ntotal = nrecs = irec;
316 
317 
318  /* */
319  /* Sort merged index by time, and quality within time */
320  /* */
321  qsort(mindx, nrecs, sizeof (swl0mindx),
322  (int (*)(const void *, const void *)) compmindx);
323 
324 
325  /* */
326  /* Reduce merged index to unique frame times. Assumes frames have */
327  /* sorted into time order, with "best" quality frame preceeding any */
328  /* lower quality frames. Thus, first frame of each time is selected.*/
329  /* */
330  lasttime = 0.0;
331  irec = 0;
332  for (i = 0; i < nrecs; i++) {
333  if (fabs(mindx[i].qual->time - lasttime) > DTLAC / 10.) {
334  lasttime = mindx[i].qual->time;
335  mindx[irec] = mindx[i];
336  irec++;
337  }
338  }
339  nrecs = irec;
340 
341 
342  /* */
343  /* Construct output filename, or extract from output path. */
344  /* */
345  if (stat(outpath, &file_stat) == 0 && S_ISDIR(file_stat.st_mode)) {
346  filename = ml0filename(mindx[0].qual->time, dataType);
347  strcat(outpath, "/");
348  strcat(outpath, filename);
349  }
350  printf("\nOutput filename is %s\n", outpath);
351 
352 
353  /* */
354  /* Open merged L0 file for writing. */
355  /* */
356  if ((ofp = fopen(outpath, "w")) == NULL) {
357  fprintf(stderr,
358  "-E- %s line %d: unable to open %s for writing\n",
359  __FILE__, __LINE__, outpath);
360  exit(FATAL_ERROR);
361  }
362 
363 
364  /* */
365  /* Construct and write merged L0 file header. */
366  /* */
367  strcpy((char *) hdr.id, "CWIF");
368  hdr.numlines = nrecs;
369  if (dataType == GACTYPE)
370  hdr.type = 0;
371  else
372  hdr.type = 1;
373  hdr.startTime = mindx[0].qual->time;
374  hdr.stopTime = mindx[nrecs - 1].qual->time;
375  if (endianess() == 1) {
376  swapc_bytes((char *) &hdr.startTime, 4, 1);
377  swapc_bytes((char *) &hdr.stopTime, 4, 1);
378  }
379  fwrite(&hdr, 1, 512, ofp);
380 
381 
382  /* */
383  /* Read selected frames, and write to merged output L0 file. */
384  /* */
385  lastfilenum = -1;
386  for (irec = 0; irec < nrecs; irec++) {
387 
388  /* Open L0 file of selected frame, if neccessary */
389  if (mindx[irec].filenum != lastfilenum) {
390  if (ifp != NULL) fclose(ifp);
391  if ((ifp = fopen(mindx[irec].filename, "r")) == NULL) {
392  fprintf(stderr,
393  "-E- %s line %d: unable to open %s for reading\n",
394  __FILE__, __LINE__, mindx[irec].filename);
395  exit(FATAL_ERROR);
396  }
397  lastfilenum = mindx[irec].filenum;
398  }
399 
400  /* Position file pointer to start of selected frame */
401  fileBytePos = sizeof (swl0hdr) + mindx[irec].framenum * (L0LEN);
402  if (fseek(ifp, fileBytePos, SEEK_SET) != 0) {
403  fprintf(stderr,
404  "-E- %s line %d: error reading %s\n",
405  __FILE__, __LINE__, mindx[irec].filename);
406  exit(FATAL_ERROR);
407  }
408 
409  /* Read frame */
410  if (fread(mnf, L0LEN, 1, ifp) != 1) {
411  fprintf(stderr,
412  "-E- %s line %d: error reading %s\n",
413  __FILE__, __LINE__, mindx[irec].filename);
414  exit(FATAL_ERROR);
415  }
416 
417  /* Write frame to merged output */
418  if (fwrite(mnf, L0LEN, 1, ofp) != 1) {
419  fprintf(stderr,
420  "-E- %s line %d: error writing frame %d to %s\n",
421  __FILE__, __LINE__, irec, outpath);
422  exit(FATAL_ERROR);
423  }
424 
425  filecnt[mindx[irec].filenum]++;
426 
427  }
428 
429  fclose(ofp);
430  fclose(ifp);
431 
432  printf("\n\n%d frames selected from %d frames in %d files\n", nrecs, ntotal, nfiles);
433  printf("Compression ratio is %f\n", 1.0 * nrecs / ntotal);
434  for (i = 0; i < nfiles; i++)
435  printf("%10d frames selected from %s\n", filecnt[i], l0files[i]);
436 
437  exit(0);
438 }
439 
440 
441 
442 
443 
INT32 getl0indx(char *filename, swl0ctl *l0ctl, swl0indx *indx)
Definition: getl0indx.c:15
#define DTLAC
Definition: swl0_parms.h:47
data_t t[NROOTS+1]
Definition: decode_rs.h:77
double FLOAT64
Definition: elements.h:8
int j
Definition: decode_rs.h:73
char * ml0filename(double time, unsigned char dataType)
Definition: main_l0merge.c:121
INT32 read_file_list(char *filename, char files[][FILENAME_MAX], INT32 maxfiles)
Definition: main_l0merge.c:43
int16_t * qual
Definition: l2bin.cpp:86
#define NULL
Definition: decode_rs.h:63
int32_t INT32
Definition: elements.h:6
float tm[MODELMAX]
#define LACTYPE
Definition: swl0_parms.h:20
#define GAC
Definition: l1stat.h:33
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed file
Definition: HISTORY.txt:413
int endianess(void)
determine endianess
Definition: endianess.c:10
int swapc_bytes(char *in, int nbyte, int ntime)
Definition: swapc_bytes.c:4
int setlinebuf(FILE *stream)
unsigned char BYTE
Definition: elements.h:4
#define MAXFILES
Definition: main_l0merge.c:39
#define HRPT
Definition: l1stat.h:35
void printindx(swl0indx *indx)
Definition: printindx.c:29
#define FATAL_ERROR
Definition: swl0_parms.h:5
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
#define L01VERSION
Definition: swl0_parms.h:4
#define GACTYPE
Definition: swl0_parms.h:19
#define CMD_ARGS
Definition: main_l0merge.c:40
string outpath
Definition: color_dtdb.py:224
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution offsets between the high resolution geolocation and a bi linear interpolation extrapolation of the positions This can be used to reconstruct the high resolution geolocation Resolved Bug by delaying cumulation of gflags until after validation of derived products Resolved Bug by setting Latitude and Longitude to the correct fill resolving to support Near Real Time because they may be unnecessary if use of entrained ephemeris and attitude data is turned resolving bug report Corrected to filter out Aqua attitude records with missing status helping resolve bug MOD_PR03 will still correctly write scan and pixel data that does not depend upon the start time
Definition: HISTORY.txt:248
int main(int argc, char *argv[])
Definition: main_l0merge.c:166
#define L0LEN
Definition: swl0_parms.h:8
#define fabs(a)
Definition: misc.h:93
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 files
Definition: HISTORY.txt:442
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
double rint(double)
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int compmindx(swl0mindx *rec1, swl0mindx *rec2)
Definition: main_l0merge.c:64
void usage(char *file)
Definition: main_l0merge.c:148