| 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 $"}; | 
|---|