NASA Logo
Ocean Color Science Software

ocssw V2022
l2_generic.c
Go to the documentation of this file.
1 /* =========================================================== */
2 /* Module l2_generic.c */
3 /* */
4 /* Functions to open and write a multi-sensor (generic) l2 */
5 /* file in HDF/NCDF format. */
6 /* */
7 /* Written By: */
8 /* Bryan A. Franz, SAIC GSC, March 1998. */
9 /* Gary Fu, SAIC GSC, March 1999. */
10 /* Joel M. Gales, Futuretech, Sept. 1999. */
11 /* Gene Eplee, SAIC GSC, SeaWiFS Project, December 2000. */
12 /* Update time correction and mirror side */
13 /* factors. */
14 /* Gene Eplee, SAIC, SeaWiFS Project, March 2004. */
15 /* Convert time correction and mirror side */
16 /* factors to simultaneous exponentials. */
17 /* Joel Gales, Futuretech, OBPG Project, Sept 2012. */
18 /* Add support for L2 NETCDF4 output */
19 /* Joel Gales, Futuretech, OBPG Project, Feb 2013. */
20 /* Add support for INT8,UINT8 datatypes for NETCDF4 */
21 /* Joel Gales, Futuretech, OBPG Project, Nov 2013. */
22 /* Add support for CF-compliant metadata */
23 /* =========================================================== */
24 
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <time.h>
31 #include <math.h>
32 #include "l12_proto.h"
33 #include "l2_generic.h"
34 #include <timeutils.h>
35 #include "l2prod.h"
36 #include "l1_aci.h"
37 #include "flags_sst.h"
38 #include "flags_iop.h"
39 #include "mph_flags.h"
40 #include "version.h"
41 #include "l1_seabass.h"
42 #include <scene_meta.h>
43 #include "l1_hawkeye.h"
44 
45 /* Global variables to facilitate communication */
46 static float bad_float = BAD_FLT;
47 //static float fill_float = FIL_FLT;
48 //static float fill_int = FIL_INT;
49 //static float fill_byte = FIL_BYT;
50 static int32 numScans;
51 static int32 numPixels;
52 static int32 numBands;
53 static int32 numLvlProf;
54 static int32 n_refl_loc;
55 static int32 n_cloud_phase;
56 static int32 numBandsIR;
57 static int32 spix;
58 static int32 cpix;
59 static int32 epix;
60 static int32 cscan;
61 
62 static FILE *fp_meta = NULL;
63 
64 #define GEOBOX_INC 20.0
65 
66 /* -------------------------------------------------------- */
67 /* -------------------------------------------------------- */
68 #define RFACTOR 100
69 
70 /* -------------------------------------------------------- */
71 /* Assign SDSes to Vgroups */
72 
73 /* -------------------------------------------------------- */
74 int MakeVgroups(filehandle *l2file) {
75 
76  int32 h_id;
77  int32 v_id;
78  int32 sd_id = l2file->sd_id;
79  int i;
80 
81  /* Do we have the extra meta-data for SeaWiFS */
82  int seawifs_meta = 0;
83  if (l2file->sensorID == SEAWIFS) {
84  int32 sds_id;
85  if (sd_select(sd_id, "scan_ell", &sds_id) == 0)
86  seawifs_meta = 1;
87  }
88 
89  h_id = Hopen(l2file->name, DFACC_RDWR, 0);
90  if (h_id == FAIL) {
91  fprintf(stderr, "-E- %s line %d: Hopen() failed for file, %s.\n",
92  __FILE__, __LINE__, l2file->name);
93  return (HDF_FUNCTION_ERROR);
94  }
95  Vstart(h_id);
96 
97  /* Scan-Line Attributes */
98  DPTB(v_attach(h_id, &v_id));
99  Vsetclass(v_id, "Per File Data");
100  Vsetname(v_id, "Sensor Band Parameters");
101  DPTB(AddSdsToVgroup(sd_id, v_id, "wavelength"));
102  DPTB(AddSdsToVgroup(sd_id, v_id, "vcal_gain"));
103  DPTB(AddSdsToVgroup(sd_id, v_id, "vcal_offset"));
104  DPTB(AddSdsToVgroup(sd_id, v_id, "F0"));
105  DPTB(AddSdsToVgroup(sd_id, v_id, "k_oz"));
106  DPTB(AddSdsToVgroup(sd_id, v_id, "Tau_r"));
107  Vdetach(v_id);
108 
109  if (seawifs_meta) {
110 
111  /* Sensor Tilt */
112  DPTB(v_attach(h_id, &v_id));
113  Vsetclass(v_id, "Per File Data");
114  Vsetname(v_id, "Sensor Tilt");
115  DPTB(AddSdsToVgroup(sd_id, v_id, "ntilts"));
116  DPTB(AddSdsToVgroup(sd_id, v_id, "tilt_flags"));
117  DPTB(AddSdsToVgroup(sd_id, v_id, "tilt_ranges"));
118  Vdetach(v_id);
119 
120  }
121 
122  /* Scan-Line Attributes */
123  DPTB(v_attach(h_id, &v_id));
124  Vsetclass(v_id, "Per Scan Data");
125  Vsetname(v_id, "Scan-Line Attributes");
126  DPTB(AddSdsToVgroup(sd_id, v_id, "year"));
127  DPTB(AddSdsToVgroup(sd_id, v_id, "day"));
128  DPTB(AddSdsToVgroup(sd_id, v_id, "msec"));
129  DPTB(AddSdsToVgroup(sd_id, v_id, "slon"));
130  DPTB(AddSdsToVgroup(sd_id, v_id, "clon"));
131  DPTB(AddSdsToVgroup(sd_id, v_id, "elon"));
132  DPTB(AddSdsToVgroup(sd_id, v_id, "slat"));
133  DPTB(AddSdsToVgroup(sd_id, v_id, "clat"));
134  DPTB(AddSdsToVgroup(sd_id, v_id, "elat"));
135  DPTB(AddSdsToVgroup(sd_id, v_id, "csol_z"));
136  Vdetach(v_id);
137 
138  /* Geophysical Data */
139  DPTB(v_attach(h_id, &v_id));
140  Vsetclass(v_id, "Per Scan Data");
141  Vsetname(v_id, "Geophysical Data");
142  for (i = 0; i < l2file->tot_prod; i++) {
143  DPTB(AddSdsToVgroup(sd_id, v_id, l2file->l2_prod_names[i]));
144  }
145  Vdetach(v_id);
146 
147  /* Navigation */
148  DPTB(v_attach(h_id, &v_id));
149  Vsetclass(v_id, "Per Scan Data");
150  Vsetname(v_id, "Navigation Data");
151  DPTB(AddSdsToVgroup(sd_id, v_id, "longitude"));
152  DPTB(AddSdsToVgroup(sd_id, v_id, "latitude"));
153  DPTB(AddSdsToVgroup(sd_id, v_id, "cntl_pt_cols"));
154  DPTB(AddSdsToVgroup(sd_id, v_id, "cntl_pt_rows"));
155  DPTB(AddSdsToVgroup(sd_id, v_id, "tilt"));
156  if (seawifs_meta) {
157  DPTB(AddSdsToVgroup(sd_id, v_id, "orb_vec"));
158  DPTB(AddSdsToVgroup(sd_id, v_id, "sun_ref"));
159  DPTB(AddSdsToVgroup(sd_id, v_id, "att_ang"));
160  DPTB(AddSdsToVgroup(sd_id, v_id, "sen_mat"));
161  DPTB(AddSdsToVgroup(sd_id, v_id, "scan_ell"));
162  DPTB(AddSdsToVgroup(sd_id, v_id, "nflag"));
163  }
164  Vdetach(v_id);
165 
166  Vend(h_id);
167 
168  if (Hclose(h_id) != SUCCEED) {
169  fprintf(stderr, "-E- %s line %d: Hclose(%d) failed for file, %s .\n",
170  __FILE__, __LINE__, h_id, l2file->name);
171  return (HDF_FUNCTION_ERROR);
172  }
173  return (LIFE_IS_GOOD);
174 }
175 
176 
177 /*----------------------------------------------------------------- */
178 /* Open an L2 file and store global attributes in it. */
179 
180 /* ---------------------------------------------------------------- */
181 int openl2(filehandle *l2file) {
182  char title[256];
183  char soft_id[200]; /* software version info */
184  int32_t tot_prod;
185  VOIDP pbuf;
186 
187  int i, k;
188  l2prodstr *p;
189  char tmp_str[2048];
190  char avhrrbird[10];
191  int flagbits[32];
192  int16_t sstflagbits[16];
193  uint8_t byteflagbits[8];
194  char buf1[1024];
195 
196  idDS ds_id;
197 
198  int32 dm[3];
199  const char dm_name[3][80];
200  char *end_str;
201  float tmpFloat;
202 
203  // strings for the different named global attributes
204  char* calibrationDataStr;
205  char* equatorCrossingLonStr;
206  char* historyStr;
207  char* inputFilesStr;
208  char* maskNamesStr;
209  char* orbitNumberStr;
210  char* processingVersionStr;
211  char* productNameStr;
212  char* softwareNameStr;
213  char* softwareVersionStr;
214  char* titleStr;
215 
216  char* numberOfScanLinesStr;
217  char* pixelsPerScanLineStr;
218  char* bandsPerPixelStr;
219  char* n_refl_loc_str;
220  char* n_cloud_phase_str;
221  char* profLvlPerPixelStr;
222  char* totalBandNumberStr;
223  char* bandNumberStr;
224 
225  char *wavelength_3d_str;
226  int product_3d_exists = 0;
227 
228  int profileProductsExist = 0;
229 
230  if (strcmp(input->metafile, "") != 0) {
231  fp_meta = fopen(input->metafile, "w");
232  if (fp_meta == NULL) {
233  fprintf(stderr,
234  "-E- %s line %d: Unable to open specified meta-data file, %s .\n",
235  __FILE__, __LINE__, input->metafile);
236  return (HDF_FUNCTION_ERROR);
237  }
238  }
239 
240  /* Create the L2 file */
241  ds_format_t fileFormat = DS_NCDF;
242  int32 nt_chr, nt_u8, nt_i16, nt_i32, nt_f32;
243  if (l2file->format == FT_L2HDF) {
244  fileFormat = DS_HDF;
245  nt_chr = DFNT_CHAR;
246  nt_u8 = DFNT_UINT8;
247  nt_i16 = DFNT_INT16;
248  nt_i32 = DFNT_INT32;
249  nt_f32 = DFNT_FLOAT32;
250 
251  calibrationDataStr = "Calibration Data";
252  equatorCrossingLonStr = "Orbit Node Longitude";
253  historyStr = "Processing Control";
254  inputFilesStr = "Input Files";
255  maskNamesStr = "Mask Names";
256  orbitNumberStr = "Orbit Number";
257  processingVersionStr = "Processing Version";
258  productNameStr = "Product Name";
259  softwareNameStr = "Software Name";
260  softwareVersionStr = "Software Version";
261  titleStr = "Title";
262  numberOfScanLinesStr = "Number of Scan Lines";
263  pixelsPerScanLineStr = "Pixels per Scan Line";
264  bandsPerPixelStr = "Bands per Pixel";
265  n_refl_loc_str = "Number of Reflectance Location Values";
266  n_cloud_phase_str = "Number of Cloud Phases";
267  profLvlPerPixelStr = "Profile Levels per Pixel";
268  totalBandNumberStr = "total band number";
269  bandNumberStr = "band number";
270 
271 
272  } else if (l2file->format == FT_L2NCDF) {
273  fileFormat = DS_NCDF;
274  nt_chr = NC_CHAR;
275  nt_u8 = NC_UBYTE;
276  nt_i16 = NC_SHORT;
277  nt_i32 = NC_INT;
278  nt_f32 = NC_FLOAT;
279 
280  calibrationDataStr = "calibration_data";
281  equatorCrossingLonStr = "equatorCrossingLongitude";
282  historyStr = "history";
283  inputFilesStr = "input_sources";
284  maskNamesStr = "mask_names";
285  orbitNumberStr = "orbit_number";
286  processingVersionStr = "processing_version";
287  productNameStr = "product_name";
288  softwareNameStr = "software_name";
289  softwareVersionStr = "software_version";
290  titleStr = "title";
291  numberOfScanLinesStr = "number_of_lines";
292  pixelsPerScanLineStr = "pixels_per_line";
293  bandsPerPixelStr = "bands_per_pixel";
294  profLvlPerPixelStr = "profile_levels_per_pixel";
295  n_refl_loc_str = "number_of_reflectance_location_values";
296  n_cloud_phase_str = "number_of_cloud_phases";
297  totalBandNumberStr = "number_of_bands";
298  bandNumberStr = "number_of_reflective_bands";
299  wavelength_3d_str = "wavelength_3d";
300 
301  } else if ( l2file->format == FT_SEABASSRRS) {
302 
303  seabass *priv = (seabass*)l2file->private_data;
304  priv->fp = fopen(l2file->name, "w");
305 
306  numPixels = l2file->npix;
307  numScans = l2file->nscan;
308  numBands = l2file->nbands;
309  numBandsIR = l2file->nbandsir;
310  spix = 0;
311  cpix = numPixels/2;
312  epix = numPixels-1;
313  cscan = numScans/2;
314 
315  bindex_set(l2file->iwave,l2file->nbands+l2file->nbandsir,BANDW);
316 
317  tot_prod = prodlist(l2file->sensorID,l1_input->evalmask,l2file->l2prod, l2file->def_l2prod,l2file->l2_prod_names);
318 
319  printf("\n\nThe following products will be included in %s.\n",l2file->name);
320  for (i=0; i<tot_prod; i++)
321  printf("%d %s\n",i,l2file->l2_prod_names[i]);
322 
323  l2file->tot_prod = tot_prod;
324 
325  // cache the product and procuctInfo structures
326  l2file->productInfos = (productInfo_t**) allocateMemory(tot_prod * sizeof(productInfo_t*), "l2file->productInfos");
327 
328  l2file->prodptr = (l2prodstr*) allocateMemory(tot_prod * sizeof(l2prodstr), "l2file->prodptr");
329  for (i=0; i<tot_prod; i++) {
330  l2file->productInfos[i] = allocateProductInfo();
331  if(!findProductInfo(l2file->l2_prod_names[i], l2file->sensorID, l2file->productInfos[i])) {
332  fprintf(stderr, "-E- %s line %d: product %s not found.\n", __FILE__,__LINE__, l2file->l2_prod_names[i]);
333  return(1);
334  }
335  }
336  }
337  ds_id = startDS(l2file->name, fileFormat, DS_WRITE, input->deflate);
338  if (ds_id.fid == FAIL) return (HDF_FUNCTION_ERROR);
339  l2file->sd_id = ds_id.fid;
340 
341  /* Get number of bands, pixels, scans */
342  numPixels = l2file->npix;
343  numScans = l2file->nscan;
344  numBands = l2file->nbands;
345  numBandsIR = l2file->nbandsir;
346  numLvlProf = l2file->nlvl;
347  n_refl_loc = l2file->n_refl_loc;
348  n_cloud_phase = l2file->n_cloud_phase;
349  spix = 0;
350  cpix = numPixels / 2;
351  epix = numPixels - 1;
352  cscan = numScans / 2;
353 
354  /* Get number of bands and band indexing from sensor table */
355  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "Bindx", (void **) &l2file->bindx);
356 
357  /* set wavelength index */
358  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "Lambda", (void **) &l2file->iwave);
359  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "fwave", (void **) &l2file->fwave);
360  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "Fobar", (void **) &l2file->Fobar);
361  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "Tau_r", (void **) &l2file->Tau_r);
362  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "k_oz", (void **) &l2file->k_oz);
363  rdsensorinfo(l2file->sensorID, l1_input->evalmask, "k_no2", (void **) &l2file->k_no2);
364 
365  bindex_set(l2file->iwave, l2file->nbands + l2file->nbandsir, BANDW);
366 
367  if (l2file->aw == NULL) {
368  l2file->aw = (float *) allocateMemory(numBands * sizeof (float), "l2file->aw");
369  }
370  if (l2file->bbw == NULL) {
371  l2file->bbw = (float *) allocateMemory(numBands * sizeof (float), "l2file->bbw");
372  }
373  if (l2file->Fonom == NULL) {
374  l2file->Fonom = (float *) allocateMemory(numBands * sizeof (float), "l2file->Fonom");
375  }
376 
377  for (i = 0; i < l2file->nbands; i++) {
378  l2file->aw[i] = aw_spectra(l2file->iwave[i], BANDW);
379  l2file->bbw[i] = bbw_spectra(l2file->iwave[i], BANDW);
380  if (l1_input->outband_opt >= 2) {
381  get_f0_thuillier_ext(l2file->iwave[i], BANDW, l2file->Fonom + i);
382  } else {
383  l2file->Fonom[i] = l2file->Fobar[i];
384  }
385  }
386 
387  /* */
388  /* Build list of dataset names from input parameters */
389  /* ---------------------------------------------------------------- */
390  /* */
391  tot_prod = prodlist(l2file->sensorID, l1_input->evalmask, l2file->l2prod,
392  l2file->def_l2prod, l2file->l2_prod_names);
393 
394  strcpy(l2file->l2_prod_names[tot_prod++], "l2_flags");
395 
396  printf("\n\nThe following products will be included in %s.\n", l2file->name);
397  for (i = 0; i < tot_prod; i++)
398  printf("%d %s\n", i, l2file->l2_prod_names[i]);
399 
400  l2file->tot_prod = tot_prod;
401 
402  // cache the product and procuctInfo structures
403  l2file->productInfos = (productInfo_t**) allocateMemory(tot_prod * sizeof (productInfo_t*), "l2file->productInfos");
404 
405  l2file->prodptr = (l2prodstr*) allocateMemory(tot_prod * sizeof (l2prodstr), "l2file->prodptr");
406  for (i = 0; i < tot_prod; i++) {
407  l2file->productInfos[i] = allocateProductInfo();
408  if (!findProductInfo(l2file->l2_prod_names[i], l2file->sensorID, l2file->productInfos[i])) {
409  fprintf(stderr,
410  "-E- %s line %d: product %s not found.\n",
411  __FILE__, __LINE__, l2file->l2_prod_names[i]);
412  return (1);
413  }
414 
415  if ((p = get_l2prod_index(l2file->l2_prod_names[i], l2file->sensorID,
416  numBands + numBandsIR, numPixels, numScans, l2file->iwave)) == NULL) {
417  fprintf(stderr,
418  "-E- %s line %d: product index failure.\n",
419  __FILE__, __LINE__);
420  return (1);
421  }
422  l2file->prodptr[i] = *p; // need to actually copy all the memory
423 
424  // see if any 3D products are requested
425  if(p->rank == 3) {
426  product_3d_exists = 1;
427  }
428 
429  }
430 
431  // see if there are any profile products so we don't add profile stuff that is not needed
432  for (i = 0; i < tot_prod; i++) {
433  if( strcmp( l2file->productInfos[i]->category, "Anc_profile" ) == 0 ) {
434  profileProductsExist = 1;
435  break;
436  }
437  }
438 
439  if (l2file->format == FT_L2NCDF) {
440  int dumdim;
441  if (nc_def_dim(ds_id.fid, numberOfScanLinesStr, numScans, &dumdim)
442  != NC_NOERR) exit(1);
443  if (nc_def_dim(ds_id.fid, pixelsPerScanLineStr, numPixels, &dumdim)
444  != NC_NOERR) exit(1);
445  if ( nc_def_dim(ds_id.fid, bandsPerPixelStr, numBands, &dumdim)
446  != NC_NOERR) exit(1);
447  if (profileProductsExist) {
448  if ( nc_def_dim(ds_id.fid, profLvlPerPixelStr, numLvlProf, &dumdim)
449  != NC_NOERR) exit(1);
450  }
451  if (nc_def_dim(ds_id.fid, n_refl_loc_str, n_refl_loc, &dumdim)
452  != NC_NOERR) exit(1);
453  if (nc_def_dim(ds_id.fid, n_cloud_phase_str, n_cloud_phase, &dumdim)
454  != NC_NOERR) exit(1);
455  if (nc_def_dim(ds_id.fid, totalBandNumberStr, numBands + numBandsIR, &dumdim)
456  != NC_NOERR) exit(1);
457  if (nc_def_dim(ds_id.fid, bandNumberStr, numBands, &dumdim)
458  != NC_NOERR) exit(1);
459  if(product_3d_exists) {
460  if (nc_def_dim(ds_id.fid, wavelength_3d_str, input->nwavelengths_3d, &dumdim)
461  != NC_NOERR) exit(1);
462  }
463 
464  nc_def_grp(ds_id.fid, "sensor_band_parameters", &l2file->grp_id[0]);
465  nc_def_grp(ds_id.fid, "scan_line_attributes", &l2file->grp_id[2]);
466  nc_def_grp(ds_id.fid, "geophysical_data", &l2file->grp_id[3]);
467  nc_def_grp(ds_id.fid, "navigation_data", &l2file->grp_id[4]);
468  nc_def_grp(ds_id.fid, "processing_control", &l2file->grp_id[5]);
469  }
470 
471 
472  /* */
473  /* Create the scan-line datasets */
474  /* ---------------------------------------------------------------- */
475  /* */
476  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[2];
477 
478  dm[0] = numScans;
479  strcpy((char *) dm_name[0], numberOfScanLinesStr);
480  dm[1] = numPixels;
481  strcpy((char *) dm_name[1], pixelsPerScanLineStr);
482 
483  PTB(createDS(ds_id, (int) l2file->sensorID, "year", dm, dm_name));
484  PTB(createDS(ds_id, (int) l2file->sensorID, "day", dm, dm_name));
485  PTB(createDS(ds_id, (int) l2file->sensorID, "msec", dm, dm_name));
486  PTB(createDS(ds_id, (int) l2file->sensorID, "time", dm, dm_name));
487  PTB(createDS(ds_id, (int) l2file->sensorID, "detnum", dm, dm_name));
488  PTB(createDS(ds_id, (int) l2file->sensorID, "mside", dm, dm_name));
489  PTB(createDS(ds_id, (int) l2file->sensorID, "slon", dm, dm_name));
490  PTB(createDS(ds_id, (int) l2file->sensorID, "clon", dm, dm_name));
491  PTB(createDS(ds_id, (int) l2file->sensorID, "elon", dm, dm_name));
492  PTB(createDS(ds_id, (int) l2file->sensorID, "slat", dm, dm_name));
493  PTB(createDS(ds_id, (int) l2file->sensorID, "clat", dm, dm_name));
494  PTB(createDS(ds_id, (int) l2file->sensorID, "elat", dm, dm_name));
495  PTB(createDS(ds_id, (int) l2file->sensorID, "csol_z", dm, dm_name));
496 
497  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[4];
498 
499  PTB(createDS(ds_id, (int) l2file->sensorID, "longitude", dm, dm_name));
500  PTB(createDS(ds_id, (int) l2file->sensorID, "latitude", dm, dm_name));
501  PTB(createDS(ds_id, (int) l2file->sensorID, "tilt", dm, dm_name));
502 
503  /* */
504  /* Create the geophysical datasets */
505  /* ---------------------------------------------------------------- */
506  /* */
507  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[3];
508 
509  for (i = 0; i < tot_prod; i++) {
510  // Skip parameters already included if user requested them specifically
511  if (!strcmp(l2file->l2_prod_names[i], "detnum") ||
512  !strcmp(l2file->l2_prod_names[i], "mside") ||
513  !strcmp(l2file->l2_prod_names[i], "year") ||
514  !strcmp(l2file->l2_prod_names[i], "day") ||
515  !strcmp(l2file->l2_prod_names[i], "msec") ||
516  !strcmp(l2file->l2_prod_names[i], "time") ||
517  !strcmp(l2file->l2_prod_names[i], "slon") ||
518  !strcmp(l2file->l2_prod_names[i], "clon") ||
519  !strcmp(l2file->l2_prod_names[i], "elon") ||
520  !strcmp(l2file->l2_prod_names[i], "slat") ||
521  !strcmp(l2file->l2_prod_names[i], "clat") ||
522  !strcmp(l2file->l2_prod_names[i], "elat") ||
523  !strcmp(l2file->l2_prod_names[i], "csol_z") ||
524  !strcmp(l2file->l2_prod_names[i], "latitude") ||
525  !strcmp(l2file->l2_prod_names[i], "longitude") ||
526  !strcmp(l2file->l2_prod_names[i], "tilt")
527  )
528  continue;
529 
530  /* the 3rd dimension can now change - so determine it per-product */
531  if( strcmp( l2file->productInfos[i]->category, "Anc_profile" ) == 0 ) {
532  dm[2] = numLvlProf;
533  strcpy((char *) dm_name[2], profLvlPerPixelStr );
534  }else if( strcmp( l2file->productInfos[i]->category,
535  "Reflectance_loc" ) == 0 ) {
536  dm[2] = n_refl_loc;
537  strcpy((char *) dm_name[2], n_refl_loc_str );
538  }else if( strcmp( l2file->productInfos[i]->category,
539  "CTH_parameters" ) == 0 ) {
540  dm[2] = n_cloud_phase;
541  strcpy((char *) dm_name[2], n_cloud_phase_str );
542  }else {
543  dm[2] = input->nwavelengths_3d;
544  strcpy((char *) dm_name[2], wavelength_3d_str);
545  }
546 
547  PTB(createDS2(ds_id, l2file->l2_prod_names[i], l2file->productInfos[i],
548  dm, dm_name));
549 
550  ds_id.sid = selectDS(ds_id, l2file->l2_prod_names[i]);
551 
552  /* */
553  /* Add flag-name attributes if this is a flag product */
554  /* */
555  if ((strcmp(l2file->l2_prod_names[i], "l2_flags") == 0) ||
556  (strcmp(l2file->l2_prod_names[i], "flags_sst") == 0) ||
557  (strcmp(l2file->l2_prod_names[i], "flags_sst3") == 0) ||
558  (strcmp(l2file->l2_prod_names[i], "flags_sst4") == 0) ||
559  (strcmp(l2file->l2_prod_names[i], "qual_sst") == 0) ||
560  (strcmp(l2file->l2_prod_names[i], "qual_sst3") == 0) ||
561  (strcmp(l2file->l2_prod_names[i], "qual_sst4") == 0) ||
562  (strcmp(l2file->l2_prod_names[i], "flags_habs") == 0) ||
563  (strcmp(l2file->l2_prod_names[i], "flags_mph") == 0)) {
564 
565  if ((strcmp(l2file->l2_prod_names[i], "l2_flags") == 0)) {
566  tmp_str[0] = '\0';
567  int32_t val = 1;
568  for (k = 0; k < L1_NFLAGS; k++) {
569  // in case if the geo_mask is set. GEOREGION = SPARE1
570  if( k == 7 && input->georegionfile[0])
571  strcat(tmp_str, "GEOREGION");
572  else
573  strcat(tmp_str, l2_flag_lname[k]);
574 
575  flagbits[k] = val;
576  val = val << 1;
577  if (k < L1_NFLAGS - 1)
578  strcat(tmp_str, " ");
579  /*
580  * Keep the old flag attribute set for HDF4 files
581  */
582  if (l2file->format == FT_L2HDF) {
583  PTB(setAttr(ds_id, l2_flag_sname[k], nt_chr,
584  strlen(l2_flag_lname[k]) + 1, (VOIDP) l2_flag_lname[k]));
585  }
586  }
587  PTB(setAttr(ds_id, "flag_masks", nt_i32, L1_NFLAGS, (VOIDP) flagbits));
588 
589  } else if ((strcmp(l2file->l2_prod_names[i], "flags_sst") == 0) ||
590  (strcmp(l2file->l2_prod_names[i], "flags_sst3") == 0) ||
591  (strcmp(l2file->l2_prod_names[i], "flags_sst4") == 0)) {
592  tmp_str[0] = '\0';
593  int16_t val = 1;
594  for (k = 0; k < NSSTFLAGS; k++) {
595  sstflagbits[k] = val;
596  val = val << 1;
597  if (l2file->sensorID == AVHRR) {
598  strcat(tmp_str, avhrr_sst_flag_lname[k]);
599  } else if ((l2file->sensorID == VIIRSN) ||
600  (l2file->sensorID == VIIRSJ1) ||
601  (l2file->sensorID == VIIRSJ2)) {
602  strcat(tmp_str, viirs_sst_flag_lname[k]);
603  } else {
604  strcat(tmp_str, sst_flag_lname[k]);
605  }
606  if (k < NSSTFLAGS - 1)
607  strcat(tmp_str, " ");
608  }
609  PTB(setAttr(ds_id, "flag_masks", nt_i16, NSSTFLAGS, (VOIDP) sstflagbits));
610 
611  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst") == 0) ||
612  (strcmp(l2file->l2_prod_names[i], "qual_sst3") == 0) ||
613  (strcmp(l2file->l2_prod_names[i], "qual_sst4") == 0)) {
614  tmp_str[0] = '\0';
615  for (k = 0; k < NQSSTFLAGS; k++) {
616  sstflagbits[k] = k;
617  strcat(tmp_str, qual_sst_flag_lname[k]);
618  if (k < NQSSTFLAGS - 1)
619  strcat(tmp_str, " ");
620  }
621  PTB(setAttr(ds_id, "flag_masks", nt_i16, NQSSTFLAGS, (VOIDP) sstflagbits));
622 
623  } else if ((strcmp(l2file->l2_prod_names[i], "flags_mph") == 0)) {
624  tmp_str[0] = '\0';
625  uint8_t val = 1;
626  for (k = 0; k < NMPHFLAGS; k++) {
627  byteflagbits[k] = val;
628  val = val << 1;
629  strcat(tmp_str, mph_flag_lname[k]);
630  if (k < NMPHFLAGS - 1)
631  strcat(tmp_str, " ");
632  }
633  PTB(setAttr(ds_id, "flag_masks", nt_u8, NMPHFLAGS, (VOIDP) byteflagbits));
634  } else if ((strcmp(l2file->l2_prod_names[i], "flags_habs") == 0)) {
635  tmp_str[0] = '\0';
636  uint8_t val = 1;
637  for (k = 0; k < NHABSFLAGS; k++) {
638  byteflagbits[k] = val;
639  val = val << 1;
640  strcat(tmp_str, habs_flag_lname[k]);
641  if (k < NHABSFLAGS - 1)
642  strcat(tmp_str, " ");
643  }
644  PTB(setAttr(ds_id, "flag_masks", nt_u8, NHABSFLAGS, (VOIDP) byteflagbits));
645  }
646  PTB(setAttr(ds_id, "flag_meanings", nt_chr, strlen(tmp_str) + 1, (VOIDP) tmp_str));
647 
648  }
649  /* */
650  /* Add solar irradiance meta-data if this is the nLw or Rrs */
651  /* */
652  p = l2file->prodptr + i; // get product structure from cache
653  switch (p->cat_ix) {
654  case CAT_nLw:
655  case CAT_Rrs:
656  if(p->prod_ix != -1) {
657  tmpFloat = l2file->Fonom[p->prod_ix] * 10.0;
658  PTB(setAttr(ds_id, "solar_irradiance", nt_f32, 1, &tmpFloat));
659  }
660  }
661  /* */
662  /* Add bad value attributes to HDF4 files */
663  /* */
664  if ((l2file->format == FT_L2HDF) && ((strcmp(l2file->l2_prod_names[i], "l2_flags") != 0) ||
665  (strcmp(l2file->l2_prod_names[i], "flags_sst") != 0) ||
666  (strcmp(l2file->l2_prod_names[i], "flags_sst3") != 0) ||
667  (strcmp(l2file->l2_prod_names[i], "flags_sst4") != 0))) {
668 
669  switch (p->datatype) {
670  case DFNT_UINT8:
671  pbuf = (VOIDP) float2uint8((VOIDP) & bad_float, 0, 1, 1, p->slope, p->offset);
672  setAttr(ds_id, "bad_value_scaled", nt_chr, 1, pbuf);
673  pbuf = (VOIDP) unscale_sds(pbuf, l2file->productInfos[i], 0, 1, 1);
674  setAttr(ds_id, "bad_value_unscaled", nt_f32, 1, pbuf);
675  break;
676  case DFNT_INT16:
677  pbuf = (VOIDP) float2int16((VOIDP) & bad_float, 0, 1, 1, p->slope, p->offset);
678  setAttr(ds_id, "bad_value_scaled", nt_i16, 1, pbuf);
679  pbuf = (VOIDP) unscale_sds(pbuf, l2file->productInfos[i], 0, 1, 1);
680  setAttr(ds_id, "bad_value_unscaled", nt_f32, 1, pbuf);
681  break;
682  case DFNT_INT32:
683  break;
684  case DFNT_FLOAT32:
685  setAttr(ds_id, "bad_value_scaled", nt_f32, 1, &bad_float);
686  setAttr(ds_id, "bad_value_unscaled", nt_f32, 1, &bad_float);
687  break;
688  default:
689  break;
690  }
691  }
692 
693  endaccessDS(ds_id);
694  }
695 
696  /* */
697  /* Create the Sensor Band Parameters datasets */
698  /* ---------------------------------------------------------------- */
699  /* */
700  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[0];
701 
702  dm[0] = numBands + numBandsIR;
703  strcpy((char *) dm_name[0], totalBandNumberStr);
704  PTB(createDS(ds_id, l2file->sensorID, "wavelength", dm, dm_name));
705 
706  if(product_3d_exists) {
707  dm[0] = input->nwavelengths_3d;
708  strcpy((char *) dm_name[0], wavelength_3d_str);
709  PTB(createDS(ds_id, l2file->sensorID, "wavelength_3d", dm, dm_name));
710  }
711 
712  dm[0] = numBands;
713  strcpy((char *) dm_name[0], bandNumberStr);
714 
715  if (numBands > 0) {
716  PTB(createDS(ds_id, l2file->sensorID, "vcal_gain", dm, dm_name));
717  PTB(createDS(ds_id, l2file->sensorID, "vcal_offset", dm, dm_name));
718  PTB(createDS(ds_id, l2file->sensorID, "F0", dm, dm_name));
719  PTB(createDS(ds_id, l2file->sensorID, "aw", dm, dm_name));
720  PTB(createDS(ds_id, l2file->sensorID, "bbw", dm, dm_name));
721  PTB(createDS(ds_id, l2file->sensorID, "k_oz", dm, dm_name));
722  PTB(createDS(ds_id, l2file->sensorID, "k_no2", dm, dm_name));
723  PTB(createDS(ds_id, l2file->sensorID, "Tau_r", dm, dm_name));
724  }
725 
726  /* */
727  /* Write out some global attributes */
728  /* ---------------------------------------------------------------- */
729  /* */
730  if (input->suite[0])
731  sprintf(title, "%s Level-2 Data %s", sensorId2SensorName(l2file->sensorID), input->suite);
732  else
733  sprintf(title, "%s Level-2 Data", sensorId2SensorName(l2file->sensorID));
734  sprintf(soft_id, "%d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, GITSHA);
735 
736  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->sd_id;
737 
738  PTB(SetChrGA(ds_id, titleStr, title));
739  PTB(SetChrGA(ds_id, productNameStr, basename(l2file->name)));
740  PTB(SetChrGA(ds_id, processingVersionStr, l1_input->pversion));
741  if (l2file->orbit_node_lon > -180.0 && l2file->orbit_node_lon < 180.0)
742  PTB(SetF32GA(ds_id, equatorCrossingLonStr, l2file->orbit_node_lon));
743  if (l2file->orbit_number > 0)
744  PTB(SetI32GA(ds_id, orbitNumberStr, l2file->orbit_number));
745  PTB(SetChrGA(ds_id, historyStr, input->pro_control));
746 
747  // Processing Control attibutes
748  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[5];
749  PTB(SetChrGA(ds_id, softwareNameStr, PROGRAM));
750  PTB(SetChrGA(ds_id, softwareVersionStr, soft_id));
751  PTB(SetChrGA(ds_id, inputFilesStr, l1_input->input_files));
752 
753  // cleanup and populate calfile metadata
754  char *calfile_str;
755  if ((calfile_str = malloc(strlen(l1_input->calfile) + 1)) == NULL) {
756  fprintf(stderr, "-E- %s line %d: Unable to copy calfile string.\n",
757  __FILE__, __LINE__);
758  exit(1);
759  }
760  strcpy(calfile_str, "\0");
761  char *tmp_calfile;
762  if ((tmp_calfile = strdup(l1_input->calfile)) == NULL) {
763  fprintf(stderr, "-E- %s line %d: Unable to copy calfile string.\n",
764  __FILE__, __LINE__);
765  exit(1);
766  }
767 
768  char *token = strtok_r(tmp_calfile, ",", &end_str);
769  while (token != NULL) {
770  strcpy(tmp_str, token);
771  trimBlanks(tmp_str);
772  strcat(calfile_str, basename(tmp_str));
773  token = strtok_r(NULL, ",", &end_str);
774  if (token != NULL)
775  strcat(calfile_str, ", ");
776  }
777  free(tmp_calfile);
778 
779  PTB(SetChrGA(ds_id, calibrationDataStr, calfile_str));
780 
781  PTB(SetChrGA(ds_id, maskNamesStr, input->mask_names));
782 
783  if (l2file->format == FT_L2NCDF) {
784  // write out netCDF specific attributes
785 
786  // global attr
787  ds_id.fid = l2file->sd_id;
788  PTB(SetChrGA(ds_id, "instrument", sensorId2InstrumentName(l2file->sensorID)));
789 
790  if (l2file->sensorID == AVHRR) {
791  strcpy(avhrrbird, "NOAA-");
792 #ifdef BUILD_HISTORICAL
793  strncat(avhrrbird, xsatid2name(l2file->subsensorID) + 2, 2);
794 #endif
795  PTB(SetChrGA(ds_id, "platform", avhrrbird));
796  } else {
797  PTB(SetChrGA(ds_id, "platform", sensorId2PlatformName(l2file->sensorID)));
798  }
799  PTB(SetChrGA(ds_id, "Conventions", "CF-1.8 ACDD-1.3"));
800  PTB(SetChrGA(ds_id, "license", LICENSE));
801  PTB(SetChrGA(ds_id, "naming_authority", NAMING_AUTHORITY));
802  // create the id -
803  if (strcmp(l1_input->pversion, "Unspecified") != 0) {
804  strcpy(buf1, l1_input->pversion);
805  strcat(buf1, "/L2/");
806  } else {
807  strcpy(buf1, "L2/");
808  }
809  strcat(buf1, basename(l2file->name));
810  PTB(SetChrGA(ds_id, "id", buf1));
811 
812 
813  time_t tnow;
814  time(&tnow);
815  strcpy(buf1, unix2isodate(tnow, 'G'));
816  PTB(SetChrGA(ds_id, "date_created", buf1));
817 
818  const char* keywordStr = getGCMDKeywords(input->suite);
819  if(keywordStr) {
820  PTB(SetChrGA(ds_id, "keywords_vocabulary", KEYWORDS_VOCABULARY));
821  PTB(SetChrGA(ds_id, "keywords", keywordStr));
822  }
823 
824  PTB(SetChrGA(ds_id, "standard_name_vocabulary", STDNAME_VOCABULARY));
825  PTB(SetChrGA(ds_id, "institution", INSTITUTION));
826  PTB(SetChrGA(ds_id, "creator_name", CREATOR_NAME));
827  PTB(SetChrGA(ds_id, "creator_email", CREATOR_EMAIL));
828  PTB(SetChrGA(ds_id, "creator_url", CREATOR_URL));
829  PTB(SetChrGA(ds_id, "project", PROJECT));
830  PTB(SetChrGA(ds_id, "publisher_name", PUBLISHER_NAME));
831  PTB(SetChrGA(ds_id, "publisher_url", PUBLISHER_URL));
832  PTB(SetChrGA(ds_id, "publisher_email", PUBLISHER_EMAIL));
833 
834  //Some missions have DOIs
835  if(strlen(input->doi) > 0) {
836  PTB(SetChrGA(ds_id, "identifier_product_doi_authority", "http://dx.doi.org"));
837  PTB(SetChrGA(ds_id, "identifier_product_doi", input->doi));
838  }
839 
840  PTB(SetChrGA(ds_id, "processing_level", "L2"));
841  PTB(SetChrGA(ds_id, "cdm_data_type", "swath"));
842  // if (strlen(l2file->node_crossing_time) > 1) {
843  if (l2file->node_crossing_time > 0) {
844  // double eqcrosstm = zulu2unix(l2file->node_crossing_time);
845  strcpy(buf1, unix2isodate(l2file->node_crossing_time, 'G'));
846  PTB(SetChrGA(ds_id, "equatorCrossingDateTime", buf1));
847  }
848 
849  PTB(SetChrGA(ds_id, "spatialResolution", l2file->spatialResolution));
850 
851  if (l2file->sensorID == HAWKEYE) {
852  hawkeye_t *data = (hawkeye_t*)l2file->private_data;
853  PTB(SetI32GA(ds_id, "exposureID", (data->exposureID)));
854 
855  // change to navigation group
856  ds_id.fid = l2file->grp_id[4];
857  PTB(SetF32GA(ds_id, "roll_offset", (data->roll_offset)));
858  PTB(SetF32GA(ds_id, "time_offset", (data->time_offset)));
859  }
860 
861  // Write input parameters metadata
862  ds_id.fid = l2file->grp_id[5];
863  int32_t grp_id_input_parms;
864  nc_def_grp(l2file->grp_id[5], "input_parameters", &grp_id_input_parms);
865  ds_id.fid = grp_id_input_parms;
866 
867  char *tmp_parms = replace_ocroots(l1_input->input_parms);
868  char *token = strtok_r(tmp_parms, "\n", &end_str);
869  while (token != NULL) {
870  char *end_token;
871  char *name = strtok_r(token, "=", &end_token);
872  trimBlanks(name);
873  char *value = strtok_r(NULL, ";", &end_token);
874  trimBlanks(value);
875  if (name[0] != '#') {
876  PTB(SetChrGA(ds_id, name, value));
877  }
878  token = strtok_r(NULL, "\n", &end_str);
879  }
880  free(tmp_parms);
881 
882  } else {
883 
884  // write out HDF4 specific attributes
885  PTB(SetChrGA(ds_id, "Sensor Name", sensorId2SensorName(l2file->sensorID)));
886  PTB(SetChrGA(ds_id, "Mission", sensorId2PlatformName(l2file->sensorID)));
887  PTB(SetI32GA(ds_id, "Number of Bands", numBands));
888  if(profileProductsExist)
889  PTB(SetI32GA(ds_id, "Number of Profile Levels", numLvlProf));
890  PTB(SetI32GA(ds_id, "Number of Scan Lines", numScans));
891  PTB(SetI32GA(ds_id, "Pixels per Scan Line", numPixels));
892  PTB(SetI32GA(ds_id, "Scene Center Scan Line", cscan));
893 
894  PTB(SetChrGA(ds_id, "Node Crossing Time", ydhmsf(l2file->node_crossing_time, 'G')));
895  PTB(SetChrGA(ds_id, "Processing Time", ydhmsf(now(), 'G')));
896  PTB(SetChrGA(ds_id, "Input Parameters", l1_input->input_parms));
897 
898  }
899 
900  /* */
901  /* Write out some global datasets */
902  /* ---------------------------------------------------------------- */
903  /* */
904  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[0];
905  PTB(writeDS(ds_id, "wavelength", l2file->iwave, 0, 0, 0, numBands + numBandsIR, 0, 0));
906 
907  if(product_3d_exists) {
908  PTB(writeDS(ds_id, "wavelength_3d", input->wavelength_3d, 0, 0, 0, input->nwavelengths_3d, 0, 0));
909  }
910 
911  if (numBands > 0) {
912  PTB(writeDS(ds_id, "vcal_gain", l1_input->gain, 0, 0, 0, numBands, 0, 0));
913  PTB(writeDS(ds_id, "vcal_offset", l1_input->offset, 0, 0, 0, numBands, 0, 0));
914 
915  // multiply by 10 to put into W/m2/um, since internally all radiances are mW/cm2/um
916  float tmpFobar[numBands];
917  for (i = 0; i < numBands; i++)
918  tmpFobar[i] = l2file->Fobar[i] * 10.0;
919  PTB(writeDS(ds_id, "F0", tmpFobar, 0, 0, 0, numBands, 0, 0));
920 
921  PTB(writeDS(ds_id, "aw", l2file->aw, 0, 0, 0, numBands, 0, 0));
922  PTB(writeDS(ds_id, "bbw", l2file->bbw, 0, 0, 0, numBands, 0, 0));
923  PTB(writeDS(ds_id, "k_oz", l2file->k_oz, 0, 0, 0, numBands, 0, 0));
924  PTB(writeDS(ds_id, "k_no2", l2file->k_no2, 0, 0, 0, numBands, 0, 0));
925  PTB(writeDS(ds_id, "Tau_r", l2file->Tau_r, 0, 0, 0, numBands, 0, 0));
926  }
927 
928  free(calfile_str);
929 
930  return (LIFE_IS_GOOD);
931 }
932 
933 
934 /*----------------------------------------------------------------- */
935 /* Update scan-line datasets for the specified scan. */
936 
937 /* ---------------------------------------------------------------- */
938 
939 int writel2(filehandle *l2file, int32_t recnum, l2str *l2rec, int outfile_number) {
940  static int32 *buf = NULL;
941  static float fsol = -1.0;
942  VOIDP pbuf;
943  int32 i, j;
944  l2prodstr *p;
945 
946  idDS ds_id;
947  static int32_t l2_flag_cnt[L1_NFLAGS];
948  static int32_t sst_flag_cnt[NSSTFLAGS];
949  static int32_t sst3_flag_cnt[NSSTFLAGS];
950  static int32_t sst4_flag_cnt[NSSTFLAGS];
951  static int32_t giop_flag_cnt[NGIOPFLAGS];
952  static int32_t qualsst_flag_cnt[NQSSTFLAGS];
953  static int32_t qualsst3_flag_cnt[NQSSTFLAGS];
954  static int32_t qualsst4_flag_cnt[NQSSTFLAGS];
955  static int32_t qaa_flag_cnt[1] = {0};
956  static int32_t carder_flag_cnt[1] = {0};
957  static int32_t niwa_flag_cnt[1] = {0};
958  static const char *flag_lname[1] = {"PRODFAIL"};
959 
960  static uint8_t first = 1;
961  static float last_lat;
962  static float geobox[4][100];
963  static int32 geobox_cnt = 0;
964  float gring_fval[100];
965  int32 gring_ival[100];
966 
967 
968  if (l2file->format == FT_SEABASSRRS) {
969  seabass *priv = (seabass*)l2file->private_data;
970  if (first) {
971  char buffer[2048];
972  priv->fp = fopen(l2rec->l1rec->l1file->name, "r");
973  while (1) {
974  fgets(buffer, 2047, priv->fp);
975 
976  int32_t fld_cnt = 0;
977  int32_t count = 0;
978  char value[128];
979 
980  // Write only Rrs fieldnames to output file
981  if (strncmp(buffer, "/fields=", 8) == 0) {
982  char *token = strtok(&buffer[8], ",");
983  memcpy(value, buffer, 8);
984  value[8] = 0;
985  fputs(value, priv->fp);
986 
987  // Loop through comma-separated fieldnames
988  while (token != NULL) {
989  strcpy(value, token);
990 
991  // Get index of next Rrs field
992  char *ptr =
993  (char *) (l2rec->l1rec->l1file->private_data+count*sizeof(int32_t));
994  int32_t fld_idx;
995  memcpy(&fld_idx, ptr, sizeof(int32_t));
996 
997  // If field in data string is desired Rrs field than write to output file
998  if (fld_cnt == fld_idx) {
999  if (count != (l2file->nbands-1)) {
1000  strcat(value, ",");
1001  } else {
1002  if (value[strlen(value)-1] == '\n') value[strlen(value)-1] = 0;
1003  strcat(value, ",");
1004  }
1005  // printf("%s\n", value);
1006  fputs(value, priv->fp);
1007  count++;
1008  if (count == l2file->nbands) {
1009  strcpy(value, l2file->productInfos[0]->prefix);
1010  strcat(value, l2file->productInfos[0]->suffix);
1011  fputs(value, priv->fp);
1012  fputs("\n", priv->fp);
1013  }
1014  }
1015 
1016  token = strtok(NULL, ",");
1017  fld_cnt++;
1018  } // end while
1019  } else if (strncmp(buffer, "/units=", 7) == 0) {
1020  char *token = strtok(&buffer[8], ",");
1021  memcpy(value, buffer, 7);
1022  value[7] = 0;
1023  fputs(value, priv->fp);
1024 
1025  // Loop through comma-separated fieldnames
1026  while (token != NULL) {
1027  strcpy(value, token);
1028 
1029  // Get index of next Rrs unit
1030  char *ptr = (char *) (l2rec->l1rec->l1file->private_data+count*sizeof(int32_t));
1031  int32_t fld_idx;
1032  memcpy(&fld_idx, ptr, sizeof(int32_t));
1033 
1034  // If unit in data string is desired Rrs unit than write to output file
1035  if (fld_cnt == fld_idx) {
1036  if (count != (l2file->nbands-1)) {
1037  strcat(value, ",");
1038  } else {
1039  if (value[strlen(value)-1] == '\n') value[strlen(value)-1] = 0;
1040  strcat(value, ",");
1041  }
1042  fputs(value, priv->fp);
1043  count++;
1044  if (count == l2file->nbands) {
1045  strcpy(value, l2file->productInfos[0]->units);
1046  fputs(value, priv->fp);
1047  fputs("\n", priv->fp);
1048  }
1049  }
1050 
1051  token = strtok(NULL, ",");
1052  fld_cnt++;
1053  } // end while
1054  } else if (strncmp(buffer, "/end_header", 11) == 0){
1055  fputs(buffer, priv->fp);
1056  break;
1057  } else {
1058  fputs(buffer, priv->fp);
1059  }
1060 
1061  } // while loop
1062  first = 0;
1063  } // if first
1064  // fclose(priv->fp);
1065 
1066  for (i=0; i<l2file->tot_prod; i++) {
1067  // get the product index record
1068  p = l2file->prodptr + i; // get product structure from cache
1069  // extract the product and scale (if needed)
1070  pbuf = prodgen(p,l2rec);
1071  if (p->slope != 1.0 || p->offset != 0.0) {
1072  pbuf = scale_sds( pbuf, l2file->productInfos[i], l2file->npix);
1073  }
1074 
1075  char buffer[2048];
1076 
1077  // if chlor_a then write Rrs value to output file
1078  if (strcmp(l2file->productInfos[i]->productName, "chlor_a") == 0) {
1079  for (j=0; j<l2file->nbands; j++) {
1080  sprintf(buffer, "%15.6e", l2rec->Rrs[j]);
1081  fputs(buffer, priv->fp);
1082  }
1083  }
1084 
1085  // write pbuf to output text file
1086  float f;
1087  memcpy(&f, pbuf, sizeof(float));
1088  sprintf(buffer, "%15.6f\n", f);
1089  fputs(buffer, priv->fp);
1090 
1091  return 0;
1092  }
1093  } // SeaBASS
1094  ds_id.deflate = 0;
1095  ds_id.fid = l2file->sd_id;
1096  if (l2file->format == FT_L2NCDF)
1097  ds_id.fftype = DS_NCDF;
1098  else
1099  ds_id.fftype = DS_HDF;
1100 
1101  if (recnum >= numScans) {
1102  fprintf(stderr, "-W- %s line %d: ", __FILE__, __LINE__);
1103  fprintf(stderr, "attempt to write rec %d of %d\n", recnum, numScans);
1104  return (1);
1105  }
1106 
1107  if (recnum >= cscan && fsol < 0.0) {
1108  fsol = l2rec->l1rec->fsol;
1109  }
1110 
1111  /* allocate buffer space */
1112  if (buf == NULL) {
1113  if ((buf = calloc(numPixels, sizeof (int32))) == NULL) {
1114  fprintf(stderr,
1115  "-E- %s line %d: Unable to allocate buffer space.\n",
1116  __FILE__, __LINE__);
1117  exit(1);
1118  }
1119  }
1120 
1121  /* Write the scan-line data */
1122  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[2];
1123  int16_t year, day;
1124  double sec;
1125 
1126  unix2yds(l2rec->l1rec->scantime, &year, &day, &sec);
1127  int32_t year32 = (int32_t) year;
1128  int32_t day32 = (int32_t) day;
1129  int32_t msec32 = (int32_t) round(sec * 1.e3);
1130 
1131  // find good geolocation for spix and epix
1132  int32_t good_spix = spix;
1133  int32_t good_epix = epix;
1134 
1135  for(int i=spix; i<epix; i++) {
1136  if(!l2rec->l1rec->navfail[i]) {
1137  good_spix = i;
1138  break;
1139  }
1140  }
1141  for(int i=epix; i>=spix; i--) {
1142  if(!l2rec->l1rec->navfail[i]) {
1143  good_epix = i;
1144  break;
1145  }
1146  }
1147 
1148  PTB(writeDS(ds_id, "year", &year32, recnum, 0, 0, 1, 1, 1));
1149  PTB(writeDS(ds_id, "day", &day32, recnum, 0, 0, 1, 1, 1));
1150  PTB(writeDS(ds_id, "msec", &msec32, recnum, 0, 0, 1, 1, 1));
1151  PTB(writeDS(ds_id, "time", &l2rec->l1rec->scantime, recnum, 0, 0, 1, 1, 1));
1152  PTB(writeDS(ds_id, "mside", &l2rec->l1rec->mside, recnum, 0, 0, 1, 1, 1));
1153  PTB(writeDS(ds_id, "detnum", &l2rec->l1rec->detnum, recnum, 0, 0, 1, 1, 1));
1154  PTB(writeDS(ds_id, "slon", &(l2rec->l1rec->lon[good_spix]), recnum, 0, 0, 1, 1, 1));
1155  PTB(writeDS(ds_id, "clon", &(l2rec->l1rec->lon[cpix]), recnum, 0, 0, 1, 1, 1));
1156  PTB(writeDS(ds_id, "elon", &(l2rec->l1rec->lon[good_epix]), recnum, 0, 0, 1, 1, 1));
1157  PTB(writeDS(ds_id, "slat", &(l2rec->l1rec->lat[good_spix]), recnum, 0, 0, 1, 1, 1));
1158  PTB(writeDS(ds_id, "clat", &(l2rec->l1rec->lat[cpix]), recnum, 0, 0, 1, 1, 1));
1159  PTB(writeDS(ds_id, "elat", &(l2rec->l1rec->lat[good_epix]), recnum, 0, 0, 1, 1, 1));
1160  PTB(writeDS(ds_id, "csol_z", &(l2rec->l1rec->solz[cpix]), recnum, 0, 0, 1, 1, 1));
1161 
1162  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[4];
1163  PTB(writeDS(ds_id, "longitude", l2rec->l1rec->lon, recnum, 0, 0, 1, numPixels, 1));
1164  PTB(writeDS(ds_id, "latitude", l2rec->l1rec->lat, recnum, 0, 0, 1, numPixels, 1));
1165  PTB(writeDS(ds_id, "tilt", &(l2rec->l1rec->tilt), recnum, 0, 0, 1, 1, 1));
1166 
1167  if (outfile_number == 0) {
1168  if ((first == 1) || (fabs(last_lat - l2rec->l1rec->lat[cpix]) > GEOBOX_INC)
1169  || (recnum == (numScans - 1))) {
1170  // make sure the points used in the gring are valid
1171  if (!(l2rec->l1rec->flags[cpix] & NAVFAIL)) {
1172 
1173  if ((!(l2rec->l1rec->flags[good_spix] & NAVFAIL)
1174  && !(l2rec->l1rec->flags[good_epix] & NAVFAIL))) {
1175 
1176  first = 0;
1177  geobox[0][geobox_cnt] = l2rec->l1rec->lon[good_spix];
1178  geobox[1][geobox_cnt] = l2rec->l1rec->lat[good_spix];
1179  geobox[2][geobox_cnt] = l2rec->l1rec->lon[good_epix];
1180  geobox[3][geobox_cnt] = l2rec->l1rec->lat[good_epix];
1181  last_lat = l2rec->l1rec->lat[cpix];
1182  geobox_cnt++;
1183  }
1184  }
1185  }
1186  // just in case the last line is buggered...
1187  if ((first == 0) && (recnum < (numScans - 1))
1188  && (l2rec->l1rec->lat[cpix] != last_lat)) { // && (geobox_cnt < 2)) {
1189  if (!(l2rec->l1rec->flags[cpix] & NAVFAIL)) {
1190 
1191  if ((!(l2rec->l1rec->flags[good_spix] & NAVFAIL)
1192  && !(l2rec->l1rec->flags[good_epix] & NAVFAIL))) {
1193  geobox[0][geobox_cnt] = l2rec->l1rec->lon[good_spix];
1194  geobox[1][geobox_cnt] = l2rec->l1rec->lat[good_spix];
1195  geobox[2][geobox_cnt] = l2rec->l1rec->lon[good_epix];
1196  geobox[3][geobox_cnt] = l2rec->l1rec->lat[good_epix];
1197  }
1198  }
1199  }
1200  if (recnum == (numScans - 1) && geobox_cnt == 1) geobox_cnt++;
1201  }
1202  /* */
1203  /* Write the geophysical data */
1204  /* ---------------------------------------------------------------- */
1205  /* */
1206  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[3];
1207  for (i = 0; i < l2file->tot_prod; i++) {
1208  // Skip parameters already included if user requested them specifically
1209  if (!strcmp(l2file->l2_prod_names[i], "detnum") ||
1210  !strcmp(l2file->l2_prod_names[i], "mside") ||
1211  !strcmp(l2file->l2_prod_names[i], "year") ||
1212  !strcmp(l2file->l2_prod_names[i], "day") ||
1213  !strcmp(l2file->l2_prod_names[i], "msec") ||
1214  !strcmp(l2file->l2_prod_names[i], "time") ||
1215  !strcmp(l2file->l2_prod_names[i], "slon") ||
1216  !strcmp(l2file->l2_prod_names[i], "clon") ||
1217  !strcmp(l2file->l2_prod_names[i], "elon") ||
1218  !strcmp(l2file->l2_prod_names[i], "slat") ||
1219  !strcmp(l2file->l2_prod_names[i], "clat") ||
1220  !strcmp(l2file->l2_prod_names[i], "elat") ||
1221  !strcmp(l2file->l2_prod_names[i], "csol_z") ||
1222  !strcmp(l2file->l2_prod_names[i], "latitude") ||
1223  !strcmp(l2file->l2_prod_names[i], "longitude") ||
1224  !strcmp(l2file->l2_prod_names[i], "tilt")
1225  )
1226  continue;
1227 
1228  // get the product index record
1229  p = l2file->prodptr + i; // get product structure from cache
1230 
1231  // find the correct 3rd dimension
1232  int32_t num_3d;
1233  if(p->rank == 3) {
1234  // use another 3rd dim for the anc profiles
1235  num_3d = ( strcmp( l2file->productInfos[i]->category,
1236  "Anc_profile" ) == 0 ) ? numLvlProf : input->nwavelengths_3d;
1237  // for the reflectance diagnostics
1238  num_3d = ( strcmp( l2file->productInfos[i]->category,
1239  "Reflectance_loc" ) == 0 ) ? n_refl_loc : num_3d;
1240  // for the cloud phase
1241  num_3d = ( strcmp( l2file->productInfos[i]->category,
1242  "CTH_parameters" ) == 0 ) ? n_cloud_phase : num_3d;
1243  }
1244 
1245  // extract the product and scale (if needed)
1246  pbuf = prodgen(p, l2rec);
1247  if (p->slope != 1.0 || p->offset != 0.0) {
1248  if(p->rank == 3)
1249  pbuf = scale_sds(pbuf, l2file->productInfos[i], l2file->npix * num_3d);
1250  else
1251  pbuf = scale_sds(pbuf, l2file->productInfos[i], l2file->npix);
1252  }
1253  /* update flag counters when appropriate */
1254  if ((strcmp(l2file->l2_prod_names[i], "flags_sst") == 0)) {
1255  update_flag_cnts16(sst_flag_cnt, pbuf, NSSTFLAGS, l2rec->l1rec->npix, 1L);
1256  } else if ((strcmp(l2file->l2_prod_names[i], "flags_sst4") == 0)) {
1257  update_flag_cnts16(sst4_flag_cnt, pbuf, NSSTFLAGS, l2rec->l1rec->npix, 1L);
1258  } else if ((strcmp(l2file->l2_prod_names[i], "flags_sst3") == 0)) {
1259  update_flag_cnts16(sst3_flag_cnt, pbuf, NSSTFLAGS, l2rec->l1rec->npix, 1L);
1260  } else if ((strcmp(l2file->l2_prod_names[i], "flags_giop") == 0)) {
1261  update_flag_cnts(giop_flag_cnt, pbuf, NGIOPFLAGS, l2rec->l1rec->npix, 1L);
1262  } else if ((strcmp(l2file->l2_prod_names[i], "flags_qaa") == 0)) {
1263  update_flag_cnts(qaa_flag_cnt, pbuf, 1, l2rec->l1rec->npix, PRODFAIL);
1264  } else if ((strcmp(l2file->l2_prod_names[i], "flags_carder") == 0)) {
1265  update_flag_cnts(carder_flag_cnt, pbuf, 1, l2rec->l1rec->npix, PRODFAIL);
1266  } else if ((strcmp(l2file->l2_prod_names[i], "flags_niwa") == 0)) {
1267  update_flag_cnts(niwa_flag_cnt, pbuf, 1, l2rec->l1rec->npix, PRODFAIL);
1268  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst") == 0)) {
1269  update_qual_cnts(qualsst_flag_cnt, pbuf, NQSSTFLAGS, l2rec->l1rec->npix);
1270  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst3") == 0)) {
1271  update_qual_cnts(qualsst3_flag_cnt, pbuf, NQSSTFLAGS, l2rec->l1rec->npix);
1272  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst4") == 0)) {
1273  update_qual_cnts(qualsst4_flag_cnt, pbuf, NQSSTFLAGS, l2rec->l1rec->npix);
1274  }
1275 
1276  // write to L2 file
1277  if (p->rank == 3) {
1278  PTB( writeDS(ds_id,l2file->l2_prod_names[i],pbuf,
1279  recnum,0,0,1,numPixels,num_3d) );
1280  } else if (p->rank == 2) {
1281  PTB(writeDS(ds_id, l2file->l2_prod_names[i], pbuf,
1282  recnum, 0, 0, 1, numPixels, 1));
1283  } else {
1284  PTB(writeDS(ds_id, l2file->l2_prod_names[i], pbuf,
1285  recnum, 0, 0, 1, 1, 1));
1286  }
1287  }
1288 
1289  /* Update global flag counter */
1290  update_flag_cnts(l2_flag_cnt, l2rec->l1rec->flags, L1_NFLAGS, l2rec->l1rec->npix, 1L);
1291 
1292  if ((l2file->format == FT_L2NCDF) && !(recnum % 200)) {
1293  nc_sync(l2file->sd_id);
1294  }
1295 
1296  /* Write global attributes */
1297  if (recnum == (numScans - 1)) {
1298  float flag_perc[L1_NFLAGS];
1299  if (l2file->format == FT_L2NCDF) {
1300 
1301  // write out to netCDF file
1302  ds_id.fid = l2file->sd_id;
1303 
1304  scene_meta_write(ds_id);
1305 
1306  PTB(SetF64GA(ds_id, "earth_sun_distance_correction", fsol));
1307 
1308  // Write flag percentages metadata
1309  int32_t grp_id_flag_percentages;
1310  ds_id.sid = NC_GLOBAL;
1311 
1312  /* Report flag percentages */
1313  /* determine if there are any flag products */
1314  for (i = 0; i < l2file->tot_prod; i++) {
1315  if ((strcmp(l2file->l2_prod_names[i], "flags_sst") == 0)) {
1316  nc_def_grp(l2file->grp_id[5], "sst_flag_percentages", &grp_id_flag_percentages);
1317  ds_id.fid = grp_id_flag_percentages;
1318  printf("\nSST: Percentage of pixels flagged:\n");
1319  if (l2file->sensorID == AVHRR)
1320  write_flag_pcnts(ds_id, fp_meta, sst_flag_cnt, NSSTFLAGS, avhrr_sst_flag_lname, numScans, numPixels);
1321  else if ((l2file->sensorID == VIIRSN) ||
1322  (l2file->sensorID == VIIRSJ1) ||
1323  (l2file->sensorID == VIIRSJ2))
1324  write_flag_pcnts(ds_id, fp_meta, sst_flag_cnt, NSSTFLAGS, viirs_sst_flag_lname, numScans, numPixels);
1325  else
1326  write_flag_pcnts(ds_id, fp_meta, sst_flag_cnt, NSSTFLAGS, sst_flag_lname, numScans, numPixels);
1327  } else if ((strcmp(l2file->l2_prod_names[i], "flags_sst4") == 0)) {
1328  nc_def_grp(l2file->grp_id[5], "sst4_flag_percentages", &grp_id_flag_percentages);
1329  ds_id.fid = grp_id_flag_percentages;
1330  printf("\nSST4: Percentage of pixels flagged:\n");
1331  write_flag_pcnts(ds_id, fp_meta, sst4_flag_cnt, NSSTFLAGS, sst_flag_lname, numScans, numPixels);
1332  } else if ((strcmp(l2file->l2_prod_names[i], "flags_sst3") == 0)) {
1333  nc_def_grp(l2file->grp_id[5], "sst3_flag_percentages", &grp_id_flag_percentages);
1334  ds_id.fid = grp_id_flag_percentages;
1335  printf("\nSST3: Percentage of pixels flagged:\n");
1336  write_flag_pcnts(ds_id, fp_meta, sst3_flag_cnt, NSSTFLAGS, viirs_sst_flag_lname, numScans, numPixels);
1337  } else if ((strcmp(l2file->l2_prod_names[i], "flags_giop") == 0)) {
1338  nc_def_grp(l2file->grp_id[5], "giop_flag_percentages", &grp_id_flag_percentages);
1339  ds_id.fid = grp_id_flag_percentages;
1340  printf("\nGIOP: Percentage of pixels flagged:\n");
1341  write_flag_pcnts(ds_id, fp_meta, giop_flag_cnt, NGIOPFLAGS, giop_flag_lname, numScans, numPixels);
1342  } else if ((strcmp(l2file->l2_prod_names[i], "flags_qaa") == 0)) {
1343  nc_def_grp(l2file->grp_id[5], "qaa_flag_percentages", &grp_id_flag_percentages);
1344  ds_id.fid = grp_id_flag_percentages;
1345  printf("\nQAA: Percentage of pixels flagged:\n");
1346  write_flag_pcnts(ds_id, fp_meta, qaa_flag_cnt, 1, flag_lname, numScans, numPixels);
1347  } else if ((strcmp(l2file->l2_prod_names[i], "flags_carder") == 0)) {
1348  nc_def_grp(l2file->grp_id[5], "carder_flag_percentages", &grp_id_flag_percentages);
1349  ds_id.fid = grp_id_flag_percentages;
1350  printf("\nCARDER: Percentage of pixels flagged:\n");
1351  write_flag_pcnts(ds_id, fp_meta, carder_flag_cnt, 1, flag_lname, numScans, numPixels);
1352  } else if ((strcmp(l2file->l2_prod_names[i], "flags_niwa") == 0)) {
1353  nc_def_grp(l2file->grp_id[5], "niwa_flag_percentages", &grp_id_flag_percentages);
1354  ds_id.fid = grp_id_flag_percentages;
1355  printf("\nNIWA: Percentage of pixels flagged:\n");
1356  write_flag_pcnts(ds_id, fp_meta, niwa_flag_cnt, 1, flag_lname, numScans, numPixels);
1357  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst") == 0)) {
1358  nc_def_grp(l2file->grp_id[5], "qual_sst_percentages", &grp_id_flag_percentages);
1359  ds_id.fid = grp_id_flag_percentages;
1360  printf("\nQUAL_SST: Percentage of pixels flagged:\n");
1361  write_qual_flag_pcnts(ds_id, fp_meta, qualsst_flag_cnt, NQSSTFLAGS, qual_sst_flag_lname);
1362  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst4") == 0)) {
1363  nc_def_grp(l2file->grp_id[5], "qual_sst4_percentages", &grp_id_flag_percentages);
1364  ds_id.fid = grp_id_flag_percentages;
1365  printf("\nQUAL_SST4: Percentage of pixels flagged:\n");
1366  write_qual_flag_pcnts(ds_id, fp_meta, qualsst4_flag_cnt, NQSSTFLAGS, qual_sst_flag_lname);
1367  } else if ((strcmp(l2file->l2_prod_names[i], "qual_sst3") == 0)) {
1368  nc_def_grp(l2file->grp_id[5], "qual_sst3_percentages", &grp_id_flag_percentages);
1369  ds_id.fid = grp_id_flag_percentages;
1370  printf("\nQUAL_SST3: Percentage of pixels flagged:\n");
1371  write_qual_flag_pcnts(ds_id, fp_meta, qualsst3_flag_cnt, NQSSTFLAGS, qual_sst_flag_lname);
1372  }
1373 
1374  }
1375  nc_def_grp(l2file->grp_id[5], "flag_percentages", &grp_id_flag_percentages);
1376  ds_id.fid = grp_id_flag_percentages;
1377  printf("\nPercentage of pixels flagged:\n");
1378  write_flag_pcnts(ds_id, fp_meta, l2_flag_cnt, L1_NFLAGS, l2_flag_lname, numScans, numPixels);
1379 
1380 
1381  // Geobox attributes
1382  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->sd_id;
1383  j = 1;
1384  gring_fval[0] = geobox[0][0];
1385  for (i = 0; i < geobox_cnt; i++) {
1386  gring_fval[j++] = geobox[2][i];
1387  }
1388  for (i = 0; i < geobox_cnt - 1; i++) {
1389  gring_fval[j++] = geobox[0][geobox_cnt - 1 - i];
1390  }
1391  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[4];
1392  PTB(setAttr(ds_id, "gringpointlongitude", NC_FLOAT, j, (VOIDP) gring_fval));
1393 
1394  j = 1;
1395  gring_fval[0] = geobox[1][0];
1396  gring_ival[0] = j;
1397  for (i = 0; i < geobox_cnt; i++) {
1398  gring_ival[j] = j + 1;
1399  gring_fval[j++] = geobox[3][i];
1400  }
1401  for (i = 0; i < geobox_cnt - 1; i++) {
1402  gring_ival[j] = j + 1;
1403  gring_fval[j++] = geobox[1][geobox_cnt - 1 - i];
1404  }
1405  if (l2file->format == FT_L2NCDF) ds_id.fid = l2file->grp_id[4];
1406  PTB(setAttr(ds_id, "gringpointlatitude", NC_FLOAT, j, (VOIDP) gring_fval));
1407  PTB(setAttr(ds_id, "gringpointsequence", NC_INT, j, (VOIDP) gring_ival));
1408 
1409  } else {
1410 
1411  // write out to HDF4
1412  scene_meta_write(ds_id);
1413 
1414  PTB(SetF64GA(ds_id, "Earth-Sun Distance Correction", fsol));
1415 
1416  /* Report flag percentages */
1417  printf("\nPercentage of pixels flagged:\n");
1418  for (i = 0; i < L1_NFLAGS; i++) {
1419  flag_perc[i] = ((float) l2_flag_cnt[i]) / numScans / numPixels * 100.0;
1420  printf("Flag #%2d: %16s %10d %8.4f\n",
1421  i + 1, l2_flag_lname[i], l2_flag_cnt[i], flag_perc[i]);
1422  if (fp_meta != NULL)
1423  fprintf(fp_meta, "Flag #%2d: %16s %10d %8.4f\n",
1424  i + 1, l2_flag_lname[i], l2_flag_cnt[i], flag_perc[i]);
1425  }
1426  PTB(sd_setattr(ds_id.fid, "Flag Percentages", DFNT_FLOAT32,
1427  L1_NFLAGS, (VOIDP) flag_perc));
1428 
1429  }
1430 
1431  }
1432 
1433  return (LIFE_IS_GOOD);
1434 }
1435 
1436 /* -------------------------------------------------------- */
1437 /* Finish access for the current file. */
1438 
1439 /* -------------------------------------------------------- */
1440 int closel2(filehandle *l2file) {
1441  idDS ds_id;
1442 
1443  if ( l2file->format == FT_SEABASSRRS) {
1444  seabass *priv = (seabass*)l2file->private_data;
1445  fclose(priv->fp);
1446  return(LIFE_IS_GOOD);
1447  }
1448  ds_id.deflate = 0;
1449  ds_id.fid = l2file->sd_id;
1450  if (l2file->format == FT_L2NCDF)
1451  ds_id.fftype = DS_NCDF;
1452  else
1453  ds_id.fftype = DS_HDF;
1454 
1455  if (l2file->format == FT_L2HDF) {
1457  }
1458 
1459  if (endDS(ds_id)) {
1460  fprintf(stderr, "-E- %s line %d: endDS(%d) failed for file, %s.\n",
1461  __FILE__, __LINE__, ds_id.fid, l2file->name);
1462  return (HDF_FUNCTION_ERROR);
1463  }
1464 
1465  free(l2file->aw);
1466  l2file->aw = NULL;
1467  free(l2file->bbw);
1468  l2file->bbw = NULL;
1469  free(l2file->Fonom);
1470  l2file->Fonom = NULL;
1471 
1472  int i;
1473  for(i=0; i<l2file->tot_prod; i++)
1474  freeProductInfo(l2file->productInfos[i]);
1475  free(l2file->productInfos);
1476  l2file->productInfos = NULL;
1477  free(l2file->prodptr);
1478  l2file->prodptr = NULL;
1479 
1480  if (fp_meta != NULL)
1481  fclose(fp_meta);
1482  fp_meta = NULL;
1483 
1484  return (LIFE_IS_GOOD);
1485 }
1486 
1487 void update_flag_cnts(int32_t *flag_cnt, int32_t*flags, int32_t nflags, int32_t npix, uint32_t init_mask) {
1488  int32_t i, ip;
1489  uint32_t mask;
1490 
1491  /* Update flag counter */
1492  for (ip = 0; ip < npix; ip++) {
1493  mask = init_mask;
1494  for (i = 0; i < nflags; i++) {
1495  flag_cnt[i] += ((flags[ip] & mask) > 0);
1496  mask *= 2L;
1497  }
1498  }
1499  return;
1500 }
1501 
1502 void update_flag_cnts16(int32_t *flag_cnt, int16_t *flags, int32_t nflags, int32_t npix, uint32_t init_mask) {
1503  int32_t i, ip;
1504  uint32_t mask;
1505 
1506  /* Update flag counter */
1507  for (ip = 0; ip < npix; ip++) {
1508  mask = init_mask;
1509  for (i = 0; i < nflags; i++) {
1510  flag_cnt[i] += ((flags[ip] & mask) > 0);
1511  mask *= 2L;
1512  }
1513  }
1514  return;
1515 }
1516 
1517 void update_qual_cnts(int32_t *flag_cnt, int8_t* flags, int32_t nflags, int32_t npix) {
1518  int32_t i, ip;
1519  uint32_t mask;
1520 
1521  /* Update flag counter */
1522  for (ip = 0; ip < npix; ip++) {
1523  mask = 0;
1524  for (i = 0; i < nflags; i++) {
1525  flag_cnt[i] += ((flags[ip] == mask));
1526  mask++;
1527  }
1528  }
1529  return;
1530 }
1531 
1532 int write_flag_pcnts(idDS ds_id, FILE *fpmeta, int32_t *flag_cnt, int32_t nflags, const char * const flag_lname[], int32_t numScans, int32_t numPixels) {
1533  int32_t i;
1534  float *flag_perc;
1535 
1536  flag_perc = (float *) calloc(nflags, sizeof (float));
1537  char tmp_str[256];
1538  /* Report flag percentages */
1539  for (i = 0; i < nflags; i++) {
1540  if( i == 7 && input->georegionfile[0])
1541  strcpy(tmp_str, "GEOREGION");
1542  else
1543  strcpy(tmp_str,flag_lname[i]);
1544  flag_perc[i] = ((float) flag_cnt[i]) / numScans / numPixels * 100.0;
1545  printf("Flag #%2d: %16s %10d %8.4f\n", i + 1, tmp_str, flag_cnt[i], flag_perc[i]);
1546  if (fp_meta != NULL)
1547  fprintf(fpmeta, "Flag #%2d: %16s %10d %8.4f\n", i + 1, tmp_str, flag_cnt[i], flag_perc[i]);
1548 
1549  PTB(setAttr(ds_id, tmp_str, NC_FLOAT, 1, (VOIDP) (flag_perc + i)));
1550  }
1551 
1552  free(flag_perc);
1553  return 0;
1554 }
1555 
1556 int write_qual_flag_pcnts(idDS ds_id, FILE *fpmeta, int32_t *flag_cnt, int32_t nflags, const char * const flag_lname[]) {
1557  int32_t i, sumflags = 0;
1558  float *flag_perc;
1559 
1560  flag_perc = (float *) calloc(nflags, sizeof (float));
1561 
1562  for (i = 0; i < nflags; i++) sumflags += flag_cnt[i];
1563 
1564  /* Report flag percentages */
1565  for (i = 0; i < nflags; i++) {
1566  flag_perc[i] = ((float) flag_cnt[i]) / sumflags * 100.0;
1567  printf("Flag #%2d: %16s %10d %8.4f\n", i + 1, flag_lname[i], flag_cnt[i], flag_perc[i]);
1568  if (fp_meta != NULL)
1569  fprintf(fpmeta, "Flag #%2d: %16s %10d %8.4f\n", i + 1, flag_lname[i], flag_cnt[i], flag_perc[i]);
1570 
1571  PTB(setAttr(ds_id, flag_lname[i], NC_FLOAT, 1, (VOIDP) (flag_perc + i)));
1572  }
1573 
1574  return 0;
1575 }
char * ydhmsf(double dtime, char zone)
Definition: ydhmsf.c:12
int v_attach(int32_t h_id, int32_t *v_id)
Definition: hdf_utils.c:404
int SetF32GA(idDS ds_id, const char *name, float value)
int32 value
Definition: Granule.c:1235
void bindex_set(int32_t wave[], int nwave, int dwave_vswir)
Definition: windex.c:15
int openl2(filehandle *l2file)
Definition: l2_generic.c:181
void freeProductInfo(productInfo_t *info)
int j
Definition: decode_rs.h:73
const char * getGCMDKeywords(const char *suite)
int32_t day
#define L(lambda, T)
Definition: PreprocessP.h:185
int sd_select(int32_t sd_id, const char *name, int32_t *sds_id)
Definition: hdf_utils.c:355
void update_flag_cnts16(int32_t *flag_cnt, int16_t *flags, int32_t nflags, int32_t npix, uint32_t init_mask)
Definition: l2_generic.c:1502
#define AVHRR
Definition: sensorDefs.h:15
int write_qual_flag_pcnts(idDS ds_id, FILE *fpmeta, int32_t *flag_cnt, int32_t nflags, const char *const flag_lname[])
Definition: l2_generic.c:1556
int32_t selectDS(idDS ds_id, const char *l2_prod_names)
Definition: wrapper.c:435
#define STDNAME_VOCABULARY
Definition: OutFile.h:31
#define FAIL
Definition: ObpgReadGrid.h:18
void * allocateMemory(size_t numBytes, const char *name)
Definition: allocateMemory.c:7
#define VERSION_MINOR
Definition: version.h:2
#define NULL
Definition: decode_rs.h:63
void update_qual_cnts(int32_t *flag_cnt, int8_t *flags, int32_t nflags, int32_t npix)
Definition: l2_generic.c:1517
#define NSSTFLAGS
Definition: l12_parms.h:16
#define VIIRSN
Definition: sensorDefs.h:23
void trimBlanks(char *str)
Definition: trimBlanks.c:10
#define PUBLISHER_URL
Definition: OutFile.h:38
const char * sensorId2PlatformName(int sensorId)
Definition: sensorInfo.c:301
#define NQSSTFLAGS
Definition: l12_parms.h:19
#define GITSHA
Definition: version.h:4
int32_t deflate
Definition: dfutils.h:32
void update_flag_cnts(int32_t *flag_cnt, int32_t *flags, int32_t nflags, int32_t npix, uint32_t init_mask)
Definition: l2_generic.c:1487
#define VERSION_PATCH
Definition: version.h:3
HDF4 data type of the output SDS Default is DFNT_FLOAT32 Common types used DFNT_INT32
#define PRODFAIL
Definition: l2_flags.h:41
#define CREATOR_EMAIL
Definition: OutFile.h:33
uint8_t * float2uint8(float fbuf[], int32_t spix, int32_t npix, int32_t incr, float slope, float offset)
This should be set to the NetCDF standard name if exists for this product Create a function that computes your product edit get_myprod c add prototype to l12_proto h add get_myprod c to L2GEN_PRODUCT_FILES in CMakeLists txt Add an entry to the output routine to call your function edit prodgen c edit function prodgen() case CAT_myprod pbuf
ds_format_t fftype
Definition: dfutils.h:31
#define NAMING_AUTHORITY
Definition: OutFile.h:26
@ FT_L2NCDF
Definition: filetype.h:23
int createDS(idDS ds_id, int sensorId, const char *sname, int32_t dm[3], const char dm_name[3][80])
Definition: wrapper.c:341
#define LICENSE
Definition: OutFile.h:25
#define VERSION_MAJOR
Definition: version.h:1
#define PUBLISHER_EMAIL
Definition: OutFile.h:37
instr * input
character(len=1000) if
Definition: names.f90:13
#define LIFE_IS_GOOD
Definition: passthebuck.h:4
#define DPTB(function)
Definition: passthebuck.h:24
int sd_setattr(int32_t id, const char *nam, int32_t typ, int32_t cnt, const void *data)
Definition: hdf_utils.c:216
int endaccessDS(idDS ds_id)
Definition: wrapper.c:617
int32_t prodlist(int32_t sensorID, int32_t evalmask, const char *inprod, const char *defprod, char outprod[L1_MAXPROD][32])
#define PUBLISHER_NAME
Definition: OutFile.h:36
int closel2(filehandle *l2file)
Definition: l2_generic.c:1440
double precision function f(R1)
Definition: tmd.lp.f:1454
int writel2(filehandle *l2file, int32_t recnum, l2str *l2rec, int outfile_number)
Definition: l2_generic.c:939
void scene_meta_write(idDS ds_id)
Definition: scene_meta.c:241
read recnum
#define CAT_Rrs
Definition: l2prod.h:61
productInfo_t * allocateProductInfo()
char * strdup(const char *)
idDS startDS(const char *filename, ds_format_t format, ds_access_t accessmode, int32_t deflate)
Definition: wrapper.c:558
FILE * fp
Definition: l1_seabass.h:12
#define HAWKEYE
Definition: sensorDefs.h:39
int16_t * float2int16(float fbuf[], int32_t spix, int32_t npix, int32_t incr, float slope, float offset)
#define INSTITUTION
Definition: OutFile.h:24
float aw_spectra(int32_t wl, int32_t width)
l1_input_t * l1_input
Definition: l1_options.c:9
float bbw_spectra(int32_t wl, int32_t width)
#define CREATOR_NAME
Definition: OutFile.h:32
a context in which it is NOT documented to do so subscript which cannot be easily calculated when extracting TONS attitude data from the Terra L0 files Corrected several defects in extraction of entrained ephemeris and and as HDF file for both the L1A and Geolocation enabling retrieval of South Polar DEM data Resolved Bug by changing to opent the geolocation file only after a successful read of the L1A and also by checking for fatal errors from not restoring C5 and to report how many of those high resolution values were water in the new WaterPresent SDS Added valid_range attribute to Land SeaMask Changed to bilinearly interpolate the geoid_height to remove artifacts at one degree lines Made corrections to const qualification of pointers allowed by new version of M API library Removed casts that are no longer for same not the geoid Corrected off by one error in calculation of high resolution offsets Corrected parsing of maneuver list configuration parameter Corrected to set Height SDS to fill values when geolocation when for elevation and land water mask
Definition: HISTORY.txt:114
#define NHABSFLAGS
Definition: mph_flags.h:17
void unix2yds(double usec, short *year, short *day, double *secs)
#define KEYWORDS_VOCABULARY
Definition: OutFile.h:27
int writeDS(idDS ds_id, const char *name, const void *data, int32_t s0, int32_t s1, int32_t s2, int32_t e0, int32_t e1, int32_t e2)
Definition: wrapper.c:472
char * replace_ocroots(const char *inStr)
constexpr double bad_float
int SetF64GA(idDS ds_id, const char *name, double value)
int write_flag_pcnts(idDS ds_id, FILE *fpmeta, int32_t *flag_cnt, int32_t nflags, const char *const flag_lname[], int32_t numScans, int32_t numPixels)
Definition: l2_generic.c:1532
HDF4 data type of the output SDS Default is DFNT_FLOAT32 Common types used DFNT_INT16
@ DS_NCDF
Definition: dfutils.h:20
#define PTB(function)
Definition: passthebuck.h:16
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
#define NGIOPFLAGS
Definition: l12_parms.h:17
int32_t sid
Definition: dfutils.h:30
#define CAT_nLw
Definition: l2prod.h:8
int SetI32GA(idDS ds_id, const char *name, int32_t value)
Definition: wrapper.c:323
#define basename(s)
Definition: l0chunk_modis.c:29
int findProductInfo(const char *productName, int sensorId, productInfo_t *info)
#define GEOBOX_INC
Definition: l2_generic.c:64
const char * xsatid2name(int xsatid)
Definition: l1_aci.c:1180
float * unscale_sds(void *data, productInfo_t *p, int32_t spix, int32_t npix, int incr)
Definition: scale_sds.c:245
intn setAttr(uint8 isHDF5, int32 obj_id, const char *attr_name, int32 data_type, int32 count, VOIDP values)
Definition: put_smi.cpp:20
#define BAD_FLT
Definition: jplaeriallib.h:19
@ FT_SEABASSRRS
Definition: filetype.h:60
flags
Definition: DDAlgorithm.h:22
const char * sensorId2SensorName(int sensorId)
Definition: sensorInfo.c:273
@ DS_WRITE
Definition: dfutils.h:25
int SetChrGA(idDS ds_id, const char *name, const char *value)
Definition: wrapper.c:233
#define CREATOR_URL
Definition: OutFile.h:34
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
#define fabs(a)
Definition: misc.h:93
void * scale_sds(float *data, productInfo_t *p, int32_t npix)
int32_t fid
Definition: dfutils.h:29
void * prodgen(l2prodstr *p, l2str *l2rec)
Definition: prodgen.c:101
u5 which has been done in the LOCALGRANULEID metadata should have an extension NRT It is requested to identify the NRT production Changes from v6 which may affect scientific the sector rotation may actually occur during one of the scans earlier than the one where it is first reported As a the b1 values are about the LOCALGRANULEID metadata should have an extension NRT It is requested to identify the NRT to fill pixels affected by dead subframes with a special value Output the metadata of noisy and dead subframe Dead Subframe EV and Detector Quality Flag2 Removed the function call of Fill_Dead_Detector_SI to stop interpolating SI values for dead but also for all downstream products for science test only Changes from v5 which will affect scientific to conform to MODIS requirements Removed the Mixed option from the ScanType in the code because the L1A Scan Type is never Mixed Changed for ANSI C compliance and comments to better document the fact that when the HDF_EOS metadata is stricly the and products are off by and in the track respectively Corrected some misspelling of RCS swir_oob_sending_detector to the Reflective LUTs to enable the SWIR OOB correction detector so that if any of the sending detectors becomes noisy or non near by good detectors from the same sending band can be specified as the substitute in the new look up table Code change for adding an additional dimension of mirror side to the Band_21_b1 LUT to separate the coefficient of the two mirror sides for just like other thermal emissive so that the L1B code can calibrate Band scan to scan with mirror side dependency which leads better calibration result Changes which do not affect scientific when the EV data are not provided in this Crosstalk Correction will not be performed to the Band calibration data Changes which do not affect scientific and BB_500m in L1A Logic was added to turn off the or to spatial aggregation processes and the EV_250m_Aggr1km_RefSB and EV_500m_Aggr1km_RefSB fields were set to fill values when SDSs EV_250m and EV_500m are absent in L1A file Logic was added to skip the processing and turn off the output of the L1B QKM and HKM EV data when EV_250m and EV_500m are absent from L1A In this the new process avoids accessing and reading the and L1A EV skips and writing to the L1B and EV omits reading and subsampling SDSs from geolocation file and writing them to the L1B and omits writing metadata to L1B and EV and skips closing the L1A and L1B EV and SDSs Logic was added to turn off the L1B OBC output when the high resolution OBC SDSs are absent from L1A This is accomplished by skipping the openning the writing of metadata and the closing of the L1B OBC hdf which is Bit in the scan by scan bit QA has been changed Until now
Definition: HISTORY.txt:361
char * unix2isodate(double dtime, char zone)
Definition: unix2isodate.c:10
const char * sensorId2InstrumentName(int sensorId)
Definition: sensorInfo.c:287
#define PROJECT
Definition: OutFile.h:35
@ DS_HDF
Definition: dfutils.h:19
Definition: dfutils.h:28
#define NMPHFLAGS
Definition: mph_flags.h:11
int AddSdsToVgroup(int32_t sd_id, int32_t v_id, const char *name)
Definition: hdf_utils.c:383
int32 epix
Definition: l1_czcs_hdf.c:23
#define VIIRSJ2
Definition: sensorDefs.h:44
int32_t rdsensorinfo(int32_t, int32_t, const char *, void **)
Definition: rdsensorinfo.c:69
#define BANDW
Definition: l1.h:53
HDF4 data type of the output SDS Default is DFNT_FLOAT32 Common types used DFNT_FLOAT32
ds_format_t
Definition: dfutils.h:18
#define PROGRAM
Definition: ice2hdf.c:10
int MakeVgroups(filehandle *l2file)
Definition: l2_generic.c:74
#define SEAWIFS
Definition: sensorDefs.h:12
int endDS(idDS ds_id)
Definition: wrapper.c:624
int i
Definition: decode_rs.h:71
int32 l2file(int32 sdfid, int32 *nsamp, int32 *nscans, char *dtype)
Definition: l2stat_chk.c:313
void get_f0_thuillier_ext(int32_t wl, int32_t width, float *f0)
Definition: get_f0.c:137
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
#define VIIRSJ1
Definition: sensorDefs.h:37
#define L1_NFLAGS
Definition: filehandle.h:21
int k
Definition: decode_rs.h:73
int npix
Definition: get_cmp.c:28
#define HDF_FUNCTION_ERROR
Definition: passthebuck.h:7
int createDS2(idDS ds_id, const char *sname, productInfo_t *pinfo, int32_t dm[3], const char dm_name[3][80])
Definition: wrapper.c:357
float p[MODELMAX]
Definition: atrem_corl1.h:131
@ FT_L2HDF
Definition: filetype.h:22
int32_t get_l2prod_index(const l2_prod &l2, const char *prodname)
Definition: l2bin.cpp:109
#define NAVFAIL
Definition: l2_flags.h:36
int count
Definition: decode_rs.h:79