OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
GEO_solar_and_lunar_vectors.c
Go to the documentation of this file.
1 #include "PGS_CSC.h"
2 #include "PGS_TD.h"
3 #include "PGS_MODIS_35251.h"
4 #include "GEO_earth.h"
5 #include "GEO_output.h"
6 #include "GEO_inst.h"
7 #include "GEO_util.h"
8 #include "GEO_validation.h"
9 #include "smfio.h"
10 
12  PGSt_double const frame_time[],
13  frame_data_struct const * const frame_data,
14  GEO_param_struct const * const geo_params,
15  fill_values_struct const * const fill_values,
16  celestial_bodies_struct * const cb_vectors)
17 /******************************************************************************
18 !C
19 
20 !Description:
21  Subroutine in output group of the Level-1A geolocation software to compute
22  the celestial body vectors for one scan. Outputs produced are:
23  spacecraft state in ECR frame at Earth View center
24  sun unit vector in ECR frame at Earth View center
25  sun azimuth and zenith angle to the Solar Diffuser at Solar Diffuser
26  scan center
27  lunar unit vector in MODIS instrument frame at Space Scan view center.
28  (The Earth View center time is defined as the midpoint of the
29  integration of the middle frame of the Earth View scan. If the Earth
30  View has an even number of frames, the integration midpoint of the lower
31  number frame adjacent to the scan center is used.)
32 
33 !Input Parameters:
34  frame_data scan start times and frame sizes
35  geo_params geolocation parameters read from input file
36  fill_values a list of the fill values from the L1A file
37  frame_time The time from the start of the scan to the
38  collection of data for each frame.
39 
40 !Output Parameters:
41  cb_vectors spacecraft, solar and lunar position vectors
42 
43 Return Values:
44  MODIS_E_BAD_INPUT_ARG If mandatory pointer arguments are NULL
45  MODIS_E_GEO If any subroutine failed.
46  PGS_S_SUCCESS Otherwise.
47 
48 Externally Defined:
49  BAD_DATA "GEO_validation.h"
50  GEO_DOUBLE_FILLVALUE "GEO_output.h"
51  GOOD_DATA "GEO_validation.h"
52  MAX_FRAMES "GEO_geo.h"
53  MODIS_E_BAD_INPUT_ARG "PGS_MODIS_35251.h"
54  MODIS_E_GEO "PGS_MODIS_35251.h"
55  PGS_FALSE "PGS_SMF.h"
56  PGS_S_SUCCESS "PGS_SMF.h"
57  PGSd_GEO_ERROR_VALUE "PGS_TD.h"
58  PGSd_MOON "PGS_CBP.h"
59  PGSd_SUN "PGS_CBP.h"
60  SUCCESS "GEO_basic.h"
61  TIMECODEASIZE "smfio.h"
62 
63 Called by:
64  GEO_write_one_scan
65 
66 Routines Called:
67  GEO_interp_ECR "GEO_earth.h"
68  GEO_vec_unit3 "GEO_utils.h"
69  modsmf "smfio.h"
70  PGS_CBP_Earth_CB_Vector "PGS_CBP.h"
71  PGS_CSC_ECItoECR "PGS_CSC.h"
72  PGS_SMF_TestWarningLevel "PGS_SMF.h"
73 
74 !Revision History:
75  $Log: GEO_solar_and_lunar_vectors.c,v $
76  Revision 6.5 2017/03/27 18:46:03 jkuyper
77  Corrected to treat a return of PGSCSC_W_BAD_TRANSFORM_VALUE from
78  PGS_CSC_ECItoECR() as an error.
79 
80  Revision 6.4 2010/06/29 18:48:30 kuyper
81  Converted floating point equality tests into inequalities.
82 
83  Revision 6.3 2010/05/27 15:18:27 kuyper
84  Changed pointers to input-only data to be pointers to const.
85 
86  Revision 6.2 2010/05/19 22:10:00 kuyper
87  Helped resolve Bug 1969 by creating rpy and passing it to GEO_interp_ECR().
88  Helped resolve Bug 2472 by passing params rather a couple of it's members
89  to GEO_interp_ECR, as well as by creating sample_quality, and passing it
90  as well.
91 
92  James Kuyper Jr. James.R.Kuyper@NASA.gov
93 
94  Revision 6.1 2009/05/22 16:54:28 xgeng
95  Change MAX_SCAN_SAMPLE to MAX_FRAMES.
96  Change global array sample_time to a pointer parameter named frame_time.
97 
98  Xu Geng (xu.geng@saic.com)
99 
100  Revision 5.4 2006/07/21 17:36:42 kuyper
101  Changed order of enumeration, so that GEO_interp_ECR() will use the
102  center time of the Earth view for calculating solar elevation correction,
103  matching the value used for the frame-level calculations.
104 
105  Revision 5.3 2004/10/20 19:14:15 kuyper
106  Corrected handling of return value from GEO_interp_ECR().
107 
108  Revision 5.2 2004/10/19 15:46:07 kuyper
109  Added fill_values to list of pointer parameters needing to be checked.
110 
111  Revision 5.1 2004/09/23 15:40:26 kuyper
112  Removed obsolete parameter.
113  Added validity check of EV start time versus L1A fill value.
114  Changed to return status codes, rather than a pointer.
115 
116  Revision 4.7 2004/04/09 18:16:13 kuyper
117  Corrected to make MODIS_E_GEO returns from GEO_interp_ECR() non-fatal.
118 
119  Revision 4.6 2003/10/07 21:32:17 kuyper
120  Corrected error handling of solar angles.
121 
122  Revision 4.5 2003/08/28 16:00:09 kuyper
123  Corrected prolog.
124 
125  Revision 4.4 2003/08/26 20:07:47 kuyper
126  Corrected return value for a bad position vector.
127 
128  Revision 4.3 2003/08/25 21:41:14 kuyper
129  Changed to calculate sunSD using T_sc2SD and T_sc2ecr, rather than T_inst2SD
130  and T_inst2ecr.
131  Corrected to actually calculate Solar Diffuser angles.
132 
133  Revision 4.2 2003/08/19 21:27:06 kuyper
134  Corrected some type-changing copies to not use memcpy.
135  Corrected handling of MOON_AT_SV case.
136 
137  Revision 4.1 2003/08/14 15:50:18 vlin
138  Simplified by moving common code with GEO_locate_one_scan() out
139  into GEO_interp_ECR(). Cleaned up messages.
140 
141  Revision 2.5 1999/05/12 22:23:59 kuyper
142  Corrected to produce spacecraft position and velocity in ECR coordinates.
143 
144  Revision 2.4 1999/01/29 21:18:48 kuyper
145  Changed to log error messages if GEO_interp_ephemeris returns a WARNING.
146  Changed to call GEO_get_sample_time() to load sample_time[].
147  Removed max_extrap argument of GEO_interp_ephemeris_attitude().
148 
149  Revision 1.1 1996/12/10 20:08:22 fshaw
150  Initial revision
151 
152 Requirements:
153  PR03-F-3.5.2-1
154  PR03-F-3.5.3-1
155  PR03-F-3.5.3-2
156  PR03-F-3.5.3-3
157  PR03-F-3.6.2-1
158  PR03-F-3.6.3-1
159  PR03-F-3.6.3-2
160  PR03-I-1
161  PR03-I-2
162 
163 !Team-unique Header:
164 
165  This software is developed by the MODIS Science Data Support
166  Team for the National Aeronautics and Space Administration,
167  Goddard Space Flight Center, under contract NAS5-32373.
168 
169 References and Credits: None
170 
171 !END
172 *******************************************************************************/
173 
174 {
175  enum {SUN_AT_SD, SUN_AT_EV, MOON_AT_SV, NUM_TIMES};
176  static celestial_bodies_struct const empty_cb={
177  { /* frame state structure */
178  GEO_DOUBLE_FILLVALUE, /* time, position, velocity, euler angles */
182  { /* T_inst2ecr */
186  },
187  BAD_DATA /* qa_flag */
188  },
189  /* Sun unit vector. */
191  GEO_DOUBLE_FILLVALUE, GEO_DOUBLE_FILLVALUE, /* Solar Zenith, Azimuth */
192  /* Moon unit vectory. */
194  };
195  sc_state_struct sc_state[NUM_TIMES]; /* the SC kinematic state record */
196  double sunSD[3] = {0.0}; /* Solar Diffuser frame solar vector */
197  double sunsc[3]; /* MODIS instrument frame solar vector */
198  double moonecr[3] = {0.0}; /* the ECR frame lunar vector */
199  double mooninst[3] = {0.0}; /* MODIS instrument frame lunar vector */
200  double T_sc2ecr[NUM_TIMES][3][3] = {0.0};
201  double T_inst2ecr[NUM_TIMES][3][3] = {0.0};
202  /* instrument frame to ECR frame transform */
203  PGSt_double sunecr[3] = {0.0}; /* ECR frame solar vector */
204  PGSt_double moon_vector[1][3] = {0.0}; /* ECI frame lunar vector */
205  PGSt_double sun_vector[2][3] = {0.0}; /* the ECI frame solar vector */
206  PGSt_double toff[NUM_TIMES] = {0.0}; /* time offsets from CCSDS_EV_start */
207  PGSt_double tveci[NUM_TIMES][6] = {0.0};
208  /* ECI position/velocity vector pair*/
209  PGSt_double tvecr[NUM_TIMES][6] = {0.0};
210  /* ECR position/velocity vector pair.*/
211  PGSt_double positionECR[NUM_TIMES][3], velocityECR[NUM_TIMES][3];
212  PGSt_SMF_status PGS_error_code = PGS_S_SUCCESS;
213  int ecr, eci, inst, sc, sd;
214  PGSt_SMF_status retval=PGS_S_SUCCESS;
215  char CCSDS_EV_start[TIMECODEASIZE] = "";
216  PGSt_double rpy[3];
217  uint32 sample_quality[NUM_TIMES][2];
218  char msgbuf[PGS_SMF_MAX_MSGBUF_SIZE] = "";
219  static char filefunc[] = __FILE__ ", GEO_solar_and_lunar_vectors";
220 
221  if (frame_data == NULL || geo_params == NULL || fill_values==NULL ||
222  cb_vectors == NULL || frame_time == NULL)
223  {
224  sprintf(msgbuf,
225  "frame_data = %p, geo_params = %p, fill_values=%p, cb_vectors = %p"
226  "frame_time = %p", (void*)frame_data, (void*)geo_params,
227  (void*)fill_values, (void*)cb_vectors, (void*)frame_time);
228  modsmf(MODIS_E_BAD_INPUT_ARG, msgbuf, filefunc);
229  return MODIS_E_BAD_INPUT_ARG;
230  }
231 
232  *cb_vectors = empty_cb;
233 
234  /* Spacecraft state at Earth View center */
235  /* The Earth View center time is defined as the midpoint
236  of the integration of the middle frame of the Earth View
237  scan. If the Earth View has an even number of frames,
238  the integration midpoint of the lower numbered frame
239  adjacent to the scan center is used. */
240 
241  if(frame_data->EV_start == fill_values->EV_start_time)
242  {
243  modsmf(MODIS_E_BAD_INPUT_ARG, "EV start time is a Fill value.", filefunc);
244  return MODIS_E_BAD_INPUT_ARG;
245  }
246 
247  if (frame_data->EV_frames < 0 || frame_data->EV_frames > MAX_FRAMES)
248  toff[SUN_AT_EV] = frame_time[MAX_FRAMES/2];
249  else
250  toff[SUN_AT_EV] = frame_time[frame_data->EV_frames/2];
251 
252  /* Note: we could check whether SD_start or SV_start are fill values.
253  * However, that would require splitting up the next function call into two
254  * calls. Since the current fill values should produce error condition which
255  * should set the corresponding outputs to PGSd_GEO_ERROR_VALUE, it should
256  * still have the right effect.
257  */
258  toff[SUN_AT_SD] = (frame_data->SD_start - frame_data->EV_start) +
259  geo_params->geometry_params.t_frame * (double)frame_data->SD_frames / 2.0;
260  toff[MOON_AT_SV] = (frame_data->SV_start - frame_data->EV_start) +
261  geo_params->geometry_params.t_frame * (double)frame_data->SV_frames / 2.0;
262 
263  PGS_error_code = GEO_interp_ECR(frame_data->EV_start, NUM_TIMES, toff,
264  geo_params, CCSDS_EV_start, sc_state, T_sc2ecr, T_inst2ecr, positionECR,
265  velocityECR, rpy, sample_quality);
266  if (PGS_error_code != PGS_S_SUCCESS) {
267  sprintf(msgbuf, "GEO_interp_ECR(%.3f)", frame_data->EV_start);
268  modsmf(MODIS_E_GEO, msgbuf, filefunc);
269  return PGS_error_code == MODIS_E_GEO ? PGS_S_SUCCESS : MODIS_E_GEO;
270  }
271 
272  if (sc_state[SUN_AT_EV].position[0] < PGSd_GEO_ERROR_VALUE)
273  {
274  cb_vectors->sc.time = (float64)sc_state[SUN_AT_EV].time;
275  for (ecr=0; ecr<3; ecr++)
276  {
277  cb_vectors->sc.positionECR[ecr] =
278  (float64)positionECR[SUN_AT_EV][ecr];
279  cb_vectors->sc.velocityECR[ecr] =
280  (float64)velocityECR[SUN_AT_EV][ecr];
281  cb_vectors->sc.eulerAngles[ecr] =
282  (float64)sc_state[SUN_AT_EV].eulerAngles[ecr];
283  for (inst=0; inst<3; inst++)
284  cb_vectors->sc.T_inst2ecr[ecr][inst] =
285  (float64)T_inst2ecr[SUN_AT_EV][ecr][inst];
286  }
287  cb_vectors->sc.qa_flag = GOOD_DATA;
288  }
289 
290  if (positionECR[SUN_AT_EV][0] < PGSd_GEO_ERROR_VALUE ||
291  positionECR[SUN_AT_SD][0] < PGSd_GEO_ERROR_VALUE)
292  {
293  PGS_error_code = PGS_CBP_Earth_CB_Vector(2, CCSDS_EV_start, toff,
294  PGSd_SUN, sun_vector);
295  if (PGS_error_code != PGS_S_SUCCESS) {
296  sprintf(msgbuf, "PGS_CBP_Earth_CB_Vector(%s, SUN)", CCSDS_EV_start);
297  modsmf(MODIS_E_GEO, msgbuf, filefunc);
298  retval = MODIS_E_GEO;
299  }
300  else
301  {
302  /* Sun vectors retrieved OK. Sun Vector from spacecraft at SD center
303  * time tveci[SUN_AT_SD] =
304  * sun_vector[SUN_AT_SD] - sc_state[SUN_AT_SD].position:
305  * Adjustment of sun vector from wrt/Earth center to wrt/ spacecraft
306  * sufficiently small to be ignored
307  */
308 
309  memcpy(tveci[SUN_AT_SD], sun_vector[SUN_AT_SD],
310  sizeof(sun_vector[SUN_AT_SD]));
311  memcpy(tveci[SUN_AT_EV], sun_vector[SUN_AT_EV],
312  sizeof(sun_vector[SUN_AT_EV]));
313 
314  PGS_error_code =
315  PGS_CSC_ECItoECR(2, CCSDS_EV_start, toff, tveci, tvecr);
316  if (PGS_error_code != PGS_S_SUCCESS &&
317  PGS_error_code != PGSCSC_W_PREDICTED_UT1)
318  {
319  sprintf(msgbuf, "PGS_CSC_ECItoECR(%s, SUN)", CCSDS_EV_start);
320  modsmf(MODIS_E_GEO, msgbuf, filefunc);
321  retval = MODIS_E_GEO;
322  }
323  else /* ECR-frame sun vectors computed OK */
324  {
325  if(positionECR[SUN_AT_EV][0] < PGSd_GEO_ERROR_VALUE &&
326  tvecr[SUN_AT_EV][0] < PGSd_GEO_ERROR_VALUE &&
327  cb_vectors->sc.qa_flag == GOOD_DATA)
328  {
329  for(ecr=0; ecr<3; ecr++)
330  sunecr[ecr] = (double)tvecr[SUN_AT_EV][ecr];
331 
332  if (GEO_vec_unit3(sunecr, cb_vectors->sun_unit_vector)
333  != SUCCESS)
334  {
335  modsmf(MODIS_E_GEO, "GEO_vec_unit3(sun_unit_vector)",
336  filefunc);
337  retval = MODIS_E_GEO;
338  }
339  }
340 
341  /* complete computation of sun on solar diffuser */
342 
343  if(positionECR[SUN_AT_SD][0] < PGSd_GEO_ERROR_VALUE &&
344  tvecr[SUN_AT_SD][0] < PGSd_GEO_ERROR_VALUE)
345  {
346  for(ecr=0; ecr<3; ecr++)
347  sunecr[ecr] = (double)tvecr[SUN_AT_SD][ecr];
348 
349  /* transform the sunecr vector in ECR coordinates at the
350  * SD_center_time to sunsc, the vector in the MODIS instrument
351  * frame using the transpose of the T_inst2ecr matrix.
352  */
353  for (sc=0; sc<3; sc++)
354  {
355  sunsc[sc] = 0.0;
356  for (ecr=0; ecr<3; ecr++)
357  sunsc[sc] +=
358  T_sc2ecr[SUN_AT_SD][ecr][sc] * sunecr[ecr];
359  }
360 
361  /* transform the suninst vector in instrument coordinates at
362  * the SD center time to sunSD, the vector in the Solar
363  * Diffuser frame instrument frame using the
364  * geo_params->coord_trans.T_inst2SD matrix:
365  */
366  for (sd=0; sd<3; sd++)
367  {
368  sunSD[sd] = 0.0;
369  for (sc=0; sc<3; sc++)
370  sunSD[sd] += geo_params->coord_trans.T_sc2SD[sd][sc]
371  * sunsc[sc];
372  }
373 
374  /* Note: the sign of the arctangent arguments is used to
375  * determine the quadrant of the angle returned
376  */
377  cb_vectors->SD_sun_zenith = PGS_PI/2.0 - atan2(sunSD[2],
378  sqrt(sunSD[0] * sunSD[0] + sunSD[1] * sunSD[1]));
379  cb_vectors->SD_sun_azimuth = atan2(sunSD[1], sunSD[0]);
380  }
381  } /* ECR-frame sun vectors computed OK */
382  } /* sun vectors retrieved OK */
383  }
384 
385  /* Lunar vectors */
386 
387  PGS_error_code = PGS_CBP_Earth_CB_Vector(1, CCSDS_EV_start, &toff[MOON_AT_SV],
388  PGSd_MOON, moon_vector);
389  if (PGS_error_code != PGS_S_SUCCESS) {
390  sprintf(msgbuf, "PGS_CBP_Earth_CB_Vector(%s, MOON)", CCSDS_EV_start);
391  modsmf(MODIS_E_GEO, msgbuf, filefunc);
392  retval = MODIS_E_GEO;
393  }
394  else
395  { /* sc_state retrieved OK */
396  for (eci = 0; eci < 3; eci++)
397  tveci[MOON_AT_SV][eci] =
398  moon_vector[0][eci] - sc_state[MOON_AT_SV].position[eci];
399 
400  PGS_error_code = PGS_CSC_ECItoECR(1, CCSDS_EV_start, toff+MOON_AT_SV,
401  tveci+MOON_AT_SV, tvecr+MOON_AT_SV);
402  if (PGS_error_code != PGS_S_SUCCESS &&
403  PGS_error_code != PGSCSC_W_PREDICTED_UT1 && (
404  tvecr[MOON_AT_SV][0] >= PGSd_GEO_ERROR_VALUE ||
405  tvecr[MOON_AT_SV][1] >= PGSd_GEO_ERROR_VALUE ||
406  tvecr[MOON_AT_SV][2] >= PGSd_GEO_ERROR_VALUE))
407  {
408  sprintf(msgbuf, "PGS_CSC_ECItoECR(%s, MOON)", CCSDS_EV_start);
409  modsmf(MODIS_E_GEO, msgbuf, filefunc);
410  retval = MODIS_E_GEO;
411  }
412  else
413  {
414  for(ecr=0; ecr<3; ecr++)
415  moonecr[ecr] = (double)tvecr[MOON_AT_SV][ecr];
416  /* transform the moonecr vector in ECR coordinates at the SV center
417  * time to mooninst, the vector in the MODIS instrument frame using the
418  * transpose of the T_inst2ecr matrix. */
419 
420  for(inst=0; inst<3; inst++) {
421  mooninst[inst] = 0.0;
422  for (ecr=0; ecr<3; ecr++)
423  mooninst[inst] += T_inst2ecr[MOON_AT_SV][ecr][inst] * moonecr[ecr];
424  }
425 
426  if (GEO_vec_unit3(mooninst, cb_vectors->moon_unit_vector) != SUCCESS) {
427  modsmf(MODIS_E_GEO, "GEO_vec_unit3(moon_unit_vector)", filefunc);
428  retval = MODIS_E_GEO;
429  }
430  }
431  } /* sc_state retrieved OK */
432 
433  return retval;
434 }
#define SUCCESS
Definition: ObpgReadGrid.h:15
float64 eulerAngles[3]
#define NULL
Definition: decode_rs.h:63
#define MODIS_E_BAD_INPUT_ARG
#define MAX_FRAMES
Definition: GEO_geo.h:79
#define PGS_PI
Definition: GEO_geo.h:172
internal_coord_trans_struct coord_trans
PGSt_SMF_status GEO_interp_ECR(PGSt_double const base_time, PGSt_integer const numValues, const PGSt_double offsets[], GEO_param_struct const *params, char asciiUTC[], sc_state_struct sc_state[], double T_sc2ecr[][3][3], double T_inst2ecr[][3][3], double positionECR[][3], double velocityECR[][3], PGSt_double rpy[], uint32 sample_quality[][2])
Definition: GEO_interp_ECR.c:4
float64 T_inst2ecr[3][3]
const int BAD_DATA
#define TIMECODEASIZE
Definition: Metadata.c:59
#define MODIS_E_GEO
int GEO_vec_unit3(double vec[3], double unit_vec[3])
Definition: GEO_vec_unit3.c:9
#define GEO_DOUBLE_FILLVALUE
Definition: GEO_output.h:106
focal_plane_geometry_struct geometry_params
frame_state_struct sc
float64 positionECR[3]
const int GOOD_DATA
float64 velocityECR[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
PGSt_SMF_status GEO_solar_and_lunar_vectors(PGSt_double const frame_time[], frame_data_struct const *const frame_data, GEO_param_struct const *const geo_params, fill_values_struct const *const fill_values, celestial_bodies_struct *const cb_vectors)