OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
l1bgen_oci.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <string.h>
5 #include <unistd.h>
6 
7 #include <sstream>
8 #include <fstream>
9 #include <iomanip>
10 #include <getopt.h>
11 #include <libgen.h>
12 
13 #include "nc4utils.h"
14 #include "l1bgen_oci.h"
15 
16 using namespace std;
17 using namespace netCDF;
18 using namespace netCDF::exceptions;
19 
20 #define VERSION "0.045"
21 
22 // Modification history:
23 // Programmer Organization Date Ver Description of change
24 // ---------- ------------ ---- --- ---------------------
25 // Joel Gales SAIC 04/29/20 0.01 Original development
26 // Joel Gales SAIC 01/13/21 0.02 Add support for SWIR
27 // Joel Gales SAIC 08/11/21 0.03 Add support for handling
28 // fill values in science data
29 // Joel Gales SAIC 08/12/21 0.04 Add support for hysteresis
30 // correction
31 // Joel Gales SAIC 09/23/21 0.045 Initialize uninitialized
32 // variables
33 
34 ofstream tempOut;
35 
36 int main (int argc, char* argv[])
37 {
38 
39  cout << "l1bgen_oci " << VERSION << " ("
40  << __DATE__ << " " << __TIME__ << ")" << endl;
41 
42  if ( argc == 1) {
43  cout << endl <<
44  "l1bgen_oci OCI_L1A_file, cal_LUT_file temp_GEO_LUT_file OCI_L1B_file"
45  << endl;
46  return 0;
47  }
48 
49  // ********************************* //
50  // *** Read calibration LUT file *** //
51  // ********************************* //
52  NcFile *calLUTfile = new NcFile( argv[2], NcFile::read);
53 
54  NcGroup gidCommon, gidBlue, gidRed, gidSWIR;
55  gidCommon = calLUTfile->getGroup( "common");
56  gidBlue = calLUTfile->getGroup( "blue");
57  gidRed = calLUTfile->getGroup( "red");
58  gidSWIR = calLUTfile->getGroup( "SWIR");
59 
60  float bwave[NBWAVE];
61  float rwave[NRWAVE];
62  float swave[NIWAVE];
63  float spass[NIWAVE] = {45, 80, 30, 30, 15, 75, 75, 50, 75};
64  double K2t[NTIMES];
65  float K3T[NTEMPS];
66 
67  NcVar var;
68 
69  var = gidCommon.getVar( "blue_wavelength");
70  var.getVar( bwave);
71 
72  var = gidCommon.getVar( "red_wavelength");
73  var.getVar( rwave);
74 
75  var = gidCommon.getVar( "SWIR_wavelength");
76  var.getVar( swave);
77 
78  var = gidCommon.getVar( "K2t");
79  var.getVar( K2t);
80 
81  var = gidCommon.getVar( "K3T");
82  var.getVar( K3T);
83 
84  string tag;
85 
86  cal_lut_struct blue_lut;
87  cal_lut_struct red_lut;
88  cal_lut_struct swir_lut;
89 
90  uint32_t bbanddim, rbanddim, sbanddim;
91 
92  tag.assign("blue");
93  read_oci_cal_lut( calLUTfile, tag, gidBlue, bbanddim, blue_lut);
94 
95  tag.assign("red");
96  read_oci_cal_lut( calLUTfile, tag, gidRed, rbanddim, red_lut);
97 
98  tag.assign("SWIR");
99  read_oci_cal_lut( calLUTfile, tag, gidSWIR, sbanddim, swir_lut);
100 
101  // Read hysterisis parameters
102  float hysttime[9][3];
103  float hystamp[9][3];
104 
105  var = gidSWIR.getVar( "hyst_time_const");
106  var.getVar( &hysttime[0][0]);
107  var = gidSWIR.getVar( "hyst_amplitude");
108  var.getVar( &hystamp[0][0]);
109 
110  calLUTfile->close();
111 
112  // for (size_t i=0; i<NBWAVE; i++) cout << bwave[i] << endl;
113 
114 
115  // ******************************** //
116  // *** Read geo LUT (temporary) *** //
117  // ******************************** //
118  NcFile *geoLUTfile = new NcFile( argv[3], NcFile::read);
119  geo_struct geoLUT;
120 
121  NcGroup gidTime, gidCT, gidRTA_HAM;
122 
123  gidTime = geoLUTfile->getGroup( "time_params");
124  var = gidTime.getVar( "master_clock");
125  var.getVar( &geoLUT.master_clock);
126  var = gidTime.getVar( "MCE_clock");
127  var.getVar( &geoLUT.MCE_clock);
128 
129  gidCT = geoLUTfile->getGroup( "coord_trans");
130  var = gidCT.getVar( "sc_to_tilt");
131  var.getVar( &geoLUT.sc_to_tilt);
132  var = gidCT.getVar( "tilt_axis");
133  var.getVar( &geoLUT.tilt_axis);
134  var = gidCT.getVar( "tilt_angles");
135  var.getVar( &geoLUT.tilt_angles);
136  var = gidCT.getVar( "tilt_to_oci_mech");
137  var.getVar( &geoLUT.tilt_to_oci_mech);
138  var = gidCT.getVar( "oci_mech_to_oci_opt");
139  var.getVar( &geoLUT.oci_mech_to_oci_opt);
140 
141  gidRTA_HAM = geoLUTfile->getGroup( "RTA_HAM_params");
142  var = gidRTA_HAM.getVar( "RTA_axis");
143  var.getVar( &geoLUT.rta_axis);
144  var = gidRTA_HAM.getVar( "HAM_axis");
145  var.getVar( &geoLUT.ham_axis);
146  var = gidRTA_HAM.getVar( "HAM_AT_angles");
147  var.getVar( &geoLUT.ham_at_angles);
148  var = gidRTA_HAM.getVar( "HAM_CT_angles");
149  var.getVar( &geoLUT.ham_ct_angles);
150  var = gidRTA_HAM.getVar( "RTA_enc_scale");
151  var.getVar( &geoLUT.rta_enc_scale);
152  var = gidRTA_HAM.getVar( "HAM_enc_scale");
153  var.getVar( &geoLUT.ham_enc_scale);
154  var = gidRTA_HAM.getVar( "RTA_nadir");
155  var.getVar( &geoLUT.rta_nadir);
156 
157  geoLUTfile->close();
158 
159  // Open a read data from L1Afile
160  NcFile *l1afile = new NcFile( argv[1], NcFile::read);
161 
162  NcGroup ncGrps[4];
163 
164  ncGrps[0] = l1afile->getGroup( "scan_line_attributes");
165  ncGrps[1] = l1afile->getGroup( "spatial_spectral_modes");
166  ncGrps[2] = l1afile->getGroup( "engineering_data");
167  ncGrps[3] = l1afile->getGroup( "science_data");
168 
169  NcGroupAtt att;
170 
171  // Get date (change this when year and day are added to time field)
172  string tstart, tend;
173  att = l1afile->getAtt("time_coverage_start");
174  att.getValues(tstart);
175  cout << tstart << endl;
176 
177  att = l1afile->getAtt("time_coverage_end");
178  att.getValues(tend);
179  cout << tend << endl;
180 
181  uint16_t iyr, imn, idom;
182  istringstream iss;
183 
184  iss.str(tstart.substr(0,4));
185  iss >> iyr; iss.clear();
186  iss.str(tstart.substr(5,2));
187  iss >> imn; iss.clear();
188  iss.str(tstart.substr(8,2));
189  iss >> idom;
190  int32_t jd = jday(iyr, imn, idom);
191 
192  int32_t iyr32, idy32;
193  jdate( jd, &iyr32, &idy32);
194 
195  // Get numbers of blue and red bands
196  NcDim blue_dim = l1afile->getDim("blue_bands");
197  uint32_t bbands = blue_dim.getSize();
198  NcDim red_dim = l1afile->getDim("red_bands");
199  uint32_t rbands = red_dim.getSize();
200 
201  // Scan time, spin ID and HAM side
202  NcDim nscan_dim = l1afile->getDim("number_of_scans");
203  uint32_t nscan = nscan_dim.getSize();
204 
205  double *sstime = new double[nscan];
206  var = ncGrps[0].getVar( "scan_start_time");
207  var.getVar( sstime);
208 
209  int32_t *spin = new int32_t[nscan];
210  var = ncGrps[0].getVar( "spin_ID");
211  var.getVar( spin);
212 
213  uint8_t *hside = new uint8_t[nscan];
214  var = ncGrps[0].getVar( "HAM_side");
215  var.getVar( hside);
216 
217  uint32_t nscan_good=0;
218  for (size_t i=0; i<nscan; i++) {
219  if ( spin[i] > 0) {
220  sstime[nscan_good] = sstime[i];
221  hside[nscan_good] = hside[i];
222  nscan_good++;
223  }
224  }
225 
226  // Check for and fill in missing scan times
228 
229 
230  // ******************************************** //
231  // *** Get spatial and spectral aggregation *** //
232  // ******************************************** //
233  NcDim ntaps_dim = l1afile->getDim("number_of_taps");
234  uint32_t ntaps = ntaps_dim.getSize();
235  NcDim spatzn_dim = l1afile->getDim("spatial_zones");
236  uint32_t spatzn = spatzn_dim.getSize();
237 
238  int16_t *dtype = new int16_t[spatzn];
239  var = ncGrps[1].getVar( "spatial_zone_data_type");
240  var.getVar( dtype);
241 
242  int16_t *lines = new int16_t[spatzn];
243  var = ncGrps[1].getVar( "spatial_zone_lines");
244  var.getVar( lines);
245 
246  int16_t *iagg = new int16_t[spatzn];
247  var = ncGrps[1].getVar( "spatial_aggregation");
248  var.getVar( iagg);
249 
250  int16_t *bagg = new int16_t[ntaps];
251  var = ncGrps[1].getVar( "blue_spectral_mode");
252  var.getVar( bagg);
253 
254  int16_t *ragg = new int16_t[ntaps];
255  var = ncGrps[1].getVar( "red_spectral_mode");
256  var.getVar( ragg);
257 
258 
259  // ********************************************************************* //
260  // *** Get # of EV lines/offset from scan start time to EV mid-time *** //
261  // ********************************************************************* //
262  // This will be done by geolocation when integrated into L1B
263  int32_t ppr_off;
264  double revpsec, secpline;
265  int32_t *mspin = new int32_t[nscan];
266  int32_t *ot_10us = new int32_t[nscan];
267  uint8_t *enc_count = new uint8_t[nscan];
268 
269  NcDim nenc_dim = l1afile->getDim("encoder_samples");
270  uint32_t nenc = nenc_dim.getSize();
271 
272  float **hamenc = new float *[nscan];
273  hamenc[0] = new float[nenc*nscan];
274  for (size_t i=1; i<nscan; i++) hamenc[i] = hamenc[i-1] + nenc;
275 
276  float **rtaenc = new float *[nscan];
277  rtaenc[0] = new float[nenc*nscan];
278  for (size_t i=1; i<nscan; i++) rtaenc[i] = rtaenc[i-1] + nenc;
279 
280  read_mce_tlm( l1afile, ncGrps[2], nscan, nenc, ppr_off, revpsec, secpline,
281  mspin, ot_10us, enc_count, &hamenc[0], rtaenc);
282 
283  float clines[32400], slines[4050];
284  uint16_t pcdim, psdim;
285  int16_t iret;
286  double ev_toff, deltc[32400], delts[4050];
287  get_ev( secpline, dtype, lines, iagg, pcdim, psdim, ev_toff, clines, slines,
288  deltc, delts, iret);
289  if ( iret < 0) {
290  cout << "No science collect in file: " << argv[1] << endl;
291  l1afile->close();
292  return 1;
293  }
294 
295  double *evtime = new double[nscan];
296  for (size_t i=0; i<nscan_good; i++) evtime[i] = sstime[i] + ev_toff;
297 
298  size_t ka;
299  for (size_t i=0; i<spatzn; i++) {
300  if ( dtype[i] != 0 && dtype[i] != 2 && dtype[i] != 10) {
301  ka = i;
302  break;
303  }
304  }
305 
306 
307  // *********************************************************** //
308  // *** Generate matrices for spectral and gain aggregation *** //
309  // *********************************************************** //
310  size_t *ia;
311  uint32_t iia;
312  uint32_t ntb[16];
313  ia = new size_t[ntaps];
314 
315  // Blue bands
316  iia=0;
317  for (size_t i=0; i<ntaps; i++) {
318  if ( bagg[i] > 0) {
319  ia[iia] = i;
320  iia++;
321  }
322  }
323 
324  uint32_t bib=1, bbb=1;
325  if ( iia == 0) {
326  cout << "All blue taps disabled" << endl;
327  } else {
328  for (size_t i=0; i<16; i++) ntb[i] = 0;
329  for (size_t i=0; i<iia; i++) ntb[ia[i]] = 32 / bagg[ia[i]];
330  bib = 0;
331  for (size_t i=0; i<16; i++) bib += ntb[i];
332  }
333 
334  // Note: bgmat & rgmat not necessarily contiguous
335  float **bamat = new float*[bib];
336  float **bgmat = new float*[512];
337 
338  if (bib != 1)
339  get_agg_mat( ia, iagg[ka], bagg, bib, bbb, ntb, bamat, bgmat);
340 
341  if (bib != bbands) {
342  cout << "Number of blue bands in file: " << argv[1] <<
343  " not consistent with spectral aggregation" << endl;
344  l1afile->close();
345  return 1;
346  } else if ( bib < 4) cout << "No blue bands in file: " << argv[1] << endl;
347 
348  // Red bands
349  iia=0;
350  for (size_t i=0; i<ntaps; i++) {
351  if ( ragg[i] > 0) {
352  ia[iia] = i;
353  iia++;
354  }
355  }
356 
357  uint32_t rib=1, rbb=1;
358  if ( iia == 0) {
359  cout << "All red taps disabled" << endl;
360  } else {
361  for (size_t i=0; i<16; i++) ntb[i] = 0;
362  for (size_t i=0; i<iia; i++) ntb[ia[i]] = 32 / ragg[ia[i]];
363  rib = 0;
364  for (size_t i=0; i<16; i++) rib += ntb[i];
365  }
366 
367  float **ramat = new float*[rib];
368  float **rgmat = new float*[512];
369 
370  if (rib != 1)
371  get_agg_mat( ia, iagg[ka], ragg, rib, rbb, ntb, ramat, rgmat);
372 
373  if (rib != rbands) {
374  cout << "Number of red bands in file: " << argv[1] <<
375  " not consistent with spectral aggregation" << endl;
376  l1afile->close();
377  return 1;
378  } else if ( rib < 4) cout << "No red bands in file: " << argv[1] << endl;
379 
380  uint16_t swb = 9;
381 
382 
383  // ********************************* //
384  // *** Get dark collect location *** //
385  // ********************************* //
386  int16_t kd=-1;
387  for (size_t i=0; i<spatzn; i++) {
388  if ( dtype[i] == 2) {
389  kd = (int16_t) i;
390  }
391  }
392  if ( kd == -1) {
393  cout << "No dark collect in file: " << argv[1] << endl;
394  l1afile->close();
395  return 1;
396  }
397 
398  int16_t ldc=0, lds=0;
399  for (size_t i=0; i<(size_t) kd; i++) {
400  if ( dtype[i] != 0 && dtype [1] != 10) {
401  ldc += lines[i] / iagg[i];
402  lds += lines[i] / 8;
403  }
404  }
405  int16_t ndc = lines[kd] / iagg[kd];
406  int16_t nds = lines[kd] / 8;
407 
408 
409  // *********************************************************************** //
410  // *** Generate band gain structs from LUTs, date/time & gain matrices *** //
411  // *********************************************************************** //
412  gains_struct bgains;
413  gains_struct rgains;
414  gains_struct sgains;
415  /*
416  for (size_t i=0; i<64; i++)
417  for (size_t j=0; j<512; j++)
418  cout << "0: " << i << " " << j << " " << bgmat[j][i] << endl;
419  */
420  // Note: bgmat & rgmat not necessarily contiguous
421  // That's why we pass the location of the array of pointers
422  if ( bib >= 4)
423  make_oci_gains( bib, bbanddim, iyr, idom, evtime[0], K2t, blue_lut,
424  &bgmat[0], bgains);
425 
426  if ( rib >= 4)
427  make_oci_gains( rib, rbanddim, iyr, idom, evtime[0], K2t, red_lut,
428  &rgmat[0], rgains);
429 
430  float **sgmat = new float*[swb];
431  for (size_t i=0; i<swb; i++) {
432  sgmat[i] = new float[swb];
433  for (size_t j=0; j<swb; j++) {
434  if (i == j) sgmat[i][j] = 1.0; else sgmat[i][j] = 0.0;
435  }
436  }
437  make_oci_gains( swb, swb, iyr, idom, evtime[0], K2t, swir_lut,
438  &sgmat[0], sgains);
439 
440  // Read selected temperature fields and interpolate to scan times
441  float **caltemps = new float *[nscan_good];
442  caltemps[0] = new float[30*nscan_good];
443  for (size_t i=1; i<nscan_good; i++) caltemps[i] = caltemps[i-1] + 30;
444 
445  // get_oci_cal_temps JMG not yet defined
446  for (size_t i=0; i<nscan_good; i++)
447  for (size_t j=1; j<30; j++)
448  caltemps[i][j] = 0.0;
449 
450  // Read dark collects from science data arrays
451  vector<size_t> start, count;
452  start.push_back(0);
453  start.push_back(0);
454  start.push_back(ldc);
455 
456  size_t dims[3];
457  dims[0] = nscan_good; dims[1] = bib; dims[2] = ndc;
458  uint16_t ***bdark = make3dT<uint16_t>(dims);
459  dims[0] = nscan_good; dims[1] = rib; dims[2] = ndc;
460  uint16_t ***rdark = make3dT<uint16_t>(dims);
461 
462  uint16_t bfill;
463  uint16_t rfill;
464 
465  if ( bib > 4) {
466  count.push_back(nscan_good);
467  count.push_back(bib);
468  count.push_back(ndc);
469 
470  var = ncGrps[3].getVar( "sci_blue");
471  var.getVar( start, count, &bdark[0][0][0]);
472 
473  var.getAtt("_FillValue").getValues(&bfill);
474  }
475 
476  if ( rib > 4) {
477  count.clear();
478  count.push_back(nscan_good);
479  count.push_back(rib);
480  count.push_back(ndc);
481 
482  var = ncGrps[3].getVar( "sci_red");
483  var.getVar( start, count, &rdark[0][0][0]);
484 
485  var.getAtt("_FillValue").getValues(&rfill);
486  }
487 
488  dims[0] = nscan_good; dims[1] = swb; dims[2] = nds;
489  uint32_t ***sdark = make3dT<uint32_t>(dims);
490 
491  uint32_t sfill;
492 
493  start.clear();
494  start.push_back(0);
495  start.push_back(0);
496  start.push_back(lds);
497 
498  count.clear();
499  count.push_back(nscan_good);
500  count.push_back(swb);
501  count.push_back(nds);
502 
503  var = ncGrps[3].getVar( "sci_SWIR");
504  var.getVar( start, count, &sdark[0][0][0]);
505 
506  var.getAtt("_FillValue").getValues(&sfill);
507 
508  uint32_t fill32;
509 
510  static l1bFile outfile;
511 
512  // nscan_good: Number of scans in L1A file
513  // pcdim: Number of CCD band pixels
514  // bbb: Number of blue bands]
515  // rbb: Number of red bands
516  // psdim: Number of SWIR band pixels
517  // swb: Number of SWIR bands
518  outfile.createl1b( (char *) argv[4], nscan_good, pcdim, bbb, rbb, psdim, swb);
519 
520  // number of scans of dark data to average; will make this an input parameter
521  uint16_t ndsc = 1;
522  //number of dark pixels to skip; will make this an input parameter
523  uint16_t nskp = 0;
524  // adjust SWIR skip factor in case of CCD aggregation LT 8
525  // uint32_t nsskp = (nskp * iagg[kd]) / 8;
526 
527  uint32_t bicount[3] = {1,bib,(uint32_t) pcdim};
528  uint32_t ricount[3] = {1,rib,(uint32_t) pcdim};
529  uint32_t sicount[3] = {1,swb,(uint32_t) psdim};
530  uint32_t bcount[3] = {bbb,1,(uint32_t) pcdim};
531  uint32_t rcount[3] = {rbb,1,(uint32_t) pcdim};
532  uint32_t scount[3] = {swb,1,(uint32_t) psdim};
533 
534  // Calibrated data variables
535  float **bdn = new float *[bib];
536  bdn[0] = new float[pcdim*bib];
537  for (size_t i=1; i<bib; i++) bdn[i] = bdn[i-1] + pcdim;
538 
539  float **rdn = new float *[rib];
540  rdn[0] = new float[pcdim*rib];
541  for (size_t i=1; i<rib; i++) rdn[i] = rdn[i-1] + pcdim;
542 
543  float **sdn = new float *[swb];
544  sdn[0] = new float[psdim*swb];
545  for (size_t i=1; i<swb; i++) sdn[i] = sdn[i-1] + psdim;
546 
547  float **bcal = new float *[bib];
548  bcal[0] = new float[pcdim*bib];
549  for (size_t i=1; i<bib; i++) bcal[i] = bcal[i-1] + pcdim;
550 
551  float **rcal = new float *[rib];
552  rcal[0] = new float[pcdim*rib];
553  for (size_t i=1; i<rib; i++) rcal[i] = rcal[i-1] + pcdim;
554 
555  float **scal = new float *[swb];
556  scal[0] = new float[psdim*swb];
557  for (size_t i=1; i<swb; i++) scal[i] = scal[i-1] + psdim;
558 
559  double *thetap = new double[pcdim];
560  double *thetas = new double[psdim];
561 
562  float **pview = new float *[pcdim];
563  pview[0] = new float[3*pcdim];
564  for (size_t i=1; i<pcdim; i++) pview[i] = pview[i-1] + 3;
565 
566  float **sview = new float *[psdim];
567  sview[0] = new float[3*psdim];
568  for (size_t i=1; i<psdim; i++) sview[i] = sview[i-1] + 3;
569 
570  // ; pview(3,pdim) R*4 O View vectors in the instrument frame
571  //; theta(pdim) R*4 O Scan angles for science pixels
572 
573  // Read, calibrate and write science data
574  for (size_t iscn=0; iscn<nscan_good; iscn++) {
575 
576  if ((iscn % 50) == 0) cout << "Calibrating scan: " << iscn << endl;
577 
578  // Check for valid mirror side
579  if ( hside[iscn] == 0 || hside[iscn] == 1) {
580 
581  // Write evtime
582  start.clear();
583  start.push_back(iscn);
584 
585  count.clear();
586  count.push_back(1);
587 
588  var = outfile.ncGrps[1].getVar( "time");
589  var.putVar( start, count, &evtime[iscn]);
590 
591  var = outfile.ncGrps[1].getVar( "HAM_side");
592  var.putVar( start, count, &hside[iscn]);
593 
594  // Get scan angle
595  // This will be done by geolocation when integrated into L1B
596  get_oci_vecs( nscan, pcdim, geoLUT, ev_toff, spin[iscn], clines, deltc,
597  revpsec, ppr_off, mspin, ot_10us, enc_count, &hamenc[0],
598  &rtaenc[0], pview, thetap, iret);
599 
600  tempOut.open ("pview.bin", ios::out | ios::trunc | ios::binary);
601  tempOut.write((char *) &pview[0][0], sizeof(float)*3*pcdim);
602  tempOut.close();
603 
604  tempOut.open ("thetap.bin", ios::out | ios::trunc | ios::binary);
605  tempOut.write((char *) &thetap[0], sizeof(double)*pcdim);
606  tempOut.close();
607 
608  get_oci_vecs( nscan, psdim, geoLUT, ev_toff, spin[iscn], slines, delts,
609  revpsec, ppr_off, mspin, ot_10us, enc_count, &hamenc[0],
610  &rtaenc[0], sview, thetas, iret);
611 
612  tempOut.open ("sview.bin", ios::out | ios::trunc | ios::binary);
613  tempOut.write((char *) &sview[0][0], sizeof(float)*3*psdim);
614  tempOut.close();
615 
616  tempOut.open ("thetas.bin", ios::out | ios::trunc | ios::binary);
617  tempOut.write((char *) &thetas[0], sizeof(double)*psdim);
618  tempOut.close();
619 
620  // Blue bands
621  if (bib >= 4) {
622 
623  start.clear();
624  start.push_back(iscn);
625  start.push_back(0);
626  start.push_back(0);
627 
628  count.clear();
629  count.push_back(bicount[0]);
630  count.push_back(bicount[1]);
631  count.push_back(bicount[2]);
632 
633  uint16_t **bsci = new uint16_t *[bib];
634  bsci[0] = new uint16_t[pcdim*bib];
635  for (size_t i=1; i<bib; i++) bsci[i] = bsci[i-1] + pcdim;
636 
637  var = ncGrps[3].getVar( "sci_blue");
638  var.getVar( start, count, bsci[0]);
639 
640  tempOut.open ("bsci.bin", ios::out | ios::trunc | ios::binary);
641  tempOut.write((char *) bsci[0], sizeof(uint16_t)*pcdim*bib);
642  tempOut.close();
643 
644  // Compute dark offset, correct data, and apply absolute and
645  // temporal gain and temperature correction
646  float *bdc = new float[bib];
647 
648  fill32 = bfill;
649  int16_t iret;
650  get_oci_dark<uint16_t>( iscn, nscan_good, hside, ndsc, nskp,
651  iagg[ka], iagg[kd], ntaps, bagg, fill32,
652  ndc, bdark, bib, bdc, iret);
653 
654  float *k3 = new float[bib];
655  get_oci_temp_corr( bib, bgains, K3T, caltemps[iscn], nscan_good, k3);
656  for (size_t j=0; j<bib; j++) {
657  for (size_t k=0; k<pcdim; k++) {
658 
659  // Handle fill value
660  if (bsci[j][k] == bfill) {
661  bdn[j][k] = -999;
662  bcal[j][k] = -999;
663  continue;
664  }
665 
666  // Need to save dn for linearity correction
667  bdn[j][k] = bsci[j][k] - bdc[j];
668  bcal[j][k] = k3[j] * bgains.K1K2[j][hside[iscn]] * bdn[j][k];
669  }
670  }
671 
672  delete [] k3;
673  delete [] bdc;
674 
675  // Compute and apply RVS and linearity
676  //k4 = fltarr(pdim,nib)
677  float **k4 = new float *[bib];
678  k4[0] = new float[pcdim*bib];
679  for (size_t i=1; i<bib; i++) k4[i] = k4[i-1] + pcdim;
680 
681  get_oci_rvs_corr( bib, pcdim, hside[iscn], bgains, thetap, k4);
682 
683  float **k5 = new float *[bib];
684  k5[0] = new float[pcdim*bib];
685  for (size_t i=1; i<bib; i++) k5[i] = k5[i-1] + pcdim;
686 
687  get_oci_lin_corr( bib, pcdim, bgains, K3T, caltemps[iscn], bdn, k5);
688 
689  for (size_t j=0; j<bib; j++) {
690  for (size_t k=0; k<pcdim; k++) {
691  bcal[j][k] *= k4[j][k] * k5[j][k];
692  }
693  }
694 
695  delete [] k4[0];
696  delete [] k4;
697  delete [] k5[0];
698  delete [] k5;
699 
700  float **bcalb = new float *[bib];
701  bcalb[0] = new float[pcdim*bib];
702  for (size_t i=1; i<bib; i++) bcalb[i] = bcalb[i-1] + pcdim;
703 
704  // Aggregate to L1B bands
705  //bcalb = transpose(bamat#transpose(bcal))
706  for (size_t j=0; j<bib; j++) {
707  for (size_t k=0; k<pcdim; k++) {
708  float sum = 0.0;
709  for (size_t l=0; l<bib; l++)
710  if (bcal[l][k] != -999) sum += bamat[j][l]*bcal[l][k];
711  bcalb[j][k] = sum;
712  }
713  }
714 
715  start.clear();
716  start.push_back(0);
717  start.push_back(iscn);
718  start.push_back(0);
719 
720  count.clear();
721  count.push_back(bcount[0]);
722  count.push_back(bcount[1]);
723  count.push_back(bcount[2]);
724 
725  // Output to L1B file
726  var = outfile.ncGrps[4].getVar( "Lt_blue");
727  var.putVar( start, count, &bcalb[0][0]);
728  // BCALB FLOAT = Array[1306, 64]
729 
730  delete [] bcalb[0];
731  delete [] bcalb;
732  delete [] bsci[0];
733  delete [] bsci;
734  } // End blue
735 
736 
737  // Red bands
738  if (rib >= 4) {
739 
740  start.clear();
741  start.push_back(iscn);
742  start.push_back(0);
743  start.push_back(0);
744 
745  count.clear();
746  count.push_back(ricount[0]);
747  count.push_back(ricount[1]);
748  count.push_back(ricount[2]);
749 
750  uint16_t **rsci = new uint16_t *[rib];
751  rsci[0] = new uint16_t[pcdim*rib];
752  for (size_t i=1; i<rib; i++) rsci[i] = rsci[i-1] + pcdim;
753 
754  var = ncGrps[3].getVar( "sci_red");
755  var.getVar( start, count, rsci[0]);
756 
757  tempOut.open ("rsci.bin", ios::out | ios::trunc | ios::binary);
758  tempOut.write((char *) rsci[0], sizeof(uint16_t)*pcdim*rib);
759  tempOut.close();
760 
761  // Compute dark offset, correct data, and apply absolute and
762  // temporal gain and temperature correction
763  float *rdc = new float[rib];
764  fill32 = rfill;
765  int16_t iret;
766  get_oci_dark<uint16_t>( iscn, nscan_good, hside, ndsc, nskp,
767  iagg[ka], iagg[kd], ntaps, ragg, fill32,
768  ndc, rdark, rib, rdc, iret);
769 
770  tempOut.open ("rdc.bin", ios::out | ios::trunc | ios::binary);
771  tempOut.write((char *) rdc, sizeof(float)*rib);
772  tempOut.close();
773  float *k3 = new float[rib];
774  get_oci_temp_corr( rib, rgains, K3T, caltemps[iscn], nscan_good, k3);
775  tempOut.open ("k3.bin", ios::out | ios::trunc | ios::binary);
776  tempOut.write((char *) k3, sizeof(float)*rib);
777  tempOut.close();
778  for (size_t j=0; j<rib; j++) {
779  for (size_t k=0; k<pcdim; k++) {
780 
781  // Handle fill value
782  if (rsci[j][k] == rfill) {
783  rdn[j][k] = -999;
784  rcal[j][k] = -999;
785  continue;
786  }
787 
788  // Need to save dn for linearity correction
789  rdn[j][k] = rsci[j][k] - rdc[j];
790  rcal[j][k] = k3[j] * rgains.K1K2[j][hside[iscn]] * rdn[j][k];
791  }
792  }
793  tempOut.open ("rdn.bin", ios::out | ios::trunc | ios::binary);
794  tempOut.write((char *) rdn[0], sizeof(float)*pcdim*rib);
795  tempOut.close();
796 
797  delete [] k3;
798  delete [] rdc;
799 
800  // Compute and apply RVS and linearity
801  //k4 = fltarr(pdim,nib)
802  float **k4 = new float *[rib];
803  k4[0] = new float[pcdim*rib];
804  for (size_t i=1; i<rib; i++) k4[i] = k4[i-1] + pcdim;
805  get_oci_rvs_corr( rib, pcdim, hside[iscn], rgains, thetap, k4);
806  tempOut.open ("k4.bin", ios::out | ios::trunc | ios::binary);
807  tempOut.write((char *) k4[0], sizeof(float)*pcdim*rib);
808  tempOut.close();
809 
810  float **k5 = new float *[rib];
811  k5[0] = new float[pcdim*rib];
812  for (size_t i=1; i<rib; i++) k5[i] = k5[i-1] + pcdim;
813 
814  get_oci_lin_corr( rib, pcdim, rgains, K3T, caltemps[iscn], rdn, k5);
815  tempOut.open ("k5.bin", ios::out | ios::trunc | ios::binary);
816  tempOut.write((char *) k5[0], sizeof(float)*pcdim*rib);
817  tempOut.close();
818  for (size_t j=0; j<rib; j++) {
819  for (size_t k=0; k<pcdim; k++) {
820  rcal[j][k] *= k4[j][k] * k5[j][k];
821  }
822  }
823 
824  tempOut.open ("rcal.bin", ios::out | ios::trunc | ios::binary);
825  tempOut.write((char *) rcal[0], sizeof(float)*pcdim*rib);
826  tempOut.close();
827 
828  delete [] k4[0];
829  delete [] k4;
830  delete [] k5[0];
831  delete [] k5;
832 
833  float **rcalb = new float *[rib];
834  rcalb[0] = new float[pcdim*rib];
835  for (size_t i=1; i<rib; i++) rcalb[i] = rcalb[i-1] + pcdim;
836 
837  // Aggregate to L1B bands
838  for (size_t j=0; j<rib; j++) {
839  for (size_t k=0; k<pcdim; k++) {
840  float sum = 0.0;
841  for (size_t l=0; l<rib; l++)
842  if (rcal[l][k] != -999) sum += ramat[j][l]*rcal[l][k];
843  rcalb[j][k] = sum;
844  }
845  }
846 
847  tempOut.open ("rcalb.bin", ios::out | ios::trunc | ios::binary);
848  tempOut.write((char *) rcalb[0], sizeof(float)*pcdim*rib);
849  tempOut.close();
850 
851  start.clear();
852  start.push_back(0);
853  start.push_back(iscn);
854  start.push_back(0);
855 
856  count.clear();
857  count.push_back(rcount[0]);
858  count.push_back(rcount[1]);
859  count.push_back(rcount[2]);
860 
861  // Output to L1B file
862  var = outfile.ncGrps[4].getVar( "Lt_red");
863  var.putVar( start, count, &rcalb[0][0]);
864 
865  delete [] rcalb[0];
866  delete [] rcalb;
867  delete [] rsci[0];
868  delete [] rsci;
869  } // End red
870 
871  // SWIR bands
872  start.clear();
873  start.push_back(iscn);
874  start.push_back(0);
875  start.push_back(0);
876 
877  count.clear();
878  count.push_back(sicount[0]);
879  count.push_back(sicount[1]);
880  count.push_back(sicount[2]);
881 
882  uint32_t **ssci = new uint32_t *[swb];
883  ssci[0] = new uint32_t[psdim*swb];
884  for (size_t i=1; i<swb; i++) ssci[i] = ssci[i-1] + psdim;
885 
886  var = ncGrps[3].getVar( "sci_SWIR");
887  var.getVar( start, count, ssci[0]);
888 
889  // Compute dark offset, correct data, and apply absolute and
890  // temporal gain and temperature correction
891  float *sdc = new float[swb];
892  // int16_t sagg = 8;
893  int16_t sagg = 1;
894  int16_t iret;
895  get_oci_dark<uint32_t>( iscn, nscan_good, hside, ndsc, nskp,
896  1, 1, 1, &sagg, sfill, nds, sdark,
897  swb, sdc, iret);
898 
899  float *k3 = new float[swb];
900  if ( iret != -1) {
901  get_oci_temp_corr( swb, sgains, K3T, caltemps[iscn], nscan_good, k3);
902 
903  for (size_t j=0; j<swb; j++) {
904  for (size_t k=0; k<psdim; k++) {
905 
906  // Handle fill value
907  if (ssci[j][k] == sfill) {
908  sdn[j][k] = -999;
909  scal[j][k] = -999;
910  continue;
911  }
912 
913  // Need to save dn for linearity correction
914  sdn[j][k] = ssci[j][k] - sdc[j];
915 
916  // Hysteresis correction
917  float hc_prev[3];
918  float hc[3]={0,0,0};
919  float hyst = 0.0;
920  for (size_t l=0; l<3; l++) {
921  // Compute exponential decay constants
922  float e = exp(-1.0/hysttime[j][l]);
923 
924  if ( k > 0) {
925  hc[l] = hc_prev[l]*e + sdn[j][k-1]*hystamp[j][l];
926  hyst += hc[l];
927  }
928  hc_prev[l] = hc[l];
929  } // l-loop
930 
931  scal[j][k] =
932  k3[j] * sgains.K1K2[j][hside[iscn]] * (sdn[j][k] - hyst);
933  } // k-loop
934  }
935  } // iret != -1
936 
937  delete [] k3;
938  delete [] sdc;
939 
940  // Compute and apply RVS and linearity
941  float **k4 = new float *[swb];
942  k4[0] = new float[psdim*swb];
943  for (size_t i=1; i<swb; i++) k4[i] = k4[i-1] + psdim;
944  if ( iret != -1)
945  get_oci_rvs_corr( swb, psdim, hside[iscn], sgains, thetap, k4);
946 
947  float **k5 = new float *[swb];
948  k5[0] = new float[psdim*swb];
949  for (size_t i=1; i<swb; i++) k5[i] = k5[i-1] + psdim;
950 
951  if ( iret != -1)
952  get_oci_lin_corr( swb, psdim, sgains, K3T, caltemps[iscn], sdn, k5);
953 
954  for (size_t j=0; j<swb; j++) {
955  for (size_t k=0; k<psdim; k++) {
956  if (scal[j][k] != -999)
957  scal[j][k] *= k4[j][k] * k5[j][k];
958  }
959  }
960 
961  delete [] k4[0];
962  delete [] k4;
963  delete [] k5[0];
964  delete [] k5;
965 
966  start.clear();
967  start.push_back(0);
968  start.push_back(iscn);
969  start.push_back(0);
970 
971  count.clear();
972  count.push_back(scount[0]);
973  count.push_back(scount[1]);
974  count.push_back(scount[2]);
975 
976  // Output to L1B file
977  var = outfile.ncGrps[4].getVar( "Lt_SWIR");
978  var.putVar( start, count, &scal[0][0]);
979 
980  delete [] ssci[0];
981  delete [] ssci;
982 
983  } else {
984  cout << "No mirror side index for scan: " << iscn << endl;
985  } // Check for valid mirror side
986  } // Scan loop
987 
988 
989  // BAMAT FLOAT = Array[64, 64]
990  // BGMAT FLOAT = Array[64, 512]
991  // Write spectral band information
992  // Calculate band centers for aggregated hyperspectral bands
993  // b1bwave = bamat#bgmat#bwave
994  if (bib >= 4) {
995  // bgmat#bwave
996  float *b1bwave = new float[bib];
997  float *sum = new float[bib];
998  for (size_t i=0; i<bib; i++) {
999  sum[i] = 0.0;
1000  for (size_t j=0; j<512; j++) {
1001  sum[i] += bwave[j]*bgmat[j][i];
1002  }
1003  }
1004 
1005  // bamat#sum
1006  for (size_t i=0; i<bib; i++) {
1007  b1bwave[i] = 0.0;
1008  for (size_t j=0; j<bib; j++) {
1009  b1bwave[i] += bamat[i][j]*sum[j];
1010  }
1011  }
1012 
1013  start.clear();
1014  start.push_back(0);
1015 
1016  count.clear();
1017  count.push_back(bbands);
1018  var = outfile.ncGrps[0].getVar( "blue_wavelength");
1019  var.putVar( start, count, b1bwave);
1020 
1021  delete [] b1bwave;
1022  delete [] sum;
1023  }
1024 
1025  if (rib >= 4) {
1026  float *r1bwave = new float[rib];
1027  float *sum = new float[rib];
1028  for (size_t i=0; i<rib; i++) {
1029  sum[i] = 0.0;
1030  for (size_t j=0; j<512; j++) {
1031  sum[i] += rwave[j]*rgmat[j][i];
1032  }
1033  }
1034 
1035  for (size_t i=0; i<rib; i++) {
1036  r1bwave[i] = 0.0;
1037  for (size_t j=0; j<rib; j++) {
1038  r1bwave[i] += ramat[i][j]*sum[j];
1039  }
1040  }
1041 
1042  start.clear();
1043  start.push_back(0);
1044 
1045  count.clear();
1046  count.push_back(rbands);
1047  var = outfile.ncGrps[0].getVar( "red_wavelength");
1048  var.putVar( start, count, r1bwave);
1049 
1050  delete [] r1bwave;
1051  delete [] sum;
1052  }
1053 
1054  // SWIR wavelengths/bandpass
1055  start.clear();
1056  start.push_back(0);
1057  count.clear();
1058  count.push_back(NIWAVE);
1059 
1060  var = outfile.ncGrps[0].getVar( "SWIR_wavelength");
1061  var.putVar( start, count, swave);
1062  var = outfile.ncGrps[0].getVar( "SWIR_bandpass");
1063  var.putVar( start, count, spass);
1064 
1065 
1066  string l1b_filename;
1067  l1b_filename.assign(argv[4]);
1068  outfile.write_granule_metadata( tstart, tend, l1b_filename);
1069 
1070  outfile.close();
1071 
1072  delete [] sstime;
1073  delete [] spin;
1074  delete [] hside;
1075  delete [] dtype;
1076  delete [] lines;
1077  delete [] iagg;
1078  delete [] bagg;
1079  delete [] ragg;
1080  delete [] mspin;
1081  delete [] ot_10us;
1082  delete [] enc_count;
1083  delete [] sgmat;
1084  delete [] thetap;
1085  delete [] thetas;
1086  delete [] ia;
1087  delete [] evtime;
1088 
1089  delete [] hamenc[0];
1090  delete [] hamenc;
1091  delete [] rtaenc[0];
1092  delete [] rtaenc;
1093  delete [] caltemps[0];
1094  delete [] caltemps;
1095  delete [] bdn[0];
1096  delete [] bdn;
1097  delete [] rdn[0];
1098  delete [] rdn;
1099  delete [] sdn[0];
1100  delete [] sdn;
1101  delete [] bcal[0];
1102  delete [] bcal;
1103  delete [] rcal[0];
1104  delete [] rcal;
1105  delete [] scal[0];
1106  delete [] scal;
1107  delete [] pview[0];
1108  delete [] pview;
1109  delete [] sview[0];
1110  delete [] sview;
1111 
1112  delete [] blue_lut.K1[0];
1113  delete [] blue_lut.K1;
1114  delete [] blue_lut.K5[0];
1115  delete [] blue_lut.K5;
1116 
1117  if (bgains.K1K2 != NULL) delete [] bgains.K1K2[0];
1118  if (bgains.K1K2 != NULL) delete [] bgains.K1K2;
1119  if (bgains.K5 != NULL) delete [] bgains.K5[0];
1120  if (bgains.K5 != NULL) delete [] bgains.K5;
1121 
1122  // delete [] arrT[0][0]; delete [] arrT[0]; delete [] arrT;
1123 
1124  delete [] red_lut.K1[0];
1125  delete [] red_lut.K1;
1126  delete [] red_lut.K5[0];
1127  delete [] red_lut.K5;
1128 
1129  if (rgains.K1K2 != NULL) delete [] rgains.K1K2[0];
1130  if (rgains.K1K2 != NULL) delete [] rgains.K1K2;
1131  if (rgains.K5 != NULL) delete [] rgains.K5[0];
1132  if (rgains.K5 != NULL) delete [] rgains.K5;
1133 
1134  delete [] swir_lut.K1[0];
1135  delete [] swir_lut.K1;
1136  delete [] swir_lut.K5[0];
1137  delete [] swir_lut.K5;
1138 
1139  delete [] sgains.K1K2[0];
1140  delete [] sgains.K1K2;
1141  delete [] sgains.K5[0];
1142  delete [] sgains.K5;
1143 
1144  // Add delete for dark arrays
1145 
1146  return 0;
1147 }
1148 
1149 int read_mce_tlm( NcFile *l1afile, NcGroup egid,
1150  uint32_t nscan, uint32_t nenc, int32_t& ppr_off,
1151  double& revpsec, double&secpline, int32_t *mspin,
1152  int32_t *ot_10us, uint8_t *enc_count,
1153  float **hamenc, float **rtaenc) {
1154 
1155  NcDim mce_dim = l1afile->getDim("MCE_block");
1156  uint32_t mce_blk = mce_dim.getSize();
1157  NcDim ddc_dim = l1afile->getDim("DDC_tlm");
1158  uint32_t nddc = ddc_dim.getSize();
1159  NcDim tlm_dim = l1afile->getDim("tlm_packets");
1160  uint32_t ntlm = tlm_dim.getSize();
1161 
1162  uint8_t **mtlm = new uint8_t *[nscan];
1163  mtlm[0] = new uint8_t[mce_blk*nscan];
1164  for (size_t i=1; i<nscan; i++) mtlm[i] = mtlm[i-1] + mce_blk;
1165 
1166  int16_t **enc = new int16_t *[nscan];
1167  enc[0] = new int16_t[4*nenc*nscan];
1168  for (size_t i=1; i<nscan; i++) enc[i] = enc[i-1] + 4*nenc;
1169 
1170  uint8_t **ddctlm = new uint8_t *[ntlm];
1171  ddctlm[0] = new uint8_t[nddc*ntlm];
1172  for (size_t i=1; i<ntlm; i++) ddctlm[i] = ddctlm[i-1] + nddc;
1173 
1174  NcVar var;
1175  vector<size_t> start, count;
1176  start.push_back(0);
1177  start.push_back(0);
1178  count.push_back(1);
1179 
1180  /*
1181  // Read MCE telemetry byte-by-byte to convert from int8_t to uint8_t
1182  int8_t *buf = new int8_t[mce_blk];
1183  var = egid.getVar( "MCE_telemetry");
1184  count.push_back(mce_blk);
1185  for (size_t i=0; i<nscan; i++) {
1186  start[0] = i;
1187  var.getVar( start, count, buf);
1188  for (size_t j=0; j<mce_blk; j++) {
1189  if ( buf[j] & 0x80 == 0)
1190  mtlm[i][j] = buf[j]; else mtlm[i][j] = 256 + buf[j];
1191  // cout << i << " " << j << " " << (int) mtlm[i][j] << endl;
1192  }
1193  }
1194  delete [] buf;
1195  */
1196  var = egid.getVar( "MCE_telemetry");
1197  count.push_back(mce_blk);
1198  var.getVar( &mtlm[0][0]);
1199 
1200  var = egid.getVar( "MCE_encoder_data");
1201  count.pop_back();
1202  count.push_back(4*nenc);
1203  var.getVar( &enc[0][0]);
1204 
1205  var = egid.getVar( "MCE_spin_ID");
1206  var.getVar( mspin);
1207 
1208  var = egid.getVar( "DDC_telemetry");
1209  var.getVar( &ddctlm[0][0]);
1210 
1211  int32_t max_enc_cts = 131072; // 2^17
1212  double clock[2] = {1.36e8,1.0e8};
1213 
1214  // Get ref_pulse_divider and compute commanded rotation rate
1215  uint32_t ui32;
1216  uint32_t ref_pulse_div[2];
1217  memcpy( &ui32, &mtlm[0][0], 4);
1218  ref_pulse_div[0] = SWAP_4( ui32) % 16777216; // 2^24
1219  memcpy( &ui32, &mtlm[0][4], 4);
1220  ref_pulse_div[1] = SWAP_4( ui32) % 16777216; // 2^24
1221 
1222  int32_t ref_pulse_sel = mtlm[0][9] / 128;
1223 
1224  revpsec = clock[ref_pulse_sel] / 2 / max_enc_cts /
1225  (ref_pulse_div[ref_pulse_sel]/256.0 + 1);
1226 
1227  // Get PPR offset and on-time_10us
1228  memcpy( &ui32, &mtlm[0][8], 4);
1229  ppr_off = SWAP_4( ui32) % max_enc_cts;
1230  for (size_t i=0; i<nscan; i++) {
1231  memcpy( &ui32, &mtlm[i][368], 4);
1232  ot_10us[i] = SWAP_4( ui32) % 4;
1233  }
1234 
1235  // Get TDI time and compute time increment per line
1236  uint16_t ui16;
1237  memcpy( &ui16, &ddctlm[0][346], 2);
1238  int32_t tditime = SWAP_2( ui16);
1239  secpline = (tditime+1) / clock[0];
1240 
1241  // Get valid encoder count, HAM and RTA encoder data
1242  for (size_t i=0; i<nscan; i++) enc_count[i] = mtlm[i][475];
1243  float enc_s = 81.0 / 2560;
1244  for (size_t i=0; i<nscan; i++) {
1245  for (size_t j=0; j<nenc; j++) {
1246  hamenc[i][j] = enc[i][4*j+0] * enc_s;
1247  rtaenc[i][j] = enc[i][4*j+1] * enc_s;
1248  }
1249  }
1250 
1251  delete[] mtlm[0];
1252  delete[] mtlm;
1253 
1254  delete [] enc[0];
1255  delete [] enc;
1256 
1257  delete [] ddctlm[0];
1258  delete [] ddctlm;
1259 
1260  return 0;
1261 }
1262 
1263 int get_ev( double secpline, int16_t *dtype, int16_t *lines, int16_t *iagg,
1264  uint16_t& pcdim, uint16_t& psdim, double& ev_toff,
1265  float *clines, float *slines, double *deltc, double *delts,
1266  int16_t &iret) {
1267 
1268  // Find end of no-data zone
1269  int16_t iz=0, line0=0, linen;
1270  iret = -1;
1271  while ( dtype[iz] == 0) {
1272  line0 += lines[iz];
1273  iz++;
1274  }
1275  if (iz == 10) return 0;
1276 
1277  // Find number of pixels in Earth views
1278  pcdim = 0;
1279  psdim = 0;
1280  linen = line0;
1281  for (size_t i=iz; i<9; i++) {
1282  // Check for Earth, solar, lunar or diagnostic mode
1283  if ( dtype[i] == 1 || dtype[i] == 3 || dtype[i] == 4 || dtype[i] == 6 ||
1284  dtype[i] == 7 || dtype[i] == 9) {
1285  uint16_t np = lines[i] / iagg[i];
1286  for (size_t j=0; j<np; j++) {
1287  clines[pcdim+j] = linen + j*iagg[i] + 0.5*(iagg[i]-1);
1288  }
1289  pcdim += np;
1290  uint16_t ns = lines[i] / 8;
1291  for (size_t j=0; j<ns; j++) {
1292  slines[psdim+j] = linen + j*8 + 3.5;
1293  }
1294  psdim += ns;
1295  iret = 0;
1296  }
1297  linen += lines[i];
1298  }
1299 
1300  // Calculate times
1301  for (size_t i=0; i<(size_t) pcdim; i++) deltc[i] = secpline * clines[i];
1302  ev_toff = 0.5 * (deltc[0] + deltc[pcdim-1]);
1303  for (size_t i=0; i<(size_t) pcdim; i++) deltc[i] -= ev_toff;
1304 
1305  for (size_t i=0; i<(size_t) psdim; i++)
1306  delts[i] = secpline * slines[i] - ev_toff;
1307 
1308  return 0;
1309 }
1310 
1311 
1312 int get_agg_mat( size_t *ia, int16_t iagg, int16_t jagg[16], uint16_t nib,
1313  uint32_t& nbb, uint32_t ntb[16], float **amat, float **gmat) {
1314 
1315  // Populate gain aggregation matrix
1316 
1317  for (size_t i=0; i<512; i++) {
1318  gmat[i] = new float[nib];
1319  for (size_t j=0; j<nib; j++) gmat[i][j] = 0.0;
1320  }
1321 
1322  int16_t ii = 0;
1323  int16_t itt[16][2];
1324  for (size_t i=0; i<16; i++) {
1325  if ( jagg[i] > 0) {
1326  int16_t iaf = 4;
1327  if ( iagg*jagg[i] < iaf) iaf = iagg*jagg[i];
1328  for (size_t k=0; k<ntb[i]; k++) {
1329  size_t ic = 32*i;
1330  size_t kj = k*jagg[i];
1331  for (size_t j=0; j<(size_t) jagg[i]; j++)
1332  gmat[ic+kj+j][ii+k] = (1.0/jagg[i]) * (4/iaf);
1333  }
1334  itt[i][0] = ii;
1335  ii += ntb[i];
1336  itt[i][1] = ii - 1;
1337  }
1338  }
1339 
1340  // Compute number of bands for 8x aggregation with overlapping bands
1341  nbb = (ntb[0]*3) / 4 + 1;
1342  //amat(nbb,nib)
1343  for (size_t i=1; i<16; i++) {
1344  if (jagg[i] >= jagg[i-1])
1345  nbb += ntb[i];
1346  else
1347  nbb += (ntb[i]*3) / 4 + ntb[i-1]/4;
1348  }
1349 
1350  for (size_t i=0; i<nib; i++) {
1351  amat[i] = new float[nbb];
1352  for (size_t j=0; j<nbb; j++) amat[i][j] = 0;
1353  }
1354 
1355  // First tap
1356  int16_t ib;
1357  for (size_t k=0; k<=(ntb[ia[0]]*3)/4; k++) {
1358  amat[k+ntb[ia[0]]/4-1][k] = jagg[ia[0]]/8.0;
1359  }
1360  ib = (ntb[ia[0]]*3)/4 + 1;
1361 
1362  // Remaining taps
1363  uint16_t nr;
1364  for (size_t i=ia[1]; i<16; i++) {
1365  if (ntb[i] > 0) {
1366  if (ntb[i] >= ntb[i-1]) {
1367  // Transition resolution determined by preceding tap
1368  nr = ntb[i-1]/4 - 1;
1369  // Remaining bands using preceding tap
1370  if (nr > 0) {
1371  for (size_t k=0; k<nr; k++) {
1372  uint16_t k1 = nr - k - 1;
1373  uint16_t k2 = ((k+1)*ntb[i]) / ntb[i-1] - 1;
1374  for (size_t j=0; j<k1; j++)
1375  amat[itt[i-1][1]-k1+j][ib+k] = jagg[i-1] / 8.0;
1376  for (size_t j=0; j<k2; j++)
1377  amat[itt[i][0]+j][ib+k] = jagg[i] / 8.0;
1378  }
1379  ib += nr;
1380  }
1381  } else {
1382  // Transition resolution determined using current tap
1383  nr = ntb[i]/4 - 1;
1384  // Remaining bands using previous tap
1385  if (nr > 0) {
1386  for (size_t k=0; k<nr; k++) {
1387  uint16_t k1 = ((nr-k)*ntb[i-1]) / ntb[i] - 1;
1388  uint16_t k2 = k;
1389  for (size_t j=0; j<k1; j++)
1390  amat[itt[i-1][1]-k1+j][ib+k] = jagg[i-1] / 8.0;
1391  for (size_t j=0; j<k2; j++)
1392  amat[itt[i][0]+j][ib+k] = jagg[i] / 8.0;
1393  }
1394  ib += nr;
1395  }
1396  }
1397  // Remaining bands using this tap
1398  for (size_t k=0; k<=(ntb[i]*3)/4; k++) {
1399  for (size_t j=0; j<ntb[i]/4; j++)
1400  amat[itt[i][0]+k+j][ib+k] = jagg[i] / 8.0;
1401  }
1402  ib += (ntb[i]*3) / 4 + 1;
1403  }
1404  }
1405 
1406  return 0;
1407 }
1408 
1409 int read_oci_cal_lut( NcFile *calLUTfile, string tag, NcGroup gidLUT,
1410  uint32_t& banddim, cal_lut_struct& cal_lut) {
1411 
1412  size_t dims[3];
1413  NcDim ncDIM;
1414  uint32_t timedim, tempdim, tcdim, rvsdim, nldim, msdim=2;
1415  string bandname;
1416  bandname.assign( tag);
1417  bandname.append( "_bands");
1418 
1419  ncDIM = calLUTfile->getDim(bandname.c_str());
1420  banddim = ncDIM.getSize();
1421 
1422  ncDIM = calLUTfile->getDim("number_of_times");
1423  timedim = ncDIM.getSize();
1424  ncDIM = calLUTfile->getDim("number_of_temperatures");
1425  tempdim = ncDIM.getSize();
1426  ncDIM = calLUTfile->getDim("number_of_T_coefficients");
1427  tcdim = ncDIM.getSize();
1428  ncDIM = calLUTfile->getDim("number_of_RVS_coefficients");
1429  rvsdim = ncDIM.getSize();
1430  ncDIM = calLUTfile->getDim("number_of_nonlinearity_coefficients");
1431  nldim = ncDIM.getSize();
1432 
1433  float **K1 = new float *[banddim];
1434  K1[0] = new float[msdim*banddim];
1435  for (size_t i=1; i<banddim; i++) K1[i] = K1[i-1] + msdim;
1436  cal_lut.K1 = K1;
1437 
1438  dims[0] = banddim; dims[1] = msdim; dims[2] = timedim;
1439  float ***K2 = make3dT<float>(dims);
1440  cal_lut.K2 = K2;
1441  dims[0] = banddim; dims[1] = tempdim; dims[2] = tcdim;
1442  float ***K3_coef = make3dT<float>(dims);
1443  cal_lut.K3_coef = K3_coef;
1444  dims[0] = banddim; dims[1] = msdim; dims[2] = rvsdim;
1445  float ***K4_coef = make3dT<float>(dims);
1446  cal_lut.K4_coef = K4_coef;
1447 
1448  double **K5 = new double *[banddim];
1449  K5[0] = new double[nldim*banddim];
1450  for (size_t i=1; i<banddim; i++) K5[i] = K5[i-1] + nldim;
1451  cal_lut.K5 = K5;
1452 
1453  cal_lut.ldims[0] = timedim; cal_lut.ldims[1] = tempdim;
1454  cal_lut.ldims[2] = tcdim; cal_lut.ldims[3] = rvsdim;
1455  cal_lut.ldims[4] = nldim; cal_lut.ldims[5] = msdim;
1456 
1457  NcVar var;
1458 
1459  var = gidLUT.getVar( "K1");
1460  var.getVar( &cal_lut.K1[0][0]);
1461  var = gidLUT.getVar( "K2");
1462  var.getVar( &cal_lut.K2[0][0][0]);
1463  var = gidLUT.getVar( "K3_coef");
1464  var.getVar( &cal_lut.K3_coef[0][0][0]);
1465  var = gidLUT.getVar( "K4_coef");
1466  var.getVar( &cal_lut.K4_coef[0][0][0]);
1467  var = gidLUT.getVar( "K5");
1468  var.getVar( &cal_lut.K5[0][0]);
1469 
1470  return 0;
1471 }
1472 
1473 // float K1K2[nib][msdim]: absolute and temporal gain
1474 // float K3_coef[nib][tempdim][tcdim]: temperature correction
1475 // float K4_coef[nib][msdim][rvsdim]: RVS correction
1476 // double K5[nib][nldim]: linearity correction
1477 
1478 int make_oci_gains( uint32_t nib, uint32_t banddim, uint16_t iyr, uint16_t idom,
1479  double stime, double K2t[NTIMES], cal_lut_struct& cal_lut,
1480  float **gmat, gains_struct& gains) {
1481 
1482  for (size_t i=0; i<6; i++) gains.ldims[i] = cal_lut.ldims[i];
1483 
1484  uint16_t timedim = gains.ldims[0];
1485  uint16_t tempdim = gains.ldims[1];
1486  uint16_t tcdim = gains.ldims[2];
1487  uint16_t rvsdim = gains.ldims[3];
1488  uint16_t nldim = gains.ldims[4];
1489  uint16_t msdim = gains.ldims[5];
1490 
1491  size_t dims[3];
1492 
1493  float **K1K2 = new float *[nib];
1494  K1K2[0] = new float[nib*msdim];
1495  for (size_t i=1; i<nib; i++) K1K2[i] = K1K2[i-1] + msdim;
1496  gains.K1K2 = K1K2;
1497 
1498  dims[0] = nib; dims[1] = tempdim; dims[2] = tcdim;
1499  float ***K3_coef = make3dT<float>(dims);
1500  gains.K3_coef = K3_coef;
1501  dims[0] = nib; dims[1] = msdim; dims[2] = rvsdim;
1502  float ***K4_coef = make3dT<float>(dims);
1503  gains.K4_coef = K4_coef;
1504 
1505  double **K5 = new double *[nib];
1506  K5[0] = new double[nib*nldim];
1507  for (size_t i=1; i<nib; i++) K5[i] = K5[i-1] + nldim;
1508  gains.K5 = K5;
1509 
1510  // Mirror-side dependent gains
1511  double *K2 = new double[banddim];
1512  for (size_t ms=0; ms<msdim; ms++) {
1513 
1514  // Get temporal gain and combine with absolute gain
1515  double d2 = jday(iyr, 1, idom) - 2451545 + stime/864.0;
1516 
1517  size_t kd=0;
1518  for (size_t j=NTIMES-1; j>=0; j--) {
1519  if ( d2 > K2t[j]) {
1520  kd = j;
1521  break;
1522  }
1523  }
1524  if ( kd < (size_t) (timedim-1)) {
1525  double ff = (d2 - K2t[kd]) / (K2t[kd+1] - K2t[kd]);
1526  for (size_t j=0; j<banddim; j++)
1527  K2[j] = cal_lut.K2[j][ms][kd]*(1.0-ff) + cal_lut.K2[j][ms][kd+1]*ff;
1528  } else {
1529  for (size_t j=0; j<banddim; j++) K2[j] = cal_lut.K2[j][ms][kd];
1530  }
1531  for (size_t j=0; j<banddim; j++) K2[j] *= cal_lut.K1[j][ms];
1532  for (size_t i=0; i<nib; i++) {
1533  gains.K1K2[i][ms] = 0;
1534  for (size_t j=0; j<banddim; j++)
1535  gains.K1K2[i][ms] += gmat[j][i] * cal_lut.K1[j][ms];
1536  }
1537 
1538  // Generate RVS coefficents
1539  for (size_t i=0; i<nib; i++) {
1540  for (size_t k=0; k<rvsdim; k++) {
1541  gains.K4_coef[i][ms][k] = 0;
1542  for (size_t j=0; j<banddim; j++)
1543  gains.K4_coef[i][ms][k] += gmat[j][i] * cal_lut.K4_coef[j][ms][k];
1544  }
1545  }
1546  }
1547  delete [] K2;
1548 
1549  // Generate temperature coefficients
1550  for (size_t i=0; i<nib; i++) {
1551  for (size_t k=0; k<tcdim; k++) {
1552  for (size_t l=0; l<tempdim; l++) {
1553  gains.K3_coef[i][l][k] = 0;
1554  for (size_t j=0; j<banddim; j++)
1555  gains.K3_coef[i][l][k] += gmat[j][i] * cal_lut.K3_coef[j][l][k];
1556  }
1557  }
1558  }
1559 
1560  // Generate linearity coefficients
1561  for (size_t i=0; i<nib; i++) {
1562  for (size_t k=0; k<nldim; k++) {
1563  gains.K5[i][k] = 0;
1564  for (size_t j=0; j<banddim; j++)
1565  gains.K5[i][k] += gmat[j][i] * cal_lut.K5[j][k];
1566  }
1567  }
1568  /*
1569  for (size_t i=0; i<nib; i++) {
1570  for (size_t j=0; j<banddim; j++)
1571  cout << "2: " << i << " " << j << " " << gmat[j][i] << endl;
1572  }
1573  */
1574  return 0;
1575 }
1576 
1577 
1578 int get_oci_vecs( uint32_t nscan, uint16_t pdim, geo_struct& geoLUT,
1579  double ev_toff, int32_t spin, float *slines, double *delt,
1580  double revpsec, int32_t ppr_off, int32_t *mspin,
1581  int32_t *ot_10us, uint8_t *enc_count, float **hamenc,
1582  float **rtaenc, float **pview, double *theta, int16_t& iret) {
1583 
1584  // This program generates the OCI Earth view vectors for one spin.
1585  // It uses MCE telemetry and encoder data. Further refinements will be made
1586  // as the instrument optics model and test results become available.
1587  // Reference: "Use of OCI Telemetry to Determine Pixel Line-of-Sight",
1588  // F. Patt, 2020-05-18
1589 
1590  int32_t max_enc_cts = 131072; // 2^17
1591  double dtenc = 0.001;
1592  constexpr double pi = 3.14159265358979323846;
1593 
1594  double rad2asec = (180/pi) * 3600;
1595 
1596  // Compute scan angle corresponding to PPR
1597  float pprang = 2 * pi * (ppr_off - geoLUT.rta_nadir) / max_enc_cts;
1598  if (pprang > pi) pprang -= 2*pi;
1599 
1600  // Compute ideal scan angles for science pixels
1601  double *toff = new double[pdim];
1602  for (size_t i=0; i<pdim; i++) toff[i] = delt[i] + ev_toff;
1603 
1604  for (size_t i=0; i<pdim; i++)
1605  theta[i] = pprang + 2 * pi * revpsec * toff[i];
1606  // Interpolate encoder data to pixel times and add to scan angles
1607  // RTA only for now, include HAM when we know how.
1608 
1609  double *thetacor = new double[pdim];
1610 
1611  int isp = -1;
1612  for (size_t i=0; i<nscan; i++) {
1613  if ( mspin[i] == spin) {
1614  isp = (int) i;
1615  break;
1616  }
1617  }
1618  if ( isp == -1) {
1619  cout << "No MCE encoder data for spin: " << spin << endl;
1620  iret = 1;
1621  }
1622  size_t ip = 0, ke;
1623  double tenc_ke;
1624  while ( ip < pdim) {
1625  // Encoder sample times at 1 KHz
1626  for (size_t j=0; j<enc_count[isp]; j++) {
1627  double tenc = j*dtenc;
1628  if ( tenc < toff[ip] && (tenc+dtenc) > toff[ip]) {
1629  ke = j;
1630  tenc_ke = tenc;
1631  break;
1632  }
1633  }
1634  size_t njp=0;
1635  for (size_t i=0; i<pdim; i++) {
1636  if ( toff[i] >= tenc_ke && toff[i] < tenc_ke+dtenc) {
1637  double ft = (toff[i] - tenc_ke) / dtenc;
1638  thetacor[i] = (1-ft)*rtaenc[isp][ke] + ft*rtaenc[isp][ke+1];
1639  njp++;
1640  }
1641  }
1642  ip += njp;
1643  }
1644 
1645  // Simple, planar view vector model to start
1646  // Update when optical model is available.
1647  for (size_t i=0; i<pdim; i++) {
1648  theta[i] = theta[i] + thetacor[i] / rad2asec;
1649  pview[i][1] = sin(theta[i]);
1650  pview[i][2] = cos(theta[i]);
1651  }
1652 
1653  delete [] thetacor;
1654  delete [] toff;
1655 
1656  return 0;
1657 }
1658 
1659 
1660 template <typename T>
1661 int get_oci_dark( size_t iscn, uint32_t nscan, uint8_t *hside, uint16_t ndsc,
1662  uint16_t nskp, int16_t iags, int16_t iagd, uint32_t ntaps,
1663  int16_t *jagg, uint32_t dfill, int16_t ndc, T ***dark,
1664  uint32_t nib, float *dc, int16_t& iret) {
1665 
1666  // Program to generate dark corrections for OCI data by averaging the
1667  // dark collect data and correcting for bit shift/truncation if necessary
1668 
1669  // Determine number of bands per tap for hyperspectral data
1670  int16_t *nbndt = new int16_t[ntaps];
1671 
1672  if (ntaps == 16) {
1673  // hyperspectral bands
1674  for (size_t i=0; i<ntaps; i++)
1675  if ( jagg[i] > 0) nbndt[i] = 32 / jagg[i]; else nbndt[i] = 0;
1676  } else {
1677  for (size_t i=0; i<ntaps; i++) nbndt[i] = 9;
1678  }
1679  int16_t nbnd = 0;
1680  for (size_t i=0; i<ntaps; i++) nbnd += nbndt[i];
1681 
1682  // Select data for HAM side and determine scan indices
1683  int32_t *kh = new int32_t[nscan];
1684  int32_t nkh=0;
1685  for (size_t i=0; i<nscan; i++) {
1686  if ( hside[i] == hside[iscn]) {
1687  kh[i] = (int32_t) i;
1688  nkh++;
1689  } else {
1690  kh[i] = -1;
1691  }
1692  }
1693 
1694  int32_t js=0;
1695  for (size_t i=0; i<nscan; i++) {
1696  if ( kh[i] == (int32_t) iscn) {
1697  js = (int32_t) i;
1698  break;
1699  }
1700  }
1701 
1702  // Check for valid dark collect data within specified range
1703  uint16_t ndscl = ndsc;
1704  bool valid_dark_found = false;
1705  int32_t is1=js, is2=js;
1706 
1707  while (!valid_dark_found && ndscl <= nkh) {
1708  if ( ndsc > 1) {
1709  is1 = js - ndsc/2;
1710  is2 = js + ndsc/2;
1711  // Check for start or end of granule
1712  if (is1 < 0) {
1713  is1 = 0;
1714  is2 = ndsc - 1;
1715  }
1716  if (is2 >= nkh) {
1717  is1 = nkh - ndsc;
1718  is2 = nkh - 1;
1719  }
1720  }
1721 
1722  // If no valid dark data, expand scan range
1723  for (size_t i=is1; i<=(size_t) is2; i++) {
1724  for (size_t j=nskp; j<(size_t) ndc; j++) {
1725  if ( dark[kh[i]][0][j] != dfill) {
1726  valid_dark_found = true;
1727  break;
1728  }
1729  }
1730  }
1731  if ( !valid_dark_found) ndscl += 2;
1732  }
1733 
1734  if ( !valid_dark_found) {
1735  iret =-1;
1736  return 0;
1737  }
1738 
1739  // Loop through taps and compute dark correction
1740  int16_t ibnd=0;
1741  for (size_t i=0; i<ntaps; i++) {
1742  if ( jagg[i] > 0) {
1743  float ddiv = 1.0;
1744  float doff = 0.0;
1745  if ( iags*jagg[i] > 4) {
1746  ddiv = iagd * jagg[i] / 4.0;
1747  doff = (ddiv-1) / (2*ddiv);
1748  }
1749 
1750  for (size_t j=0; j<(size_t) nbndt[i]; j++) {
1751  float sum = 0.0;
1752  int nv = 0;
1753  for (size_t k=kh[is1]; k<=(size_t) kh[is2]; k++) {
1754  for (size_t l=nskp; l<(size_t) ndc; l++) {
1755  if (dark[k][ibnd+j][l] != dfill) {
1756  sum += dark[k][ibnd+j][l];
1757  nv++;
1758  }
1759  }
1760  }
1761  // dc[ibnd+j] = ((sum/(ndc-nskp))/ddiv) - doff;
1762  dc[ibnd+j] = ((sum/(nv))/ddiv) - doff;
1763  } // j loop
1764  } // if (
1765  ibnd += nbndt[i];
1766  } // i loop
1767 
1768  delete [] kh;
1769  delete [] nbndt;
1770 
1771  iret = 0;
1772  if (ndscl > ndsc) iret = 1;
1773 
1774  return 0;
1775 }
1776 
1777 
1778 int get_oci_temp_corr( uint32_t nib, gains_struct gains, float K3T[NTEMPS],
1779  float *caltemps, uint32_t nscan, float *k3) {
1780 
1781  uint16_t tempdim = gains.ldims[1];
1782  uint16_t tcdim = gains.ldims[2];
1783 
1784  for (size_t i=0; i<nib; i++) k3[i] = 1.0;
1785 
1786  for (size_t i=0; i<tempdim; i++) {
1787  float td = caltemps[i] - K3T[i];
1788  for (size_t j=0; j<tcdim; j++) {
1789  for (size_t k=0; k<nib; k++) {
1790  k3[k] -= gains.K3_coef[k][i][j] * powf(td, j+1);
1791  }
1792  }
1793  }
1794 
1795  return 0;
1796 }
1797 
1798 int get_oci_rvs_corr( uint32_t nib, uint16_t pdim, uint8_t hside,
1799  gains_struct gains, double *theta, float **k4) {
1800 
1801  // Program to compute RVS correction from coefficients and scan angle
1802 
1803  uint16_t rvsdim = gains.ldims[3];
1804 
1805  for (size_t i=0; i<nib; i++)
1806  for (size_t j=0; j<pdim; j++)
1807  k4[i][j] = 1.0;
1808 
1809  for (size_t i=0; i<rvsdim; i++)
1810  for (size_t j=0; j<nib; j++)
1811  for (size_t k=0; k<pdim; k++)
1812  k4[j][k] += gains.K4_coef[j][hside][i] * powf(theta[k], j+1);
1813 
1814  return 0;
1815 }
1816 
1817 int get_oci_lin_corr( uint32_t nib, uint16_t pdim, gains_struct gains,
1818  float K3T[NTEMPS], float *caltemps, float **dn,
1819  float **k5) {
1820 
1821  // Program to compute OCI linearity correction from coefficients, dn and
1822  // temperatures 3rd-order polynomial of dn with 2nd-order temperature effects
1823  // for three temperatures.
1824  // This is currently a SWAG at the functional form and will be revised when
1825  // better known
1826 
1827  // Index for which temperatures to use for linearity; revisit this when known
1828  int16_t ibtmp[3] = {1,2,3};
1829  float td[3];
1830  for (size_t i=0; i<3; i++) td[i] = caltemps[ibtmp[i]] - K3T[ibtmp[i]];
1831 
1832  for (size_t i=0; i<pdim; i++) {
1833  // Zeroth-order correction
1834  for (size_t j=0; j<nib; j++) k5[j][i] = gains.K5[j][0];
1835  // First and second-order corrections are quadratic functions of
1836  // temperatures
1837  for (size_t k=1; k<=2; k++) {
1838  for (size_t l=0; l<nib; l++) {
1839  k5[l][i] += (gains.K5[l][k] + gains.K5[l][k+3]*powf(td[0], k) +
1840  gains.K5[l][k+5]*powf(td[1], k) +
1841  gains.K5[l][k+7]*powf(td[2], k))*powf(dn[l][i], k);
1842  }
1843  // Third-order correction
1844  for (size_t l=0; l<nib; l++)
1845  k5[l][i] += gains.K5[l][3]*powf(dn[l][i], 3);
1846  }
1847  }
1848 
1849  return 0;
1850 }
1851 
1852 
1853 /*------------------------------------------------------------------ */
1854 /* Create an Generic NETCDF4 level1B file */
1855 /* ----------------------------------------------------------------- */
1856 int l1bFile::createl1b( char* l1b_filename, uint16_t nscan_good,
1857  uint16_t pcdim, uint16_t bbb, uint16_t rbb,
1858  uint16_t psdim, uint16_t swb) {
1859 
1860  // nscan_good: Number of scans in L1A file
1861  // pcdim: Number of CCD band pixels
1862  // bbb: Number of blue bands]
1863  // rbb: Number of red bands
1864  // psdim: Number of SWIR band pixels
1865  // swb: Number of SWIR bands
1866 
1867  try {
1868  l1bfile = new NcFile( l1b_filename, NcFile::replace);
1869  }
1870  catch ( NcException& e) {
1871  e.what();
1872  cerr << "Failure creating OCI L1B file: " << l1b_filename << endl;
1873  exit(1);
1874  }
1875 
1876  fileName.assign( l1b_filename);
1877 
1878  ifstream oci_l1b_data_structure;
1879  string line;
1880  string dataStructureFile;
1881  dataStructureFile.assign("$OCDATAROOT/oci/OCI_Level-1B_Data_Structure.cdl");
1882  expandEnvVar( &dataStructureFile);
1883 
1884  oci_l1b_data_structure.open( dataStructureFile.c_str(), ifstream::in);
1885  if ( oci_l1b_data_structure.fail() == true) {
1886  cout << "\"" << dataStructureFile.c_str() << "\" not found" << endl;
1887  exit(1);
1888  }
1889 
1890  // Find "dimensions" section of CDL file
1891  while(1) {
1892  getline( oci_l1b_data_structure, line);
1893  size_t pos = line.find("dimensions:");
1894  if ( pos == 0) break;
1895  }
1896 
1897  // Define dimensions from "dimensions" section of CDL file
1898  ndims = 0;
1899 
1900  while(1) {
1901  getline( oci_l1b_data_structure, line);
1902  if (line.substr(0,2) == "//") continue;
1903 
1904  size_t pos = line.find(" = ");
1905  size_t semi = line.find(" ;");
1906  if ( pos == string::npos) break;
1907 
1908  uint32_t dimSize;
1909  istringstream iss;
1910  // istringstream iss(line.substr(pos+2, string::npos));
1911  string dimString = line.substr(pos+2, semi-(pos+2));
1912  if (dimString.find("UNLIMITED") == string::npos) {
1913  iss.str(dimString);
1914  iss >> dimSize;
1915  } else {
1916  dimSize = NC_UNLIMITED;
1917  }
1918 
1919  iss.clear();
1920  iss.str( line);
1921  iss >> skipws >> line;
1922 
1923  if (line.compare("ccd_pixels") == 0) {
1924  dimSize = pcdim;
1925  }
1926 
1927  if (line.compare("SWIR_pixels") == 0) {
1928  dimSize = psdim;
1929  }
1930 
1931  if (line.compare("blue_bands") == 0) {
1932  dimSize = bbb;
1933  }
1934 
1935  if (line.compare("red_bands") == 0) {
1936  dimSize = rbb;
1937  }
1938 
1939  if (line.compare("SWIR_bands") == 0) {
1940  dimSize = swb;
1941  }
1942 
1943  try {
1944  ncDims[ndims++] = l1bfile->addDim( line, dimSize);
1945  }
1946  catch ( NcException& e) {
1947  e.what();
1948  cerr << "Failure creating dimension: " << line.c_str() << endl;
1949  exit(1);
1950  }
1951 
1952  cout << "Dimension Name: " << line.c_str() << " Dimension Size: "
1953  << dimSize << endl;
1954 
1955  } // while loop
1956 
1957  // Read global attributes (string attributes only)
1958  while(1) {
1959  getline( oci_l1b_data_structure, line);
1960  size_t pos = line.find("// global attributes");
1961  if ( pos == 0) break;
1962  }
1963 
1964  while(1) {
1965  getline( oci_l1b_data_structure, line);
1966  size_t pos = line.find(" = ");
1967  if ( pos == string::npos) break;
1968 
1969  string attValue;
1970 
1971  // Remove leading and trailing quotes
1972  attValue.assign(line.substr(pos+4));
1973  size_t posQuote = attValue.find("\"");
1974  attValue.assign(attValue.substr(0, posQuote));
1975 
1976  istringstream iss(line.substr(pos+2));
1977  iss.clear();
1978  iss.str( line);
1979  iss >> skipws >> line;
1980 
1981  // Skip commented out attributes
1982  if (line.substr(0,2) == "//") continue;
1983 
1984  string attName;
1985  attName.assign(line.substr(1).c_str());
1986 
1987  // Skip non-string attributes
1988  if (attName.compare("orbit_number") == 0) continue;
1989  if (attName.compare("history") == 0) continue;
1990  if (attName.compare("format_version") == 0) continue;
1991  if (attName.compare("instrument_number") == 0) continue;
1992  if (attName.compare("pixel_offset") == 0) continue;
1993  if (attName.compare("number_of_filled_scans") == 0) continue;
1994 
1995  // cout << attName.c_str() << " " << attValue.c_str() << endl;
1996  try {
1997  l1bfile->putAtt(attName, attValue);
1998  }
1999  catch ( NcException& e) {
2000  e.what();
2001  cerr << "Failure creating attribute: " + attName << endl;
2002  exit(1);
2003  }
2004 
2005  } // while(1)
2006 
2007 
2008  ngrps = 0;
2009  // Loop through groups
2010  while(1) {
2011  getline( oci_l1b_data_structure, line);
2012 
2013  // Check if end of CDL file
2014  // If so then close CDL file and return
2015  if (line.substr(0,1).compare("}") == 0) {
2016  oci_l1b_data_structure.close();
2017  return 0;
2018  }
2019 
2020  // Check for beginning of new group
2021  size_t pos = line.find("group:");
2022 
2023  // If found then create new group and variables
2024  if ( pos == 0) {
2025 
2026  // Parse group name
2027  istringstream iss(line.substr(6, string::npos));
2028  iss >> skipws >> line;
2029 
2030  ncGrps[ngrps++] = l1bfile->addGroup(line);
2031 
2032  int numDims=0;
2033  string sname;
2034  string lname;
2035  string standard_name;
2036  string units;
2037  string flag_values;
2038  string flag_meanings;
2039  double valid_min=0.0;
2040  double valid_max=0.0;
2041  double fill_value=0.0;
2042 
2043  vector<NcDim> varVec;
2044 
2045  int ntype=0;
2046  NcType ncType;
2047 
2048  // Loop through datasets in group
2049  getline( oci_l1b_data_structure, line); // skip "variables:"
2050  while(1) {
2051  getline( oci_l1b_data_structure, line);
2052 
2053  if (line.substr(0,2) == "//") continue;
2054  if (line.length() == 0) continue;
2055  if (line.substr(0,1).compare("\r") == 0) continue;
2056  if (line.substr(0,1).compare("\n") == 0) continue;
2057 
2058  size_t pos = line.find(":");
2059 
2060  // No ":" found, new dataset or empty line or end-of-group
2061  if ( pos == string::npos) {
2062 
2063  if ( numDims > 0) {
2064  // Create previous dataset
2065 
2066  createField( ncGrps[ngrps-1], sname.c_str(), lname.c_str(),
2067  standard_name.c_str(), units.c_str(),
2068  (void *) &fill_value,
2069  flag_values.c_str(), flag_meanings.c_str(),
2070  valid_min, valid_max, ntype, varVec);
2071 
2072  flag_values.assign("");
2073  flag_meanings.assign("");
2074  units.assign("");
2075  varVec.clear();
2076  }
2077 
2078  valid_min=0.0;
2079  valid_max=0.0;
2080  fill_value=0.0;
2081 
2082  if (line.substr(0,10).compare("} // group") == 0) break;
2083 
2084  // Parse variable type
2085  string varType;
2086  istringstream iss(line);
2087  iss >> skipws >> varType;
2088 
2089  // Get corresponding NC variable type
2090  if ( varType.compare("char") == 0) ntype = NC_CHAR;
2091  else if ( varType.compare("byte") == 0) ntype = NC_BYTE;
2092  else if ( varType.compare("short") == 0) ntype = NC_SHORT;
2093  else if ( varType.compare("int") == 0) ntype = NC_INT;
2094  else if ( varType.compare("long") == 0) ntype = NC_INT;
2095  else if ( varType.compare("float") == 0) ntype = NC_FLOAT;
2096  else if ( varType.compare("real") == 0) ntype = NC_FLOAT;
2097  else if ( varType.compare("double") == 0) ntype = NC_DOUBLE;
2098  else if ( varType.compare("ubyte") == 0) ntype = NC_UBYTE;
2099  else if ( varType.compare("ushort") == 0) ntype = NC_USHORT;
2100  else if ( varType.compare("uint") == 0) ntype = NC_UINT;
2101  else if ( varType.compare("ulong") == 0) ntype = NC_UINT;
2102  else if ( varType.compare("int64") == 0) ntype = NC_INT64;
2103  else if ( varType.compare("uint64") == 0) ntype = NC_UINT64;
2104 
2105  // Parse short name (sname)
2106  pos = line.find("(");
2107  size_t posSname = line.substr(0, pos).rfind(" ");
2108  sname.assign(line.substr(posSname+1, pos-posSname-1));
2109  cout << "sname: " << sname.c_str() << endl;
2110 
2111  // Parse variable dimension info
2112  this->parseDims( line.substr(pos+1, string::npos), varVec);
2113  numDims = varVec.size();
2114 
2115  } else {
2116  // Parse variable attributes
2117  size_t posEql = line.find("=");
2118  size_t pos1qte = line.find("\"");
2119  size_t pos2qte = line.substr(pos1qte+1, string::npos).find("\"");
2120  // cout << line.substr(pos+1, posEql-pos-2).c_str() << endl;
2121 
2122  string attrName = line.substr(pos+1, posEql-pos-2);
2123 
2124  // Get long_name
2125  if ( attrName.compare("long_name") == 0) {
2126  lname.assign(line.substr(pos1qte+1, pos2qte));
2127  // cout << "lname: " << lname.c_str() << endl;
2128  }
2129 
2130  // Get units
2131  else if ( attrName.compare("units") == 0) {
2132  units.assign(line.substr(pos1qte+1, pos2qte));
2133  // cout << "units: " << units.c_str() << endl;
2134  }
2135 
2136  // Get _FillValue
2137  else if ( attrName.compare("_FillValue") == 0) {
2138  iss.clear();
2139  iss.str( line.substr(posEql+1, string::npos));
2140  iss >> fill_value;
2141  }
2142 
2143  // Get flag_values
2144  else if ( attrName.compare("flag_values") == 0) {
2145  flag_values.assign(line.substr(pos1qte+1, pos2qte));
2146  }
2147 
2148  // Get flag_meanings
2149  else if ( attrName.compare("flag_meanings") == 0) {
2150  flag_meanings.assign(line.substr(pos1qte+1, pos2qte));
2151  }
2152 
2153  // Get valid_min
2154  else if ( attrName.compare("valid_min") == 0) {
2155  iss.clear();
2156  iss.str( line.substr(posEql+1, string::npos));
2157  iss >> valid_min;
2158  // cout << "valid_min: " << valid_min << endl;
2159  }
2160 
2161  // Get valid_max
2162  else if ( attrName.compare("valid_max") == 0) {
2163  iss.clear();
2164  iss.str( line.substr(posEql+1, string::npos));
2165  iss >> valid_max;
2166  // cout << "valid_max: " << valid_max << endl;
2167  }
2168 
2169  } // if ( pos == string::npos)
2170  } // datasets in group loop
2171  } // New Group loop
2172  } // Main Group loop
2173 
2174  return 0;
2175 }
2176 
2177 
2178 int createField( NcGroup &ncGrp, const char *sname, const char *lname,
2179  const char *standard_name, const char *units,
2180  void *fill_value, const char *flag_values,
2181  const char *flag_meanings,
2182  double low, double high, int nt, vector<NcDim>& varVec) {
2183 
2184  size_t dimlength;
2185 
2186 
2187  /* Create the NCDF dataset */
2188  NcVar ncVar;
2189  try {
2190  ncVar = ncGrp.addVar(sname, nt, varVec);
2191  }
2192  catch ( NcException& e) {
2193  cout << e.what() << endl;
2194  cerr << "Failure creating variable: " << sname << endl;
2195  exit(1);
2196  }
2197 
2198  // Set fill value
2199  double fill_value_dbl;
2200  memcpy( &fill_value_dbl, fill_value, sizeof(double));
2201 
2202  int8_t i8;
2203  uint8_t ui8;
2204  int16_t i16;
2205  uint16_t ui16;
2206  int32_t i32;
2207  uint32_t ui32;
2208  float f32;
2209 
2210  if ( low != fill_value_dbl) {
2211  if ( nt == NC_BYTE) {
2212  i8 = fill_value_dbl;
2213  ncVar.setFill(true, (void *) &i8);
2214  } else if ( nt == NC_UBYTE) {
2215  ui8 = fill_value_dbl;
2216  ncVar.setFill(true, (void *) &ui8);
2217  } else if ( nt == NC_SHORT) {
2218  i16 = fill_value_dbl;
2219  ncVar.setFill(true, (void *) &i16);
2220  } else if ( nt == NC_USHORT) {
2221  ui16 = fill_value_dbl;
2222  ncVar.setFill(true, (void *) &ui16);
2223  } else if ( nt == NC_INT) {
2224  i32 = fill_value_dbl;
2225  ncVar.setFill(true, (void *) &i32);
2226  } else if ( nt == NC_UINT) {
2227  ui32 = fill_value_dbl;
2228  ncVar.setFill(true, (void *) &ui32);
2229  } else if ( nt == NC_FLOAT) {
2230  f32 = fill_value_dbl;
2231  ncVar.setFill(true, (void *) &f32);
2232  } else {
2233  ncVar.setFill(true, (void *) &fill_value_dbl);
2234  }
2235  }
2236 
2237  /* vary chunck size based on dimensions */
2238  int do_deflate = 0;
2239  vector<size_t> chunkVec;
2240  if ( varVec.size() == 3 && (strncmp(sname, "EV_", 3) == 0)) {
2241  dimlength = varVec[2].getSize();
2242 
2243  chunkVec.push_back(1);
2244  chunkVec.push_back(16);
2245  chunkVec.push_back(dimlength/10);
2246 
2247  do_deflate = 1;
2248  }
2249 
2250  /* Set compression */
2251  if ( do_deflate) {
2252  /* First set chunking */
2253  try {
2254  ncVar.setChunking(ncVar.nc_CHUNKED, chunkVec);
2255  }
2256  catch ( NcException& e) {
2257  e.what();
2258  cerr << "Failure setting chunking: " << sname << endl;
2259  exit(1);
2260  }
2261 
2262  try {
2263  ncVar.setCompression(true, true, 5);
2264  }
2265  catch ( NcException& e) {
2266  e.what();
2267  cerr << "Failure setting compression: " << sname << endl;
2268  exit(1);
2269  }
2270  }
2271 
2272 
2273  /* Add a "long_name" attribute */
2274  try {
2275  ncVar.putAtt("long_name", lname);
2276  }
2277  catch ( NcException& e) {
2278  e.what();
2279  cerr << "Failure creating 'long_name' attribute: " << lname << endl;
2280  exit(1);
2281  }
2282 
2283  if ( strcmp( flag_values, "") != 0) {
2284 
2285  size_t curPos=0;
2286 
2287  string fv;
2288  fv.assign( flag_values);
2289  size_t pos = fv.find("=", curPos);
2290  fv = fv.substr(pos+1);
2291 
2292  size_t semicln = fv.find(";");
2293  pos = 0;
2294 
2295  int8_t vec[1024];
2296  int n = 0;
2297  while(pos != semicln) {
2298  pos = fv.find(",", curPos);
2299  if ( pos == string::npos)
2300  pos = semicln;
2301 
2302  string flag_value;
2303  istringstream iss(fv.substr(curPos, pos-curPos));
2304  iss >> skipws >> flag_value;
2305  vec[n++] = atoi( flag_value.c_str());
2306  curPos = pos + 1;
2307  }
2308 
2309  try {
2310  ncVar.putAtt("flag_values", NC_BYTE, n, vec);
2311  }
2312  catch ( NcException& e) {
2313  e.what();
2314  cerr << "Failure creating 'flag_values' attribute: " << lname << endl;
2315  exit(1);
2316  }
2317  }
2318 
2319  /* Add a "flag_meanings" attribute if specified*/
2320  if ( strcmp( flag_meanings, "") != 0) {
2321 
2322  try {
2323  ncVar.putAtt("flag_meanings", flag_meanings);
2324  }
2325  catch ( NcException& e) {
2326  e.what();
2327  cerr << "Failure creating 'flag_meanings' attribute: "
2328  << flag_meanings << endl;
2329  exit(1);
2330  }
2331  }
2332 
2333  /* Add "valid_min/max" attributes if specified */
2334  if (low < high) {
2335  switch(nt) { /* Use the appropriate number type */
2336  case NC_BYTE:
2337  {
2338  uint8_t vr[2];
2339  vr[0] = (uint8_t)low;
2340  vr[1] = (uint8_t)high;
2341 
2342  try {
2343  ncVar.putAtt("valid_min", NC_BYTE, 1, &vr[0]);
2344  }
2345  catch ( NcException& e) {
2346  e.what();
2347  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2348  exit(1);
2349  }
2350 
2351  try {
2352  ncVar.putAtt("valid_max", NC_BYTE, 1, &vr[1]);
2353  }
2354  catch ( NcException& e) {
2355  e.what();
2356  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2357  exit(1);
2358  }
2359  }
2360  break;
2361  case NC_UBYTE:
2362  {
2363  uint8_t vr[2];
2364  vr[0] = (uint8_t)low;
2365  vr[1] = (uint8_t)high;
2366 
2367  try {
2368  ncVar.putAtt("valid_min", NC_UBYTE, 1, &vr[0]);
2369  }
2370  catch ( NcException& e) {
2371  e.what();
2372  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2373  exit(1);
2374  }
2375 
2376  try {
2377  ncVar.putAtt("valid_max", NC_UBYTE, 1, &vr[1]);
2378  }
2379  catch ( NcException& e) {
2380  e.what();
2381  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2382  exit(1);
2383  }
2384  }
2385  break;
2386  case NC_SHORT:
2387  {
2388  int16_t vr[2];
2389  vr[0] = (int16_t)low;
2390  vr[1] = (int16_t)high;
2391 
2392  try {
2393  ncVar.putAtt("valid_min", NC_SHORT, 1, &vr[0]);
2394  }
2395  catch ( NcException& e) {
2396  e.what();
2397  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2398  exit(1);
2399  }
2400 
2401  try {
2402  ncVar.putAtt("valid_max", NC_SHORT, 1, &vr[1]);
2403  }
2404  catch ( NcException& e) {
2405  e.what();
2406  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2407  exit(1);
2408  }
2409  }
2410  break;
2411  case NC_USHORT:
2412  {
2413  uint16_t vr[2];
2414  vr[0] = (uint16_t)low;
2415  vr[1] = (uint16_t)high;
2416 
2417  try {
2418  ncVar.putAtt("valid_min", NC_USHORT, 1, &vr[0]);
2419  }
2420  catch ( NcException& e) {
2421  e.what();
2422  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2423  exit(1);
2424  }
2425 
2426  try {
2427  ncVar.putAtt("valid_max", NC_USHORT, 1, &vr[1]);
2428  }
2429  catch ( NcException& e) {
2430  e.what();
2431  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2432  exit(1);
2433  }
2434  }
2435  break;
2436  case NC_INT:
2437  {
2438  int32_t vr[2];
2439  vr[0] = (int32_t)low;
2440  vr[1] = (int32_t)high;
2441 
2442  try {
2443  ncVar.putAtt("valid_min", NC_INT, 1, &vr[0]);
2444  }
2445  catch ( NcException& e) {
2446  e.what();
2447  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2448  exit(1);
2449  }
2450 
2451  try {
2452  ncVar.putAtt("valid_max", NC_INT, 1, &vr[1]);
2453  }
2454  catch ( NcException& e) {
2455  e.what();
2456  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2457  exit(1);
2458  }
2459 
2460  }
2461  break;
2462  case NC_UINT:
2463  {
2464  uint32_t vr[2];
2465  vr[0] = (uint32_t)low;
2466  vr[1] = (uint32_t)high;
2467 
2468  try {
2469  ncVar.putAtt("valid_min", NC_UINT, 1, &vr[0]);
2470  }
2471  catch ( NcException& e) {
2472  e.what();
2473  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2474  exit(1);
2475  }
2476 
2477  try {
2478  ncVar.putAtt("valid_max", NC_UINT, 1, &vr[1]);
2479  }
2480  catch ( NcException& e) {
2481  e.what();
2482  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2483  exit(1);
2484  }
2485 
2486  }
2487  break;
2488  case NC_FLOAT:
2489  {
2490  float vr[2];
2491  vr[0] = (float)low;
2492  vr[1] = (float)high;
2493 
2494  try {
2495  ncVar.putAtt("valid_min", NC_FLOAT, 1, &vr[0]);
2496  }
2497  catch ( NcException& e) {
2498  e.what();
2499  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2500  exit(1);
2501  }
2502 
2503  try {
2504  ncVar.putAtt("valid_max", NC_FLOAT, 1, &vr[1]);
2505  }
2506  catch ( NcException& e) {
2507  e.what();
2508  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2509  exit(1);
2510  }
2511  }
2512  break;
2513  case NC_DOUBLE:
2514  {
2515  double vr[2];
2516  vr[0] = low;
2517  vr[1] = high;
2518 
2519  try {
2520  ncVar.putAtt("valid_min", NC_DOUBLE, 1, &vr[0]);
2521  }
2522  catch ( NcException& e) {
2523  e.what();
2524  cerr << "Failure creating 'valid_min' attribute: " << vr[0] << endl;
2525  exit(1);
2526  }
2527 
2528  try {
2529  ncVar.putAtt("valid_max", NC_DOUBLE, 1, &vr[1]);
2530  }
2531  catch ( NcException& e) {
2532  e.what();
2533  cerr << "Failure creating 'valid_max' attribute: " << vr[1] << endl;
2534  exit(1);
2535  }
2536  }
2537  break;
2538  default:
2539  fprintf(stderr,"-E- %s line %d: ",__FILE__,__LINE__);
2540  fprintf(stderr,"Got unsupported number type (%d) ",nt);
2541  fprintf(stderr,"while trying to create NCDF variable, \"%s\", ",sname);
2542  return(1);
2543  }
2544  }
2545 
2546  /* Add a "units" attribute if one is specified */
2547  if(units != NULL && *units != 0) {
2548 
2549  try {
2550  ncVar.putAtt("units", units);
2551  }
2552  catch ( NcException& e) {
2553  e.what();
2554  cerr << "Failure creating 'units' attribute: " << units << endl;
2555  exit(1);
2556  }
2557  }
2558 
2559  /* Add a "standard_name" attribute if one is specified */
2560  if(standard_name != NULL && *standard_name != 0) {
2561  try {
2562  ncVar.putAtt("standard_name", units);
2563  }
2564  catch ( NcException& e) {
2565  e.what();
2566  cerr << "Failure creating 'standard_name' attribute: "
2567  << standard_name << endl;
2568  exit(1);
2569  }
2570  }
2571 
2572  return 0;
2573 }
2574 
2575 
2576 int l1bFile::parseDims( string dimString, vector<NcDim>& varDims) {
2577 
2578  size_t curPos=0;
2579  // char dimName[NC_MAX_NAME+1];
2580  string dimName;
2581 
2582  while(1) {
2583  size_t pos = dimString.find(",", curPos);
2584  if ( pos == string::npos)
2585  pos = dimString.find(")");
2586 
2587  string varDimName;
2588  istringstream iss(dimString.substr(curPos, pos-curPos));
2589  iss >> skipws >> varDimName;
2590 
2591  for (int i=0; i<ndims; i++) {
2592 
2593  try {
2594  dimName = ncDims[i].getName();
2595  }
2596  catch ( NcException& e) {
2597  e.what();
2598  cerr << "Failure accessing dimension: " + dimName << endl;
2599  exit(1);
2600  }
2601 
2602  if ( varDimName.compare(dimName) == 0) {
2603  cout << " " << dimName << " " << ncDims[i].getSize() << endl;
2604  varDims.push_back(ncDims[i]);
2605  break;
2606  }
2607  }
2608  if ( dimString.substr(pos, 1).compare(")") == 0) break;
2609 
2610  curPos = pos + 1;
2611  }
2612 
2613  return 0;
2614 }
2615 
2616 
2618  std::string l1b_name) {
2619 
2620  // Date created
2621  char buf[32];
2622  strcpy( buf, unix2isodate(now(), 'G'));
2623  l1bfile->putAtt("date_created", buf);
2624 
2625  l1bfile->putAtt("time_coverage_start", tstart.c_str());
2626 
2627  l1bfile->putAtt("time_coverage_end", tend.c_str());
2628 
2629  // Write product file name
2630  l1bfile->putAtt("product_name", l1b_name.c_str());
2631 
2632  return 0;
2633 }
2634 
2635 
2637 
2638  try {
2639  l1bfile->close();
2640  }
2641  catch ( NcException& e) {
2642  cout << e.what() << endl;
2643  cerr << "Failure closing: " + fileName << endl;
2644  exit(1);
2645  }
2646 
2647  return 0;
2648 }
2649 
2650 
2651 template <typename T>
2652 T*** make3dT( size_t dims[3]) {
2653 
2654  T ***arr3d = new T **[dims[0]];
2655 
2656  arr3d[0] = new T*[dims[0]*dims[1]];
2657  arr3d[0][0] = new T[dims[0]*dims[1]*dims[2]];
2658 
2659  for (size_t i=1; i<dims[0]; i++) arr3d[i] = arr3d[i-1] + dims[1];
2660 
2661  for (size_t i=0; i<dims[0]; i++) {
2662  if ( i > 0) arr3d[i][0] = arr3d[i-1][0] + dims[1]*dims[2];
2663  for (size_t j=1; j<dims[1]; j++)
2664  arr3d[i][j] = arr3d[i][j-1] + dims[2];
2665  }
2666 
2667  return arr3d;
2668 }
2669 
int32_t imn
Definition: atrem_corl1.h:161
int get_oci_temp_corr(uint32_t nib, gains_struct gains, float K3T[NTEMPS], float *caltemps, uint32_t nscan, float *k3)
int j
Definition: decode_rs.h:73
double tilt_angles[2]
Definition: common.h:15
int make_oci_gains(uint32_t nib, uint32_t banddim, uint16_t iyr, uint16_t idom, double stime, double K2t[NTIMES], cal_lut_struct &cal_lut, float **gmat, gains_struct &gains)
int main(int argc, char *argv[])
Definition: l1bgen_oci.cpp:36
int createField(NcGroup &ncGrp, const char *sname, const char *lname, const char *standard_name, const char *units, void *fill_value, const char *flag_values, const char *flag_meanings, double low, double high, int nt, vector< NcDim > &varVec)
uint16_t ldims[6]
Definition: l1bgen_oci.h:33
#define NULL
Definition: decode_rs.h:63
void spin(double st, double *pos1, double *pos2)
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in out
Definition: HISTORY.txt:422
const double pi
float32 * pos
Definition: l1_czcs_hdf.c:35
#define SWAP_4(x)
Definition: common.h:18
int jdate(int32_t julian, int32_t *year, int32_t *doy)
Definition: jdate.c:5
int read_mce_tlm(NcFile *l1afile, NcGroup egid, uint32_t nscan, uint32_t nenc, int32_t &ppr_off, double &revpsec, double &secpline, int32_t *mspin, int32_t *ot_10us, uint8_t *enc_count, float **hamenc, float **rtaenc)
int32_t jday(int16_t i, int16_t j, int16_t k)
Definition: jday.c:4
int32 nscan
Definition: l1_czcs_hdf.c:19
int get_oci_vecs(uint32_t nscan, uint16_t pdim, geo_struct &geoLUT, double ev_toff, int32_t spin, float *slines, double *delt, double revpsec, int32_t ppr_off, int32_t *mspin, int32_t *ot_10us, uint8_t *enc_count, float **hamenc, float **rtaenc, float **pview, double *theta, int16_t &iret)
@ string
double tilt_axis[3]
Definition: common.h:14
int nbnd
Definition: get_cmp.c:29
double ham_ct_angles[2]
Definition: common.h:21
#define K1
Definition: get_cal_swf.c:88
float *** K3_coef
Definition: l1bgen_oci.h:44
int createl1b(char *l1b_filename, uint16_t nscan_good, uint16_t pcdim, uint16_t bbb, uint16_t rbb, uint16_t psdim, uint16_t swb)
double tilt_to_oci_mech[3][3]
Definition: common.h:16
float ** K1
Definition: l1bgen_oci.h:34
double sc_to_tilt[3][3]
Definition: common.h:13
double ham_enc_scale
Definition: common.h:23
int parseDims(std::string dimString, std::vector< netCDF::NcDim > &varDims)
double rta_enc_scale
Definition: common.h:22
int get_oci_rvs_corr(uint32_t nib, uint16_t pdim, uint8_t hside, gains_struct gains, double *theta, float **k4)
double ** K5
Definition: l1bgen_oci.h:38
int expandEnvVar(string *sValue)
Definition: hawkeyeUtil.h:41
Definition: jd.py:1
int get_agg_mat(size_t *ia, int16_t iagg, int16_t jagg[16], uint16_t nib, uint32_t &nbb, uint32_t ntb[16], float **amat, float **gmat)
#define NTIMES
Definition: l1bgen_oci.h:10
ofstream tempOut
Definition: l1bgen_oci.cpp:34
int parseDims(int ncid, int ndims, string dimString, int *numDims, int *dimid, int *varDims)
int32_t rta_nadir
Definition: common.h:25
float *** K2
Definition: l1bgen_oci.h:35
double rta_axis[3]
Definition: common.h:18
double MCE_clock
Definition: common.h:11
#define SWAP_2(x)
int write_granule_metadata(std::string tstart, std::string tend, std::string l1b_name)
double oci_mech_to_oci_opt[3][3]
Definition: common.h:17
#define NIWAVE
Definition: l1bgen_oci.h:9
double master_clock
Definition: common.h:10
double trunc(double)
float ** K1K2
Definition: l1bgen_oci.h:43
double ** K5
Definition: l1bgen_oci.h:46
float *** K4_coef
Definition: l1bgen_oci.h:37
dtype
Definition: DDataset.hpp:31
int read_oci_cal_lut(NcFile *calLUTfile, string tag, NcGroup gidLUT, uint32_t &banddim, cal_lut_struct &cal_lut)
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
int get_oci_dark(size_t iscn, uint32_t nscan, uint8_t *hside, uint16_t ndsc, uint16_t nskp, int16_t iags, int16_t iagd, uint32_t ntaps, int16_t *jagg, uint32_t dfill, int16_t ndc, T ***dark, uint32_t nib, float *dc, int16_t &iret)
float *** K3_coef
Definition: l1bgen_oci.h:36
double ham_at_angles[2]
Definition: common.h:20
float *** K4_coef
Definition: l1bgen_oci.h:45
netCDF::NcGroup ncGrps[10]
Definition: l1bgen_oci.h:72
int close()
for(i=0;i< NROOTS;i++) s[i]
Definition: decode_rs.h:85
#define NBWAVE
Definition: l1bgen_oci.h:7
uint16_t ldims[6]
Definition: l1bgen_oci.h:42
#define VERSION
Definition: l1bgen_oci.cpp:20
#define NRWAVE
Definition: l1bgen_oci.h:8
These two strings are used for the product XML output If product_id is not set then prefix is used If the last char of the name_prefix is _ then it is removed If algorithm_id is not set then name_suffix is used If the first char is _ then it is removed l2prod standard_name[0]
int i
Definition: decode_rs.h:71
int get_oci_lin_corr(uint32_t nib, uint16_t pdim, gains_struct gains, float K3T[NTEMPS], float *caltemps, float **dn, float **k5)
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int32_t iyr
Definition: atrem_corl1.h:161
int k
Definition: decode_rs.h:73
T *** make3dT(size_t dims[3])
float32 f32
Definition: l2bin.cpp:104
int get_ev(double secpline, int16_t *dtype, int16_t *lines, int16_t *iagg, uint16_t &pcdim, uint16_t &psdim, double &ev_toff, float *clines, float *slines, double *deltc, double *delts, int16_t &iret)
#define NTEMPS
Definition: l1bgen_oci.h:11
double ham_axis[3]
Definition: common.h:19
int count
Definition: decode_rs.h:79