OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
GEO_ephem_attit.c
Go to the documentation of this file.
1 /* GEO_ephem_attit.c includes geolocation functions GEO_get_ancil_packet_time(),
2  * GEO_interp_ephemeris_attitude() and GEO_prepare_ancil_data().
3  *
4  * $Log: GEO_ephem_attit.c,v $
5  * Revision 6.11 2015/05/20 21:39:44 jkuyper
6  * Corrected resolution of Bug 5334.
7  *
8  * Revision 6.10 2014/08/18 22:36:00 jkuyper
9  * Resolved Bug 5535 by changing to delta <= 0.
10  *
11  * Revision 6.9 2013/07/29 19:39:17 jkuyper
12  * Corrected defective subscripting of eulerAngles introduced in Revision 6.3.
13  *
14  * Revision 6.8 2013/06/24 22:39:54 jkuyper
15  * Corrected to zero-initialize sample_quality.
16  * Corrected subscript.
17  * Corrected to search qualityFlags for good attitude records.
18  *
19  * Revision 6.7 2013/06/18 20:12:14 jkuyper
20  * Reverted attitQuat to a local variable.
21  *
22  * Revision 6.6 2010/06/29 19:27:02 kuyper
23  * GEO_prepare_ancil_data(): Corrected typo, and off-by-one error.
24  * GEO_interp_ephemeris_attitude(): made many minor fixes to the code for
25  * handling entrained ephemeris and attitude data, without resolving known bugs.
26  * I'll have to deliver it as is, for a science test, which won't make use of
27  * entrained data.
28  *
29  * Revision 6.5 2010/06/18 20:37:10 kuyper
30  * Corrected to initialize last_qcount.
31  * Corrected syntax error in bit-field test.
32  *
33  * Revision 6.4 2010/06/01 17:45:18 kuyper
34  * Changed GEO_prepapre_ancil_data() to return a status code.
35  *
36  * Revision 6.3 2010/05/14 22:19:16 kuyper
37  * Simplified interface of GEO_prepare_ancil_data().
38  * Changed to pass ephemeris and attitude quality flags returned by
39  * PGS_EPH_EphemAttit back to caller.
40  * Changed to set the quality flags when using entrained ephemeris and attitude
41  * information, and to use those quality flags the same way as when they're
42  * retrieved from PGS_EPH_EphemAttit. As a result, a major rearrangement of
43  * orbit and attitude validation procedures was required.
44  * Removed global validation parameters.
45  * Changed to use "Safe Mode" rather than "Science Abnormal state" to reject
46  * ancillary data packets.
47  * Corrected to set attitQuat by calling PGS_CSC_EulerToQuat when using entrained
48  * attitude data.
49  *
50  * Revision 6.2 2009/05/31 01:29:07 ltan
51  * Minor corrections.
52  *
53  * Revision 6.1 2009/05/18 22:18:11 ltan
54  * Changed macro name to MAX_PADDED. Removed leading dimensions of "array" parameters. Changed MAX_SCAN_SAMPLE to PADDED_SAMPLES.
55  *
56  * Revision 5.6 2009/05/15 19:00:41 kuyper
57  * Corrected to initialize sc_state[].position[0], to resolve Bug 2403.
58  *
59  * James Kuyper Jr. James.R.Kuyper@nasa.gov
60  *
61  * Revision 5.5 2006/12/06 23:02:13 kuyper
62  * Corrected macro names.
63  *
64  * Revision 5.4 2006/11/08 22:24:05 kuyper
65  * Added PM-1 specific quality flags.
66  * Changed to use PGSd_PLATFORM_FATAL to filter data.
67  * Net effect will be to drop data points collected with missing status words
68  * for the attitude files.
69  *
70  * Revision 5.3 2004/10/27 16:20:27 kuyper
71  * Changed to produce a valid, but (negligibly) incorrect quaternion if run
72  * in "MODIS packet" mode.
73  *
74  * Revision 5.2 2004/10/18 14:51:51 kuyper
75  * Added attitQuat to the pointer validity test check list.
76  *
77  * Revision 5.1 2004/09/20 19:14:35 kuyper
78  * Made attitQuat an output parameter.
79  *
80  * Revision 4.3 2003/10/30 22:46:07 kuyper
81  * Corrected re-ordering of attitude angles.
82  *
83  * Revision 4.2 2003/08/26 20:27:54 kuyper
84  * Corrected offsets to be a constant.
85  *
86  * Revision 4.1 2003/07/17 18:56:32 vlin
87  * updated after code walkthrough.
88  *
89  * Revision 4.0 2003/05/23 18:47:03 vlin
90  * Changes to function GEO_interp_ephemeris_attitude:
91  * Take an array of time offsets for input, and to write to an output array.
92  * Treat missing eph/att files as an error condition, while treating missing data
93  * within those files as a normal condition. Changed to return a status value,
94  * use automatically allocated arrays for storing PGS_EPH_EphemAttit() output
95  * handle numValues==0 as a valid value, allow excess ephemeris/attitude files.
96  * Added new function GEO_get_ancil_packet_time.
97  *
98  * Revision 3.1 2002/06/13 22:48:25 kuyper
99  * Removed unnecessary NCSA acknowledgement.
100  *
101  * Revision 2.6 2000/08/15 18:56:26 kuyper
102  * Corrected strcasecmp() to strcmp().
103  *
104  * Revision 2.5 2000/08/07 14:56:55 fhliang
105  * Changes to GEO_prepare_ancil_data():
106  * Changed to use the spacecraft_ID to determine which function should be used
107  * to convert packet header timestamps to TAI times.
108  * Changed to set sc_evolution.spacecraftTag, based upon the value of
109  * spacecraft_ID.
110  * Corrected to not bother loading or ancillary data if it comes from Aqua.
111  * Changes to GEO_interp_ephemeris_attitude():
112  * Changed to use sc_evolution.spacecraftTag in call to PGS_EPH_EphemAttit.
113  * Made the message printed if that call fails somewhat more useful.
114  *
115  * Revision 2.4 1999/02/11 22:27:45 kuyper
116  * Changes to GEO_prepare_ancil_data():
117  * Moved in setting of orbit/attit validation globals from
118  * GEO_prepare_l1a_data().
119  * Added max_extrap member to sc_evolution.
120  * Changed to take GEO_param_struct parameter, rather than ancil_scale_struct.
121  * Expanded index names to clarify code.
122  * Moved initialization of num_samples to just before corresponding changes.
123  * Corrected to not use SCI_STATE to validate packets.
124  * Changed checks of ==FAIL to !=SUCCESS.
125  * Changes to GEO_interp_ephemeris_attitude():
126  * Removed max_extrap parameter.
127  * Added check of qFlag values.
128  *
129  * Check the RCS directory at modular:/L1A/INHOUSE/PGE01/MOD_PR03
130  * for earlier revision history
131  */
132 
133 #include <float.h>
134 #include "PGS_CSC.h"
135 #include "smfio.h"
136 #include "GEO_earth.h"
137 #include "GEO_input.h"
138 #include "GEO_product.h"
139 #include "GEO_util.h"
140 #include "PGS_MODIS_35251.h"
141 #ifndef STATIC
142 #define STATIC static
143 #endif
144 
145 double position_abs_limit[2]; /* orbit position absolute limits */
146 double position_mag_limit[2]; /* orbit position magnitude limits */
147 double velocity_abs_limit[2]; /* orbit velocity absolute limits */
148 double velocity_mag_limit[2]; /* orbit velocity magnitude limits */
149 double ang_mom_limit[2]; /* angular momentum magnitude limits */
150 double ang_mom_z_limit[2]; /* angular momentum Z component absolute limits */
151 double orbit_consistency; /* orbit position/velocity consistency limit */
152 double angvel_abs_limit[2]; /* angular velocity absolute limits */
153 double angvel_del_limit; /* angular velocity delta limits */
154 double attit_consistency; /* angle/angular velocity consistency limit */
155 double attitude_abs_limit[2]; /* attitude angle absolute limits */
156 double attitude_del_limit; /* attitude angle delta limits */
157 
158 typedef struct {
159  /* number of validated ephemeris and attitude samples */
161  double max_extrap;
163  PGSt_tag spacecraftTag;
165 
166 static sc_evolution_t *sc_evolution = NULL;
167 
168 PGSt_double GEO_get_ancil_packet_time( PGSt_double in_time)
169 
170 /*****************************************************************************
171 !C
172 
173 !Description:
174  Determines the time of the last ancillary data packet in sc_evolution,
175  with a timestamp less than or equal to the specified time.
176 
177 !Input Parameters:
178  in_time Time value that controls the search.
179 
180 !Output Parameters: None
181 
182 Return Value:
183  -DBL_MAX If there are no ancillary data packets, or if the
184  requested time comes before the earliest one.
185  the requested time If there are some ancillary data packets.
186 
187 Externally Defined:
188  DBL_MAX "float.h"
189  sc_evolution GEO_ephem_attit.c
190 
191 Called by:
192  GEO_prepare_mirr_data
193 
194 Routines Called: None
195 
196 !Revision History:
197  Revision history is located at the beginning of this file.
198 
199 Requirements:
200 
201 !Team-unique Header:
202 
203  This software is developed by the MODIS Science Data Support
204  Team for the National Aeronautics and Space Administration,
205  Goddard Space Flight Center, under contract NAS5-32373.
206 
207 References and Credits: None
208 
209 Design Notes:
210  Assumes that sc_evolution contains records in ascending order by time.
211 
212 !END
213 *****************************************************************************/
214 
215 {
216  int samp;
217 
218  for (samp = sc_evolution->num_samples - 1 ; samp > -1 ; samp--) {
219  if (sc_evolution->sc_state[samp].time <= in_time)
220  break;
221  }
222 
223  if (samp < 0)
224  return -DBL_MAX;
225  else
226  return sc_evolution->sc_state[samp].time;
227 }
228 
229 /*============================================================================*/
230 
231 /* Value for SS_CP_MODE field in L1A file that indicates instrument is in
232  * safe mode. */
233 #define SAFE_MODE 2
234 
235 PGSt_SMF_status GEO_prepare_ancil_data(
236  int const number_of_scans,
237  const GEO_param_struct * params,
238  const sc_ancil_struct sc_ancillary_data[2],
239  const uint16 ss_cp_mode[]
240  )
241 /*
242 !C*****************************************************************************
243 !Description:
244  Routine in Input group of the Level-1A geolocation software to unpack,
245  convert and validate the spacecraft orbit and attitude data from the
246  ancillary packets.
247 
248 !Input Parameters:
249  number_of_scans the number of scans in the granule
250  params Geolocation paramters structure.
251  sc_ancillary_data Spacecraft ancillary data
252  ss_cp_mode Command processor mode
253 
254 !Output Parameters:
255  None
256 
257 Return Values:
258  MODIS_E_BAD_INPUT_ARG If any pointer argument is invalid.
259  MODIS_E_GEO_ANCIL_DATA If there are too few valid samples to permit
260  interpolation.
261  PGS_S_SUCCESS Otherwise.
262 
263 Externally Defined:
264  ATT_IDX "GEO_global_arrays.h"
265  EPH_IDX "GEO_global_arrays.h"
266  EPH_LONG_FOLLOW "GEO_global_arrays.h"
267  EPH_LONG_PRECEED "GEO_global_arrays.h"
268  EPH_SAFE_MODE "GEO_global_arrays.h"
269  EPH_SHORT_FOLLOW "GEO_global_arrays.h"
270  EPH_SHORT_PRECEED "GEO_global_arrays.h"
271  EPH_YELLOWHI "GEO_global_arrays.h"
272  EPH_YELLOWLO "GEO_global_arrays.h"
273  MAX_SCAN_NUMBER "GEO_geo.h"
274  MODIS_E_BAD_INPUT_ARG "PGS_MODIS_35251.h"
275  MODIS_E_GEO "PGS_MODIS_35251.h"
276  MIN_TIME_OFFSET "GEO_geo.h"
277  PGS_PI "GEO_geo.h"
278  PGS_S_SUCCESS "PGS_SMF.h"
279  PGSd_EOS_AM1 "PGS_TD.h"
280  PGSd_EOS_PM1 "PGS_TD.h"
281  PGSd_NO_DATA "PGS_EPH.h"
282  PGSd_PLATFORM_FATAL "PGS_EPH.h"
283  QFL_IDXS "GEO_global_arrays.h"
284  SC_CURRENT "GEO_input.h"
285  SC_PRIOR "GEO_input.h"
286  SS_CP_MODE "L1a_data.h"
287  TAI_FLAG "GEO_geo.h"
288 
289 Called by:
290  GEO_prepare_l1a_data()
291 
292 Routines called:
293  PGS_TD_EOSAMtoTAI Converts AM timestamps to TAI
294  modsmf writes error status messages to log
295 
296 
297 !Revision History:
298  See top of file for revision history after merge into GEO_ephem_attit.c
299 
300 Requirements:
301  PR03-F-2.2-1
302  PR03-F-2.2-2
303  PR03-F-3.2.1-3
304  PR03-I-1
305  PR03-I-2
306 
307 !Team-unique Header:
308  This software is developed by the MODIS Science Data Support
309  Team for the National Aeronautics and Space Administration,
310  Goddard Space Flight Center, under contract NAS5-32373.
311 
312 !END*************************************************************************
313 */
314 {
315 
316  /* Factor for conversion of arcseconds to radians */
317  static double const arcsec_to_rad = PGS_PI/(180.0*3600.0);
318  /* spacecraft attitude rate */
319  int scan = 0; /* scan loop index */
320  int pack = 0; /* prior/current index */
321  int cmb = 0; /* combined scan& prior/current index. */
322  int samp = 0; /* index in selected packets */
323  int eci = 0; /* dimension loop index */
324 
325  /* ancillary packet quality*/
326  int last_qcount = INT_MAX; /* Last value for qcount[cmb] */
327  double delta; /* Time difference between packets. */
328  int last_att;
329  static char filefunc[] = __FILE__ ", GEO_prepare_ancil_data";
330  char msgbuf[128];
331 
332  typedef double double3_t[3];
333  static double3_t *sc_position; /* spacecraft position */
334  static double3_t *sc_velocity; /* spacecraft velocity */
335  static double3_t *sc_attit; /* spacecraft attitude */
336  static double3_t *sc_xyzRotRates;
337 
338  typedef uint32 ancil_flags_t[MAX_SCAN_NUMBER*2];
339  static ancil_flags_t *ancil_flags;
340  static int *qcount; /* Overall packet quality */
341 
342  static int firstRun = 1;
343  if(firstRun) {
344  firstRun = 0;
345 
346  sc_position = (double3_t*) calloc(MAX_SCAN_NUMBER*2, sizeof(double3_t)); /* spacecraft position */
347  sc_velocity = (double3_t*) calloc(MAX_SCAN_NUMBER*2, sizeof(double3_t)); /* spacecraft velocity */
348  sc_attit = (double3_t*) calloc(MAX_SCAN_NUMBER*2, sizeof(double3_t)); /* spacecraft attitude */
349  sc_xyzRotRates = (double3_t*) calloc(MAX_SCAN_NUMBER*2, sizeof(double3_t));
350 
351  ancil_flags = (ancil_flags_t*) calloc(QFL_IDXS, sizeof(ancil_flags_t));
352  qcount = (int*) calloc(MAX_SCAN_NUMBER*2, sizeof(int)); /* Overall packet quality */
353 
354  }
355  bzero(ancil_flags, QFL_IDXS * sizeof(ancil_flags_t));
356  bzero(qcount, MAX_SCAN_NUMBER*2 * sizeof(int)); /* Overall packet quality */
357 
358  if(number_of_scans<0 || number_of_scans>MAX_SCAN_NUMBER || params==NULL ||
359  sc_ancillary_data==NULL || ss_cp_mode==NULL)
360  {
361  sprintf(msgbuf, "number_of_scans:%d, params:%p, ancil_scale_factors:%p "
362  "ss_cp_mode:%p", number_of_scans, (void*)params,
363  (void*)sc_ancillary_data, (void*)ss_cp_mode);
364  modsmf(MODIS_E_BAD_INPUT_ARG, msgbuf, filefunc);
365  return MODIS_E_BAD_INPUT_ARG;
366  }
367 
368  if(number_of_scans==0)
369  return PGS_S_SUCCESS;
370 
371  if(!sc_evolution) {
372  sc_evolution = calloc(1, sizeof(sc_evolution_t));
373  } else {
374  memset(sc_evolution, 0, sizeof(sc_evolution_t));
375  }
376 
377  if (strcmp(params->spacecraft_ID, "Aqua") == 0) {
378  sc_evolution->spacecraftTag = PGSd_EOS_PM;
379  return PGS_S_SUCCESS; /* There is no valid ancillary data available.*/
380  }
381  else
382  { /* Assume that the spacecraft_ID is "Terra"; it's been validated *
383  * elsewhere, there's no need for a redundant validity check. */
384  sc_evolution->spacecraftTag = PGSd_EOS_AM;
385  }
386 
387  /* First extract data from ancillary data message */
388  /* Loop through scans */
389  for (scan = 0; scan < number_of_scans; scan++)
390  {
391  /* Loop for previous and current data */
392  for (pack=SC_PRIOR; pack<=SC_CURRENT; pack++)
393  {
394  double ang_mom[3]; /* Angular momentum pseudo-vector. */
395  double pos2_sum=0.0, vel2_sum=0.0, ang_mom2_sum=0.0; /* Cumulators */
396  double pos_mag, vel_mag, ang_mag; /* vector magnitudes */
397 
398  cmb = 2*scan+pack;
399 
400  for(eci = 0; eci < 3; eci++)
401  {
402  /* Validity tests on pre-scaled data */
403  if(sc_ancillary_data[pack].attit_angvel[scan][eci] <
404  params->attit_valid_params.att_valid_range[0] ||
405  params->attit_valid_params.att_valid_range[1] <
406  sc_ancillary_data[pack].attit_angvel[scan][eci])
407  {
408  ancil_flags[ATT_IDX][cmb] |= PGSd_NO_DATA;
409  qcount[cmb] += 3;
410  }
411 
412  /* Apply scale factors. */
413  sc_position[cmb][eci] =
414  (double)sc_ancillary_data[pack].posvel[scan][eci]
415  * params->ancil_params.ancil_scale_factors.S_position;
416  sc_velocity[cmb][eci] =
417  (double)sc_ancillary_data[pack].posvel[scan][eci+3]
418  * params->ancil_params.ancil_scale_factors.S_velocity;
419  sc_attit[cmb][eci] =
420  (double)sc_ancillary_data[pack].attit_angvel[scan][eci]
421  * params->ancil_params.ancil_scale_factors.S_attitude;
422  sc_xyzRotRates[cmb][eci] =
423  (double)sc_ancillary_data[pack].attit_angvel[scan][eci+3]
424  * params->ancil_params.ancil_scale_factors.S_angvel;
425 
426  pos2_sum += sc_position[cmb][eci]* sc_position[cmb][eci];
427  vel2_sum += sc_velocity[cmb][eci]* sc_velocity[cmb][eci];
428 
429  /* Per-component single-packet validity tests. */
430  if(sc_position[cmb][eci] <
431  params->orbit_valid_params.position_abs_limit[0])
432  {
433  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWLO;
434  qcount[cmb] += 3;
435  }
436  else if( params->orbit_valid_params.position_abs_limit[1] <
437  sc_position[cmb][eci])
438  {
439  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWHI;
440  qcount[cmb] += 3;
441  }
442 
443  if(sc_velocity[cmb][eci] <
444  params->orbit_valid_params.velocity_abs_limit[0])
445  {
446  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWLO;
447  qcount[cmb] += 3;
448  }
449  else if( params->orbit_valid_params.velocity_abs_limit[1] <
450  sc_velocity[cmb][eci])
451  {
452  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWHI;
453  qcount[cmb] += 3;
454  }
455 
456  if(sc_attit[cmb][eci] <
457  params->attit_valid_params.attitude_abs_limit[0])
458  {
459  ancil_flags[ATT_IDX][cmb] |= EPH_YELLOWLO;
460  qcount[cmb] += 3;
461  }
462  else if( params->attit_valid_params.attitude_abs_limit[1] <
463  sc_attit[cmb][eci])
464  {
465  ancil_flags[ATT_IDX][cmb] |= EPH_YELLOWHI;
466  qcount[cmb] += 3;
467  }
468 
469  if(sc_xyzRotRates[cmb][eci] <
470  params->attit_valid_params.angvel_abs_limit[0])
471  {
472  ancil_flags[ATT_IDX][cmb] |= EPH_YELLOWLO;
473  qcount[cmb] += 3;
474  }
475  else if( params->attit_valid_params.angvel_abs_limit[1] <
476  sc_xyzRotRates[cmb][eci])
477  {
478  ancil_flags[ATT_IDX][cmb] |= EPH_YELLOWHI;
479  qcount[cmb] += 3;
480  }
481 
482  }
483  /* Calculate ang_mom as a cross product. */
484  GEO_vec_mul3(sc_position[cmb], sc_velocity[cmb], ang_mom);
485 
486  for(eci = 0; eci < 3; eci++)
487  ang_mom2_sum += ang_mom[eci]*ang_mom[eci];
488 
489  pos_mag = sqrt(pos2_sum);
490  vel_mag = sqrt(vel2_sum);
491  ang_mag = sqrt(ang_mom2_sum);
492 
493  /* Other single packet validity checks. */
494  if(pos_mag < params->orbit_valid_params.position_mag_limit[0])
495  {
496  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWLO;
497  qcount[cmb]++;
498  }
499  else if( params->orbit_valid_params.position_mag_limit[1] < pos_mag)
500  {
501  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWHI;
502  qcount[cmb]++;
503  }
504 
505  if(vel_mag < params->orbit_valid_params.velocity_mag_limit[0])
506  {
507  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWLO;
508  qcount[cmb]++;
509  }
510  else if( params->orbit_valid_params.velocity_mag_limit[1] < vel_mag)
511  {
512  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWHI;
513  qcount[cmb]++;
514  }
515 
516  if(ang_mag < params->orbit_valid_params.ang_mom_limit[0])
517  {
518  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWLO;
519  qcount[cmb]++;
520  }
521  else if( params->orbit_valid_params.ang_mom_limit[1] < ang_mag)
522  {
523  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWHI;
524  qcount[cmb]++;
525  }
526 
527  if(ang_mom[2] < params->orbit_valid_params.ang_mom_z_limit[0])
528  {
529  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWLO;
530  qcount[cmb]++;
531  }
532  else if( params->orbit_valid_params.ang_mom_z_limit[1] < ang_mom[2])
533  {
534  ancil_flags[EPH_IDX][cmb] |= EPH_YELLOWHI;
535  qcount[cmb]++;
536  }
537  }
538  }
539 
540  sc_evolution->max_extrap = params->max_extrap;
541 
542  for (scan = 0; scan < number_of_scans; scan++)
543  {
544  if(ss_cp_mode[scan] == SAFE_MODE)
545  continue; /* Safe mode packets should not be used. */
546 
547  /* Loop for previous and current data */
548  for (pack=SC_PRIOR; pack<=SC_CURRENT; pack++)
549  {
550 
551  PGSt_double time_stamp[MAX_SCAN_NUMBER*2]; /* spacecraft time stamp */
552  /* Secondary packet header for Terra */
553  PGSt_IO_L0_SecPktHdrEOS_AM AM_packet;
554  cmb = 2*scan+pack;
555 
556  /* Unpack time stamp */
557  memcpy(AM_packet.scTime, sc_ancillary_data[pack].second_header[scan],
558  sizeof(AM_packet.scTime));
559  /* This memcpy() is done solely to cover the remote possiblity that:
560  * the type of scTime is changed to be different from the type of
561  * second_header. memcpy() is used rather than a pointer cast, in case
562  * scTime is changed to a type with stricter alignment requirements than
563  * second_header; an even more unlikely possibilty, and one that is
564  * irrelevant so long as both fields are the first ones in their
565  * respective structures. With the current typedefs and structure
566  * definitions, both fields are arrays of unsigned char.
567  */
568 
569  /* Convert from spacecraft time to TAI */
570 
571  if (PGS_TD_EOSAMtoTAI(AM_packet.scTime, &time_stamp[cmb])
572  != PGS_S_SUCCESS)
573  {
574  /* call SDP function to report error */
575  sprintf(msgbuf, "PGS_TD_EOSAMtoTAI() for scan:%d pack:%d", scan, pack);
576  modsmf(MODIS_E_GEO, msgbuf, filefunc);
577 
578  continue; /* Skip packets with invalid time tags. */
579  }
580 
581  if(sc_evolution->num_samples > 0)
582  {
583  delta = time_stamp[cmb] -
584  sc_evolution->sc_state[sc_evolution->num_samples-1].time;
585  if(delta <= 0)
586  { /* Duplicate packet */
587  if(qcount[cmb] < last_qcount)
588  {
589  sc_evolution->num_samples--; /* Replace existing packet */
590  if(sc_evolution->num_samples > 0)
591  delta = time_stamp[cmb] -
592  sc_evolution->sc_state[sc_evolution->num_samples-1].time;
593  sc_evolution->sc_state[sc_evolution->num_samples].
594  qualityFlags[ATT_IDX] = 0;
595  sc_evolution->sc_state[sc_evolution->num_samples].
596  qualityFlags[EPH_IDX] = 0;
597  }
598  else
599  continue; /* Skip packet */
600  }
601 
602  if(params->max_non_gap < delta)
603  {
604  if(params->orbit_valid_params.eph_max_short_gap < delta)
605  {
606  sc_evolution->sc_state[sc_evolution->num_samples-1].
607  qualityFlags[EPH_IDX] |= EPH_LONG_FOLLOW;
608  sc_evolution->sc_state[sc_evolution->num_samples].
609  qualityFlags[EPH_IDX] |= EPH_LONG_PRECEED;
610  }
611  else{
612  sc_evolution->sc_state[sc_evolution->num_samples-1].
613  qualityFlags[EPH_IDX] |= EPH_SHORT_FOLLOW;
614  sc_evolution->sc_state[sc_evolution->num_samples].
615  qualityFlags[EPH_IDX] |= EPH_SHORT_PRECEED;
616  }
617 
618  if(params->attit_valid_params.att_max_short_gap < delta)
619  {
620  sc_evolution->sc_state[sc_evolution->num_samples-1].
621  qualityFlags[ATT_IDX] |= EPH_LONG_FOLLOW;
622  sc_evolution->sc_state[sc_evolution->num_samples].
623  qualityFlags[ATT_IDX] |= EPH_LONG_PRECEED;
624  }
625  else{
626  sc_evolution->sc_state[sc_evolution->num_samples-1].
627  qualityFlags[ATT_IDX] |= EPH_SHORT_FOLLOW;
628  sc_evolution->sc_state[sc_evolution->num_samples].
629  qualityFlags[ATT_IDX] |= EPH_SHORT_PRECEED;
630  }
631  }
632  }
633 
634  last_qcount = qcount[cmb];
635  sc_evolution->sc_state[sc_evolution->num_samples].qualityFlags[ATT_IDX]
636  |= ancil_flags[ATT_IDX][cmb];
637  sc_evolution->sc_state[sc_evolution->num_samples].qualityFlags[EPH_IDX]
638  |= ancil_flags[EPH_IDX][cmb];
639 
640  sc_evolution->sc_state[sc_evolution->num_samples].time = time_stamp[cmb];
641 
642  for (eci = 0; eci < 3; eci++)
643  {
644 
645  sc_evolution->sc_state[sc_evolution->num_samples].position[eci] =
646  sc_position[cmb][eci];
647  sc_evolution->sc_state[sc_evolution->num_samples].velocity[eci] =
648  sc_velocity[cmb][eci];
649 
650  /* Need to convert attitude from arcseconds to radians */
651  sc_evolution->sc_state[sc_evolution->num_samples].eulerAngles[eci] =
652  sc_attit[cmb][eci];
653  sc_evolution->sc_state[sc_evolution->num_samples].xyzRotRates[eci] =
654  sc_xyzRotRates[cmb][eci];
655  } /* End of vector loop */
656 
657  sc_evolution->num_samples++;
658  }
659  }
660 
661  /* Set unused time samples to flag values to be safe */
662  for (samp = sc_evolution->num_samples; samp < MAX_SCAN_NUMBER*2; samp++)
663  sc_evolution->sc_state[samp].time = TAI_FLAG;
664 
665  if (sc_evolution->num_samples < 2) {
666 
667  /* call SDP function to report error */
668  sprintf(msgbuf, "%d", sc_evolution->num_samples);
669  modsmf(MODIS_E_GEO_ANCIL_DATA, msgbuf, filefunc);
670  sc_evolution->num_samples = 0;
671  return MODIS_E_GEO_ANCIL_DATA;
672  }
673 
674  last_att = sc_evolution->sc_state[samp].qualityFlags[ATT_IDX] & PGSd_NO_DATA
675  ? -1 : 0;
676  for(samp=0; samp < sc_evolution->num_samples-1; samp++)
677  {
678  double del; /* Difference between interpolated and actual value.*/
679 
680  delta = sc_evolution->sc_state[samp+1].time -
681  sc_evolution->sc_state[samp].time;
682 
683  for(eci = 0; eci < 3; eci++)
684  {
685  del = fabs(sc_evolution->sc_state[samp+1].position[eci] -
686  sc_evolution->sc_state[samp ].position[eci] -
687  (sc_evolution->sc_state[samp+1].velocity[eci] +
688  sc_evolution->sc_state[samp ].velocity[eci]) * delta/2.0);
689  if(params->orbit_valid_params.orbit_consistency < del)
690  {
691  sc_evolution->sc_state[samp ].qualityFlags[EPH_IDX]
692  |= EPH_YELLOWHI;
693  sc_evolution->sc_state[samp+1].qualityFlags[EPH_IDX]
694  |= EPH_YELLOWHI;
695  }
696 
697  }
698 
699  if((sc_evolution->sc_state[samp+1].qualityFlags[ATT_IDX] & PGSd_NO_DATA)
700  == 0)
701  {
702  if(last_att > -1)
703  {
704  delta = sc_evolution->sc_state[samp+1].time -
705  sc_evolution->sc_state[last_att].time;
706  for(eci = 0; eci < 3; eci++)
707  {
708  double del_att =
709  fabs(sc_evolution->sc_state[samp+1 ].eulerAngles[eci] -
710  sc_evolution->sc_state[last_att].eulerAngles[eci]);
711  double del_angv =
712  fabs(sc_evolution->sc_state[samp+1 ].xyzRotRates[eci] -
713  sc_evolution->sc_state[last_att].xyzRotRates[eci]);
714  del = fabs(sc_evolution->sc_state[samp + 1].position[eci] -
715  sc_evolution->sc_state[last_att].position[eci] -
716  (sc_evolution->sc_state[samp + 1].velocity[eci] +
717  sc_evolution->sc_state[last_att].velocity[eci])
718  * delta/2.0);
719  if(del_att >
720  params->attit_valid_params.attitude_del_limit * delta ||
721  del_angv >
722  params->attit_valid_params.angvel_del_limit * delta ||
723  del >
724  params->attit_valid_params.attit_consistency * delta)
725  {
726  sc_evolution->sc_state[last_att].qualityFlags[ATT_IDX]
727  |= EPH_YELLOWHI;
728  sc_evolution->sc_state[samp + 1].qualityFlags[ATT_IDX]
729  |= EPH_YELLOWHI;
730  }
731  }
732  }
733  }
734  }
735 
736  /* The validity criteria are in arcseconds, so this conversion had to be
737  * delayed */
738  for(samp=0; samp < sc_evolution->num_samples; samp++)
739  for(eci = 0; eci < 3; eci++)
740  sc_evolution->sc_state[samp].eulerAngles[eci] *= arcsec_to_rad;
741 
742  return PGS_S_SUCCESS;
743 }
744 
745 /*============================================================================*/
746 
748  PGSt_integer numValues,
749  char asciiUTC[],
750  PGSt_double target_time,
751  const PGSt_double offsets[],
752  GEO_param_struct const *params,
753  sc_state_struct sc_state[],
754  uint32 sample_quality[][QFL_IDXS],
755  PGSt_scTagInfo *scTagInfo
756 )
757 /*******************************************************************************
758 !C
759 
760 !Description:
761  Routine in Earth Location group of the Level-1A geolocation software
762  to interpolate the ephemeris and attitude to the sample time. Spacecraft
763  kinematic state data is retrieved from either the spacecraft ancillary
764  data message in the L1A or through the SDP toolkit Spacecraft and
765  Attitude Data Access Tools. Data from the spacecraft (SC) ancillary data
766  message are interpolated using a cubic polynomial based on successive
767  values and their first derivatives described on pp. 3-1 - 3-3 in the
768  "Theoretical Basis of the SDP Toolkit Geolocation Package for the ECS
769  Project" (445-TP-002-002). It first checks whether the requested time
770  is within the range of coefficients previously computed. If not, it
771  finds the bracketing ephemeris and attitude samples and recomputes the
772  interpolation coefficients. Finally it interpolates the orbit position,
773  orbit velocity attitude angles and body rates to the sample time.
774 
775 !Input Parameters:
776  numValues The number of values requested
777  asciiUTC UTC reference start time
778  target_time TAI reference start time, should match asciiUTC
779  offsets An array of offsets, in seconds, from asciiUTC
780  params Geolocation parameters structure.
781 
782 !Output Parameters:
783  sc_state SC kinematic state records to be filled in for
784  the specified times
785  sample_quality Ephemeris/attitude quality flags for each sample
786 
787 Return Values:
788  MODIS_E_GEO If any subroutine fails.
789  MODIS_E_BAD_INPUT_ARG If sc_state is a null pointer or
790  numValues is too large.
791  MODIS_E_INSUFFICIENT_PKTS If there's too few ancillary pacekts.
792  MODIS_E_UNKNOWN_PARAMETER If EA source has an invalid value.
793  PGS_S_SUCCESS Otherwise
794 
795 Externally Defined:
796  CUBIC "GEO_util.h
797  EA_SOURCE "GEO_product.h"
798  EA_SOURCE_SELECT_LUN "GEO_geo.h"
799  L1A_PKT_EA "GEO_product.h"
800  MODIS_E_GEO "PGS_MODIS_35251.h"
801  MODIS_E_BAD_INPUT_ARG "PGS_MODIS_35251.h"
802  MODIS_E_INSUFFICIENT_PKTS "PGS_MODIS_35251.h"
803  MODIS_E_SAMP_TIME_OOR "PGS_MODIS_35251.h"
804  MODIS_E_UNKNOWN_PARAMETER "PGS_MODIS_35251.h"
805  MODIS_N_GEO_EXCESS_FILES "PGS_MODIS_35251.h"
806  MAX_PADDED "GEO_geo.h"
807  PGS_S_SUCCESS "PGS_SMF.h"
808  PGSd_NO_DATA "PGS_EPH.h"
809  PGSd_PC_LINE_LENGTH_MAX "PGS_PC.h"
810  PGSd_GEO_ERROR_VALUE "PGS_TD.h"
811  PGSEPH_W_BAD_EPHEM_VALUE "PGS_EPH_5.h"
812  PGSEPH_E_NO_SC_EPHEM_FILE "PGS_EPH_5.h"
813  sc_evolution GEO_ephem_attit.c
814  SUCCESS "GEO_basic.h"
815  TOOLKIT_EA "GEO_product.h"
816 
817 Routines Called:
818  GEO_check_ea_headers "GEO_earth.h"
819  GEO_poly_coef1 "GEO_util.h"
820  GEO_poly_fit "GEO_util.h"
821  modsmf "smfio.h"
822  PGS_EPH_EphemAttit "PGS_EPH.h"
823  PGS_PC_GetConfigData "PGS_PC.h"
824 
825 Called by:
826  GEO_interp_ECR()
827 
828 !Revision History:
829  See top of file for revision history after merge into GEO_ephem_attit.c
830 
831 !Team-unique Header:
832 
833  This software is developed by the MODIS Science Data Support
834  Team for the National Aeronautics and Space Administration,
835  Goddard Space Flight Center, under contract NAS5-32373.
836 
837 Requirements:
838  PR03-F-3.2.1-1
839  PR03-F-3.2.1-2
840  PR03-F-3.2.1-3
841  PR03-I-1
842  PR03-I-2
843  PR03-S-1
844 
845 Design Notes:
846  Assumes sc_evolution global structure contains temporally monitonically
847  increasing data.
848  Assumes the L1A file does not temporally overlap.
849 
850 !END
851 ******************************************************************************/
852 {
853  static sc_state_struct const empty_sc={0.0};
854  double t_norm = 0.0; /* normalized sample time */
855  static double position_coef[3][CUBIC]={0.0};
856  static int eph = -1;
857  static int attlo, atthi;
858  static char ea_source[PGSd_PC_LINE_LENGTH_MAX]="";
859  PGSt_SMF_status PGS_error_code = PGS_S_SUCCESS;
860  PGSt_SMF_status retval = PGS_S_SUCCESS;
861  PGSt_integer qualityFlags[MAX_PADDED][2] = {0};
862  PGSt_double positionECI[MAX_PADDED][3], eulerAngles[MAX_PADDED][3],
863  velocityECI[MAX_PADDED][3], xyzRotRates[MAX_PADDED][3];
864  PGSt_double attitQuat[MAX_PADDED][4];
865  int samp = 0; /* iteration parameter */
866  char msgbuf[PGS_SMF_MAX_MSGBUF_SIZE] = "";
867  static char filefunc[] = __FILE__ ", GEO_interp_ephemeris_attitude";
868 
869  static const unsigned EPH_CRITERIA=(PGSd_NO_DATA|PGSd_PLATFORM_FATAL);
870 
871  /* Check output structure available */
872  if (sc_state == NULL || offsets == NULL || params==NULL ||
873  sample_quality == NULL || scTagInfo == NULL)
874  {
875  sprintf(msgbuf, "sc_state = %p, offsets = %p, params=%p, \n"
876  "sample_quality=%p, scTagInfo = %p",
877  (void *)sc_state, (void *)offsets, (void*)params,
878  (void*)sample_quality, (void*)scTagInfo);
879  modsmf(MODIS_E_BAD_INPUT_ARG, msgbuf, filefunc);
880  return MODIS_E_BAD_INPUT_ARG;
881  }
882 
883  *sc_state = empty_sc;
884 
885  /* Check if EA_SOURCE has already been read in to static memory */
886  if (ea_source[0]=='\0') { /* Select source of SC kinematic data */
887  PGS_error_code=PGS_PC_GetConfigData(EA_SOURCE_SELECT_LUN, ea_source);
888  if (PGS_error_code!=PGS_S_SUCCESS) {
889  sprintf(msgbuf,"PGS_PC_GetConfigData(%ld)",(long)EA_SOURCE_SELECT_LUN);
890  modsmf(MODIS_E_GEO, msgbuf, filefunc);
891  return MODIS_E_GEO;
892  }
893  }
894 
895  if(scTagInfo->eulerAngleOrder[0] < 0)
896  { /* scTagInfo has not yet been filled in. */
897  if (PGS_EPH_GetSpacecraftData(sc_evolution->spacecraftTag, "",
898  PGSe_TAG_SEARCH, scTagInfo) != PGS_S_SUCCESS)
899  {
900  modsmf(MODIS_E_GEO, "PGS_EPH_GetSpacecraftData()", filefunc);
901  return MODIS_E_GEO;
902  }
903  }
904 
905  if (strcmp(ea_source, TOOLKIT_EA)==0)
906  { /* Use SDP toolkit to retrieve SC state */
907  PGS_error_code = GEO_check_ea_headers(target_time, scTagInfo);
908  if (PGS_error_code != PGS_S_SUCCESS &&
909  PGS_error_code != MODIS_N_GEO_EXCESS_FILES) {
910  sprintf(msgbuf, "GEO_check_ea_headers(%s)", asciiUTC);
911  modsmf(MODIS_E_GEO, msgbuf, filefunc);
912  retval = MODIS_E_GEO;
913  }
914 
915  if (numValues > MAX_PADDED)
916  {
917  sprintf(msgbuf, "numValues: %ld", (long)numValues);
918  modsmf(MODIS_E_BAD_INPUT_ARG, msgbuf, filefunc);
919  return MODIS_E_BAD_INPUT_ARG;
920  }
921 
922  if (numValues == 0)
923  return PGS_S_SUCCESS;
924 
925  PGS_error_code = PGS_EPH_EphemAttit(sc_evolution->spacecraftTag,
926  (PGSt_integer)numValues, asciiUTC, (PGSt_double*)offsets, PGS_TRUE,
927  PGS_TRUE, qualityFlags, positionECI, velocityECI, eulerAngles,
928  xyzRotRates, attitQuat);
929 
930  if (PGS_error_code != PGS_S_SUCCESS &&
931  PGS_error_code != PGSEPH_W_BAD_EPHEM_VALUE)
932  {
933  if (PGS_error_code != PGSEPH_E_NO_SC_EPHEM_FILE)
934  { /* Because GEO_check_ea_headers() succeeded, a value of
935  * PGSEPH_E_NO_SC_EPHEM_FILE woud merely indicate a data gap in
936  * the files, not an actual operator error of failing to stage the
937  * right files. However, all other error codes are serious:
938  */
939  sprintf(msgbuf, "PGS_EPH_EphemAttit(%s)", asciiUTC);
940  modsmf(MODIS_E_GEO, msgbuf, filefunc);
941  retval = MODIS_E_GEO;
942  }
943  /* Since the output values from PGS_EPH_EphemAttit are meaningless
944  * there's no point in copying them over - except for the error code
945  * that is used later on to determine whether or not the data is
946  * useful. Resolves bug 5334.
947  */
948  for (samp = 0; samp < numValues; samp++)
949  sc_state[samp].position[0] = PGSd_GEO_ERROR_VALUE;
950  }
951  else
952  { /* Successful retrieval of SC state. Copy to output records */
953  for (samp = 0; samp < numValues; samp++)
954  {
955  int i = 0;
956 
957  sc_state[samp].time = target_time + offsets[samp];
958  for (i = 0; i < 3; i++)
959  {
960  sc_state[samp].position[i] = positionECI[samp][i];
961  sc_state[samp].velocity[i] = velocityECI[samp][i];
962  }
963  sc_state[samp].eulerAngles[0] = eulerAngles[samp][1];
964  sc_state[samp].eulerAngles[1] = eulerAngles[samp][2];
965  sc_state[samp].eulerAngles[2] = eulerAngles[samp][0];
966  if ( ((unsigned)qualityFlags[samp][ATT_IDX] |
967  (unsigned)qualityFlags[samp][EPH_IDX]) & EPH_CRITERIA )
968  sc_state[samp].position[0] = PGSd_GEO_ERROR_VALUE;
969  sample_quality[samp][ATT_IDX] =
970  (uint32)qualityFlags[samp][ATT_IDX];
971  sample_quality[samp][EPH_IDX] =
972  (uint32)qualityFlags[samp][EPH_IDX];
973  }
974  }
975  }
976  else if (strcmp(ea_source, L1A_PKT_EA) == 0)
977  {
978  /* Interpolate spacecraft state from data in L1A ancillary data packets.
979  This is essentially the algorithm from the beta version */
980  if (sc_evolution->num_samples < 2)
981  {
982  modsmf(MODIS_E_INSUFFICIENT_PKTS, "", filefunc);
983  retval = MODIS_E_INSUFFICIENT_PKTS;
984  }
985  else
986  {
987  memset(sample_quality, 0, numValues * sizeof *sample_quality);
988  for (samp = 0; samp < numValues; samp++)
989  {
990  int eci; /* ECI coordinates loop counter */
991  sc_state[samp].time = target_time + offsets[samp];
992  sc_state[samp].position[0] = 0.0;
993 
994  /* Check if sample time is outside the period bracketed by the
995  * spacecraft state records used for the previous sample. */
996 
997  if (eph < 0 || eph >= sc_evolution->num_samples-2
998  || sc_state[samp].time < sc_evolution->sc_state[eph].time
999  || sc_state[samp].time >= sc_evolution->sc_state[eph+1].time)
1000  { /* New polynomial parameters for the interpolation
1001  must be calculated if in range of available data. */
1002  if (sc_state[samp].time >= sc_evolution->sc_state[0].time &&
1003  sc_state[samp].time <
1004  sc_evolution->sc_state[sc_evolution->num_samples-1].time)
1005  {
1006  /* Find spacecraft records bracketing the sample time */
1007  for(eph = 0; sc_state[samp].time >=
1008  sc_evolution->sc_state[eph+1].time; eph++);
1009  }
1010  else if (fabs(sc_evolution->sc_state[0].time -
1011  sc_state[samp].time) <= params->max_extrap)
1012  eph = 0;
1013  else if (fabs(sc_state[samp].time - sc_evolution->sc_state
1014  [sc_evolution->num_samples - 1].time) <
1015  params->max_extrap)
1016  eph = sc_evolution->num_samples - 2;
1017  else
1018  {
1019  sprintf(msgbuf, "%.6f for samp = %d is more than %.3f "
1020  "seconds outside the range from %.6f to %.6f\n",
1021  sc_state[samp].time, samp, params->max_extrap,
1022  sc_evolution->sc_state[0].time,
1023  sc_evolution->sc_state
1024  [sc_evolution->num_samples-1].time);
1025  modsmf(MODIS_W_SAMP_TIME_OOR, msgbuf, filefunc);
1026  sc_state[samp].position[0] = PGSd_GEO_ERROR_VALUE;
1027  sample_quality[samp][EPH_IDX] |= PGSd_NO_DATA; /* ?? */
1028  eph = -1;
1029  continue;
1030  }
1031  /* get coefficients for the cubic polynomial to interpolate
1032  * the spacecraft's position */
1033  for (eci = 0; retval==SUCCESS && eci < 3; ++eci)
1034  retval = GEO_poly_coef1(
1035  sc_evolution->sc_state[eph ].position[eci],
1036  sc_evolution->sc_state[eph+1].position[eci],
1037  sc_evolution->sc_state[eph ].velocity[eci],
1038  sc_evolution->sc_state[eph+1].velocity[eci],
1039  sc_evolution->sc_state[eph ].time,
1040  sc_evolution->sc_state[eph+1].time,
1041  position_coef[eci]);
1042  } /* end if sample time is outside the period */
1043 
1044  if (sc_state[samp].position[0] < PGSd_GEO_ERROR_VALUE)
1045  { /* normalize target sample time to a fraction of the
1046  * period between SC state records */
1047  int efat; /* Ephemeris/attitude loop counter. */
1048 
1049  t_norm = (sc_state[samp].time -
1050  sc_evolution->sc_state[eph].time) /
1051  (sc_evolution->sc_state[eph+1].time -
1052  sc_evolution->sc_state[eph ].time);
1053  for (eci = 0; retval==SUCCESS && eci < 3; eci++)
1054  {
1055  retval = GEO_poly_fit(position_coef[eci], t_norm, CUBIC-1,
1056  &sc_state[samp].position[eci]);
1057  sc_state[samp].velocity[eci] = (position_coef[eci][1] +
1058  2*position_coef[eci][2]*t_norm +
1059  3*position_coef[eci][3]*t_norm*t_norm) /
1060  (sc_evolution->sc_state[eph+1].time -
1061  sc_evolution->sc_state[eph ].time) ;
1062  }
1063 
1064  if (eci != 3)
1065  {
1066  modsmf(MODIS_E_GEO, "GEO_poly_fit()", filefunc);
1067  retval = MODIS_E_GEO;
1068  sc_state[samp].position[0] = PGSd_GEO_ERROR_VALUE;
1069  }
1070 
1071  if(sc_state[samp].time <= sc_evolution->sc_state[eph].time)
1072  sample_quality[samp][EPH_IDX] =
1073  sc_evolution->sc_state[eph ].qualityFlags[EPH_IDX];
1074  else if(sc_evolution->sc_state[eph+1].time
1075  <= sc_state[samp].time)
1076  sample_quality[samp][EPH_IDX] =
1077  sc_evolution->sc_state[eph+1].qualityFlags[EPH_IDX];
1078  else
1079  {
1080  sample_quality[samp][EPH_IDX] =
1081  sc_evolution->sc_state[eph ].qualityFlags[EPH_IDX]|
1082  sc_evolution->sc_state[eph+1].qualityFlags[EPH_IDX];
1083  if(sc_evolution->sc_state[eph].time +
1084  params->max_non_gap <
1085  sc_evolution->sc_state[eph+1].time)
1086  sample_quality[samp][EPH_IDX] |= EPH_REPAIRED;
1087  }
1088 
1089  /* Interpolate attitude data */
1090  /* Find previous bracketing good attitude samples. */
1091  for(attlo = eph; attlo > -1 &&
1092  sc_evolution->sc_state[attlo].qualityFlags[ATT_IDX] &
1093  PGSd_NO_DATA; attlo--);
1094  for(atthi = eph + 1; atthi < sc_evolution->num_samples &&
1095  sc_evolution->sc_state[atthi].qualityFlags[ATT_IDX] &
1096  PGSd_NO_DATA; atthi++);
1097  if(attlo < 0 || attlo >= sc_evolution->num_samples)
1098  {
1099  sample_quality[samp][ATT_IDX] |= PGSd_NO_DATA;
1100  sc_state[samp].position[0] = PGSd_GEO_ERROR_VALUE;
1101  }
1102  else
1103  {
1104  if(attlo + 1 < atthi)
1105  { /* t_norm needs to be recalculated. */
1106  t_norm = (sc_state[samp].time -
1107  sc_evolution->sc_state[attlo].time) /
1108  (sc_evolution->sc_state[atthi].time -
1109  sc_evolution->sc_state[attlo].time);
1110  }
1111 
1112  /* Set quality flags. */
1113  if(sc_state[samp].time <=
1114  sc_evolution->sc_state[attlo].time)
1115  sample_quality[samp][ATT_IDX] = sc_evolution->
1116  sc_state[attlo].qualityFlags[ATT_IDX];
1117  else if(sc_state[samp].time >=
1118  sc_evolution->sc_state[atthi].time)
1119  sample_quality[samp][ATT_IDX] = sc_evolution->
1120  sc_state[atthi].qualityFlags[ATT_IDX];
1121  else
1122  {
1123  sample_quality[samp][ATT_IDX] = sc_evolution->
1124  sc_state[attlo].qualityFlags[ATT_IDX] |
1125  sc_evolution->sc_state[atthi].
1126  qualityFlags[ATT_IDX] | PGSd_INTERPOLATED_POINT;
1127  if(sc_evolution->sc_state[attlo].time +
1128  params->max_non_gap <
1129  sc_evolution->sc_state[atthi].time)
1130  sample_quality[samp][ATT_IDX] |= EPH_REPAIRED;
1131  }
1132 
1133  for (eci = 0; retval==SUCCESS && eci < 3; eci++)
1134  {
1135  sc_state[samp].eulerAngles[eci] =
1136  sc_evolution->sc_state[attlo].eulerAngles[eci] *
1137  (1-t_norm) +
1138  sc_evolution->sc_state[atthi].eulerAngles[eci] *
1139  t_norm;
1140  }
1141  }
1142 
1143  /* Adjustments to make flag values internally consistent. */
1144  for(efat = 0; efat < QFL_IDXS; efat++)
1145  {
1146  if(sample_quality[samp][efat] &&
1147  sample_quality[samp][efat] != PGSd_NO_DATA)
1148  {
1149  if(sample_quality[samp][efat] & PGSd_NO_DATA-1)
1150  sample_quality[samp][efat] |= EPH_DATA;
1151  sample_quality[samp][efat] |= EPH_OVERALL;
1152  }
1153  }
1154  }
1155  } /* end for samp = 0 to numValues - 1 */
1156  } /* end else */
1157  }
1158  else
1159  { /* ea_source is neither TOOLKIT_EA nor L1A_PKT_EA */
1160  modsmf(MODIS_E_UNKNOWN_PARAMETER, ea_source, filefunc);
1161  retval = MODIS_E_UNKNOWN_PARAMETER;
1162  }
1163 
1164  return retval;
1165 }
#define EPH_OVERALL
Definition: GEO_product.h:197
double orbit_consistency
#define EPH_YELLOWHI
Definition: GEO_product.h:201
#define MODIS_W_SAMP_TIME_OOR
double position_mag_limit[2]
#define SUCCESS
Definition: ObpgReadGrid.h:15
PGSt_SMF_status GEO_prepare_ancil_data(int const number_of_scans, const GEO_param_struct *params, const sc_ancil_struct sc_ancillary_data[2], const uint16 ss_cp_mode[])
#define SAFE_MODE
#define MODIS_E_GEO_ANCIL_DATA
#define MODIS_N_GEO_EXCESS_FILES
#define CUBIC
Definition: GEO_util.h:71
@ SC_CURRENT
Definition: GEO_input.h:94
PGSt_double position[3]
double velocity_abs_limit[2]
#define TAI_FLAG
Definition: GEO_geo.h:124
#define MODIS_E_INSUFFICIENT_PKTS
uint8 second_header[MAX_SCAN_NUMBER][sizeof(((PGSt_IO_L0_SecPktHdrEOS_AM *) NULL) ->scTime)]
Definition: GEO_input.h:98
#define NULL
Definition: decode_rs.h:63
#define MODIS_E_BAD_INPUT_ARG
MOD_PR01 Production producing one five minute granule of output data in each run It can be configured to produce as many as three five minute granules per run Each execution with one construction record and one date file for each dataset In normal these are created by which splits them out of the hour datasets For LANCE they are created by which merges all session MODIS L0 datasets overlapping the requested time and extracts from the merged data those packets which fall within that time period Each scan of data is stored in the L1A granule that covers the start time of that scan
Definition: MOD_PR01_pr.txt:19
#define PGS_PI
Definition: GEO_geo.h:172
uint32 qualityFlags[QFL_IDXS]
#define EPH_LONG_FOLLOW
Definition: GEO_product.h:203
sc_state_struct sc_state[MAX_SCAN_NUMBER *2]
#define MAX_PADDED
Definition: GEO_geo.h:84
double ang_mom_limit[2]
#define MODIS_E_UNKNOWN_PARAMETER
double position_abs_limit[2]
void bzero()
#define MODIS_E_GEO
#define L1A_PKT_EA
Definition: GEO_product.h:282
PGSt_tag spacecraftTag
double attitude_del_limit
double ang_mom_z_limit[2]
PGSt_double xyzRotRates[3]
int16 attit_angvel[MAX_SCAN_NUMBER][6]
Definition: GEO_input.h:100
@ SC_PRIOR
Definition: GEO_input.h:94
#define EA_SOURCE_SELECT_LUN
Definition: GEO_geo.h:93
double velocity_mag_limit[2]
double attitude_abs_limit[2]
#define EPH_DATA
Definition: GEO_product.h:198
const double delta
#define EPH_SHORT_FOLLOW
Definition: GEO_product.h:204
int32 posvel[MAX_SCAN_NUMBER][6]
Definition: GEO_input.h:99
integer, parameter double
int GEO_vec_mul3(double vec1[3], double vec2[3], double vec[3])
Definition: GEO_vec_mul3.c:6
PGSt_SMF_status GEO_check_ea_headers(PGSt_double in_time, PGSt_scTagInfo *scTagInfo)
double angvel_abs_limit[2]
PGSt_double velocity[3]
PGSt_double eulerAngles[3]
#define EPH_SHORT_PRECEED
Definition: GEO_product.h:205
#define EPH_REPAIRED
Definition: GEO_product.h:207
#define TOOLKIT_EA
Definition: GEO_product.h:281
int GEO_poly_fit(double const *coef, double const in_x, int const degree, double *const out_fit)
Definition: GEO_poly_fit.c:8
const int MAX_SCAN_NUMBER
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
@ ATT_IDX
@ QFL_IDXS
double angvel_del_limit
@ EPH_IDX
PGSt_double GEO_get_ancil_packet_time(PGSt_double in_time)
#define EPH_LONG_PRECEED
Definition: GEO_product.h:206
#define DBL_MAX
Definition: make_L3_v1.1.c:60
#define EPH_YELLOWLO
Definition: GEO_product.h:200
double attit_consistency
int i
Definition: decode_rs.h:71
int GEO_poly_coef1(double const var_val1, double const var_val2, double const derivative1, double const derivative2, double const t1, double const t2, double fit_coef[CUBIC])
Definition: GEO_poly_coef1.c:4
PGSt_SMF_status GEO_interp_ephemeris_attitude(PGSt_integer numValues, char asciiUTC[], PGSt_double target_time, const PGSt_double offsets[], GEO_param_struct const *params, sc_state_struct sc_state[], uint32 sample_quality[][QFL_IDXS], PGSt_scTagInfo *scTagInfo)