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 | }
|
---|