OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
geolocate_oci.cpp
Go to the documentation of this file.
1 #include <fstream>
2 #include <iostream>
3 #include <sstream>
4 
5 #include <gsl/gsl_blas.h>
6 #include <gsl/gsl_linalg.h>
7 #include <gsl/gsl_matrix_double.h>
8 
9 #include "geolocate_oci.h"
10 
11 //#include <libgen.h>
12 #include <netcdf>
13 
14 #include "nc4utils.h"
15 #include "timeutils.h"
16 
17 using namespace netCDF;
18 using namespace netCDF::exceptions;
19 
20 #define VERSION "0.01"
21 
22 // Modification history:
23 // Programmer Organization Date Ver Description of change
24 // ---------- ------------ ---- --- ---------------------
25 // Joel Gales SAIC 09/13/21 0.01 Original development
26 
27 using namespace std;
28 
29 int main(int argc, char *argv[]) {
30 
31  cout << "geolocate_oci " << VERSION << " ("
32  << __DATE__ << " " << __TIME__ << ")" << endl;
33 
34  if (argc == 1) {
35  cout << endl
36  << "geolocate_oci input_l1a_filename output_geo_filename" << endl;
37 
38  return 0;
39  }
40  ofstream tempOut;
41 
42  // Open a read data from L1Afile
43  NcFile *l1afile = new NcFile( argv[1], NcFile::read);
44 
45  NcGroup ncGrps[6];
46 
47  ncGrps[0] = l1afile->getGroup( "scan_line_attributes");
48  ncGrps[1] = l1afile->getGroup( "spatial_spectral_modes");
49  ncGrps[2] = l1afile->getGroup( "engineering_data");
50  ncGrps[3] = l1afile->getGroup( "navigation_data");
51  ncGrps[4] = l1afile->getGroup( "onboard_calibration_data");
52  ncGrps[5] = l1afile->getGroup( "science_data");
53 
54  NcGroupAtt att;
55  NcVar var;
56 
57  // Get date (change this when year and day are added to time field)
58  string tstart, tend;
59  att = l1afile->getAtt("time_coverage_start");
60  att.getValues(tstart);
61  cout << tstart << endl;
62 
63  att = l1afile->getAtt("time_coverage_end");
64  att.getValues(tend);
65  cout << tend << endl;
66 
67  // Scan time, spin ID and HAM side
68  NcDim nscan_dim = l1afile->getDim("number_of_scans");
69  uint32_t nscan = nscan_dim.getSize();
70 
71  double *sstime = new double[nscan];
72  var = ncGrps[0].getVar( "scan_start_time");
73  var.getVar( sstime);
74 
75  int32_t *spin = new int32_t[nscan];
76  var = ncGrps[0].getVar( "spin_ID");
77  var.getVar( spin);
78 
79  uint8_t *hside = new uint8_t[nscan];
80  var = ncGrps[0].getVar( "HAM_side");
81  var.getVar( hside);
82 
83  uint32_t sdim=0;
84  for (size_t i=0; i<nscan; i++) {
85  if ( spin[i] > 0) {
86  sstime[sdim] = sstime[i];
87  hside[sdim] = hside[i];
88  sdim++;
89  }
90  }
91 
92  NcDim natt_dim = l1afile->getDim("att_records");
93  uint32_t n_att_rec = natt_dim.getSize();
94 
95  double *att_time = new double[n_att_rec];
96  var = ncGrps[3].getVar( "att_time");
97  var.getVar( att_time);
98 
99  NcDim nquat_dim = l1afile->getDim("quaternion_elements");
100  uint32_t n_quat_elems = nquat_dim.getSize();
101 
102  float **att_quat = new float *[n_att_rec];
103  att_quat[0] = new float[n_quat_elems*n_att_rec];
104  for (size_t i=1; i<n_att_rec; i++)
105  att_quat[i] = att_quat[i-1] + n_quat_elems;
106 
107  var = ncGrps[3].getVar( "att_quat");
108  var.getVar( &att_quat[0][0]);
109 
110  NcDim norb_dim = l1afile->getDim("orb_records");
111  uint32_t n_orb_rec = norb_dim.getSize();
112 
113  double *orb_time = new double[n_orb_rec];
114  var = ncGrps[3].getVar( "orb_time");
115  var.getVar( orb_time);
116 
117  float **orb_pos = new float *[n_orb_rec];
118  orb_pos[0] = new float[3*n_orb_rec];
119  for (size_t i=1; i<n_orb_rec; i++) orb_pos[i] = orb_pos[i-1] + 3;
120  var = ncGrps[3].getVar( "orb_pos");
121  var.getVar( &orb_pos[0][0]);
122 
123  float **orb_vel = new float *[n_orb_rec];
124  orb_vel[0] = new float[3*n_orb_rec];
125  for (size_t i=1; i<n_orb_rec; i++) orb_vel[i] = orb_vel[i-1] + 3;
126  var = ncGrps[3].getVar( "orb_vel");
127  var.getVar( &orb_vel[0][0]);
128 
129  NcDim ntilt_dim = l1afile->getDim("tilt_samples");
130  uint32_t n_tilts = ntilt_dim.getSize();
131  float *tilt = new float[n_tilts];
132  var = ncGrps[3].getVar( "tilt");
133  var.getVar( tilt);
134 
135 
136  // MCE telemetry
137  int32_t ppr_off;
138  double revpsec, secpline;
139  int32_t *mspin = new int32_t[nscan];
140  int32_t *ot_10us = new int32_t[nscan];
141  uint8_t *enc_count = new uint8_t[nscan];
142 
143  NcDim nenc_dim = l1afile->getDim("encoder_samples");
144  uint32_t nenc = nenc_dim.getSize();
145 
146  float **hamenc = new float *[nscan];
147  hamenc[0] = new float[nenc*nscan];
148  for (size_t i=1; i<nscan; i++) hamenc[i] = hamenc[i-1] + nenc;
149 
150  float **rtaenc = new float *[nscan];
151  rtaenc[0] = new float[nenc*nscan];
152  for (size_t i=1; i<nscan; i++) rtaenc[i] = rtaenc[i-1] + nenc;
153 
154  read_mce_tlm( l1afile, ncGrps[2], nscan, nenc, ppr_off, revpsec,
155  secpline, mspin, ot_10us, enc_count, hamenc, rtaenc);
156 
157  int32_t iyr, iday, msec;
158  isodate2ydmsec((char *) tstart.c_str(), &iyr, &iday, &msec);
159 
160  // Transform orbit and attitude from J2000 to ECR
161  quat_array *quatr = new quat_array[n_att_rec];
162  orb_array *posr = new orb_array[n_orb_rec];
163  orb_array *velr = new orb_array[n_orb_rec];
164 
165  double omegae = 7.29211585494e-5;
166  double ecmat[3][3];
167 
168  // Orbit
169  for (size_t i = 0; i < n_orb_rec; i++) {
170  j2000_to_ecr(iyr, iday, orb_time[i], ecmat);
171 
172  for (size_t j = 0; j < 3; j++) {
173  posr[i][j] = ecmat[j][0] * orb_pos[i][0] +
174  ecmat[j][1] * orb_pos[i][1] +
175  ecmat[j][2] * orb_pos[i][2];
176  velr[i][j] = ecmat[j][0] * orb_vel[i][0] +
177  ecmat[j][1] * orb_vel[i][1] +
178  ecmat[j][2] * orb_vel[i][2];
179  }
180  velr[i][0] += posr[i][1] * omegae;
181  velr[i][1] -= posr[i][0] * omegae;
182  } // i loop
183 
184  // Attitude
185  for (size_t i = 0; i < n_att_rec; i++) {
186  double ecq[4], qt2[4];
187  float qt1[4];
188  j2000_to_ecr(iyr, iday, att_time[i], ecmat);
189  mtoq(ecmat, ecq);
190 
191  memcpy(qt1, &att_quat[i][0], 3 * sizeof(float));
192  qt1[3] = att_quat[i][3];
193 
194  qprod(ecq, qt1, qt2);
195  for (size_t j = 0; j < 4; j++) quatr[i][j] = qt2[j];
196  } // i loop
197 
198 
199  // ******************************************** //
200  // *** Get spatial and spectral aggregation *** //
201  // ******************************************** //
202  NcDim spatzn_dim = l1afile->getDim("spatial_zones");
203  uint32_t spatzn = spatzn_dim.getSize();
204 
205  int16_t *dtype = new int16_t[spatzn];
206  var = ncGrps[1].getVar( "spatial_zone_data_type");
207  var.getVar( dtype);
208 
209  int16_t *lines = new int16_t[spatzn];
210  var = ncGrps[1].getVar( "spatial_zone_lines");
211  var.getVar( lines);
212 
213  int16_t *iagg = new int16_t[spatzn];
214  var = ncGrps[1].getVar( "spatial_aggregation");
215  var.getVar( iagg);
216 
217  float clines[32400], slines[4050];
218  uint16_t pcdim, psdim;
219  int16_t iret;
220  double ev_toff, deltc[32400], delts[4050];
221  get_ev( secpline, dtype, lines, iagg, pcdim, psdim, ev_toff,
222  clines, slines, deltc, delts, iret);
223  if ( iret < 0) {
224  cout << "No Earth view in file: " << argv[1] << endl;
225  l1afile->close();
226  return 1;
227  }
228 
229  double *evtime = new double[nscan];
230  for (size_t i = 0; i < nscan; i++) evtime[i] = sstime[i] + ev_toff;
231 
232  // Interpolate orbit and attitude to scan times
233  orb_array *posi = new orb_array[sdim]();
234  orb_array *veli = new orb_array[sdim]();
235  orb_array *rpy = new orb_array[sdim]();
236  orb_interp(n_orb_rec, sdim, orb_time, posr, velr, evtime, posi, veli);
237 
238  quat_array *quati = new quat_array[sdim]();
239  q_interp(n_att_rec, sdim, att_time, quatr, evtime, quati);
240 
241  float *xlon = new float[sdim * psdim]();
242  float *xlat = new float[sdim * psdim]();
243  short *solz = new short[sdim * psdim]();
244  short *sola = new short[sdim * psdim]();
245  short *senz = new short[sdim * psdim]();
246  short *sena = new short[sdim * psdim]();
247  uint8_t *qfl = new uint8_t[sdim * psdim]();
248  short *range = new short[sdim * psdim]();
249  short *height = new short[sdim * psdim]();
250  short *sfl = new short[sdim]();
251 
252  // Initialize output arrays
253  for (size_t i = 0; i < sdim * psdim; i++) {
254  xlon[i] = -999.9;
255  xlat[i] = -999.9;
256 
257  solz[i] = -32768;
258  sola[i] = -32768;
259  senz[i] = -32768;
260  sena[i] = -32768;
261  }
262 
263  // Generate pointing vector array
264  float **pview = new float *[psdim];
265  pview[0] = new float[3*psdim];
266  for (size_t i=1; i<psdim; i++) pview[i] = pview[i-1] + 3;
267 
268  // Get Sun vectors
269  orb_array *sunr = new orb_array[sdim]();
270  l_sun(sdim, iyr, iday, evtime, sunr);
271 
272  // ******************************** //
273  // *** Read geo LUT (temporary) *** //
274  // ******************************** //
275  NcFile *geoLUTfile = new NcFile( argv[2], NcFile::read);
276  geo_struct geoLUT;
277 
278  NcGroup gidTime, gidCT, gidRTA_HAM;
279 
280  gidTime = geoLUTfile->getGroup( "time_params");
281  var = gidTime.getVar( "master_clock");
282  var.getVar( &geoLUT.master_clock);
283  var = gidTime.getVar( "MCE_clock");
284  var.getVar( &geoLUT.MCE_clock);
285 
286  gidCT = geoLUTfile->getGroup( "coord_trans");
287  var = gidCT.getVar( "sc_to_tilt");
288  var.getVar( &geoLUT.sc_to_tilt);
289  var = gidCT.getVar( "tilt_axis");
290  var.getVar( &geoLUT.tilt_axis);
291  var = gidCT.getVar( "tilt_angles");
292  var.getVar( &geoLUT.tilt_angles);
293  var = gidCT.getVar( "tilt_to_oci_mech");
294  var.getVar( &geoLUT.tilt_to_oci_mech);
295  var = gidCT.getVar( "oci_mech_to_oci_opt");
296  var.getVar( &geoLUT.oci_mech_to_oci_opt);
297 
298  gidRTA_HAM = geoLUTfile->getGroup( "RTA_HAM_params");
299  var = gidRTA_HAM.getVar( "RTA_axis");
300  var.getVar( &geoLUT.rta_axis);
301  var = gidRTA_HAM.getVar( "HAM_axis");
302  var.getVar( &geoLUT.ham_axis);
303  var = gidRTA_HAM.getVar( "HAM_AT_angles");
304  var.getVar( &geoLUT.ham_at_angles);
305  var = gidRTA_HAM.getVar( "HAM_CT_angles");
306  var.getVar( &geoLUT.ham_ct_angles);
307  var = gidRTA_HAM.getVar( "RTA_enc_scale");
308  var.getVar( &geoLUT.rta_enc_scale);
309  var = gidRTA_HAM.getVar( "HAM_enc_scale");
310  var.getVar( &geoLUT.ham_enc_scale);
311  var = gidRTA_HAM.getVar( "RTA_nadir");
312  var.getVar( &geoLUT.rta_nadir);
313 
314  geoLUTfile->close();
315 
316  // S/C matrices
317  gsl_matrix *sc2tiltp = gsl_matrix_alloc(3, 3);
318  gsl_matrix *sc2ocim = gsl_matrix_alloc(3, 3);
319  gsl_matrix *sc_to_oci = gsl_matrix_alloc(3, 3);
320  gsl_matrix *smat = gsl_matrix_alloc(3, 3);
321 
322  double *thetap = new double[psdim]();
323 
325  // Geolocate each scan line //
327  for (size_t i = 0; i < sdim; i++) {
328  if (sstime[i] != -999.0) {
329 
330  gsl_matrix_view A;
331  gsl_matrix_view B;
332  double *ptr_C;
333 
334  // Model tilt rotation using a quaternion
335  float qt[4];
336  qt[0] = geoLUT.tilt_axis[0]*sin(tilt[i]/2/RADEG);
337  qt[1] = geoLUT.tilt_axis[1]*sin(tilt[i]/2/RADEG);
338  qt[2] = geoLUT.tilt_axis[2]*sin(tilt[i]/2/RADEG);
339  qt[3] = cos(tilt[i]/2/RADEG);
340 
341  double tiltm[3][3];
342  qtom(qt, tiltm);
343 
344  // Combine tilt and alignments
345 
346  // sc2tiltp = tiltm#geo_lut.sc_to_tilt
347  A = gsl_matrix_view_array( (double *) geoLUT.sc_to_tilt, 3, 3);
348  B = gsl_matrix_view_array( (double *) tiltm, 3, 3);
349  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0,
350  &A.matrix, &B.matrix, 0.0, sc2tiltp);
351  ptr_C = gsl_matrix_ptr(sc2tiltp, 0, 0);
352 
353  // sc2ocim = geo_lut.tilt_to_oci_mech#sc2tiltp
354  B = gsl_matrix_view_array( (double *) geoLUT.tilt_to_oci_mech, 3, 3);
355  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0,
356  sc2tiltp, &B.matrix, 0.0, sc2ocim);
357  ptr_C = gsl_matrix_ptr(sc2ocim, 0, 0);
358 
359  // sc_to_oci = geo_lut.oci_mech_to_oci_opt#sc2ocim
360  B = gsl_matrix_view_array( (double *) geoLUT.oci_mech_to_oci_opt, 3, 3);
361  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0,
362  sc2ocim, &B.matrix, 0.0, sc_to_oci);
363  ptr_C = gsl_matrix_ptr(sc_to_oci, 0, 0);
364 
365 
366  // Convert quaternion to matrix
367  double qmat[3][3];
368  qtom(quati[i], qmat);
369 
370  // smat = sc_to_oci#qmat
371  B = gsl_matrix_view_array(&qmat[0][0], 3, 3);
372  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0,
373  sc_to_oci, &B.matrix, 0.0, smat);
374 
375  // Compute attitude angles (informational only)
376  mat2rpy(posi[i], veli[i], qmat, rpy[i]);
377 
378  // Get scan ellipse coefficients
379  ptr_C = gsl_matrix_ptr(smat, 0, 0);
380  double coef[10];
381  scan_ell(posi[i], (double(*)[3])ptr_C, coef);
382 
383  // Generate pointing vector and relative time arrays in instrument frame
384  get_oci_vecs( nscan, pcdim, geoLUT, ev_toff, spin[i], slines, delts,
385  revpsec, ppr_off, mspin, ot_10us, enc_count, &hamenc[0],
386  &rtaenc[0], pview, thetap, iret);
387  sfl[i] |= 2*iret;
388 
389  // Geolocate pixels
390  size_t ip = i * psdim;
391  oci_geonav(posi[i], veli[i], (double(*)[3])ptr_C, coef,
392  sunr[i], pview, psdim, delts[i], &xlat[ip], &xlon[ip],
393  &solz[ip], &sola[ip], &senz[ip], &sena[ip], &range[ip]);
394 
395  } else {
396  qfl[i] |= 4;
397  }
398  } // scan loop
399  gsl_matrix_free(smat);
400  gsl_matrix_free(sc2tiltp);
401  gsl_matrix_free(sc2ocim);
402  gsl_matrix_free(sc_to_oci);
403 
404  string geo_name;
405  geo_name.assign(argv[3]);
406  int geo_ncid;
407  int geo_gid[10];
408 
409  static geoFile outfile;
410 
411  outfile.createFile(geo_name.c_str(),
412  "$OCDATAROOT/oci/OCI_GEO_Data_Structure.cdl",
413  sdim, &geo_ncid, geo_gid);
414 
415  string varname;
416 
417  /*
418  char buf[32];
419  strcpy(buf, unix2isodate(now(), 'G'));
420  nc_put_att_text(geo_ncid, NC_GLOBAL, "date_created", strlen(buf), buf);
421 
422  varname.assign("scan_time");
423  status = nc_inq_varid(geo_gid[scan_attr_geo], varname.c_str(), &varid);
424  status = nc_put_var_double(geo_gid[scan_attr_geo], varid, stime);
425  check_err(status, __LINE__, __FILE__);
426 
427  status = nc_put_att_text(geo_ncid, NC_GLOBAL,
428  "time_coverage_start", strlen(tstart), tstart);
429 
430  status = nc_put_att_text(geo_ncid, NC_GLOBAL,
431  "time_coverage_end", strlen(tend), tend);
432  */
433 
434 
435  vector<size_t> start, count;
436 
437  start.clear();
438  start.push_back(0);
439  start.push_back(0);
440  start.push_back(0);
441 
442  count.push_back(sdim);
443 
444  var = outfile.ncGrps[0].getVar( "time");
445  var.putVar( start, count, evtime);
446 
447  var = outfile.ncGrps[0].getVar( "HAM_side");
448  var.putVar( start, count, hside);
449 
450  var = outfile.ncGrps[0].getVar( "scan_quality");
451  var.putVar( start, count, sfl);
452 
453  count.push_back(4);
454 
455  var = outfile.ncGrps[2].getVar( "att_quat");
456  var.putVar( start, count, quati);
457 
458  count.pop_back();
459  count.push_back(3);
460 
461  var = outfile.ncGrps[2].getVar( "att_ang");
462  var.putVar( start, count, rpy);
463 
464  var = outfile.ncGrps[2].getVar( "orb_pos");
465  var.putVar( start, count, posi);
466 
467  var = outfile.ncGrps[2].getVar( "orb_vel");
468  var.putVar( start, count, veli);
469 
470  var = outfile.ncGrps[2].getVar( "sun_ref");
471  var.putVar( start, count, sunr);
472 
473  count.pop_back();
474  count.push_back(psdim);
475 
476  var = outfile.ncGrps[1].getVar( "latitude");
477  var.putVar( start, count, xlat);
478 
479  var = outfile.ncGrps[1].getVar( "longitude");
480  var.putVar( start, count, xlon);
481 
482  var = outfile.ncGrps[1].getVar( "quality_flag");
483  var.putVar( start, count, qfl);
484 
485  var = outfile.ncGrps[1].getVar( "sensor_azimuth");
486  var.putVar( start, count, sena);
487 
488  var = outfile.ncGrps[1].getVar( "sensor_zenith");
489  var.putVar( start, count, senz);
490 
491  var = outfile.ncGrps[1].getVar( "solar_azimuth");
492  var.putVar( start, count, sola);
493 
494  var = outfile.ncGrps[1].getVar( "solar_zenith");
495  var.putVar( start, count, solz);
496 
497  var = outfile.ncGrps[1].getVar( "range");
498  var.putVar( start, count, range);
499 
500  var = outfile.ncGrps[1].getVar( "height");
501  var.putVar( start, count, height);
502 
503  delete[](att_time);
504  delete[](orb_time);
505  delete[](att_quat);
506  delete[](orb_pos);
507  delete[](orb_vel);
508  delete[](quatr);
509  delete[](posr);
510  delete[](velr);
511  delete[](posi);
512  delete[](veli);
513  delete[](rpy);
514  delete[](quati);
515  delete[](xlon);
516  delete[](xlat);
517  delete[](solz);
518  delete[](sola);
519  delete[](senz);
520  delete[](sena);
521  delete[](range);
522  delete[](height);
523  delete[](qfl);
524  delete[](pview);
525  delete[](sunr);
526 
527  return 0;
528 }
529 
530 int read_mce_tlm( NcFile *l1afile, NcGroup egid,
531  uint32_t nscan, uint32_t nenc, int32_t& ppr_off,
532  double& revpsec, double&secpline, int32_t *mspin,
533  int32_t *ot_10us, uint8_t *enc_count,
534  float **hamenc, float **rtaenc) {
535 
536  NcDim mce_dim = l1afile->getDim("MCE_block");
537  uint32_t mce_blk = mce_dim.getSize();
538  NcDim ddc_dim = l1afile->getDim("DDC_tlm");
539  uint32_t nddc = ddc_dim.getSize();
540  NcDim tlm_dim = l1afile->getDim("tlm_packets");
541  uint32_t ntlm = tlm_dim.getSize();
542 
543  uint8_t **mtlm = new uint8_t *[nscan];
544  mtlm[0] = new uint8_t[mce_blk*nscan];
545  for (size_t i=1; i<nscan; i++) mtlm[i] = mtlm[i-1] + mce_blk;
546 
547  int16_t **enc = new int16_t *[nscan];
548  enc[0] = new int16_t[4*nenc*nscan];
549  for (size_t i=1; i<nscan; i++) enc[i] = enc[i-1] + 4*nenc;
550 
551  uint8_t **ddctlm = new uint8_t *[ntlm];
552  ddctlm[0] = new uint8_t[nddc*ntlm];
553  for (size_t i=1; i<ntlm; i++) ddctlm[i] = ddctlm[i-1] + nddc;
554 
555  NcVar var;
556  vector<size_t> start, count;
557  start.push_back(0);
558  start.push_back(0);
559  count.push_back(1);
560 
561  /*
562  // Read MCE telemetry byte-by-byte to convert from int8_t to uint8_t
563  uint8_t *buf = new uint8_t[mce_blk];
564  var = egid.getVar( "MCE_telemetry");
565  count.push_back(mce_blk);
566  for (size_t i=0; i<nscan; i++) {
567  start[0] = i;
568  var.getVar( start, count, buf);
569  for (size_t j=0; j<mce_blk; j++) {
570  if ( buf[j] & 0x80 == 0)
571  mtlm[i][j] = buf[j]; else mtlm[i][j] = 256 + buf[j];
572  // cout << i << " " << j << " " << (int) mtlm[i][j] << endl;
573  }
574  }
575  delete [] buf;
576  */
577 
578  var = egid.getVar( "MCE_telemetry");
579  var.getVar( &mtlm[0][0]);
580 
581  var = egid.getVar( "MCE_encoder_data");
582  count.pop_back();
583  count.push_back(4*nenc);
584  var.getVar( &enc[0][0]);
585 
586  var = egid.getVar( "MCE_spin_ID");
587  var.getVar( mspin);
588 
589  var = egid.getVar( "DDC_telemetry");
590  var.getVar( &ddctlm[0][0]);
591 
592  int32_t max_enc_cts = 131072; // 2^17
593  double clock[2] = {1.36e8,1.0e8};
594 
595  // Get ref_pulse_divider and compute commanded rotation rate
596  uint32_t ui32;
597  uint32_t ref_pulse_div[2];
598  memcpy( &ui32, &mtlm[0][0], 4);
599  ref_pulse_div[0] = SWAP_4( ui32) % 16777216; // 2^24
600  memcpy( &ui32, &mtlm[0][4], 4);
601  ref_pulse_div[1] = SWAP_4( ui32) % 16777216; // 2^24
602 
603  int32_t ref_pulse_sel = mtlm[0][9] / 128;
604 
605  revpsec = clock[ref_pulse_sel] / 2 / max_enc_cts /
606  (ref_pulse_div[ref_pulse_sel]/256.0 + 1);
607 
608  // Get PPR offset and on-time_10us
609  memcpy( &ui32, &mtlm[0][8], 4);
610  ppr_off = SWAP_4( ui32) % max_enc_cts;
611  for (size_t i=0; i<nscan; i++) {
612  memcpy( &ui32, &mtlm[i][368], 4);
613  ot_10us[i] = SWAP_4( ui32) % 4;
614  }
615 
616  // Get TDI time and compute time increment per line
617  uint16_t ui16;
618  memcpy( &ui16, &ddctlm[0][346], 2);
619  int32_t tditime = SWAP_2( ui16);
620  secpline = (tditime+1) / clock[0];
621 
622  // Get valid encoder count, HAM and RTA encoder data
623  for (size_t i=0; i<nscan; i++) enc_count[i] = mtlm[i][475];
624  float enc_s = 81.0 / 2560;
625  for (size_t i=0; i<nscan; i++) {
626  for (size_t j=0; j<nenc; j++) {
627  hamenc[i][j] = enc[i][4*j+0] * enc_s;
628  rtaenc[i][j] = enc[i][4*j+1] * enc_s;
629  }
630  }
631 
632  delete[] mtlm[0];
633  delete[] mtlm;
634 
635  delete [] enc[0];
636  delete [] enc;
637 
638  delete [] ddctlm[0];
639  delete [] ddctlm;
640 
641  return 0;
642 }
643 
644 int j2000_to_ecr(int32_t iyr, int32_t idy, double sec, double ecmat[3][3]) {
645  // Get J2000 to ECEF transformation matrix
646 
647  // Arguments:
648 
649  // Name Type I/O Description
650  // --------------------------------------------------------
651  // iyr I I Year, four digits
652  // idy I I Day of year
653  // sec R*8 I Seconds of day
654  // ecmat(3,3) R O J2000 to ECEF matrix
655 
656  // Get transformation from J2000 to mean-of-date inertial
657  double j2mod[3][3];
658  j2000_to_mod(iyr, idy, sec, j2mod);
659 
660  // Get nutation and UT1-UTC (once per run)
661  double xnut[3][3], ut1utc;
662  get_nut(iyr, idy, xnut);
663  get_ut1(iyr, idy, ut1utc);
664 
665  // Compute Greenwich hour angle for time of day
666  double day = idy + (sec + ut1utc) / 86400;
667  double gha, gham[3][3];
668  gha2000(iyr, day, gha);
669 
670  gham[0][0] = cos(gha / RADEG);
671  gham[1][1] = cos(gha / RADEG);
672  gham[2][2] = 1;
673  gham[0][1] = sin(gha / RADEG);
674  gham[1][0] = -sin(gha / RADEG);
675 
676  gham[0][2] = 0;
677  gham[2][0] = 0;
678  gham[1][2] = 0;
679  gham[2][1] = 0;
680 
681  // Combine all transformations
682  gsl_matrix_view A = gsl_matrix_view_array(&gham[0][0], 3, 3); // gham
683  gsl_matrix_view B = gsl_matrix_view_array(&xnut[0][0], 3, 3); // xnut
684  gsl_matrix *C = gsl_matrix_alloc(3, 3);
685 
686  gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0, &A.matrix, &B.matrix, 0.0, C);
687 
688  gsl_matrix_view D = gsl_matrix_view_array(&j2mod[0][0], 3, 3); // j2mod
689  gsl_matrix *E = gsl_matrix_alloc(3, 3);
690  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, C, &D.matrix, 0.0, E);
691  double *ptr_E = gsl_matrix_ptr(E, 0, 0);
692 
693  memcpy(ecmat, ptr_E, 9 * sizeof(double));
694 
695  gsl_matrix_free(C);
696  gsl_matrix_free(E);
697 
698  return 0;
699 }
700 
701 int j2000_to_mod(int32_t iyr, int32_t idy, double sec, double j2mod[3][3]) {
702  // Get J2000 to MOD (precession) transformation
703 
704  // Arguments:
705 
706  // Name Type I/O Description
707  // --------------------------------------------------------
708  // iyr I I Year, four digits
709  // idy I I Day of year
710  // sec R*8 I Seconds of day
711  // j2mod(3,3) R O J2000 to MOD matrix
712 
713  int16_t iyear = iyr;
714  int16_t iday = idy;
715 
716  double t = jday(iyear, 1, iday) - (double)2451545.5 + sec / 86400;
717  t /= 36525;
718 
719  double zeta0 = t * (2306.2181 + 0.302 * t + 0.018 * t * t) / RADEG / 3600;
720  double thetap = t * (2004.3109 - 0.4266 * t - 0.04160 * t * t) / RADEG / 3600;
721  double xip = t * (2306.2181 + 1.095 * t + 0.018 * t * t) / RADEG / 3600;
722 
723  j2mod[0][0] = -sin(zeta0) * sin(xip) + cos(zeta0) * cos(xip) * cos(thetap);
724  j2mod[0][1] = -cos(zeta0) * sin(xip) - sin(zeta0) * cos(xip) * cos(thetap);
725  j2mod[0][2] = -cos(xip) * sin(thetap);
726  j2mod[1][0] = sin(zeta0) * cos(xip) + cos(zeta0) * sin(xip) * cos(thetap);
727  j2mod[1][1] = cos(zeta0) * cos(xip) - sin(zeta0) * sin(xip) * cos(thetap);
728  j2mod[1][2] = -sin(xip) * sin(thetap);
729  j2mod[2][0] = cos(zeta0) * sin(thetap);
730  j2mod[2][1] = -sin(zeta0) * sin(thetap);
731  j2mod[2][2] = cos(thetap);
732 
733  return 0;
734 }
735 
736 int get_nut(int32_t iyr, int32_t idy, double xnut[3][3]) {
737  int16_t iyear = iyr;
738  int16_t iday = idy;
739 
740  double t = jday(iyear, 1, iday) - (double)2451545.5;
741 
742  double xls, gs, xlm, omega;
743  double dpsi, eps, epsm;
744  ephparms(t, xls, gs, xlm, omega);
745  nutate(t, xls, gs, xlm, omega, dpsi, eps, epsm);
746 
747  xnut[0][0] = cos(dpsi / RADEG);
748  xnut[1][0] = -sin(dpsi / RADEG) * cos(epsm / RADEG);
749  xnut[2][0] = -sin(dpsi / RADEG) * sin(epsm / RADEG);
750  xnut[0][1] = sin(dpsi / RADEG) * cos(eps / RADEG);
751  xnut[1][1] = cos(dpsi / RADEG) * cos(eps / RADEG) * cos(epsm / RADEG) +
752  sin(eps / RADEG) * sin(epsm / RADEG);
753  xnut[2][1] = cos(dpsi / RADEG) * cos(eps / RADEG) * sin(epsm / RADEG) -
754  sin(eps / RADEG) * cos(epsm / RADEG);
755  xnut[0][2] = sin(dpsi / RADEG) * sin(eps / RADEG);
756  xnut[1][2] = cos(dpsi / RADEG) * sin(eps / RADEG) * cos(epsm / RADEG) -
757  cos(eps / RADEG) * sin(epsm / RADEG);
758  xnut[2][2] = cos(dpsi / RADEG) * sin(eps / RADEG) * sin(epsm / RADEG) +
759  cos(eps / RADEG) * cos(epsm / RADEG);
760 
761  return 0;
762 }
763 
764 int ephparms(double t, double &xls, double &gs, double &xlm, double &omega) {
765  // This subroutine computes ephemeris parameters used by other Mission
766  // Operations routines: the solar mean longitude and mean anomaly, and
767  // the lunar mean longitude and mean ascending node. It uses the model
768  // referenced in The Astronomical Almanac for 1984, Section S
769  // (Supplement) and documented for the SeaWiFS Project in "Constants
770  // and Parameters for SeaWiFS Mission Operations", in TBD. These
771  // parameters are used to compute the solar longitude and the nutation
772  // in longitude and obliquity.
773 
774  // Sun Mean Longitude
775  xls = (double)280.46592 + ((double)0.9856473516) * t;
776  xls = fmod(xls, (double)360);
777 
778  // Sun Mean Anomaly
779  gs = (double)357.52772 + ((double)0.9856002831) * t;
780  gs = fmod(gs, (double)360);
781 
782  // Moon Mean Longitude
783  xlm = (double)218.31643 + ((double)13.17639648) * t;
784  xlm = fmod(xlm, (double)360);
785 
786  // Ascending Node of Moon's Mean Orbit
787  omega = (double)125.04452 - ((double)0.0529537648) * t;
788  omega = fmod(omega, (double)360);
789 
790  return 0;
791 }
792 
793 int nutate(double t, double xls, double gs, double xlm, double omega,
794  double &dpsi, double &eps, double &epsm) {
795  // This subroutine computes the nutation in longitude and the obliquity
796  // of the ecliptic corrected for nutation. It uses the model referenced
797  // in The Astronomical Almanac for 1984, Section S (Supplement) and
798  // documented for the SeaWiFS Project in "Constants and Parameters for
799  // SeaWiFS Mission Operations", in TBD. These parameters are used to
800  // compute the apparent time correction to the Greenwich Hour Angle and
801  // for the calculation of the geocentric Sun vector. The input
802  // ephemeris parameters are computed using subroutine ephparms. Terms
803  // are included to 0.1 arcsecond.
804 
805  // Nutation in Longitude
806  dpsi = -17.1996 * sin(omega / RADEG) + 0.2062 * sin(2. * omega / RADEG) -
807  1.3187 * sin(2. * xls / RADEG) + 0.1426 * sin(gs / RADEG) -
808  0.2274 * sin(2. * xlm / RADEG);
809 
810  // Mean Obliquity of the Ecliptic
811  epsm = (double)23.439291 - ((double)3.560e-7) * t;
812 
813  // Nutation in Obliquity
814  double deps = 9.2025 * cos(omega / RADEG) + 0.5736 * cos(2. * xls / RADEG);
815 
816  // True Obliquity of the Ecliptic
817  eps = epsm + deps / 3600;
818 
819  dpsi = dpsi / 3600;
820 
821  return 0;
822 }
823 
824 int get_ut1(int32_t iyr, int32_t idy, double &ut1utc) {
825  int16_t iyear = iyr;
826  int16_t iday = idy;
827 
828  static int32_t ijd[25000];
829  static double ut1[25000];
830  string utcpole = "$OCVARROOT/modis/utcpole.dat";
831  static bool first = true;
832  int k = 0;
833  if (first) {
834  string line;
836  istringstream istr;
837 
838  ifstream utcpfile(utcpole.c_str());
839  if (utcpfile.is_open()) {
840  getline(utcpfile, line);
841  getline(utcpfile, line);
842  while (getline(utcpfile, line)) {
843  // cout << line << '\n';
844  istr.clear();
845  istr.str(line.substr(0, 5));
846  istr >> ijd[k];
847  istr.clear();
848  istr.str(line.substr(44, 9));
849  istr >> ut1[k];
850  k++;
851  }
852  ijd[k] = 0;
853  utcpfile.close();
854  first = false;
855  } else {
856  cout << utcpole.c_str() << " not found" << endl;
857  exit(1);
858  }
859  } // if (first)
860 
861  k = 0;
862  int mjd = jday(iyear, 1, iday) - 2400000;
863  while (ijd[k] > 0) {
864  if (mjd == ijd[k]) {
865  ut1utc = ut1[k];
866  break;
867  }
868  k++;
869  }
870 
871  return 0;
872 }
873 
874 int gha2000(int32_t iyr, double day, double &gha) {
875  // This subroutine computes the Greenwich hour angle in degrees for the
876  // input time. It uses the model referenced in The Astronomical Almanac
877  // for 1984, Section S (Supplement) and documented for the SeaWiFS
878  // Project in "Constants and Parameters for SeaWiFS Mission Operations",
879  // in TBD. It includes the correction to mean sidereal time for nutation
880  // as well as precession.
881  //
882 
883  // Compute days since J2000
884  int16_t iday = day;
885  double fday = day - iday;
886  int jd = jday(iyr, 1, iday);
887  double t = jd - (double)2451545.5 + fday;
888 
889  // Compute Greenwich Mean Sidereal Time (degrees)
890  double gmst = (double)100.4606184 + (double)0.9856473663 * t +
891  (double)2.908e-13 * t * t;
892 
893  // Check if need to compute nutation correction for this day
894  double xls, gs, xlm, omega;
895  double dpsi, eps, epsm;
896  ephparms(t, xls, gs, xlm, omega);
897  nutate(t, xls, gs, xlm, omega, dpsi, eps, epsm);
898 
899  // Include apparent time correction and time-of-day
900  gha = gmst + dpsi * cos(eps / RADEG) + fday * 360;
901  gha = fmod(gha, (double)360);
902 
903  return 0;
904 }
905 
906 int mtoq(double rm[3][3], double q[4]) {
907  // Convert direction cosine matrix to equivalent quaternion
908 
909  double e[3];
910 
911  // Compute Euler angle
912  double phi;
913  double cphi = (rm[0][0] + rm[1][1] + rm[2][2] - 1) / 2;
914  if (fabs(cphi) < 0.98) {
915  phi = acos(cphi);
916  } else {
917  double ssphi = (pow(rm[0][1] - rm[1][0], 2) +
918  pow(rm[2][0] - rm[0][2], 2) +
919  pow(rm[1][2] - rm[2][1], 2)) /
920  4;
921  phi = asin(sqrt(ssphi));
922  if (cphi < 0) phi = PI - phi;
923  }
924 
925  // Compute Euler axis
926  e[0] = (rm[2][1] - rm[1][2]) / (sin(phi) * 2);
927  e[1] = (rm[0][2] - rm[2][0]) / (sin(phi) * 2);
928  e[2] = (rm[1][0] - rm[0][1]) / (sin(phi) * 2);
929  double norm = sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);
930  e[0] = e[0] / norm;
931  e[1] = e[1] / norm;
932  e[2] = e[2] / norm;
933 
934  // Compute quaternion
935  q[0] = e[0] * sin(phi / 2);
936  q[1] = e[1] * sin(phi / 2);
937  q[2] = e[2] * sin(phi / 2);
938  q[3] = cos(phi / 2);
939 
940  return 0;
941 }
942 
943 int qprod(double q1[4], float q2[4], double q3[4]) {
944  // Compute the product of two quaternions q3 = q1*q2
945 
946  q3[0] = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
947  q3[1] = -q1[0] * q2[2] + q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
948  q3[2] = q1[0] * q2[1] - q1[1] * q2[0] + q1[2] * q2[3] + q1[3] * q2[2];
949  q3[3] = -q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] + q1[3] * q2[3];
950 
951  return 0;
952 }
953 
954 int qprod(float q1[4], float q2[4], float q3[4]) {
955  // Compute the product of two quaternions q3 = q1*q2
956 
957  q3[0] = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
958  q3[1] = -q1[0] * q2[2] + q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
959  q3[2] = q1[0] * q2[1] - q1[1] * q2[0] + q1[2] * q2[3] + q1[3] * q2[2];
960  q3[3] = -q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] + q1[3] * q2[3];
961 
962  return 0;
963 }
964 
965 int orb_interp(size_t n_orb_rec, size_t sdim, double *torb, orb_array *p,
966  orb_array *v, double *time, orb_array *posi, orb_array *veli) {
967  // Purpose: Interpolate orbit position and velocity vectors to scan line
968  // times
969  //
970  //
971  // Calling Arguments:
972  //
973  // Name Type I/O Description
974  // -------- ---- --- -----------
975  // torb(*) double I Array of orbit vector times in seconds of day
976  // p(3,*) float I Array of orbit position vectors for
977  // each time torb
978  // v(3,*) float I Array of orbit velocity vectors for
979  // each time torb
980  // time(*) double I Array of time in seconds of day
981  // for every scan line
982  // pi(3,*) float O Array of interpolated positions
983  // vi(3,*) float O Array of interpolated velocities
984  //
985  //
986  // By: Frederick S. Patt, GSC, August 10, 1993
987  //
988  // Notes: Method uses cubic polynomial to match positions and velocities
989  // at input data points.
990  //
991  // Modification History:
992  //
993  // Created IDL version from FORTRAN code. F.S. Patt, SAIC, November 29, 2006
994  //
995 
996  double a0[3], a1[3], a2[3], a3[3];
997 
998  /*
999  // Make sure that first orbit vector precedes first scan line
1000  k = where (time lt torb(0))
1001  if (k(0) ne -1) then begin
1002  posi(*,k) = 0.0
1003  veli(*,k) = 0.0
1004  orbfl(k) = 1
1005  print, 'Scan line times before available orbit data'
1006  i1 = max(k) + 1
1007  endif
1008  */
1009 
1010  size_t ind = 0;
1011  for (size_t i = 0; i < sdim; i++) {
1012  // Find input orbit vectors bracketing scan
1013  for (size_t j = ind; j < n_orb_rec; j++) {
1014  if (time[i] > torb[j] && time[i] <= torb[j + 1]) {
1015  ind = j;
1016  break;
1017  }
1018  }
1019 
1020  // Set up cubic interpolation
1021  double dt = torb[ind + 1] - torb[ind];
1022  for (size_t j = 0; j < 3; j++) {
1023  a0[j] = p[ind][j];
1024  a1[j] = v[ind][j] * dt;
1025  a2[j] = 3 * p[ind + 1][j] - 3 * p[ind][j] - 2 * v[ind][j] * dt -
1026  v[ind + 1][j] * dt;
1027  a3[j] = 2 * p[ind][j] - 2 * p[ind + 1][j] + v[ind][j] * dt +
1028  v[ind + 1][j] * dt;
1029  }
1030 
1031  // Interpolate orbit position and velocity components to scan line time
1032  double x = (time[i] - torb[ind]) / dt;
1033  double x2 = x * x;
1034  double x3 = x2 * x;
1035  for (size_t j = 0; j < 3; j++) {
1036  posi[i][j] = a0[j] + a1[j] * x + a2[j] * x2 + a3[j] * x3;
1037  veli[i][j] = (a1[j] + 2 * a2[j] * x + 3 * a3[j] * x2) / dt;
1038  }
1039  } // i-loop
1040 
1041  return 0;
1042 }
1043 
1044 int q_interp(size_t n_att_rec, size_t sdim, double *tq, quat_array *q,
1045  double *time, quat_array *qi) {
1046  // Purpose: Interpolate quaternions to scan line times
1047  //
1048  //
1049 
1050  size_t ind = 0;
1051  for (size_t i = 0; i < sdim; i++) {
1052  // Find input attitude vectors bracketing scan
1053  for (size_t j = ind; j < n_att_rec; j++) {
1054  if (time[i] > tq[j] && time[i] <= tq[j + 1]) {
1055  ind = j;
1056  break;
1057  }
1058  }
1059 
1060  // Set up quaternion interpolation
1061  double dt = tq[ind + 1] - tq[ind];
1062  double qin[4];
1063  qin[0] = -q[ind][0];
1064  qin[1] = -q[ind][1];
1065  qin[2] = -q[ind][2];
1066  qin[3] = q[ind][3];
1067 
1068  double e[3], qr[4];
1069  qprod(qin, q[ind + 1], qr);
1070  memcpy(e, qr, 3 * sizeof(double));
1071  double sto2 = sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);
1072  for (size_t j = 0; j < 3; j++) e[j] /= sto2;
1073 
1074  // Interpolate quaternion to scan times
1075  double x = (time[i] - tq[ind]) / dt;
1076  float qri[4], qp[4];
1077  for (size_t j = 0; j < 3; j++) qri[j] = e[j] * sto2 * x;
1078  qri[3] = 1.0;
1079  qprod(q[ind], qri, qp);
1080  memcpy(qi[i], qp, 4 * sizeof(float));
1081  }
1082 
1083  return 0;
1084 }
1085 
1086 int l_sun(size_t sdim, int32_t iyr, int32_t iday, double *sec,
1087  orb_array *sunr) {
1088  // Computes unit Sun vector in geocentric rotating coordinates, using
1089  // subprograms to compute inertial Sun vector and Greenwich hour angle
1090 
1091  // Get unit Sun vector in geocentric inertial coordinates
1092  sun2000(sdim, iyr, iday, sec, sunr);
1093 
1094  // Get Greenwich mean sidereal angle
1095  for (size_t i = 0; i < sdim; i++) {
1096  double day = iday + sec[i] / 86400;
1097  double gha;
1098  gha2000(iyr, day, gha);
1099  double ghar = gha / RADEG;
1100 
1101  // Transform Sun vector into geocentric rotating frame
1102  float temp0 = sunr[i][0] * cos(ghar) + sunr[i][1] * sin(ghar);
1103  float temp1 = sunr[i][1] * cos(ghar) - sunr[i][0] * sin(ghar);
1104  sunr[i][0] = temp0;
1105  sunr[i][1] = temp1;
1106  }
1107 
1108  return 0;
1109 }
1110 
1111 int sun2000(size_t sdim, int32_t iyr, int32_t idy, double *sec,
1112  orb_array *sun) {
1113  // This subroutine computes the Sun vector in geocentric inertial
1114  // (equatorial) coordinates. It uses the model referenced in The
1115  // Astronomical Almanac for 1984, Section S (Supplement) and documented
1116  // for the SeaWiFS Project in "Constants and Parameters for SeaWiFS
1117  // Mission Operations", in TBD. The accuracy of the Sun vector is
1118  // approximately 0.1 arcminute.
1119 
1120  float xk = 0.0056932; // Constant of aberration
1121 
1122  // Compute floating point days since Jan 1.5, 2000
1123  // Note that the Julian day starts at noon on the specified date
1124  int16_t iyear = iyr;
1125  int16_t iday = idy;
1126 
1127  for (size_t i = 0; i < sdim; i++) {
1128  double t =
1129  jday(iyear, 1, iday) - (double)2451545.0 + (sec[i] - 43200) / 86400;
1130 
1131  double xls, gs, xlm, omega;
1132  double dpsi, eps, epsm;
1133  // Compute solar ephemeris parameters
1134  ephparms(t, xls, gs, xlm, omega);
1135 
1136  // Compute nutation corrections for this day
1137  nutate(t, xls, gs, xlm, omega, dpsi, eps, epsm);
1138 
1139  // Compute planet mean anomalies
1140  // Venus Mean Anomaly
1141  double g2 = 50.40828 + 1.60213022 * t;
1142  g2 = fmod(g2, (double)360);
1143 
1144  // Mars Mean Anomaly
1145  double g4 = 19.38816 + 0.52402078 * t;
1146  g4 = fmod(g4, (double)360);
1147 
1148  // Jupiter Mean Anomaly
1149  double g5 = 20.35116 + 0.08309121 * t;
1150  g5 = fmod(g5, (double)360);
1151 
1152  // Compute solar distance (AU)
1153  double rs =
1154  1.00014 - 0.01671 * cos(gs / RADEG) - 0.00014 * cos(2. * gs / RADEG);
1155 
1156  // Compute Geometric Solar Longitude
1157  double dls = (6893. - 4.6543463e-4 * t) * sin(gs / RADEG) +
1158  72. * sin(2. * gs / RADEG) - 7. * cos((gs - g5) / RADEG) +
1159  6. * sin((xlm - xls) / RADEG) +
1160  5. * sin((4. * gs - 8. * g4 + 3. * g5) / RADEG) -
1161  5. * cos((2. * gs - 2. * g2) / RADEG) -
1162  4. * sin((gs - g2) / RADEG) +
1163  4. * cos((4. * gs - 8. * g4 + 3. * g5) / RADEG) +
1164  3. * sin((2. * gs - 2. * g2) / RADEG) - 3. * sin(g5 / RADEG) -
1165  3. * sin((2. * gs - 2. * g5) / RADEG);
1166 
1167  double xlsg = xls + dls / 3600;
1168 
1169  // Compute Apparent Solar Longitude// includes corrections for nutation
1170  // in longitude and velocity aberration
1171  double xlsa = xlsg + dpsi - xk / rs;
1172 
1173  // Compute unit Sun vector
1174  sun[i][0] = cos(xlsa / RADEG);
1175  sun[i][1] = sin(xlsa / RADEG) * cos(eps / RADEG);
1176  sun[i][2] = sin(xlsa / RADEG) * sin(eps / RADEG);
1177  } // i-loop
1178 
1179  return 0;
1180 }
1181 
1182 int qtom(float q[4], double rm[3][3]) {
1183  // Convert quaternion to equivalent direction cosine matrix
1184 
1185  rm[0][0] = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
1186  rm[0][1] = 2 * (q[0] * q[1] + q[2] * q[3]);
1187  rm[0][2] = 2 * (q[0] * q[2] - q[1] * q[3]);
1188  rm[1][0] = 2 * (q[0] * q[1] - q[2] * q[3]);
1189  rm[1][1] = -q[0] * q[0] + q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
1190  rm[1][2] = 2 * (q[1] * q[2] + q[0] * q[3]);
1191  rm[2][0] = 2 * (q[0] * q[2] + q[1] * q[3]);
1192  rm[2][1] = 2 * (q[1] * q[2] - q[0] * q[3]);
1193  rm[2][2] = -q[0] * q[0] - q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
1194 
1195  return 0;
1196 }
1197 
1198 int scan_ell(float p[3], double sm[3][3], double coef[10]) {
1199  // This program calculates the coefficients which
1200  // represent the Earth scan track in the sensor frame.
1201 
1202  // The reference ellipsoid uses an equatorial radius of 6378.137 km and
1203  // a flattening factor of 1/298.257 (WGS 1984).
1204 
1205  // Calling Arguments
1206  //
1207  // Name Type I/O Description
1208  //
1209  // pos(3) R*4 I ECR Orbit Position Vector (km)
1210  // smat(3,3) R*4 I Sensor Orientation Matrix
1211  // coef(10) R*4 O Scan path coefficients
1212 
1213  double re = 6378.137;
1214  double f = 1 / 298.257;
1215  double omf2 = (1 - f) * (1 - f);
1216 
1217  // Compute constants for navigation model using Earth radius values
1218  double rd = 1 / omf2;
1219 
1220  // Compute coefficients of intersection ellipse in scan plane
1221  coef[0] = 1 + (rd - 1) * sm[0][2] * sm[0][2];
1222  coef[1] = 1 + (rd - 1) * sm[1][2] * sm[1][2];
1223  coef[2] = 1 + (rd - 1) * sm[2][2] * sm[2][2];
1224  coef[3] = (rd - 1) * sm[0][2] * sm[1][2] * 2;
1225  coef[4] = (rd - 1) * sm[0][2] * sm[2][2] * 2;
1226  coef[5] = (rd - 1) * sm[1][2] * sm[2][2] * 2;
1227  coef[6] = (sm[0][0] * p[0] + sm[0][1] * p[1] + sm[0][2] * p[2] * rd) * 2;
1228  coef[7] = (sm[1][0] * p[0] + sm[1][1] * p[1] + sm[1][2] * p[2] * rd) * 2;
1229  coef[8] = (sm[2][0] * p[0] + sm[2][1] * p[1] + sm[2][2] * p[2] * rd) * 2;
1230  coef[9] = p[0] * p[0] + p[1] * p[1] + p[2] * p[2] * rd - re * re;
1231 
1232  return 0;
1233 }
1234 
1235 int oci_geonav(float pos[3], float vel[3], double smat[3][3], double coef[10],
1236  float sunr[3], float **pview, size_t npix, double delt,
1237  float *xlat, float *xlon, short *solz, short *sola,
1238  short *senz, short *sena, short *range) {
1239  // This subroutine performs navigation of a scanning sensor on the
1240  // surface of an ellipsoid based on an input orbit position vector and
1241  // spacecraft orientation matrix. It uses a closed-form algorithm for
1242  // determining points on the ellipsoidal surface which involves
1243  // determining the intersection of the scan plan with the ellipsoid.
1244  // The sensor view vectors in the sensor frame are passed in as a 3xN array.
1245 
1246  // The reference ellipsoid is set according to the scan
1247  // intersection coefficients in the calling sequence// an equatorial
1248  // radius of 6378.137 km. and a flattening factor of 1/298.257 are
1249  // used by both the Geodetic Reference System (GRS) 1980 and the
1250  // World Geodetic System (WGS) 1984.
1251 
1252  // It then computes geometric parameters using the pixel locations on
1253  // the Earth, the spacecraft position vector and the unit Sun vector in
1254  // the geocentric rotating reference frame. The outputs are arrays of
1255  // geodetic latitude and longitude, solar zenith and azimuth and sensor
1256  // zenith and azimuth. The azimuth angles are measured from local
1257  // North toward East. Flag values of 999. are returned for any pixels
1258  // whose scan angle is past the Earth's horizon.
1259 
1260  // Reference: "Exact closed-form geolocation geolocation algorithm for
1261  // Earth survey sensors", F. S. Patt and W. W. Gregg, IJRS, Vol. 15
1262  // No. 18, 1994.
1263 
1264  // Calling Arguments
1265 
1266  // Name Type I/O Description
1267  //
1268  // pos(3) R*4 I ECR Orbit Position Vector (km) at scan
1269  // mid-time
1270  // vel(3) R*4 I ECR Orbit Velocity Vector (km/sec)
1271  // smat(3,3) R*4 I Sensor Orientation Matrix
1272  // coef(10) R*4 I Scan path coefficients
1273  // sunr(3) R*4 I Sun unit vector in geocentric rotating
1274  // reference frame
1275  // pview(3,*) R*4 I Array of sensor view vectors
1276  // npix R*4 I Number of pixels to geolocate
1277  // xlat(*) R*4 O Pixel geodetic latitudes
1278  // xlon(*) R*4 O Pixel geodetic longitudes
1279  // solz(*) I*2 O Pixel solar zenith angles
1280  // sola(*) I*2 O Pixel solar azimuth angles
1281  // senz(*) I*2 O Pixel sensor zenith angles
1282  // sena(*) I*2 O Pixel sensor azimuth angles
1283  //
1284 
1285  // Program written by: Frederick S. Patt
1286  // General Sciences Corporation
1287  // October 20, 1992
1288  //
1289  // Modification History:
1290 
1291  // Created universal version of the SeaWiFS geolocation algorithm
1292  // by specifying view vectors as an input. F. S. Patt, SAIC, 11/17/09
1293 
1294  // Earth ellipsoid parameters
1295  float f = 1 / 298.257;
1296  float omf2 = (1 - f) * (1 - f);
1297  gsl_vector *C = gsl_vector_alloc(3);
1298 
1299  for (size_t i = 0; i < npix; i++) {
1300  // Compute sensor-to-surface vectors for all scan angles
1301  // Compute terms for quadratic equation
1302  double o =
1303  coef[0] * pview[i][0] * pview[i][0] +
1304  coef[1] * pview[i][1] * pview[i][1] +
1305  coef[2] * pview[i][2] * pview[i][2] +
1306  coef[3] * pview[i][0] * pview[i][1] +
1307  coef[4] * pview[i][0] * pview[i][2] +
1308  coef[5] * pview[i][1] * pview[i][2];
1309 
1310  double p =
1311  coef[6] * pview[i][0] + coef[7] * pview[i][1] + coef[8] * pview[i][2];
1312 
1313  double q = coef[9];
1314 
1315  double r = p * p - 4 * q * o;
1316 
1317  xlat[i] = -999;
1318  xlon[i] = -999;
1319 
1320  solz[i] = -999;
1321  sola[i] = -999;
1322  senz[i] = -999;
1323  sena[i] = -999;
1324  // range[i] = -999;
1325 
1326  // Check for scan past edge of Earth
1327  if (r >= 0) {
1328 
1329  // Solve for magnitude of sensor-to-pixel vector and compute components
1330  double d = (-p - sqrt(r)) / (2 * o);
1331  double x1[3];
1332  for (size_t j = 0; j < 3; j++) x1[j] = d * pview[i][j];
1333 
1334  // Convert velocity vector to ground speed
1335  float re = 6378.137;
1336  double omegae = 7.29211585494e-05;
1337  double pm = sqrt(pos[0]*pos[0] + pos[1]*pos[1] + pos[2]*pos[2]);
1338  double clatg = sqrt(pos[0]*pos[0] + pos[1]*pos[1]) / pm;
1339  double rg = re*(1.-f)/sqrt(1.-(2.-f)*f*clatg*clatg);
1340  double v[3];
1341  v[0] = (vel[0] - pos[1]*omegae) * rg / pm;
1342  v[1] = (vel[1] - pos[0]*omegae) * rg / pm;
1343  v[2] = vel[2] * rg / pm;
1344 
1345  // Transform vector from sensor to geocentric frame
1346  gsl_matrix_view A = gsl_matrix_view_array((double *)smat, 3, 3);
1347  gsl_vector_view B = gsl_vector_view_array(x1, 3);
1348 
1349  gsl_blas_dgemv(CblasTrans, 1.0, &A.matrix, &B.vector, 0.0, C);
1350 
1351  float rh[3], geovec[3];
1352  double *ptr_C = gsl_vector_ptr(C, 0);
1353  for (size_t j = 0; j < 3; j++) {
1354  rh[j] = ptr_C[j];
1355  geovec[j] = pos[j] + rh[j] + v[j]*delt;
1356  }
1357 
1358  // Compute the local vertical, East and North unit vectors
1359  float uxy = geovec[0] * geovec[0] + geovec[1] * geovec[1];
1360  float temp = sqrt(geovec[2] * geovec[2] + omf2 * omf2 * uxy);
1361 
1362  float up[3];
1363  up[0] = omf2 * geovec[0] / temp;
1364  up[1] = omf2 * geovec[1] / temp;
1365  up[2] = geovec[2] / temp;
1366  float upxy = sqrt(up[0] * up[0] + up[1] * up[1]);
1367 
1368  float ea[3];
1369  ea[0] = -up[1] / upxy;
1370  ea[1] = up[0] / upxy;
1371  ea[2] = 0.0;
1372 
1373  // no = crossp(up,ea)
1374  float no[3];
1375  no[0] = -up[2] * ea[1];
1376  no[1] = up[2] * ea[0];
1377  no[2] = up[0] * ea[1] - up[1] * ea[0];
1378 
1379  // Compute geodetic latitude and longitude
1380  xlat[i] = RADEG * asin(up[2]);
1381  xlon[i] = RADEG * atan2(up[1], up[0]);
1382 // range[i] = (short)((d - 400) * 10);
1383 
1384  // Transform the pixel-to-spacecraft and Sun vectors into local frame
1385  float rl[3], sl[3];
1386  rl[0] = -ea[0] * rh[0] - ea[1] * rh[1] - ea[2] * rh[2];
1387  rl[1] = -no[0] * rh[0] - no[1] * rh[1] - no[2] * rh[2];
1388  rl[2] = -up[0] * rh[0] - up[1] * rh[1] - up[2] * rh[2];
1389 
1390  sl[0] = sunr[0] * ea[0] + sunr[1] * ea[1] + sunr[2] * ea[2];
1391  sl[1] = sunr[0] * no[0] + sunr[1] * no[1] + sunr[2] * no[2];
1392  sl[2] = sunr[0] * up[0] + sunr[1] * up[1] + sunr[2] * up[2];
1393 
1394  // Compute the solar zenith and azimuth
1395  solz[i] = (short)(100 * RADEG *
1396  atan2(sqrt(sl[0] * sl[0] + sl[1] * sl[1]), sl[2]));
1397 
1398  // Check for zenith close to zero
1399  if (solz[i] > 0.01) sola[i] = (short)(100 * RADEG * atan2(sl[0], sl[1]));
1400 
1401  // Compute the sensor zenith and azimuth
1402  senz[i] = (short)(100 * RADEG *
1403  atan2(sqrt(rl[0] * rl[0] + rl[1] * rl[1]), rl[2]));
1404 
1405  // Check for zenith close to zero
1406  if (senz[i] > 0.01) sena[i] = (short)(100 * RADEG * atan2(rl[0], rl[1]));
1407  } // if on-earth
1408  } // pixel loop
1409 
1410  gsl_vector_free(C);
1411 
1412  return 0;
1413 }
1414 
1415 int mat2rpy(float pos[3], float vel[3], double smat[3][3], float rpy[3]) {
1416  // This program calculates the attitude angles from the ECEF orbit vector and
1417  // attitude matrix. The rotation order is (1,2,3).
1418 
1419  // The reference ellipsoid uses an equatorial radius of 6378.137 km and
1420  // a flattening factor of 1/298.257 (WGS 1984).
1421 
1422  // Calling Arguments
1423 
1424  // Name Type I/O Description
1425  //
1426  // pos(3) R*4 I Orbit position vector (ECEF)
1427  // vel(3) R*4 I Orbit velocity vector (ECEF)
1428  // smat(3,3) R*8 I Sensor attitude matrix (ECEF to sensor)
1429  // rpy(3) R*4 O Attitude angles (roll, pitch, yaw)
1430 
1431  double rem = 6371;
1432  double f = 1 / (double)298.257;
1433  double omegae = 7.29211585494e-5;
1434  double omf2 = (1 - f) * (1 - f);
1435 
1436  // Determine local vertical reference axes
1437  double p[3], v[3];
1438  for (size_t j = 0; j < 3; j++) {
1439  p[j] = (double)pos[j];
1440  v[j] = (double)vel[j];
1441  }
1442  v[0] -= p[1] * omegae;
1443  v[1] += p[0] * omegae;
1444 
1445  // Compute Z axis as local nadir vector
1446  double pm = sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
1447  double omf2p = (omf2 * rem + pm - rem) / pm;
1448  double pxy = p[0] * p[0] + p[1] * p[1];
1449  double temp = sqrt(p[2] * p[2] + omf2p * omf2p * pxy);
1450 
1451  double z[3];
1452  z[0] = -omf2p * p[0] / temp;
1453  z[1] = -omf2p * p[1] / temp;
1454  z[2] = -p[2] / temp;
1455 
1456  // Compute Y axis along negative orbit normal
1457  double on[3];
1458  on[0] = v[1] * z[2] - v[2] * z[1];
1459  on[1] = v[2] * z[0] - v[0] * z[2];
1460  on[2] = v[0] * z[1] - v[1] * z[0];
1461 
1462  double onm = sqrt(on[0] * on[0] + on[1] * on[1] + on[2] * on[2]);
1463 
1464  double y[3];
1465  for (size_t j = 0; j < 3; j++) y[j] = -on[j] / onm;
1466 
1467  // Compute X axis to complete orthonormal triad (velocity direction)
1468  double x[3];
1469  x[0] = y[1] * z[2] - y[2] * z[1];
1470  x[1] = y[2] * z[0] - y[0] * z[2];
1471  x[2] = y[0] * z[1] - y[1] * z[0];
1472 
1473  // Store local vertical reference vectors in matrix
1474  double om[3][3];
1475  memcpy(&om[0][0], &x, 3 * sizeof(double));
1476  memcpy(&om[1][0], &y, 3 * sizeof(double));
1477  memcpy(&om[2][0], &z, 3 * sizeof(double));
1478 
1479  // Compute orbital-to-spacecraft matrix
1480  double rm[3][3];
1481  gsl_matrix_view rm_mat = gsl_matrix_view_array(&rm[0][0], 3, 3);
1482 
1483  int s;
1484 
1485  gsl_permutation *perm = gsl_permutation_alloc(3);
1486 
1487  // Compute the LU decomposition of this matrix
1488  gsl_matrix_view B = gsl_matrix_view_array(&om[0][0], 3, 3);
1489  gsl_linalg_LU_decomp(&B.matrix, perm, &s);
1490 
1491  // Compute the inverse of the LU decomposition
1492  double inv[3][3];
1493  gsl_matrix_view inv_mat = gsl_matrix_view_array(&inv[0][0], 3, 3);
1494 
1495  gsl_linalg_LU_invert(&B.matrix, perm, &inv_mat.matrix);
1496 
1497  gsl_matrix_view A = gsl_matrix_view_array(&smat[0][0], 3, 3);
1498 
1499  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, &A.matrix, &inv_mat.matrix,
1500  0.0, &rm_mat.matrix);
1501 
1502  gsl_permutation_free(perm);
1503 
1504  // Compute attitude angles
1505  rpy[0] = RADEG * atan(-rm[2][1] / rm[2][2]);
1506  double cosp = sqrt(rm[2][1] * rm[2][1] + rm[2][2] * rm[2][2]);
1507  if (rm[2][2] < 0) cosp *= -1;
1508  rpy[1] = RADEG * atan2(rm[2][0], cosp);
1509  rpy[2] = RADEG * atan(-rm[1][0] / rm[0][0]);
1510 
1511  return 0;
1512 }
1513 
1514 
1515 /*----------------------------------------------------------------- */
1516 /* Create an Generic NETCDF4 file */
1517 /* ---------------------------------------------------------------- */
1518 int geoFile::createFile( const char* filename, const char* cdlfile,
1519  size_t sdim, int *ncid, int *gid) {
1520 
1521  try {
1522  geofile = new NcFile( filename, NcFile::replace);
1523  }
1524  catch ( NcException& e) {
1525  e.what();
1526  cerr << "Failure creating OCI GEO file: " << filename << endl;
1527  exit(1);
1528  }
1529 
1530  ifstream output_data_structure;
1531  string line;
1532  string dataStructureFile;
1533 
1534  dataStructureFile.assign( cdlfile);
1535  expandEnvVar( &dataStructureFile);
1536 
1537  output_data_structure.open( dataStructureFile.c_str(), ifstream::in);
1538  if ( output_data_structure.fail() == true) {
1539  cout << "\"" << dataStructureFile.c_str() << "\" not found" << endl;
1540  exit(1);
1541  }
1542 
1543  // Find "dimensions" section of CDL file
1544  while(1) {
1545  getline( output_data_structure, line);
1546  size_t pos = line.find("dimensions:");
1547  if ( pos == 0) break;
1548  }
1549 
1550  // Define dimensions from "dimensions" section of CDL file
1551  ndims = 0;
1552  // int dimid[1000];
1553  while(1) {
1554  getline( output_data_structure, line);
1555  size_t pos = line.find(" = ");
1556  if ( pos == string::npos) break;
1557 
1558  uint32_t dimSize;
1559  istringstream iss(line.substr(pos+2, string::npos));
1560  iss >> dimSize;
1561 
1562  iss.clear();
1563  iss.str( line);
1564  iss >> skipws >> line;
1565 
1566  // cout << "Dimension Name: " << line.c_str() << " Dimension Size: "
1567  // << dimSize << endl;
1568 
1569  if (line.compare("number_of_scans") == 0) {
1570  dimSize = sdim;
1571  }
1572 
1573  try {
1574  ncDims[ndims++] = geofile->addDim( line, dimSize);
1575  }
1576  catch ( NcException& e) {
1577  e.what();
1578  cerr << "Failure creating dimension: " << line.c_str() << endl;
1579  exit(1);
1580  }
1581 
1582  cout << "Dimension Name: " << line.c_str() << " Dimension Size: "
1583  << dimSize << endl;
1584 
1585  } // while loop
1586 
1587  // Read global attributes (string attributes only)
1588  while(1) {
1589  getline( output_data_structure, line);
1590  size_t pos = line.find("// global attributes");
1591  if ( pos == 0) break;
1592  }
1593 
1594  while(1) {
1595  getline( output_data_structure, line);
1596  size_t pos = line.find(" = ");
1597  if ( pos == string::npos) break;
1598 
1599  string attValue;
1600 
1601  // Remove leading and trailing quotes
1602  attValue.assign(line.substr(pos+4));
1603  size_t posQuote = attValue.find("\"");
1604  attValue.assign(attValue.substr(0, posQuote));
1605 
1606  istringstream iss(line.substr(pos+2));
1607  iss.clear();
1608  iss.str( line);
1609  iss >> skipws >> line;
1610 
1611  // Skip commented out attributes
1612  if (line.compare("//") == 0) continue;
1613 
1614  string attName;
1615  attName.assign(line.substr(1).c_str());
1616 
1617  // Skip non-string attributes
1618  if (attName.compare("orbit_number") == 0) continue;
1619  if (attName.compare("history") == 0) continue;
1620  if (attName.compare("format_version") == 0) continue;
1621  if (attName.compare("instrument_number") == 0) continue;
1622  if (attName.compare("pixel_offset") == 0) continue;
1623  if (attName.compare("number_of_filled_scans") == 0) continue;
1624 
1625  cout << attName.c_str() << " " << attValue.c_str() << endl;
1626 
1627  try {
1628  geofile->putAtt(attName, attValue);
1629  }
1630  catch ( NcException& e) {
1631  e.what();
1632  cerr << "Failure creating attribute: " + attName << endl;
1633  exit(1);
1634  }
1635 
1636  } // while(1)
1637 
1638  ngrps = 0;
1639 
1640  // Loop through groups
1641  while(1) {
1642  getline( output_data_structure, line);
1643 
1644  // Check if end of CDL file
1645  // If so then close CDL file and return
1646  if (line.substr(0,1).compare("}") == 0) {
1647  output_data_structure.close();
1648  return 0;
1649  }
1650 
1651  // Check for beginning of new group
1652  size_t pos = line.find("group:");
1653 
1654  // If found then create new group and variables
1655  if ( pos == 0) {
1656 
1657  // Parse group name
1658  istringstream iss(line.substr(6, string::npos));
1659  iss >> skipws >> line;
1660 
1661  // Create NCDF4 group
1662  ncGrps[ngrps++] = geofile->addGroup(line);
1663 
1664  int numDims=0;
1665  // int varDims[NC_MAX_DIMS];
1666  //size_t dimSize[NC_MAX_DIMS];
1667  //char dimName[NC_MAX_NAME+1];
1668  string sname;
1669  string lname;
1670  string standard_name;
1671  string units;
1672  string flag_values;
1673  string flag_meanings;
1674  double valid_min=0.0;
1675  double valid_max=0.0;
1676  double fill_value=0.0;
1677 
1678  vector<NcDim> varVec;
1679 
1680  int ntype=0;
1681  NcType ncType;
1682 
1683  // Loop through datasets in group
1684  getline( output_data_structure, line); // skip "variables:"
1685  while(1) {
1686  getline( output_data_structure, line);
1687 
1688  if (line.substr(0,2) == "//") continue;
1689  if (line.length() == 0) continue;
1690  if (line.substr(0,1).compare("\r") == 0) continue;
1691  if (line.substr(0,1).compare("\n") == 0) continue;
1692 
1693  size_t pos = line.find(":");
1694 
1695  // No ":" found, new dataset or empty line or end-of-group
1696  if ( pos == string::npos) {
1697 
1698  if ( numDims > 0) {
1699  // Create previous dataset
1700  createField( ncGrps[ngrps-1], sname.c_str(), lname.c_str(),
1701  standard_name.c_str(), units.c_str(),
1702  (void *) &fill_value,
1703  flag_values.c_str(), flag_meanings.c_str(),
1704  valid_min, valid_max, ntype, varVec);
1705 
1706  flag_values.assign("");
1707  flag_meanings.assign("");
1708  units.assign("");
1709  varVec.clear();
1710  }
1711 
1712  valid_min=0.0;
1713  valid_max=0.0;
1714  fill_value=0.0;
1715 
1716  if (line.substr(0,10).compare("} // group") == 0) break;
1717 
1718  // Parse variable type
1719  string varType;
1720  istringstream iss(line);
1721  iss >> skipws >> varType;
1722 
1723  // Get corresponding NC variable type
1724  if ( varType.compare("char") == 0) ntype = NC_CHAR;
1725  else if ( varType.compare("byte") == 0) ntype = NC_BYTE;
1726  else if ( varType.compare("short") == 0) ntype = NC_SHORT;
1727  else if ( varType.compare("int") == 0) ntype = NC_INT;
1728  else if ( varType.compare("long") == 0) ntype = NC_INT;
1729  else if ( varType.compare("float") == 0) ntype = NC_FLOAT;
1730  else if ( varType.compare("real") == 0) ntype = NC_FLOAT;
1731  else if ( varType.compare("double") == 0) ntype = NC_DOUBLE;
1732  else if ( varType.compare("ubyte") == 0) ntype = NC_UBYTE;
1733  else if ( varType.compare("ushort") == 0) ntype = NC_USHORT;
1734  else if ( varType.compare("uint") == 0) ntype = NC_UINT;
1735  else if ( varType.compare("ulong") == 0) ntype = NC_UINT;
1736  else if ( varType.compare("int64") == 0) ntype = NC_INT64;
1737  else if ( varType.compare("uint64") == 0) ntype = NC_UINT64;
1738 
1739  // Parse short name (sname)
1740  pos = line.find("(");
1741  size_t posSname = line.substr(0, pos).rfind(" ");
1742  sname.assign(line.substr(posSname+1, pos-posSname-1));
1743  cout << "sname: " << sname.c_str() << endl;
1744 
1745  // Parse variable dimension info
1746  this->parseDims( line.substr(pos+1, string::npos), varVec);
1747  numDims = varVec.size();
1748 
1749  } else {
1750  // Parse variable attributes
1751  size_t posEql = line.find("=");
1752  size_t pos1qte = line.find("\"");
1753  size_t pos2qte = line.substr(pos1qte+1, string::npos).find("\"");
1754  // cout << line.substr(pos+1, posEql-pos-2).c_str() << endl;
1755 
1756  string attrName = line.substr(pos+1, posEql-pos-2);
1757 
1758  // Get long_name
1759  if ( attrName.compare("long_name") == 0) {
1760  lname.assign(line.substr(pos1qte+1, pos2qte));
1761  // cout << "lname: " << lname.c_str() << endl;
1762  }
1763 
1764  // Get units
1765  else if ( attrName.compare("units") == 0) {
1766  units.assign(line.substr(pos1qte+1, pos2qte));
1767  // cout << "units: " << units.c_str() << endl;
1768  }
1769 
1770  // Get _FillValue
1771  else if ( attrName.compare("_FillValue") == 0) {
1772  iss.clear();
1773  iss.str( line.substr(posEql+1, string::npos));
1774  iss >> fill_value;
1775  // cout << "_FillValue: " << fill_value << endl;
1776  }
1777 
1778  // Get flag_values
1779  else if ( attrName.compare("flag_values") == 0) {
1780  flag_values.assign(line.substr(pos1qte+1, pos2qte));
1781  }
1782 
1783  // Get flag_meanings
1784  else if ( attrName.compare("flag_meanings") == 0) {
1785  flag_meanings.assign(line.substr(pos1qte+1, pos2qte));
1786  }
1787 
1788  // Get valid_min
1789  else if ( attrName.compare("valid_min") == 0) {
1790  iss.clear();
1791  iss.str( line.substr(posEql+1, string::npos));
1792  iss >> valid_min;
1793  // cout << "valid_min: " << valid_min << endl;
1794  }
1795 
1796  // Get valid_max
1797  else if ( attrName.compare("valid_max") == 0) {
1798  iss.clear();
1799  iss.str( line.substr(posEql+1, string::npos));
1800  iss >> valid_max;
1801  // cout << "valid_max: " << valid_max << endl;
1802  }
1803 
1804  } // if ( pos == string::npos)
1805  } // datasets in group loop
1806  } // New Group loop
1807  } // Main Group loop
1808 
1809  return 0;
1810 }
1811 
1812 
1813 int geoFile::parseDims( string dimString, vector<NcDim>& varDims) {
1814 
1815  size_t curPos=0;
1816  // char dimName[NC_MAX_NAME+1];
1817  string dimName;
1818 
1819  while(1) {
1820  size_t pos = dimString.find(",", curPos);
1821  if ( pos == string::npos)
1822  pos = dimString.find(")");
1823 
1824  string varDimName;
1825  istringstream iss(dimString.substr(curPos, pos-curPos));
1826  iss >> skipws >> varDimName;
1827 
1828  for (int i=0; i<ndims; i++) {
1829 
1830  try {
1831  dimName = ncDims[i].getName();
1832  }
1833  catch ( NcException& e) {
1834  e.what();
1835  cerr << "Failure accessing dimension: " + dimName << endl;
1836  exit(1);
1837  }
1838 
1839  if ( varDimName.compare(dimName) == 0) {
1840  cout << " " << dimName << " " << ncDims[i].getSize() << endl;
1841  varDims.push_back(ncDims[i]);
1842  break;
1843  }
1844  }
1845  if ( dimString.substr(pos, 1).compare(")") == 0) break;
1846 
1847  curPos = pos + 1;
1848  }
1849 
1850  return 0;
1851 }
1852 
1853 
1854 
data_t q
Definition: decode_rs.h:74
int r
Definition: decode_rs.h:73
data_t t[NROOTS+1]
Definition: decode_rs.h:77
int main(int argc, char *argv[])
int parseDims(std::string dimString, std::vector< netCDF::NcDim > &varDims)
int j
Definition: decode_rs.h:73
double tilt_angles[2]
Definition: common.h:15
int32_t day
float orb_array[3]
float quat_array[4]
int scan_ell(float p[3], double sm[3][3], double coef[10])
int nutate(double t, double xls, double gs, double xlm, double omega, double &dpsi, double &eps, double &epsm)
const double C
int qtom(float q[4], double rm[3][3])
void spin(double st, double *pos1, double *pos2)
int mat2rpy(float pos[3], float vel[3], double smat[3][3], float rpy[3])
int q_interp(size_t n_att_rec, size_t sdim, double *tq, quat_array *q, double *time, quat_array *qi)
int l_sun(size_t sdim, int32_t iyr, int32_t iday, double *sec, orb_array *sunr)
float32 * pos
Definition: l1_czcs_hdf.c:35
int ephparms(double t, double &xls, double &gs, double &xlm, double &omega)
#define SWAP_4(x)
Definition: common.h:18
int32 * msec
Definition: l1_czcs_hdf.c:31
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)
Definition: common.cpp:56
double tilt_axis[3]
Definition: common.h:14
double ham_ct_angles[2]
Definition: common.h:21
#define PI
Definition: l3_get_org.c:6
double tilt_to_oci_mech[3][3]
Definition: common.h:16
double precision function f(R1)
Definition: tmd.lp.f:1454
ofstream tempOut
Definition: l1agen_oci.cpp:140
double sc_to_tilt[3][3]
Definition: common.h:13
double ham_enc_scale
Definition: common.h:23
data_t omega[NROOTS+1]
Definition: decode_rs.h:77
float rd(float x, float y, float z)
#define re
Definition: l1_czcs_hdf.c:701
double rta_enc_scale
Definition: common.h:22
int createFile(const char *filename, const char *cdlfile, size_t sdim, int *ncid, int *gid)
netCDF::NcGroup ncGrps[10]
Definition: geolocate_oci.h:40
int gha2000(int32_t iyr, double day, double &gha)
int expandEnvVar(string *sValue)
Definition: hawkeyeUtil.h:41
Definition: jd.py:1
int sun2000(size_t sdim, int32_t iyr, int32_t idy, double *sec, orb_array *sun)
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
int orb_interp(size_t n_orb_rec, size_t sdim, double *torb, orb_array *p, orb_array *v, double *time, orb_array *posi, orb_array *veli)
int parseDims(int ncid, int ndims, string dimString, int *numDims, int *dimid, int *varDims)
int32_t rta_nadir
Definition: common.h:25
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)
integer, parameter double
double rta_axis[3]
Definition: common.h:18
double MCE_clock
Definition: common.h:11
#define SWAP_2(x)
void isodate2ydmsec(char *date, int32_t *year, int32_t *day, int32_t *msec)
Definition: date2ydmsec.c:20
#define RADEG
Definition: czcs_ctl_pt.c:5
double oci_mech_to_oci_opt[3][3]
Definition: common.h:17
double master_clock
Definition: common.h:10
int j2000_to_ecr(int32_t iyr, int32_t idy, double sec, double ecmat[3][3])
float xlon[LAC_PIXEL_NUM]
Definition: l1a_seawifs.c:93
int oci_geonav(float pos[3], float vel[3], double smat[3][3], double coef[10], float sunr[3], float **pview, size_t npix, double delt, float *xlat, float *xlon, short *solz, short *sola, short *senz, short *sena, short *range)
float pm[MODELMAX]
int get_ut1(int32_t iyr, int32_t idy, double &ut1utc)
#define omf2
Definition: l1_czcs_hdf.c:703
dtype
Definition: DDataset.hpp:31
int j2000_to_mod(int32_t iyr, int32_t idy, double sec, double j2mod[3][3])
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
int qprod(double q1[4], float q2[4], double q3[4])
double ham_at_angles[2]
Definition: common.h:20
data_t s[NROOTS]
Definition: decode_rs.h:75
int get_nut(int32_t iyr, int32_t idy, double xnut[3][3])
int32_t idy
Definition: atrem_corl1.h:161
#define VERSION
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)
Definition: common.cpp:7
int16_t * tilt
Definition: l2bin.cpp:86
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
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 on(as it will be in Near-Real-Time processing).
int32_t iyr
Definition: atrem_corl1.h:161
int mtoq(double rm[3][3], double q[4])
int k
Definition: decode_rs.h:73
int npix
Definition: get_cmp.c:27
float p[MODELMAX]
Definition: atrem_corl1.h:131
double ham_axis[3]
Definition: common.h:19
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)
Definition: common.cpp:138
int count
Definition: decode_rs.h:79