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