| 1 | /* VSOP87 planetary theory
 | 
|---|
| 2 |  *
 | 
|---|
| 3 |  * currently uses version VSOP87D:
 | 
|---|
| 4 |  * heliocentric spherical, mean ecliptic of date.
 | 
|---|
| 5 |  *
 | 
|---|
| 6 |  * calculation of rates (daily changes) is optional;
 | 
|---|
| 7 |  * see header file for the necessary #define's
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * rough orientation on calculation time, miliseconds
 | 
|---|
| 10 |  * on an HP 715/75, all planets Mercury to Neptune, prec=0.0:
 | 
|---|
| 11 |  *
 | 
|---|
| 12 |  *      terms   with rates      without rates
 | 
|---|
| 13 |  *      3598    11              7.1
 | 
|---|
| 14 |  *      31577   51              44
 | 
|---|
| 15 |  *
 | 
|---|
| 16 |  * with secular terms for JD 2232395.0  19/12/1399 0h TDB:
 | 
|---|
| 17 |  *
 | 
|---|
| 18 |  *      FULL PRECISION code (31577 terms), milliseconds
 | 
|---|
| 19 |  *      prec    terms   rates   no rates
 | 
|---|
| 20 |  *      1e-8    15086   62      36
 | 
|---|
| 21 |  *      1e-7    10105   44      25
 | 
|---|
| 22 |  *      1e-6    3725    20      13
 | 
|---|
| 23 |  *      1e-5    1324    11      7.8
 | 
|---|
| 24 |  *      1e-4    443     7.0     6.0
 | 
|---|
| 25 |  *      1e-3    139     6.0     5.0
 | 
|---|
| 26 |  *
 | 
|---|
| 27 |  *      REDUCED PRECISION code (3598 terms), milliseconds
 | 
|---|
| 28 |  *      prec    terms   rates   no rates
 | 
|---|
| 29 |  *      1e-7    2463    9.9     5.5
 | 
|---|
| 30 |  *      1e-6    1939    8.0     4.5
 | 
|---|
| 31 |  *      1e-5    1131    4.9     2.9
 | 
|---|
| 32 |  *      1e-4    443     2.2     1.5
 | 
|---|
| 33 |  *      1e-3    139     1.0     0.9
 | 
|---|
| 34 |  */
 | 
|---|
| 35 | 
 | 
|---|
| 36 | #include <math.h>
 | 
|---|
| 37 | #include "P_.h"
 | 
|---|
| 38 | #include "astro.h"
 | 
|---|
| 39 | #include "vsop87.h"
 | 
|---|
| 40 | 
 | 
|---|
| 41 | #define VSOP_A1000      365250.0        /* days per millenium */
 | 
|---|
| 42 | #define VSOP_MAXALPHA   5               /* max degree of time */
 | 
|---|
| 43 | 
 | 
|---|
| 44 | /******************************************************************
 | 
|---|
| 45 |  * adapted from BdL FORTRAN Code; stern
 | 
|---|
| 46 |  *
 | 
|---|
| 47 |  *    Reference : Bureau des Longitudes - PBGF9502
 | 
|---|
| 48 |  *
 | 
|---|
| 49 |  *    Object :  calculate a VSOP87 position for a given time.
 | 
|---|
| 50 |  *
 | 
|---|
| 51 |  *    Input :
 | 
|---|
| 52 |  *
 | 
|---|
| 53 |  *    mjd      modified julian date, counted from J1900.0
 | 
|---|
| 54 |  *             time scale : dynamical time TDB.
 | 
|---|
| 55 |  *
 | 
|---|
| 56 |  *    obj       object number as in astro.h, NB: not for pluto
 | 
|---|
| 57 |  *
 | 
|---|
| 58 |  *    prec     relative precision
 | 
|---|
| 59 |  *
 | 
|---|
| 60 |  *             if prec is equal to 0 then the precision is the precision
 | 
|---|
| 61 |  *                p0 of the complete solution VSOP87.
 | 
|---|
| 62 |  *                Mercury    p0 =  0.6 10**-8
 | 
|---|
| 63 |  *                Venus      p0 =  2.5 10**-8
 | 
|---|
| 64 |  *                Earth      p0 =  2.5 10**-8
 | 
|---|
| 65 |  *                Mars       p0 = 10.0 10**-8
 | 
|---|
| 66 |  *                Jupiter    p0 = 35.0 10**-8
 | 
|---|
| 67 |  *                Saturn     p0 = 70.0 10**-8
 | 
|---|
| 68 |  *                Uranus     p0 =  8.0 10**-8
 | 
|---|
| 69 |  *                Neptune    p0 = 42.0 10**-8
 | 
|---|
| 70 |  *
 | 
|---|
| 71 |  *             if prec is not equal to 0, let us say in between p0 and
 | 
|---|
| 72 |  *             10**-3, the precision is :
 | 
|---|
| 73 |  *                for the positions :
 | 
|---|
| 74 |  *                - prec*a0 au for the distances.
 | 
|---|
| 75 |  *                - prec rad for the other variables.
 | 
|---|
| 76 |  *                for the velocities :
 | 
|---|
| 77 |  *                - prec*a0 au/day for the distances.
 | 
|---|
| 78 |  *                - prec rad/day for the other variables.
 | 
|---|
| 79 |  *                  a0 is the semi-major axis of the body.
 | 
|---|
| 80 |  *
 | 
|---|
| 81 |  *    Output :
 | 
|---|
| 82 |  *
 | 
|---|
| 83 |  *    ret[6]     array of the results (double).
 | 
|---|
| 84 |  *
 | 
|---|
| 85 |  *             for spherical coordinates :
 | 
|---|
| 86 |  *                 1: longitude (rd)
 | 
|---|
| 87 |  *                 2: latitude (rd)
 | 
|---|
| 88 |  *                 3: radius (au)
 | 
|---|
| 89 |  *              #if VSOP_GETRATE:
 | 
|---|
| 90 |  *                 4: longitude velocity (rad/day)
 | 
|---|
| 91 |  *                 5: latitude velocity (rad/day)
 | 
|---|
| 92 |  *                 6: radius velocity (au/day)
 | 
|---|
| 93 |  *
 | 
|---|
| 94 |  *    return:     error index (int)
 | 
|---|
| 95 |  *                 0: no error.
 | 
|---|
| 96 |  *                 2: object out of range [MERCURY .. NEPTUNE, SUN]
 | 
|---|
| 97 |  *                 3: precision out of range [0.0 .. 1e-3]
 | 
|---|
| 98 |  ******************************************************************/
 | 
