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