/* gplan.c Routines to chew through tables of perturbations. */ #include "plantbl.h" #if __STDC__ extern int epsiln ( double J ); double cos (double); double sin (double); double floor (double); double fabs (double); void mean_elements (double); static int sscc (int, double, int); double g1plan (double, struct plantbl *); int g2plan (double, struct plantbl *, double *); int g3plan (double, struct plantbl *, double *, int); #else int epsiln(); double cos (), sin (), floor (), fabs (); static int sscc (); #endif #define mods3600(x) ((x) - 1.296e6 * floor ((x)/1.296e6)) static double J2000 = 2451545.0; #if 0 /* Conversion factors between degrees and radians */ static double DTR = 1.7453292519943295769e-2; static double RTD = 5.7295779513082320877e1; static double RTS = 2.0626480624709635516e5; /* arc seconds per radian */ #endif static double STR = 4.8481368110953599359e-6; /* radians per arc second */ /* From Simon et al (1994) */ static double freqs[] = { /* Arc sec per 10000 Julian years. */ 53810162868.8982, 21066413643.3548, 12959774228.3429, 6890507749.3988, 1092566037.7991, 439960985.5372, 154248119.3933, 78655032.0744, 52272245.1795 }; static double phases[] = { /* Arc sec. */ 252.25090552 * 3600., 181.97980085 * 3600., 100.46645683 * 3600., 355.43299958 * 3600., 34.35151874 * 3600., 50.07744430 * 3600., 314.05500511 * 3600., 304.34866548 * 3600., 860492.1546, }; static double ss[NARGS][31]; static double cc[NARGS][31]; int gplan (J, plan, pobj) double J; struct plantbl *plan; double pobj[]; { register double su, cu, sv, cv, T; double t, sl, sb, sr; int i, j, k, m, n, k1, ip, np, nt; #ifdef _MSC_VER char FAR *p; double FAR *pl; double FAR *pb; double FAR *pr; #else /* On some systems such as Silicon Graphics, char is unsigned by default. */ #ifdef vax /* VAX CC rejects "signed char." */ char *p; #else #ifdef __STDC__ signed char *p; #else char *p; #endif #endif double *pl, *pb, *pr; #endif T = (J - J2000) / plan->timescale; n = plan->maxargs; /* Calculate sin( i*MM ), etc. for needed multiple angles. */ for (i = 0; i < n; i++) { if ((j = plan->max_harmonic[i]) > 0) { sr = (mods3600 (freqs[i] * T) + phases[i]) * STR; sscc (i, sr, j); } } /* Point to start of table of arguments. */ p = plan->arg_tbl; /* Point to tabulated cosine and sine amplitudes. */ #ifdef _MSC_VER pl = (double FAR *) plan->lon_tbl; pb = (double FAR *) plan->lat_tbl; pr = (double FAR *) plan->rad_tbl; #else pl = (double *) plan->lon_tbl; pb = (double *) plan->lat_tbl; pr = (double *) plan->rad_tbl; #endif sl = 0.0; sb = 0.0; sr = 0.0; for (;;) { /* argument of sine and cosine */ /* Number of periodic arguments. */ np = *p++; if (np < 0) break; if (np == 0) { /* It is a polynomial term. */ nt = *p++; /* Longitude polynomial. */ cu = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; } sl += mods3600 (cu); /* Latitude polynomial. */ cu = *pb++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pb++; } sb += cu; /* Radius polynomial. */ cu = *pr++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pr++; } sr += cu; continue; } k1 = 0; cv = 0.0; sv = 0.0; for (ip = 0; ip < np; ip++) { /* What harmonic. */ j = *p++; /* Which planet. */ m = *p++ - 1; if (j) { k = j; if (j < 0) k = -k; k -= 1; su = ss[m][k]; /* sin(k*angle) */ if (j < 0) su = -su; cu = cc[m][k]; if (k1 == 0) { /* set first angle */ sv = su; cv = cu; k1 = 1; } else { /* combine angles */ t = su * cv + cu * sv; cv = cu * cv - su * sv; sv = t; } } } /* Highest power of T. */ nt = *p++; /* Longitude. */ cu = *pl++; su = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; su = su * T + *pl++; } sl += cu * cv + su * sv; /* Latitiude. */ cu = *pb++; su = *pb++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pb++; su = su * T + *pb++; } sb += cu * cv + su * sv; /* Radius. */ cu = *pr++; su = *pr++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pr++; su = su * T + *pr++; } sr += cu * cv + su * sv; } pobj[0] = STR * sl; pobj[1] = STR * sb; pobj[2] = STR * plan->distance * sr + plan->distance; return (0); } /* Prepare lookup table of sin and cos ( i*Lj ) * for required multiple angles */ static int sscc (k, arg, n) int k; double arg; int n; { double cu, su, cv, sv, s; int i; su = sin (arg); cu = cos (arg); ss[k][0] = su; /* sin(L) */ cc[k][0] = cu; /* cos(L) */ sv = 2.0 * su * cu; cv = cu * cu - su * su; ss[k][1] = sv; /* sin(2L) */ cc[k][1] = cv; for (i = 2; i < n; i++) { s = su * cv + cu * sv; cv = cu * cv - su * sv; sv = s; ss[k][i] = sv; /* sin( i+1 L ) */ cc[k][i] = cv; } return (0); } /* Compute mean elements at Julian date J. */ static double Args[NARGS]; static double LP_equinox; static double NF_arcsec; static double Ea_arcsec; static double pA_precession; void mean_elements (J) double J; { double x, T, T2; /* Time variables. T is in Julian centuries. */ T = (J - 2451545.0) / 36525.0; T2 = T*T; /* Mean longitudes of planets (Simon et al, 1994) .047" subtracted from constant term for offset to DE403 origin. */ /* Mercury */ x = mods3600( 538101628.6889819 * T + 908103.213 ); x += (6.39e-6 * T - 0.0192789) * T2; Args[0] = STR * x; /* Venus */ x = mods3600( 210664136.4335482 * T + 655127.236 ); x += (-6.27e-6 * T + 0.0059381) * T2; Args[1] = STR * x; /* Earth */ x = mods3600( 129597742.283429 * T + 361679.198 ); x += (-5.23e-6 * T - 2.04411e-2 ) * T2; Ea_arcsec = x; Args[2] = STR * x; /* Mars */ x = mods3600( 68905077.493988 * T + 1279558.751 ); x += (-1.043e-5 * T + 0.0094264) * T2; Args[3] = STR * x; /* Jupiter */ x = mods3600( 10925660.377991 * T + 123665.420 ); x += ((((-3.4e-10 * T + 5.91e-8) * T + 4.667e-6) * T + 5.706e-5) * T - 3.060378e-1)*T2; Args[4] = STR * x; /* Saturn */ x = mods3600( 4399609.855372 * T + 180278.752 ); x += (((( 8.3e-10 * T - 1.452e-7) * T - 1.1484e-5) * T - 1.6618e-4) * T + 7.561614E-1)*T2; Args[5] = STR * x; /* Uranus */ x = mods3600( 1542481.193933 * T + 1130597.971 ) + (0.00002156*T - 0.0175083)*T2; Args[6] = STR * x; /* Neptune */ x = mods3600( 786550.320744 * T + 1095655.149 ) + (-0.00000895*T + 0.0021103)*T2; Args[7] = STR * x; /* Copied from cmoon.c, DE404 version. */ /* Mean elongation of moon = D */ x = mods3600( 1.6029616009939659e+09 * T + 1.0722612202445078e+06 ); x += (((((-3.207663637426e-013 * T + 2.555243317839e-011) * T + 2.560078201452e-009) * T - 3.702060118571e-005) * T + 6.9492746836058421e-03) * T /* D, t^3 */ - 6.7352202374457519e+00) * T2; /* D, t^2 */ Args[9] = STR * x; /* Mean distance of moon from its ascending node = F */ x = mods3600( 1.7395272628437717e+09 * T + 3.3577951412884740e+05 ); x += ((((( 4.474984866301e-013 * T + 4.189032191814e-011) * T - 2.790392351314e-009) * T - 2.165750777942e-006) * T - 7.5311878482337989e-04) * T /* F, t^3 */ - 1.3117809789650071e+01) * T2; /* F, t^2 */ NF_arcsec = x; Args[10] = STR * x; /* Mean anomaly of sun = l' (J. Laskar) */ x = mods3600(1.2959658102304320e+08 * T + 1.2871027407441526e+06); x += (((((((( 1.62e-20 * T - 1.0390e-17 ) * T - 3.83508e-15 ) * T + 4.237343e-13 ) * T + 8.8555011e-11 ) * T - 4.77258489e-8 ) * T - 1.1297037031e-5 ) * T + 8.7473717367324703e-05) * T - 5.5281306421783094e-01) * T2; Args[11] = STR * x; /* Mean anomaly of moon = l */ x = mods3600( 1.7179159228846793e+09 * T + 4.8586817465825332e+05 ); x += (((((-1.755312760154e-012 * T + 3.452144225877e-011) * T - 2.506365935364e-008) * T - 2.536291235258e-004) * T + 5.2099641302735818e-02) * T /* l, t^3 */ + 3.1501359071894147e+01) * T2; /* l, t^2 */ Args[12] = STR * x; /* Mean longitude of moon, re mean ecliptic and equinox of date = L */ x = mods3600( 1.7325643720442266e+09 * T + 7.8593980921052420e+05); x += ((((( 7.200592540556e-014 * T + 2.235210987108e-010) * T - 1.024222633731e-008) * T - 6.073960534117e-005) * T + 6.9017248528380490e-03) * T /* L, t^3 */ - 5.6550460027471399e+00) * T2; /* L, t^2 */ LP_equinox = x; Args[13] = STR * x; /* Precession of the equinox */ x = ((((((((( -8.66e-20*T - 4.759e-17)*T + 2.424e-15)*T + 1.3095e-12)*T + 1.7451e-10)*T - 1.8055e-8)*T - 0.0000235316)*T + 0.000076)*T + 1.105414)*T + 5028.791959)*T; /* Moon's longitude re fixed J2000 equinox. */ /* Args[13] -= x; */ pA_precession = STR * x; /* Free librations. */ /* longitudinal libration 2.891725 years */ x = mods3600( 4.48175409e7 * T + 8.060457e5 ); Args[14] = STR * x; /* libration P, 24.2 years */ x = mods3600( 5.36486787e6 * T - 391702.8 ); Args[15] = STR * x; #if 0 Args[16] = 0.0; #endif /* libration W, 74.7 years. */ x = mods3600( 1.73573e6 * T ); Args[17] = STR * x; } /* Generic program to accumulate sum of trigonometric series in three variables (e.g., longitude, latitude, radius) of the same list of arguments. */ int g3plan (J, plan, pobj, objnum) double J; struct plantbl *plan; double pobj[]; int objnum; { int i, j, k, m, n, k1, ip, np, nt; #ifdef _MSC_VER char FAR *p; long FAR *pl; long FAR *pb; long FAR *pr; #else /* On some systems such as Silicon Graphics, char is unsigned by default. */ #ifdef vax /* VAX CC rejects "signed char." */ char *p; #else #ifdef __STDC__ signed char *p; #else char *p; #endif #endif long *pl, *pb, *pr; #endif double su, cu, sv, cv; double T, t, sl, sb, sr; mean_elements (J); #if 0 /* For librations, moon's longitude is sidereal. */ if (flag) Args[13] -= pA_precession; #endif T = (J - J2000) / plan->timescale; n = plan->maxargs; /* Calculate sin( i*MM ), etc. for needed multiple angles. */ for (i = 0; i < n; i++) { if ((j = plan->max_harmonic[i]) > 0) { sscc (i, Args[i], j); } } /* Point to start of table of arguments. */ p = plan->arg_tbl; /* Point to tabulated cosine and sine amplitudes. */ #ifdef _MSC_VER pl = (long FAR *) plan->lon_tbl; pb = (long FAR *) plan->lat_tbl; pr = (long FAR *) plan->rad_tbl; #else pl = (long *) plan->lon_tbl; pb = (long *) plan->lat_tbl; pr = (long *) plan->rad_tbl; #endif sl = 0.0; sb = 0.0; sr = 0.0; for (;;) { /* argument of sine and cosine */ /* Number of periodic arguments. */ np = *p++; if (np < 0) break; if (np == 0) { /* It is a polynomial term. */ nt = *p++; /* "Longitude" polynomial (phi). */ cu = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; } /* sl += mods3600 (cu); */ sl += cu; /* "Latitude" polynomial (theta). */ cu = *pb++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pb++; } sb += cu; /* Radius polynomial (psi). */ cu = *pr++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pr++; } sr += cu; continue; } k1 = 0; cv = 0.0; sv = 0.0; for (ip = 0; ip < np; ip++) { /* What harmonic. */ j = *p++; /* Which planet. */ m = *p++ - 1; if (j) { /* k = abs (j); */ if (j < 0) k = -j; else k = j; k -= 1; su = ss[m][k]; /* sin(k*angle) */ if (j < 0) su = -su; cu = cc[m][k]; if (k1 == 0) { /* set first angle */ sv = su; cv = cu; k1 = 1; } else { /* combine angles */ t = su * cv + cu * sv; cv = cu * cv - su * sv; sv = t; } } } /* Highest power of T. */ nt = *p++; /* Longitude. */ cu = *pl++; su = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; su = su * T + *pl++; } sl += cu * cv + su * sv; /* Latitiude. */ cu = *pb++; su = *pb++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pb++; su = su * T + *pb++; } sb += cu * cv + su * sv; /* Radius. */ cu = *pr++; su = *pr++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pr++; su = su * T + *pr++; } sr += cu * cv + su * sv; } t = plan->trunclvl; pobj[0] = Args[objnum - 1] + STR * t * sl; pobj[1] = STR * t * sb; pobj[2] = plan->distance * (1.0 + STR * t * sr); return (0); } /* Generic program to accumulate sum of trigonometric series in two variables (e.g., longitude, radius) of the same list of arguments. */ int g2plan (J, plan, pobj) double J; struct plantbl *plan; double pobj[]; { int i, j, k, m, n, k1, ip, np, nt; #if _MSC_VER char FAR *p; long FAR *pl; long FAR *pr; #else /* On some systems such as Silicon Graphics, char is unsigned by default. */ #ifdef vax /* VAX CC rejects "signed char." */ char *p; #else #ifdef __STDC__ signed char *p; #else char *p; #endif #endif long *pl, *pr; #endif double su, cu, sv, cv; double T, t, sl, sr; mean_elements (J); #if 0 /* For librations, moon's longitude is sidereal. */ if (flag) Args[13] -= pA_precession; #endif T = (J - J2000) / plan->timescale; n = plan->maxargs; /* Calculate sin( i*MM ), etc. for needed multiple angles. */ for (i = 0; i < n; i++) { if ((j = plan->max_harmonic[i]) > 0) { sscc (i, Args[i], j); } } /* Point to start of table of arguments. */ p = plan->arg_tbl; /* Point to tabulated cosine and sine amplitudes. */ #ifdef _MSC_VER pl = (long FAR *) plan->lon_tbl; pr = (long FAR *) plan->rad_tbl; #else pl = (long *) plan->lon_tbl; pr = (long *) plan->rad_tbl; #endif sl = 0.0; sr = 0.0; for (;;) { /* argument of sine and cosine */ /* Number of periodic arguments. */ np = *p++; if (np < 0) break; if (np == 0) { /* It is a polynomial term. */ nt = *p++; /* Longitude polynomial. */ cu = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; } /* sl += mods3600 (cu); */ sl += cu; /* Radius polynomial. */ cu = *pr++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pr++; } sr += cu; continue; } k1 = 0; cv = 0.0; sv = 0.0; for (ip = 0; ip < np; ip++) { /* What harmonic. */ j = *p++; /* Which planet. */ m = *p++ - 1; if (j) { /* k = abs (j); */ if (j < 0) k = -j; else k = j; k -= 1; su = ss[m][k]; /* sin(k*angle) */ if (j < 0) su = -su; cu = cc[m][k]; if (k1 == 0) { /* set first angle */ sv = su; cv = cu; k1 = 1; } else { /* combine angles */ t = su * cv + cu * sv; cv = cu * cv - su * sv; sv = t; } } } /* Highest power of T. */ nt = *p++; /* Longitude. */ cu = *pl++; su = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; su = su * T + *pl++; } sl += cu * cv + su * sv; /* Radius. */ cu = *pr++; su = *pr++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pr++; su = su * T + *pr++; } sr += cu * cv + su * sv; } t = plan->trunclvl; pobj[0] = t * sl; pobj[2] = t * sr; return (0); } /* Generic program to accumulate sum of trigonometric series in one variable. */ double g1plan (J, plan) double J; struct plantbl *plan; { int i, j, k, m, k1, ip, np, nt; #ifdef _MSC_VER char FAR *p; long FAR *pl; #else /* On some systems such as Silicon Graphics, char is unsigned by default. */ #ifdef vax /* VAX CC rejects "signed char." */ char *p; #else #ifdef __STDC__ signed char *p; #else char *p; #endif #endif long *pl; #endif double su, cu, sv, cv; double T, t, sl; T = (J - J2000) / plan->timescale; mean_elements (J); /* Calculate sin( i*MM ), etc. for needed multiple angles. */ for (i = 0; i < NARGS; i++) { if ((j = plan->max_harmonic[i]) > 0) { sscc (i, Args[i], j); } } /* Point to start of table of arguments. */ p = plan->arg_tbl; /* Point to tabulated cosine and sine amplitudes. */ #ifdef _MSC_VER pl = (long FAR *) plan->lon_tbl; #else pl = (long *) plan->lon_tbl; #endif sl = 0.0; for (;;) { /* argument of sine and cosine */ /* Number of periodic arguments. */ np = *p++; if (np < 0) break; if (np == 0) { /* It is a polynomial term. */ nt = *p++; cu = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; } /* sl += mods3600 (cu); */ sl += cu; continue; } k1 = 0; cv = 0.0; sv = 0.0; for (ip = 0; ip < np; ip++) { /* What harmonic. */ j = *p++; /* Which planet. */ m = *p++ - 1; if (j) { /* k = abs (j); */ if (j < 0) k = -j; else k = j; k -= 1; su = ss[m][k]; /* sin(k*angle) */ if (j < 0) su = -su; cu = cc[m][k]; if (k1 == 0) { /* set first angle */ sv = su; cv = cu; k1 = 1; } else { /* combine angles */ t = su * cv + cu * sv; cv = cu * cv - su * sv; sv = t; } } } /* Highest power of T. */ nt = *p++; /* Cosine and sine coefficients. */ cu = *pl++; su = *pl++; for (ip = 0; ip < nt; ip++) { cu = cu * T + *pl++; su = su * T + *pl++; } sl += cu * cv + su * sv; } return (plan->trunclvl * sl); } /* Compute geocentric moon. */ extern struct plantbl moonlr, moonlat; extern double coseps, sineps; int gmoon (J, rect, pol) double J; double rect[], pol[]; { double x, cosB, sinB, cosL, sinL; g2plan (J, &moonlr, pol); x = pol[0]; x += LP_equinox; if (x < -6.48e5) x += 1.296e6; if (x > 6.48e5) x -= 1.296e6; pol[0] = STR * x; x = g1plan (J, &moonlat); pol[1] = STR * x; x = (1.0 + STR * pol[2]) * moonlr.distance; pol[2] = x; /* Convert ecliptic polar to equatorial rectangular coordinates. */ epsiln(J); cosB = cos(pol[1]); sinB = sin(pol[1]); cosL = cos(pol[0]); sinL = sin(pol[0]); rect[0] = cosB * cosL * x; rect[1] = (coseps * cosB * sinL - sineps * sinB) * x; rect[2] = (sineps * cosB * sinL + coseps * sinB) * x; return 0; }