FACT++  1.0
palUe2pv.c
Go to the documentation of this file.
1 /*
2 *+
3 * Name:
4 * palUe2pv
5 
6 * Purpose:
7 * Heliocentric position and velocity of a planet, asteroid or comet, from universal elements
8 
9 * Language:
10 * Starlink ANSI C
11 
12 * Type of Module:
13 * Library routine
14 
15 * Invocation:
16 * void palUe2pv( double date, double u[13], double pv[6], int *jstat );
17 
18 * Arguments:
19 * date = double (Given)
20 * TT Modified Julian date (JD-2400000.5).
21 * u = double [13] (Given & Returned)
22 * Universal orbital elements (updated, see note 1)
23 * given (0) combined mass (M+m)
24 * " (1) total energy of the orbit (alpha)
25 * " (2) reference (osculating) epoch (t0)
26 * " (3-5) position at reference epoch (r0)
27 * " (6-8) velocity at reference epoch (v0)
28 * " (9) heliocentric distance at reference epoch
29 * " (10) r0.v0
30 * returned (11) date (t)
31 * " (12) universal eccentric anomaly (psi) of date
32 * pv = double [6] (Returned)
33 * Position (AU) and velocity (AU/s)
34 * jstat = int * (Returned)
35 * status: 0 = OK
36 * -1 = radius vector zero
37 * -2 = failed to converge
38 
39 * Description:
40 * Heliocentric position and velocity of a planet, asteroid or comet,
41 * starting from orbital elements in the "universal variables" form.
42 
43 * Authors:
44 * PTW: Pat Wallace (STFC)
45 * TIMJ: Tim Jenness (JAC, Hawaii)
46 * {enter_new_authors_here}
47 
48 * Notes:
49 * - The "universal" elements are those which define the orbit for the
50 * purposes of the method of universal variables (see reference).
51 * They consist of the combined mass of the two bodies, an epoch,
52 * and the position and velocity vectors (arbitrary reference frame)
53 * at that epoch. The parameter set used here includes also various
54 * quantities that can, in fact, be derived from the other
55 * information. This approach is taken to avoiding unnecessary
56 * computation and loss of accuracy. The supplementary quantities
57 * are (i) alpha, which is proportional to the total energy of the
58 * orbit, (ii) the heliocentric distance at epoch, (iii) the
59 * outwards component of the velocity at the given epoch, (iv) an
60 * estimate of psi, the "universal eccentric anomaly" at a given
61 * date and (v) that date.
62 * - The companion routine is palEl2ue. This takes the conventional
63 * orbital elements and transforms them into the set of numbers
64 * needed by the present routine. A single prediction requires one
65 * one call to palEl2ue followed by one call to the present routine;
66 * for convenience, the two calls are packaged as the routine
67 * palPlanel. Multiple predictions may be made by again
68 * calling palEl2ue once, but then calling the present routine
69 * multiple times, which is faster than multiple calls to palPlanel.
70 * - It is not obligatory to use palEl2ue to obtain the parameters.
71 * However, it should be noted that because palEl2ue performs its
72 * own validation, no checks on the contents of the array U are made
73 * by the present routine.
74 * - DATE is the instant for which the prediction is required. It is
75 * in the TT timescale (formerly Ephemeris Time, ET) and is a
76 * Modified Julian Date (JD-2400000.5).
77 * - The universal elements supplied in the array U are in canonical
78 * units (solar masses, AU and canonical days). The position and
79 * velocity are not sensitive to the choice of reference frame. The
80 * palEl2ue routine in fact produces coordinates with respect to the
81 * J2000 equator and equinox.
82 * - The algorithm was originally adapted from the EPHSLA program of
83 * D.H.P.Jones (private communication, 1996). The method is based
84 * on Stumpff's Universal Variables.
85 * - Reference: Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
86 
87 * History:
88 * 2012-03-09 (TIMJ):
89 * Initial version cloned from SLA/F.
90 * Adapted with permission from the Fortran SLALIB library.
91 * {enter_further_changes_here}
92 
93 * Copyright:
94 * Copyright (C) 2005 Rutherford Appleton Laboratory
95 * Copyright (C) 2012 Science and Technology Facilities Council.
96 * All Rights Reserved.
97 
98 * Licence:
99 * This program is free software; you can redistribute it and/or
100 * modify it under the terms of the GNU General Public License as
101 * published by the Free Software Foundation; either version 3 of
102 * the License, or (at your option) any later version.
103 *
104 * This program is distributed in the hope that it will be
105 * useful, but WITHOUT ANY WARRANTY; without even the implied
106 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
107 * PURPOSE. See the GNU General Public License for more details.
108 *
109 * You should have received a copy of the GNU General Public License
110 * along with this program; if not, write to the Free Software
111 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
112 * MA 02110-1301, USA.
113 
114 * Bugs:
115 * {note_any_bugs_here}
116 *-
117 */
118 
119 #include <math.h>
120 
121 #include "pal.h"
122 #include "palmac.h"
123 
124 void palUe2pv( double date, double u[13], double pv[6], int *jstat ) {
125 
126  /* Canonical days to seconds */
127  const double CD2S = PAL__GCON / PAL__SPD;
128 
129  /* Test value for solution and maximum number of iterations */
130  const double TEST = 1e-13;
131  const int NITMAX = 25;
132 
133  int I, NIT, N;
134  double CM,ALPHA,T0,P0[3],V0[3],R0,SIGMA0,T,PSI,DT,W,
135  TOL,PSJ,PSJ2,BETA,S0,S1,S2,S3,
136  FF,R,F,G,FD,GD;
137 
138  double PLAST = 0.0;
139  double FLAST = 0.0;
140 
141  /* Unpack the parameters. */
142  CM = u[0];
143  ALPHA = u[1];
144  T0 = u[2];
145  for (I=0; I<3; I++) {
146  P0[I] = u[I+3];
147  V0[I] = u[I+6];
148  }
149  R0 = u[9];
150  SIGMA0 = u[10];
151  T = u[11];
152  PSI = u[12];
153 
154  /* Approximately update the universal eccentric anomaly. */
155  PSI = PSI+(date-T)*PAL__GCON/R0;
156 
157  /* Time from reference epoch to date (in Canonical Days: a canonical
158  * day is 58.1324409... days, defined as 1/PAL__GCON). */
159  DT = (date-T0)*PAL__GCON;
160 
161  /* Refine the universal eccentric anomaly, psi. */
162  NIT = 1;
163  W = 1.0;
164  TOL = 0.0;
165  while (fabs(W) >= TOL) {
166 
167  /* Form half angles until BETA small enough. */
168  N = 0;
169  PSJ = PSI;
170  PSJ2 = PSJ*PSJ;
171  BETA = ALPHA*PSJ2;
172  while (fabs(BETA) > 0.7) {
173  N = N+1;
174  BETA = BETA/4.0;
175  PSJ = PSJ/2.0;
176  PSJ2 = PSJ2/4.0;
177  }
178 
179  /* Calculate Universal Variables S0,S1,S2,S3 by nested series. */
180  S3 = PSJ*PSJ2*((((((BETA/210.0+1.0)
181  *BETA/156.0+1.0)
182  *BETA/110.0+1.0)
183  *BETA/72.0+1.0)
184  *BETA/42.0+1.0)
185  *BETA/20.0+1.0)/6.0;
186  S2 = PSJ2*((((((BETA/182.0+1.0)
187  *BETA/132.0+1.0)
188  *BETA/90.0+1.0)
189  *BETA/56.0+1.0)
190  *BETA/30.0+1.0)
191  *BETA/12.0+1.0)/2.0;
192  S1 = PSJ+ALPHA*S3;
193  S0 = 1.0+ALPHA*S2;
194 
195  /* Undo the angle-halving. */
196  TOL = TEST;
197  while (N > 0) {
198  S3 = 2.0*(S0*S3+PSJ*S2);
199  S2 = 2.0*S1*S1;
200  S1 = 2.0*S0*S1;
201  S0 = 2.0*S0*S0-1.0;
202  PSJ = PSJ+PSJ;
203  TOL += TOL;
204  N--;
205  }
206 
207  /* Values of F and F' corresponding to the current value of psi. */
208  FF = R0*S1+SIGMA0*S2+CM*S3-DT;
209  R = R0*S0+SIGMA0*S1+CM*S2;
210 
211  /* If first iteration, create dummy "last F". */
212  if ( NIT == 1) FLAST = FF;
213 
214  /* Check for sign change. */
215  if ( FF*FLAST < 0.0 ) {
216 
217  /* Sign change: get psi adjustment using secant method. */
218  W = FF*(PLAST-PSI)/(FLAST-FF);
219  } else {
220 
221  /* No sign change: use Newton-Raphson method instead. */
222  if (R == 0.0) {
223  /* Null radius vector */
224  *jstat = -1;
225  return;
226  }
227  W = FF/R;
228  }
229 
230  /* Save the last psi and F values. */
231  PLAST = PSI;
232  FLAST = FF;
233 
234  /* Apply the Newton-Raphson or secant adjustment to psi. */
235  PSI = PSI-W;
236 
237  /* Next iteration, unless too many already. */
238  if (NIT > NITMAX) {
239  *jstat = -2; /* Failed to converge */
240  return;
241  }
242  NIT++;
243  }
244 
245  /* Project the position and velocity vectors (scaling velocity to AU/s). */
246  W = CM*S2;
247  F = 1.0-W/R0;
248  G = DT-CM*S3;
249  FD = -CM*S1/(R0*R);
250  GD = 1.0-W/R;
251  for (I=0; I<3; I++) {
252  pv[I] = P0[I]*F+V0[I]*G;
253  pv[I+3] = CD2S*(P0[I]*FD+V0[I]*GD);
254  }
255 
256  /* Update the parameters to allow speedy prediction of PSI next time. */
257  u[11] = date;
258  u[12] = PSI;
259 
260  /* OK exit. */
261  *jstat = 0;
262  return;
263 }
static const double PAL__GCON
Definition: palmac.h:117
void palUe2pv(double date, double u[13], double pv[6], int *jstat)
Definition: palUe2pv.c:124
static const double PAL__SPD
Definition: palmac.h:102