NASA Logo
Ocean Color Science Software

ocssw V2022
hawkeye_methods.cpp
Go to the documentation of this file.
1 #include <fstream>
2 #include <iostream>
3 #include <sstream>
4 #include <gsl/gsl_blas.h>
5 #include <gsl/gsl_linalg.h>
6 #include <gsl/gsl_matrix_double.h>
7 #include <string.h>
8 #include <string>
9 #include "hawkeye_methods.h"
10 #include <netcdf>
11 #include "netcdf.h"
12 #include <cstdio>
13 #include <cstdlib>
14 #include <vector>
15 #include <math.h>
16 #include <timeutils.h>
17 #include <allocate2d.h>
18 #include "l1c_latlongrid.h"
19 #define RADEG 57.29577951
20 using namespace netCDF;
21 using namespace netCDF::exceptions;
22 using namespace std;
23 
24 // function to calculate cross product of two vectors, 3 components each vector
25 void cross_product_double2(double vector_a[], double vector_b[], double temp[]) {
26  temp[0] = vector_a[1] * vector_b[2] - vector_a[2] * vector_b[1];
27  temp[1] = -(vector_a[0] * vector_b[2] - vector_a[2] * vector_b[0]);
28  temp[2] = vector_a[0] * vector_b[1] - vector_a[1] * vector_b[0];
29 }
30 
31 double cross_product_norm_double2(double vector_a[], double vector_b[]) {
32  double temp[3], nvec;
33  temp[0] = vector_a[1] * vector_b[2] - vector_a[2] * vector_b[1];
34  temp[1] = -(vector_a[0] * vector_b[2] - vector_a[2] * vector_b[0]);
35  temp[2] = vector_a[0] * vector_b[1] - vector_a[1] * vector_b[0];
36 
37  nvec = sqrt(temp[0] * temp[0] + temp[1] * temp[1] + temp[2] * temp[2]);
38  return nvec;
39 }
40 
41 int orb_to_latlon(size_t ix_swt_ini,size_t ix_swt_end,size_t num_gridlines, int nbinx, double *orb_time_tot,
42  orb_array2 *p, orb_array2 *v, double mgv1, double *tmgv1, double *tmgvf, float **lat_gd,
43  float **lon_gd, float **alt,int FirsTerrain) {
44  double rl2, pos_norm, clatg2, fe = 1 / 298.257;
45  double v1[3], v2[3], vecout[3], orbnorm[3], nvec, vi, toff;
46  float Re = 6378.137; // Re earth radius in km at equator
47  double oangle, G[3], glat, glon, gnorm, rem = 6371, omf2, omf2p, pxy, temp;
48 
49  size_t number_orecords_corr=ix_swt_end-ix_swt_ini+1;
50 
51 
52 
53 
54  orb_array2 *posgrid = new orb_array2[num_gridlines](); // these are doubles
55  orb_array2 *velgrid = new orb_array2[num_gridlines]();
56  orb_array2 *posgrid2 = new orb_array2[num_gridlines](); // these are doubles
57  orb_array2 *velgrid2 = new orb_array2[num_gridlines]();
58 
59  orb_array2 *pos2 = new orb_array2[number_orecords_corr](); // these are doubles
60  orb_array2 *vel2 = new orb_array2[number_orecords_corr]();
61  double* orb_time_tot2 = (double*)calloc(number_orecords_corr, sizeof(double));
62  int cc=0;
63  int flag_twodays=0;
64 
65  for (size_t k=ix_swt_ini;k<=ix_swt_end;k++)
66  {
67  if(orb_time_tot[k+1]<orb_time_tot[k])
68  {
69  flag_twodays=1;
70  }
71  if(flag_twodays) orb_time_tot[k+1]+=24*3600;
72 
73  pos2[cc][0]=p[k][0];
74  pos2[cc][1]=p[k][1];
75  pos2[cc][2]=p[k][2];
76  vel2[cc][0]=v[k][0];
77  vel2[cc][1]=v[k][1];
78  vel2[cc][2]=v[k][2];
79  orb_time_tot2[cc]=orb_time_tot[k];
80 
81  cc++;
82  }
83 
84  orb_interp2(number_orecords_corr, num_gridlines, orb_time_tot2, pos2, vel2, tmgv1, posgrid, velgrid);
85 
86  for (size_t i = 0; i < num_gridlines - 1; i++) {
87  pos_norm = sqrt(posgrid[i][0] * posgrid[i][0] + posgrid[i][1] * posgrid[i][1] +
88  posgrid[i][2] * posgrid[i][2]);
89  clatg2 = sqrt(posgrid[i][0] * posgrid[i][0] + posgrid[i][1] * posgrid[i][1]) / pos_norm;
90  rl2 = Re * (1 - fe) / (sqrt(1 - (2 - fe) * fe * clatg2 * clatg2));
91 
92  v2[0] = velgrid[i][0] * rl2 / pos_norm;
93  v2[1] = velgrid[i][1] * rl2 / pos_norm;
94  v2[2] = velgrid[i][2] * rl2 / pos_norm;
95 
96  vi = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]) * 1000;
97  toff = vi / mgv1;
98  tmgvf[i] = tmgv1[i] + toff;
99  }
100  orb_interp2(number_orecords_corr, num_gridlines, orb_time_tot2, pos2, vel2, tmgvf, posgrid2, velgrid2);
101 
102  // angle subsat track----
103  omf2 = (1 - fe) * (1 - fe);
104 
105  for (size_t i = 0; i < num_gridlines - 1; i++) {
106  pos_norm = sqrt(posgrid2[i][0] * posgrid2[i][0] + posgrid2[i][1] * posgrid2[i][1] +
107  posgrid2[i][2] * posgrid2[i][2]);
108  clatg2 = sqrt(posgrid2[i][0] * posgrid2[i][0] + posgrid2[i][1] * posgrid2[i][1]) / pos_norm;
109  rl2 = Re * (1 - fe) / (sqrt(1 - (2 - fe) * fe * clatg2 * clatg2));
110  // ground pos
111  v1[0] = (posgrid2[i][0]) * rl2 / pos_norm;
112  v1[1] = (posgrid2[i][1]) * rl2 / pos_norm;
113  v1[2] = (posgrid2[i][2]) * rl2 / pos_norm;
114  // ground vel
115  v2[0] = (velgrid2[i][0]) * rl2 / pos_norm;
116  v2[1] = (velgrid2[i][1]) * rl2 / pos_norm;
117  v2[2] = (velgrid2[i][2]) * rl2 / pos_norm;
118 
119  cross_product_double2(v1, v2, vecout);
120  nvec = cross_product_norm_double2(v1, v2); // length of orb norm vect
121 
122  orbnorm[0] = vecout[0] / nvec;
123  orbnorm[1] = vecout[1] / nvec;
124  orbnorm[2] = vecout[2] / nvec;
125 
126  for (int j = 0; j < nbinx; j++) {
127  pos_norm = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); // first gridline
128  oangle = asin((j - (nbinx - 1) / 2) * 5.2 / pos_norm);
129  // Geocentric vector
130  G[0] = v1[0] * cos(oangle) - orbnorm[0] * pos_norm * sin(oangle);
131  G[1] = v1[1] * cos(oangle) - orbnorm[1] * pos_norm * sin(oangle);
132  G[2] = v1[2] * cos(oangle) - orbnorm[2] * pos_norm * sin(oangle);
133 
134  glon = atan2(G[1], G[0]) * 180 / M_PI;
135  gnorm = sqrt(G[0] * G[0] + G[1] * G[1] + G[2] * G[2]);
136  omf2p = (omf2 * rem + gnorm - rem) / gnorm;
137  pxy = G[0] * G[0] + G[1] * G[1];
138  temp = sqrt(G[2] * G[2] + omf2p * omf2p * pxy);
139  glat = asin(G[2] / temp) * 180 / M_PI;
140 
141  lat_gd[i][j] = glat;
142  lon_gd[i][j] = glon;
143  alt[i][j]=BAD_FLT;
144  }
145  }
146 
147 
148  for (size_t i = 0; i < num_gridlines-1; i++)
149  {
150  if(flag_twodays)
151  {
152  tmgvf[i]-=24*3600;
153  }
154  }
155 
156 
157  //================================================
158 //DEM info
159  if(FirsTerrain)//terrain flag =0 so DEM not added to L1C grid
160  {
161  NcFile *nc_terrain;
162  const char* dem_str="$OCDATAROOT/common/gebco_ocssw_v2020.nc";
163  char demfile[FILENAME_MAX];
164  parse_file_name(dem_str, demfile);
165 
166  try {
167  nc_terrain = new NcFile(demfile, NcFile::read);
168  } catch (NcException& e) {
169  cerr << e.what() << "l1cgen orb_to_latlon: Failure to open terrain height file: " << demfile
170  << endl;
171  exit(1);
172  }
173 
174 
175  NcVar terrain,var1,var2,var3;
176  vector<size_t> start,count,count2,start2,start3;
177  //lon/lat dimensions
178  NcDim londim = nc_terrain->getDim("lon");
179  NcDim latdim = nc_terrain->getDim("lat");
180 
181  start.push_back(0);
182  start.push_back(0);
183  count.push_back(1);
184  count.push_back(1);
185 
186  short oneheight=BAD_FLT;
187 
188  double onelat=-90.,onelon=-180.,dcoor=0.00416667;//dcoor in degrees , gridded gebco
189  size_t ix_grid,ix_grid2;
190 
191  var1=nc_terrain->getVar("height");
192  num_gridlines-=1;
193 
194  //COMPUTE L1C GRID MIN MAX LIMITS
195  for(size_t i=0;i<num_gridlines;i++)
196  {
197  for(int j=0;j<nbinx;j++)
198  {
199  ix_grid=(-1*onelat+lat_gd[i][j])/dcoor;
200  ix_grid2=(-1*onelon+lon_gd[i][j])/dcoor;
201  start[0]=ix_grid;
202  start[1]=ix_grid2;
203  var1.getVar(start,count,&oneheight);
204  alt[i][j]=oneheight;
205  if(oneheight==BAD_FLT) cout<<"WARNING: oneheight is a fillvalue"<<oneheight<<"demfile "<<"ybin# "<<i+1<<"xbin# "<<j+1<<endl;
206  }
207  if(i%500==0) cout<<"#gridline with DEM "<<i+1<<endl;
208  }
209 
210  nc_terrain->close();
211  }//if first terrain
212 
213  if (posgrid != nullptr)
214  delete[] (posgrid);
215  posgrid = nullptr;
216  if (velgrid != nullptr)
217  delete[] (velgrid);
218  velgrid = nullptr;
219  if (posgrid2 != nullptr)
220  delete[] (posgrid2);
221  posgrid2 = nullptr;
222  if (velgrid2 != nullptr)
223  delete[] (velgrid2);
224  velgrid2 = nullptr;
225 
226  if (pos2 != nullptr)
227  delete[] (pos2);
228  pos2 = nullptr;
229  if (vel2 != nullptr)
230  delete[] (vel2);
231  vel2 = nullptr;
232  if ( orb_time_tot2 != nullptr)
233  delete[] ( orb_time_tot2);
234  orb_time_tot2 = nullptr;
235 
236  return 0;
237 }
238 
239 
240 int orb_interp2(size_t n_orb_rec, size_t sdim, double *torb, orb_array2 *p, orb_array2 *v, double *time,
241  orb_array2 *posi, orb_array2 *veli) {
242  double a0[3], a1[3], a2[3], a3[3];
243 
244  size_t ind = 0;
245  for (size_t i = 0; i < sdim; i++) {
246  // Find input orbit vectors bracketing scan
247  for (size_t j = ind; j < n_orb_rec; j++) {
248  if (time[i] > torb[j] && time[i] <= torb[j + 1]) {
249  ind = j;
250  break;
251  }
252  }
253 
254  // Set up cubic interpolation
255  double dt = torb[ind + 1] - torb[ind];
256  for (size_t j = 0; j < 3; j++) {
257  a0[j] = p[ind][j];
258  a1[j] = v[ind][j] * dt;
259  a2[j] = 3 * p[ind + 1][j] - 3 * p[ind][j] - 2 * v[ind][j] * dt - v[ind + 1][j] * dt;
260  a3[j] = 2 * p[ind][j] - 2 * p[ind + 1][j] + v[ind][j] * dt + v[ind + 1][j] * dt;
261  }
262 
263  // Interpolate orbit position and velocity components to scan line time
264  double x = (time[i] - torb[ind]) / dt;
265  double x2 = x * x;
266  double x3 = x2 * x;
267  for (size_t j = 0; j < 3; j++) {
268  posi[i][j] = a0[j] + a1[j] * x + a2[j] * x2 + a3[j] * x3;
269  veli[i][j] = (a1[j] + 2 * a2[j] * x + 3 * a3[j] * x2) / dt;
270  }
271  } // i-loop
272 
273  return 0;
274 }
275 
276 int orb_interp(size_t n_orb_rec, size_t sdim, double *torb, orb_array *p, orb_array *v, double *time,
277  orb_array *posi, orb_array *veli) {
278  double a0[3], a1[3], a2[3], a3[3];
279 
280  size_t ind = 0;
281  for (size_t i = 0; i < sdim; i++) {
282  // Find input orbit vectors bracketing scan
283  for (size_t j = ind; j < n_orb_rec; j++) {
284  if (time[i] > torb[j] && time[i] <= torb[j + 1]) {
285  ind = j;
286  break;
287  }
288  }
289 
290  // Set up cubic interpolation
291  double dt = torb[ind + 1] - torb[ind];
292  for (size_t j = 0; j < 3; j++) {
293  a0[j] = p[ind][j];
294  a1[j] = v[ind][j] * dt;
295  a2[j] = 3 * p[ind + 1][j] - 3 * p[ind][j] - 2 * v[ind][j] * dt - v[ind + 1][j] * dt;
296  a3[j] = 2 * p[ind][j] - 2 * p[ind + 1][j] + v[ind][j] * dt + v[ind + 1][j] * dt;
297  }
298 
299  // Interpolate orbit position and velocity components to scan line time
300  double x = (time[i] - torb[ind]) / dt;
301  double x2 = x * x;
302  double x3 = x2 * x;
303  for (size_t j = 0; j < 3; j++) {
304  posi[i][j] = a0[j] + a1[j] * x + a2[j] * x2 + a3[j] * x3;
305  veli[i][j] = (a1[j] + 2 * a2[j] * x + 3 * a3[j] * x2) / dt;
306  }
307  } // i-loop
308 
309  return 0;
310 }
311 
312 int j2000_to_ecr(int32_t iyr, int32_t idy, double sec, double ecmat[3][3]) {
313  // Get J2000 to ECEF transformation matrix
314 
315  // Arguments:
316 
317  // Name Type I/O Description
318  // --------------------------------------------------------
319  // iyr I I Year, four digits
320  // idy I I Day of year
321  // sec R*8 I Seconds of day
322  // ecmat(3,3) R O J2000 to ECEF matrix
323 
324  // Get transformation from J2000 to mean-of-date inertial
325  double j2mod[3][3];
326  j2000_to_mod(iyr, idy, sec, j2mod);
327 
328  // Get nutation and UT1-UTC (once per run)
329  double xnut[3][3], ut1utc;
330  get_nut(iyr, idy, xnut);
331  get_ut1(iyr, idy, ut1utc);
332 
333  // Compute Greenwich hour angle for time of day
334  double day = idy + (sec + ut1utc) / 86400;
335  double gha, gham[3][3];
336  gha2000(iyr, day, gha);
337 
338  gham[0][0] = cos(gha / RADEG);
339  gham[1][1] = cos(gha / RADEG);
340  gham[2][2] = 1;
341  gham[0][1] = sin(gha / RADEG);
342  gham[1][0] = -sin(gha / RADEG);
343 
344  gham[0][2] = 0;
345  gham[2][0] = 0;
346  gham[1][2] = 0;
347  gham[2][1] = 0;
348 
349  // Combine all transformations
350  gsl_matrix_view A = gsl_matrix_view_array(&gham[0][0], 3, 3); // gham
351  gsl_matrix_view B = gsl_matrix_view_array(&xnut[0][0], 3, 3); // xnut
352  gsl_matrix *C = gsl_matrix_alloc(3, 3);
353 
354  gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0, &A.matrix, &B.matrix, 0.0, C);
355 
356  gsl_matrix_view D = gsl_matrix_view_array(&j2mod[0][0], 3, 3); // j2mod
357  gsl_matrix *E = gsl_matrix_alloc(3, 3);
358  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, C, &D.matrix, 0.0, E);
359  double *ptr_E = gsl_matrix_ptr(E, 0, 0);
360 
361  memcpy(ecmat, ptr_E, 9 * sizeof(double));
362 
363  gsl_matrix_free(C);
364  gsl_matrix_free(E);
365 
366  return 0;
367 }
368 
369 int j2000_to_mod(int32_t iyr, int32_t idy, double sec, double j2mod[3][3]) {
370  // Get J2000 to MOD (precession) transformation
371 
372  // Arguments:
373 
374  // Name Type I/O Description
375  // --------------------------------------------------------
376  // iyr I I Year, four digits
377  // idy I I Day of year
378  // sec R*8 I Seconds of day
379  // j2mod(3,3) R O J2000 to MOD matrix
380 
381  int16_t iyear = iyr;
382  int16_t iday = idy;
383 
384  double t = jday(iyear, 1, iday) - (double)2451545.5 + sec / 86400;
385  t /= 36525;
386 
387  double zeta0 = t * (2306.2181 + 0.302 * t + 0.018 * t * t) / RADEG / 3600;
388  double thetap = t * (2004.3109 - 0.4266 * t - 0.04160 * t * t) / RADEG / 3600;
389  double xip = t * (2306.2181 + 1.095 * t + 0.018 * t * t) / RADEG / 3600;
390 
391  j2mod[0][0] = -sin(zeta0) * sin(xip) + cos(zeta0) * cos(xip) * cos(thetap);
392  j2mod[0][1] = -cos(zeta0) * sin(xip) - sin(zeta0) * cos(xip) * cos(thetap);
393  j2mod[0][2] = -cos(xip) * sin(thetap);
394  j2mod[1][0] = sin(zeta0) * cos(xip) + cos(zeta0) * sin(xip) * cos(thetap);
395  j2mod[1][1] = cos(zeta0) * cos(xip) - sin(zeta0) * sin(xip) * cos(thetap);
396  j2mod[1][2] = -sin(xip) * sin(thetap);
397  j2mod[2][0] = cos(zeta0) * sin(thetap);
398  j2mod[2][1] = -sin(zeta0) * sin(thetap);
399  j2mod[2][2] = cos(thetap);
400 
401  return 0;
402 }
403 
404 int get_nut(int32_t iyr, int32_t idy, double xnut[3][3]) {
405  int16_t iyear = iyr;
406  int16_t iday = idy;
407 
408  double t = jday(iyear, 1, iday) - (double)2451545.5;
409 
410  double xls, gs, xlm, omega;
411  double dpsi, eps, epsm;
412  ephparms(t, xls, gs, xlm, omega);
413  nutate(t, xls, gs, xlm, omega, dpsi, eps, epsm);
414 
415  xnut[0][0] = cos(dpsi / RADEG);
416  xnut[1][0] = -sin(dpsi / RADEG) * cos(epsm / RADEG);
417  xnut[2][0] = -sin(dpsi / RADEG) * sin(epsm / RADEG);
418  xnut[0][1] = sin(dpsi / RADEG) * cos(eps / RADEG);
419  xnut[1][1] =
420  cos(dpsi / RADEG) * cos(eps / RADEG) * cos(epsm / RADEG) + sin(eps / RADEG) * sin(epsm / RADEG);
421  xnut[2][1] =
422  cos(dpsi / RADEG) * cos(eps / RADEG) * sin(epsm / RADEG) - sin(eps / RADEG) * cos(epsm / RADEG);
423  xnut[0][2] = sin(dpsi / RADEG) * sin(eps / RADEG);
424  xnut[1][2] =
425  cos(dpsi / RADEG) * sin(eps / RADEG) * cos(epsm / RADEG) - cos(eps / RADEG) * sin(epsm / RADEG);
426  xnut[2][2] =
427  cos(dpsi / RADEG) * sin(eps / RADEG) * sin(epsm / RADEG) + cos(eps / RADEG) * cos(epsm / RADEG);
428 
429  return 0;
430 }
431 
432 int ephparms(double t, double &xls, double &gs, double &xlm, double &omega) {
433  // This subroutine computes ephemeris parameters used by other Mission
434  // Operations routines: the solar mean longitude and mean anomaly, and
435  // the lunar mean longitude and mean ascending node. It uses the model
436  // referenced in The Astronomical Almanac for 1984, Section S
437  // (Supplement) and documented for the SeaWiFS Project in "Constants
438  // and Parameters for SeaWiFS Mission Operations", in TBD. These
439  // parameters are used to compute the solar longitude and the nutation
440  // in longitude and obliquity.
441 
442  // Sun Mean Longitude
443  xls = (double)280.46592 + ((double)0.9856473516) * t;
444  xls = fmod(xls, (double)360);
445 
446  // Sun Mean Anomaly
447  gs = (double)357.52772 + ((double)0.9856002831) * t;
448  gs = fmod(gs, (double)360);
449 
450  // Moon Mean Longitude
451  xlm = (double)218.31643 + ((double)13.17639648) * t;
452  xlm = fmod(xlm, (double)360);
453 
454  // Ascending Node of Moon's Mean Orbit
455  omega = (double)125.04452 - ((double)0.0529537648) * t;
456  omega = fmod(omega, (double)360);
457 
458  return 0;
459 }
460 
461 int nutate(double t, double xls, double gs, double xlm, double omega, double &dpsi, double &eps,
462  double &epsm) {
463  // This subroutine computes the nutation in longitude and the obliquity
464  // of the ecliptic corrected for nutation. It uses the model referenced
465  // in The Astronomical Almanac for 1984, Section S (Supplement) and
466  // documented for the SeaWiFS Project in "Constants and Parameters for
467  // SeaWiFS Mission Operations", in TBD. These parameters are used to
468  // compute the apparent time correction to the Greenwich Hour Angle and
469  // for the calculation of the geocentric Sun vector. The input
470  // ephemeris parameters are computed using subroutine ephparms. Terms
471  // are included to 0.1 arcsecond.
472 
473  // Nutation in Longitude
474  dpsi = -17.1996 * sin(omega / RADEG) + 0.2062 * sin(2. * omega / RADEG) - 1.3187 * sin(2. * xls / RADEG) +
475  0.1426 * sin(gs / RADEG) - 0.2274 * sin(2. * xlm / RADEG);
476 
477  // Mean Obliquity of the Ecliptic
478  epsm = (double)23.439291 - ((double)3.560e-7) * t;
479 
480  // Nutation in Obliquity
481  double deps = 9.2025 * cos(omega / RADEG) + 0.5736 * cos(2. * xls / RADEG);
482 
483  // True Obliquity of the Ecliptic
484  eps = epsm + deps / 3600;
485 
486  dpsi = dpsi / 3600;
487 
488  return 0;
489 }
490 
491 int get_ut1(int32_t iyr, int32_t idy, double &ut1utc) {
492  int16_t iyear = iyr;
493  int16_t iday = idy;
494 
495  static int32_t ijd[25000];
496  static double ut1[25000];
497  string utcpole = "$OCVARROOT/var/modis/utcpole.dat";
498  static bool first = true;
499  int k = 0;
500  if (first) {
501  string line;
503  istringstream istr;
504 
505  ifstream utcpfile(utcpole.c_str());
506  if (utcpfile.is_open()) {
507  getline(utcpfile, line);
508  getline(utcpfile, line);
509  while (getline(utcpfile, line)) {
510  istr.clear();
511  istr.str(line.substr(0, 5));
512  istr >> ijd[k];
513  istr.clear();
514  istr.str(line.substr(44, 9));
515  istr >> ut1[k];
516  k++;
517  }
518  ijd[k] = 0;
519  utcpfile.close();
520  first = false;
521  } else {
522  cout << utcpole.c_str() << " not found" << endl;
523  exit(1);
524  }
525  } // if (first)
526 
527  k = 0;
528  int mjd = jday(iyear, 1, iday) - 2400000;
529  while (ijd[k] > 0) {
530  if (mjd == ijd[k]) {
531  ut1utc = ut1[k];
532  break;
533  }
534  k++;
535  }
536 
537  return 0;
538 }
539 
540 int gha2000(int32_t iyr, double day, double &gha) {
541  // This subroutine computes the Greenwich hour angle in degrees for the
542  // input time. It uses the model referenced in The Astronomical Almanac
543  // for 1984, Section S (Supplement) and documented for the SeaWiFS
544  // Project in "Constants and Parameters for SeaWiFS Mission Operations",
545  // in TBD. It includes the correction to mean sidereal time for nutation
546  // as well as precession.
547  //
548 
549  // Compute days since J2000
550  int16_t iday = day;
551  double fday = day - iday;
552  int jd = jday(iyr, 1, iday);
553  double t = jd - (double)2451545.5 + fday;
554 
555  // Compute Greenwich Mean Sidereal Time (degrees)
556  double gmst = (double)100.4606184 + (double)0.9856473663 * t + (double)2.908e-13 * t * t;
557 
558  // Check if need to compute nutation correction for this day
559  double xls, gs, xlm, omega;
560  double dpsi, eps, epsm;
561  ephparms(t, xls, gs, xlm, omega);
562  nutate(t, xls, gs, xlm, omega, dpsi, eps, epsm);
563 
564  // Include apparent time correction and time-of-day
565  gha = gmst + dpsi * cos(eps / RADEG) + fday * 360;
566  gha = fmod(gha, (double)360);
567 
568  return 0;
569 }
570 
571 int expandEnvVar(std::string *sValue) {
572  if ((*sValue).find_first_of("$") == string::npos)
573  return 0;
574  string::size_type posEndIdx = (*sValue).find_first_of("/");
575  if (posEndIdx == string::npos)
576  return 0;
577  char *envVar_str = getenv((*sValue).substr(1, posEndIdx - 1).c_str());
578  if (envVar_str == 0x0) {
579  printf("Environment variable: %s not defined.\n", envVar_str);
580  exit(1);
581  }
582  *sValue = envVar_str + (*sValue).substr(posEndIdx);
583 
584  return 0;
585 }
data_t t[NROOTS+1]
Definition: decode_rs.h:77
int j
Definition: decode_rs.h:73
int32_t day
int j2000_to_mod(int32_t iyr, int32_t idy, double sec, double j2mod[3][3])
int orb_interp2(size_t n_orb_rec, size_t sdim, double *torb, orb_array2 *p, orb_array2 *v, double *time, orb_array2 *posi, orb_array2 *veli)
float orb_array[3]
const double C
Definition: calc_par.c:102
int ephparms(double t, double &xls, double &gs, double &xlm, double &omega)
int32_t jday(int16_t i, int16_t j, int16_t k)
Converts a calendar date to the corresponding Julian day starting at noon on the calendar date....
Definition: jday.c:14
double dpsi
Definition: sun2000.c:6
double eps
Definition: gha2000.c:3
@ string
void cross_product_double2(double vector_a[], double vector_b[], double temp[])
int nutate(double t, double xls, double gs, double xlm, double omega, double &dpsi, double &eps, double &epsm)
#define M_PI
Definition: dtranbrdf.cpp:19
int expandEnvVar(std::string *sValue)
const float A
Definition: calc_par.c:100
float Re
Definition: l1c.cpp:57
int j2000_to_ecr(int32_t iyr, int32_t idy, double sec, double ecmat[3][3])
int get_nut(int32_t iyr, int32_t idy, double xnut[3][3])
data_t omega[NROOTS+1]
Definition: decode_rs.h:77
double cross_product_norm_double2(double vector_a[], double vector_b[])
int get_ut1(int32_t iyr, int32_t idy, double &ut1utc)
Definition: jd.py:1
int gha2000(int32_t iyr, double day, double &gha)
integer, parameter double
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)
Utility functions for allocating and freeing two-dimensional arrays of various types.
void parse_file_name(const char *inpath, char *outpath)
const float B
Definition: calc_par.c:101
#define BAD_FLT
Definition: jplaeriallib.h:19
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame the required RAM for each execution is MB on the DEC ALPHA and MB on the SGI Octane v2
Definition: HISTORY.txt:728
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 omf2
Definition: l1_czcs.c:697
int32_t idy
Definition: atrem_corl1.h:161
int i
Definition: decode_rs.h:71
int orb_to_latlon(size_t ix_swt_ini, size_t ix_swt_end, size_t num_gridlines, int nbinx, double *orb_time_tot, orb_array2 *p, orb_array2 *v, double mgv1, double *tmgv1, double *tmgvf, float **lat_gd, float **lon_gd, float **alt, int FirsTerrain)
int32_t iyr
Definition: atrem_corl1.h:161
#define RADEG
int k
Definition: decode_rs.h:73
float p[MODELMAX]
Definition: atrem_corl1.h:131
double orb_array2[3]
int count
Definition: decode_rs.h:79