|---|
| 99 | int
 | 
|---|
| 100 | vsop87 (mjd, obj, prec, ret)
 | 
|---|
| 101 | double mjd;
 | 
|---|
| 102 | int obj;
 | 
|---|
| 103 | double prec;
 | 
|---|
| 104 | double *ret;
 | 
|---|
| 105 | {
 | 
|---|
| 106 |     static double (*vx_map[])[3] = {            /* data tables */
 | 
|---|
| 107 |                 vx_mercury, vx_venus, vx_mars, vx_jupiter,
 | 
|---|
| 108 |                 vx_saturn, vx_uranus, vx_neptune, 0, vx_earth,
 | 
|---|
| 109 |         };
 | 
|---|
| 110 |     static int (*vn_map[])[3] = {               /* indexes */
 | 
|---|
| 111 |                 vn_mercury, vn_venus, vn_mars, vn_jupiter,
 | 
|---|
| 112 |                 vn_saturn, vn_uranus, vn_neptune, 0, vn_earth,
 | 
|---|
| 113 |         };
 | 
|---|
| 114 |     static double a0[] = {      /* semimajor axes; for precision ctrl only */
 | 
|---|
| 115 |             0.39, 0.72, 1.5, 5.2, 9.6, 19.2, 30.1, 39.5, 1.0,
 | 
|---|
| 116 |         };
 | 
|---|
| 117 |     double (*vx_obj)[3] = vx_map[obj];          /* VSOP87 data and indexes */
 | 
|---|
| 118 |     int (*vn_obj)[3] = vn_map[obj];
 | 
|---|
| 119 | 
 | 
|---|
| 120 |     double t[VSOP_MAXALPHA+1];                  /* powers of time */
 | 
|---|
| 121 |     double t_abs[VSOP_MAXALPHA+1];              /* powers of abs(time) */
 | 
|---|
| 122 |     double q;                                   /* aux for precision control */
 | 
|---|
| 123 |     int i, cooidx, alpha;                       /* misc indexes */
 | 
|---|
| 124 | 
 | 
|---|
| 125 |     if (obj == PLUTO || obj > SUN)
 | 
|---|
| 126 |         return (2);
 | 
|---|
| 127 | 
 | 
|---|
| 128 |     if (prec < 0.0 || prec > 1e-3)
 | 
|---|
| 129 |         return(3);
 | 
|---|
| 130 | 
 | 
|---|
| 131 |     /* zero result array */
 | 
|---|
| 132 |     for (i = 0; i < 6; ++i) ret[i] = 0.0;
 | 
|---|
| 133 | 
 | 
|---|
| 134 |     /* time and its powers */
 | 
|---|
| 135 |     t[0] = 1.0;
 | 
|---|
| 136 |     t[1] = (mjd - J2000)/VSOP_A1000;
 | 
|---|
| 137 |     for (i = 2; i <= VSOP_MAXALPHA; ++i) t[i] = t[i-1] * t[1];
 | 
|---|
| 138 |     t_abs[0] = 1.0;
 | 
|---|
| 139 |     for (i = 1; i <= VSOP_MAXALPHA; ++i) t_abs[i] = fabs(t[i]);
 | 
|---|
| 140 | 
 | 
|---|
| 141 |     /* precision control */
 | 
|---|
| 142 |     q = -log10(prec + 1e-35) - 2;       /* decades below 1e-2 */
 | 
|---|
| 143 |     q = VSOP_ASCALE * prec / 10.0 / q;  /* reduce threshold progressively
 | 
|---|
| 144 |                                          * for higher precision */
 | 
|---|
| 145 | 
 | 
|---|
| 146 |     /* do the term summation; first the spatial dimensions */
 | 
|---|
| 147 |     for (cooidx = 0; cooidx < 3; ++cooidx) {
 | 
|---|
| 148 | 
 | 
|---|
| 149 |         /* then the powers of time */
 | 
|---|
| 150 |         for (alpha = 0; vn_obj[alpha+1][cooidx] ; ++alpha) {
 | 
|---|
| 151 |             double p, term, termdot;
 | 
|---|
| 152 | 
 | 
|---|
| 153 |             /* precision threshold */
 | 
|---|
| 154 |             p = q/(t_abs[alpha] + alpha * t_abs[alpha-1] * 1e-4 + 1e-35);
 | 
|---|
| 155 | #if VSOP_SPHERICAL
 | 
|---|
| 156 |             if (cooidx == 2)    /* scale by semimajor axis for radius */
 | 
|---|
| 157 | #endif
 | 
|---|
| 158 |                 p *= a0[obj];
 | 
|---|
| 159 | 
 | 
|---|
| 160 |             term = termdot = 0.0;
 | 
|---|
| 161 |             for (i = vn_obj[alpha][cooidx]; i < vn_obj[alpha+1][cooidx]; ++i) {
 | 
|---|
| 162 |                 double a, b, c, arg;
 | 
|---|
| 163 | 
 | 
|---|
| 164 |                 a = vx_obj[i][0];
 | 
|---|
| 165 |                 if (a < p) continue;    /* ignore small terms */
 | 
|---|
| 166 | 
 | 
|---|
| 167 |                 b = vx_obj[i][1];
 | 
|---|
| 168 |                 c = vx_obj[i][2];
 | 
|---|
| 169 | 
 | 
|---|
| 170 |                 arg = b + c * t[1];
 | 
|---|
| 171 |                 term += a * cos(arg);
 | 
|---|
| 172 | #if VSOP_GETRATE
 | 
|---|
| 173 |                 termdot += -c * a * sin(arg);
 | 
|---|
| 174 | #endif
 | 
|---|
| 175 |             }
 | 
|---|
| 176 | 
 | 
|---|
| 177 |             ret[cooidx] += t[alpha] * term;
 | 
|---|
| 178 | #if VSOP_GETRATE
 | 
|---|
| 179 |             ret[cooidx + 3] += t[alpha] * termdot +
 | 
|---|
| 180 |                     ((alpha > 0) ? alpha * t[alpha - 1] * term : 0.0);
 | 
|---|
| 181 | #endif
 | 
|---|
| 182 |         } /* alpha */
 | 
|---|
| 183 |     } /* cooidx */
 | 
|---|
| 184 | 
 | 
|---|
| 185 |     for (i = 0; i < 6; ++i) ret[i] /= VSOP_ASCALE;
 | 
|---|
| 186 | 
 | 
|---|
| 187 | #if VSOP_SPHERICAL
 | 
|---|
| 188 |     /* reduce longitude to 0..2pi */
 | 
|---|
| 189 |     ret[0] -= floor(ret[0]/(2.*PI)) * (2.*PI);
 | 
|---|
| 190 | #endif
 | 
|---|
| 191 | 
 | 
|---|
| 192 | #if VSOP_GETRATE
 | 
|---|
| 193 |     /* convert millenium rate to day rate */
 | 
|---|
| 194 |     for (i = 3; i < 6; ++i) ret[i] /= VSOP_A1000;
 | 
|---|
| 195 | #endif
 | 
|---|
| 196 | 
 | 
|---|
| 197 | #if VSOP_SPHERICAL
 | 
|---|
| 198 |     /* reduction from dynamical equinox of VSOP87 to FK5;
 | 
|---|
| 199 |      */
 | 
|---|
| 200 |     if (prec < 5e-7) {          /* 5e-7 rad = 0.1 arc seconds */
 | 
|---|
| 201 |         double L1, c1, s1;
 | 
|---|
| 202 |         L1 = ret[0] - degrad(13.97 * t[1] - 0.031 * t[2]);
 | 
|---|
| 203 |         c1 = cos(L1); s1 = sin(L1);
 | 
|---|
| 204 |         ret[0] += degrad(-0.09033 + 0.03916 * (c1 + s1) * tan(ret[1]))/3600.0;
 | 
|---|
| 205 |         ret[1] += degrad(0.03916 * (c1 - s1))/3600.0;
 | 
|---|
| 206 |     }
 | 
|---|
| 207 | #endif
 | 
|---|
| 208 | 
 | 
|---|
| 209 |     return (0);
 | 
|---|
| 210 | }
 | 
|---|
| 211 | 
 | 
|---|
| 212 | /* For RCS Only -- Do Not Edit */
 | 
|---|
| 213 | static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: vsop87.c,v $ $Date: 2001-04-10 14:40:47 $ $Revision: 1.1.1.1 $ $Name: not supported by cvs2svn $"};
 | 
|---|