File Coverage

palsrc/palUe2pv.c
Criterion Covered Total %
statement 65 69 94.2
branch 16 18 88.8
condition n/a
subroutine n/a
pod n/a
total 81 87 93.1


line stmt bran cond sub pod time code
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
120              
121             #include "pal.h"
122             #include "palmac.h"
123              
124 2102           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 2102           CM = u[0];
143 2102           ALPHA = u[1];
144 2102           T0 = u[2];
145 8408 100         for (I=0; I<3; I++) {
146 6306           P0[I] = u[I+3];
147 6306           V0[I] = u[I+6];
148             }
149 2102           R0 = u[9];
150 2102           SIGMA0 = u[10];
151 2102           T = u[11];
152 2102           PSI = u[12];
153              
154             /* Approximately update the universal eccentric anomaly. */
155 2102           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 2102           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 8402 100         while (fabs(W) >= TOL) {
166              
167             /* Form half angles until BETA small enough. */
168             N = 0;
169             PSJ = PSI;
170 6300           PSJ2 = PSJ*PSJ;
171 6300           BETA = ALPHA*PSJ2;
172 7836 100         while (fabs(BETA) > 0.7) {
173 1536           N = N+1;
174 1536           BETA = BETA/4.0;
175 1536           PSJ = PSJ/2.0;
176 1536           PSJ2 = PSJ2/4.0;
177             }
178              
179             /* Calculate Universal Variables S0,S1,S2,S3 by nested series. */
180 12600           S3 = PSJ*PSJ2*((((((BETA/210.0+1.0)
181 6300           *BETA/156.0+1.0)
182 6300           *BETA/110.0+1.0)
183 6300           *BETA/72.0+1.0)
184 6300           *BETA/42.0+1.0)
185 6300           *BETA/20.0+1.0)/6.0;
186 12600           S2 = PSJ2*((((((BETA/182.0+1.0)
187 6300           *BETA/132.0+1.0)
188 6300           *BETA/90.0+1.0)
189 6300           *BETA/56.0+1.0)
190 6300           *BETA/30.0+1.0)
191 6300           *BETA/12.0+1.0)/2.0;
192 6300           S1 = PSJ+ALPHA*S3;
193 6300           S0 = 1.0+ALPHA*S2;
194              
195             /* Undo the angle-halving. */
196             TOL = TEST;
197 7836 100         while (N > 0) {
198 1536           S3 = 2.0*(S0*S3+PSJ*S2);
199 1536           S2 = 2.0*S1*S1;
200 1536           S1 = 2.0*S0*S1;
201 1536           S0 = 2.0*S0*S0-1.0;
202 1536           PSJ = PSJ+PSJ;
203 1536           TOL += TOL;
204 1536           N--;
205             }
206              
207             /* Values of F and F' corresponding to the current value of psi. */
208 6300           FF = R0*S1+SIGMA0*S2+CM*S3-DT;
209 6300           R = R0*S0+SIGMA0*S1+CM*S2;
210              
211             /* If first iteration, create dummy "last F". */
212 6300 100         if ( NIT == 1) FLAST = FF;
213              
214             /* Check for sign change. */
215 6300 100         if ( FF*FLAST < 0.0 ) {
216              
217             /* Sign change: get psi adjustment using secant method. */
218 1352           W = FF*(PLAST-PSI)/(FLAST-FF);
219             } else {
220              
221             /* No sign change: use Newton-Raphson method instead. */
222 4948 50         if (R == 0.0) {
223             /* Null radius vector */
224 0           *jstat = -1;
225 0           return;
226             }
227 4948           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 6300           PSI = PSI-W;
236              
237             /* Next iteration, unless too many already. */
238 6300 50         if (NIT > NITMAX) {
239 0           *jstat = -2; /* Failed to converge */
240 0           return;
241             }
242 6300           NIT++;
243             }
244              
245             /* Project the position and velocity vectors (scaling velocity to AU/s). */
246 2102           W = CM*S2;
247 2102           F = 1.0-W/R0;
248 2102           G = DT-CM*S3;
249 2102           FD = -CM*S1/(R0*R);
250 2102           GD = 1.0-W/R;
251 8408 100         for (I=0; I<3; I++) {
252 6306           pv[I] = P0[I]*F+V0[I]*G;
253 6306           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 2102           u[11] = date;
258 2102           u[12] = PSI;
259              
260             /* OK exit. */
261 2102           *jstat = 0;
262 2102           return;
263             }