allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/28/89)
Posting-number: Volume 9, Issue 41 Submitted-by: ecd@umn-cs.cs.umn.edu@ncs-med.UUCP (Elwood C. Downey) Archive-name: ephem2/part04 # This is a "shell archive" file; run it with sh. # This is file 4. echo x plans.c cat > plans.c << 'xXx' #include <stdio.h> #include <math.h> #include "astro.h" #define TWOPI (2*PI) #define mod2PI(x) ((x) - (int)((x)/TWOPI)*TWOPI) /* given a modified Julian date, mjd, and a planet, p, find: * lpd0: heliocentric longitude, * psi0: heliocentric latitude, * rp0: distance from the sun to the planet, * rho0: distance from the Earth to the planet, * none corrected for light time, ie, they are the true values for the * given instant. * lam: geocentric ecliptic longitude, * bet: geocentric ecliptic latitude, * each corrected for light time, ie, they are the apparent values as * seen from the center of the Earth for the given instant. * dia: angular diameter in arcsec at 1 AU, * mag: visual magnitude when 1 AU from sun and earth at 0 phase angle. * * all angles are in radians, all distances in AU. * the mean orbital elements are found by calling pelement(), then mutual * perturbation corrections are applied as necessary. * * corrections for nutation and abberation must be made by the caller. The RA * and DEC calculated from the fully-corrected ecliptic coordinates are then * the apparent geocentric coordinates. Further corrections can be made, if * required, for atmospheric refraction and geocentric parallax although the * intrinsic error herein of about 10 arcseconds is usually the dominant * error at this stage. * TODO: combine the several intermediate expressions when get a good compiler. */ plans (mjd, p, lpd0, psi0, rp0, rho0, lam, bet, dia, mag) double mjd; int p; double *lpd0, *psi0, *rp0, *rho0, *lam, *bet, *dia, *mag; { static double plan[8][9]; static lastmjd = -10000; double dl; /* perturbation correction for longitude */ double dr; /* " orbital radius */ double dml; /* " mean longitude */ double ds; /* " eccentricity */ double dm; /* " mean anomaly */ double da; /* " semi-major axis */ double dhl; /* " heliocentric longitude */ double lsn, rsn; /* true geocentric longitude of sun and sun-earth rad */ double mas; /* mean anomaly of the sun */ double re; /* radius of earth's orbit */ double lg; /* longitude of earth */ double map[8]; /* array of mean anomalies for each planet */ double lpd, psi, rp, rho; double ll, sll, cll; double t; double dt; int pass; int j; double s, ma; double nu, ea; double lp, om; double lo, slo, clo; double inc, y; double spsi, cpsi; double rpd; /* only need to fill in plan[] once for a given mjd */ if (mjd != lastmjd) { pelement (mjd, plan); lastmjd = mjd; } dt = 0; t = mjd/36525.; sunpos (mjd, &lsn, &rsn); masun (mjd, &mas); re = rsn; lg = lsn+PI; /* first find the true position of the planet at mjd. * then repeat a second time for a slightly different time based * on the position found in the first pass to account for light-travel * time. */ for (pass = 0; pass < 2; pass++) { for (j = 0; j < 8; j++) map[j] = degrad(plan[j][0]-plan[j][2]-dt*plan[j][1]); /* set initial corrections to 0. * then modify as necessary for the planet of interest. */ dl = 0; dr = 0; dml = 0; ds = 0; dm = 0; da = 0; dhl = 0; switch (p) { case MERCURY: p_mercury (map, &dl, &dr); break; case VENUS: p_venus (t, mas, map, &dl, &dr, &dml, &dm); break; case MARS: p_mars (mas, map, &dl, &dr, &dml, &dm); break; case JUPITER: p_jupiter (t, plan[p][3], &dml, &ds, &dm, &da); break; case SATURN: p_saturn (t, plan[p][3], &dml, &ds, &dm, &da, &dhl); break; case URANUS: p_uranus (t, plan[p][3], &dl, &dr, &dml, &ds, &dm, &da, &dhl); break; case NEPTUNE: p_neptune (t, plan[p][3], &dl, &dr, &dml, &ds, &dm, &da, &dhl); break; case PLUTO: /* no perturbation theory for pluto */ break; } s = plan[p][3]+ds; ma = map[p]+dm; anomaly (ma, s, &nu, &ea); rp = (plan[p][6]+da)*(1-s*s)/(1+s*cos(nu)); lp = raddeg(nu)+plan[p][2]+raddeg(dml-dm); lp = degrad(lp); om = degrad(plan[p][5]); lo = lp-om; slo = sin(lo); clo = cos(lo); inc = degrad(plan[p][4]); rp = rp+dr; spsi = slo*sin(inc); y = slo*cos(inc); psi = asin(spsi)+dhl; spsi = sin(psi); lpd = atan(y/clo)+om+degrad(dl); if (clo<0) lpd += PI; if (lpd>TWOPI) lpd -= TWOPI; cpsi = cos(psi); rpd = rp*cpsi; ll = lpd-lg; rho = sqrt(re*re+rp*rp-2*re*rp*cpsi*cos(ll)); /* when we view a planet we see it in the position it occupied * dt hours ago, where rho is the distance between it and earth, * in AU. use this as the new time for the next pass. */ dt = rho*5.775518e-3; if (pass == 0) { /* save heliocentric coordinates after first pass since, being * true, they are NOT to be corrected for light-travel time. */ *lpd0 = lpd; *psi0 = psi; *rp0 = rp; *rho0 = rho; } } sll = sin(ll); cll = cos(ll); if (p < MARS) *lam = atan(-1*rpd*sll/(re-rpd*cll))+lg+PI; else *lam = atan(re*sll/(rpd-re*cll))+lpd; range (lam, TWOPI); *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*re*sll)); *dia = plan[p][7]; *mag = plan[p][8]; } /* set auxilliary variables used for jupiter, saturn, uranus, and neptune */ static aux_jsun (t, j1, j2, j3, j4, j5, j6) double t; double *j1, *j2, *j3, *j4, *j5, *j6; { *j1 = t/5+0.1; *j2 = mod2PI(4.14473+5.29691e1*t); *j3 = mod2PI(4.641118+2.132991e1*t); *j4 = mod2PI(4.250177+7.478172*t); *j5 = 5 * *j3 - 2 * *j2; *j6 = 2 * *j2 - 6 * *j3 + 3 * *j4; } /* find the mean anomaly of the sun at mjd. * this is the same as that used in sun() but when it was converted to C it * was not known it would be required outside that routine. * TODO: add an argument to sun() to return mas and eliminate this routine. */ static masun (mjd, mas) double mjd; double *mas; { double t, t2; double a, b; t = mjd/36525; t2 = t*t; a = 9.999736042e1*t; b = 360.*(a-(int)a); *mas = degrad (3.5847583e2-(1.5e-4+3.3e-6*t)*t2+b); } /* perturbations for mercury */ static p_mercury (map, dl, dr) double map[]; double *dl, *dr; { *dl = 2.04e-3*cos(5*map[2-1]-2*map[1-1]+2.1328e-1)+ 1.03e-3*cos(2*map[2-1]-map[1-1]-2.8046)+ 9.1e-4*cos(2*map[3]-map[1-1]-6.4582e-1)+ 7.8e-4*cos(5*map[2-1]-3*map[1-1]+1.7692e-1); *dr = 7.525e-6*cos(2*map[3]-map[1-1]+9.25251e-1)+ 6.802e-6*cos(5*map[2-1]-3*map[1-1]-4.53642)+ 5.457e-6*cos(2*map[2-1]-2*map[1-1]-1.24246)+ 3.569e-6*cos(5*map[2-1]-map[1-1]-1.35699); } /* ....venus */ static p_venus (t, mas, map, dl, dr, dml, dm) double t, mas, map[]; double *dl, *dr, *dml, *dm; { *dml = degrad (7.7e-4*sin(4.1406+t*2.6227)); *dm = *dml; *dl = 3.13e-3*cos(2*mas-2*map[2-1]-2.587)+ 1.98e-3*cos(3*mas-3*map[2-1]+4.4768e-2)+ 1.36e-3*cos(mas-map[2-1]-2.0788)+ 9.6e-4*cos(3*mas-2*map[2-1]-2.3721)+ 8.2e-4*cos(map[3]-map[2-1]-3.6318); *dr = 2.2501e-5*cos(2*mas-2*map[2-1]-1.01592)+ 1.9045e-5*cos(3*mas-3*map[2-1]+1.61577)+ 6.887e-6*cos(map[3]-map[2-1]-2.06106)+ 5.172e-6*cos(mas-map[2-1]-5.08065e-1)+ 3.62e-6*cos(5*mas-4*map[2-1]-1.81877)+ 3.283e-6*cos(4*mas-4*map[2-1]+1.10851)+ 3.074e-6*cos(2*map[3]-2*map[2-1]-9.62846e-1); } /* ....mars */ static p_mars (mas, map, dl, dr, dml, dm) double mas, map[]; double *dl, *dr, *dml, *dm; { double a; a = 3*map[3]-8*map[2]+4*mas; *dml = degrad (-1*(1.133e-2*sin(a)+9.33e-3*cos(a))); *dm = *dml; *dl = 7.05e-3*cos(map[3]-map[2]-8.5448e-1)+ 6.07e-3*cos(2*map[3]-map[2]-3.2873)+ 4.45e-3*cos(2*map[3]-2*map[2]-3.3492)+ 3.88e-3*cos(mas-2*map[2]+3.5771e-1)+ 2.38e-3*cos(mas-map[2]+6.1256e-1)+ 2.04e-3*cos(2*mas-3*map[2]+2.7688)+ 1.77e-3*cos(3*map[2]-map[2-1]-1.0053)+ 1.36e-3*cos(2*mas-4*map[2]+2.6894)+ 1.04e-3*cos(map[3]+3.0749e-1); *dr = 5.3227e-5*cos(map[3]-map[2]+7.17864e-1)+ 5.0989e-5*cos(2*map[3]-2*map[2]-1.77997)+ 3.8278e-5*cos(2*map[3]-map[2]-1.71617)+ 1.5996e-5*cos(mas-map[2]-9.69618e-1)+ 1.4764e-5*cos(2*mas-3*map[2]+1.19768)+ 8.966e-6*cos(map[3]-2*map[2]+7.61225e-1); *dr += 7.914e-6*cos(3*map[3]-2*map[2]-2.43887)+ 7.004e-6*cos(2*map[3]-3*map[2]-1.79573)+ 6.62e-6*cos(mas-2*map[2]+1.97575)+ 4.93e-6*cos(3*map[3]-3*map[2]-1.33069)+ 4.693e-6*cos(3*mas-5*map[2]+3.32665)+ 4.571e-6*cos(2*mas-4*map[2]+4.27086)+ 4.409e-6*cos(3*map[3]-map[2]-2.02158); } /* ....jupiter */ static p_jupiter (t, s, dml, ds, dm, da) double t, s; double *dml, *ds, *dm, *da; { double dp; double j1, j2, j3, j4, j5, j6, j7; double sj3, cj3, s2j3, c2j3; double sj5, cj5, s2j5; double sj6; double sj7, cj7, s2j7, c2j7, s3j7, c3j7, s4j7, c4j7, c5j7; aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6); j7 = j3-j2; sj3 = sin(j3); cj3 = cos(j3); s2j3 = sin(2*j3); c2j3 = cos(2*j3); sj5 = sin(j5); cj5 = cos(j5); s2j5 = sin(2*j5); sj6 = sin(j6); sj7 = sin(j7); cj7 = cos(j7); s2j7 = sin(2*j7); c2j7 = cos(2*j7); s3j7 = sin(3*j7); c3j7 = cos(3*j7); s4j7 = sin(4*j7); c4j7 = cos(4*j7); c5j7 = cos(5*j7); *dml = (3.31364e-1-(1.0281e-2+4.692e-3*j1)*j1)*sj5+ (3.228e-3-(6.4436e-2-2.075e-3*j1)*j1)*cj5- (3.083e-3+(2.75e-4-4.89e-4*j1)*j1)*s2j5+ 2.472e-3*sj6+1.3619e-2*sj7+1.8472e-2*s2j7+6.717e-3*s3j7+ 2.775e-3*s4j7+6.417e-3*s2j7*sj3+ (7.275e-3-1.253e-3*j1)*sj7*sj3+ 2.439e-3*s3j7*sj3-(3.5681e-2+1.208e-3*j1)*sj7*cj3; *dml += -3.767e-3*c2j7*sj3-(3.3839e-2+1.125e-3*j1)*cj7*sj3- 4.261e-3*s2j7*cj3+ (1.161e-3*j1-6.333e-3)*cj7*cj3+ 2.178e-3*cj3-6.675e-3*c2j7*cj3-2.664e-3*c3j7*cj3- 2.572e-3*sj7*s2j3-3.567e-3*s2j7*s2j3+2.094e-3*cj7*c2j3+ 3.342e-3*c2j7*c2j3; *dml = degrad(*dml); *ds = (3606+(130-43*j1)*j1)*sj5+(1289-580*j1)*cj5-6764*sj7*sj3- 1110*s2j7*sj3-224*s3j7*sj3-204*sj3+(1284+116*j1)*cj7*sj3+ 188*c2j7*sj3+(1460+130*j1)*sj7*cj3+224*s2j7*cj3-817*cj3+ 6074*cj3*cj7+992*c2j7*cj3+ 508*c3j7*cj3+230*c4j7*cj3+108*c5j7*cj3; *ds += -(956+73*j1)*sj7*s2j3+448*s2j7*s2j3+137*s3j7*s2j3+ (108*j1-997)*cj7*s2j3+480*c2j7*s2j3+148*c3j7*s2j3+ (99*j1-956)*sj7*c2j3+490*s2j7*c2j3+ 158*s3j7*c2j3+179*c2j3+(1024+75*j1)*cj7*c2j3- 437*c2j7*c2j3-132*c3j7*c2j3; *ds *= 1e-7; dp = (7.192e-3-3.147e-3*j1)*sj5-4.344e-3*sj3+ (j1*(1.97e-4*j1-6.75e-4)-2.0428e-2)*cj5+ 3.4036e-2*cj7*sj3+(7.269e-3+6.72e-4*j1)*sj7*sj3+ 5.614e-3*c2j7*sj3+2.964e-3*c3j7*sj3+3.7761e-2*sj7*cj3+ 6.158e-3*s2j7*cj3- 6.603e-3*cj7*cj3-5.356e-3*sj7*s2j3+2.722e-3*s2j7*s2j3+ 4.483e-3*cj7*s2j3-2.642e-3*c2j7*s2j3+4.403e-3*sj7*c2j3- 2.536e-3*s2j7*c2j3+5.547e-3*cj7*c2j3-2.689e-3*c2j7*c2j3; *dm = *dml-(degrad(dp)/s); *da = 205*cj7-263*cj5+693*c2j7+312*c3j7+147*c4j7+299*sj7*sj3+ 181*c2j7*sj3+204*s2j7*cj3+111*s3j7*cj3-337*cj7*cj3- 111*c2j7*cj3; *da *= 1e-6; } /* ....saturn */ static p_saturn (t, s, dml, ds, dm, da, dhl) double t, s; double *dml, *ds, *dm, *da, *dhl; { double dp; double j1, j2, j3, j4, j5, j6, j7, j8; double sj3, cj3, s2j3, c2j3, s3j3, c3j3, s4j3, c4j3; double sj5, cj5, s2j5, c2j5; double sj6; double sj7, cj7, s2j7, c2j7, s3j7, c3j7, s4j7, c4j7, c5j7, s5j7; double s2j8, c2j8, s3j8, c3j8; aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6); j7 = j3-j2; sj3 = sin(j3); cj3 = cos(j3); s2j3 = sin(2*j3); c2j3 = cos(2*j3); sj5 = sin(j5); cj5 = cos(j5); s2j5 = sin(2*j5); sj6 = sin(j6); sj7 = sin(j7); cj7 = cos(j7); s2j7 = sin(2*j7); c2j7 = cos(2*j7); s3j7 = sin(3*j7); c3j7 = cos(3*j7); s4j7 = sin(4*j7); c4j7 = cos(4*j7); c5j7 = cos(5*j7); s3j3 = sin(3*j3); c3j3 = cos(3*j3); s4j3 = sin(4*j3); c4j3 = cos(4*j3); c2j5 = cos(2*j5); s5j7 = sin(5*j7); j8 = j4-j3; s2j8 = sin(2*j8); c2j8 = cos(2*j8); s3j8 = sin(3*j8); c3j8 = cos(3*j8); *dml = 7.581e-3*s2j5-7.986e-3*sj6-1.48811e-1*sj7-4.0786e-2*s2j7- (8.14181e-1-(1.815e-2-1.6714e-2*j1)*j1)*sj5- (1.0497e-2-(1.60906e-1-4.1e-3*j1)*j1)*cj5-1.5208e-2*s3j7- 6.339e-3*s4j7-6.244e-3*sj3-1.65e-2*s2j7*sj3+ (8.931e-3+2.728e-3*j1)*sj7*sj3-5.775e-3*s3j7*sj3+ (8.1344e-2+3.206e-3*j1)*cj7*sj3+1.5019e-2*c2j7*sj3; *dml += (8.5581e-2+2.494e-3*j1)*sj7*cj3+1.4394e-2*c2j7*cj3+ (2.5328e-2-3.117e-3*j1)*cj7*cj3+ 6.319e-3*c3j7*cj3+6.369e-3*sj7*s2j3+9.156e-3*s2j7*s2j3+ 7.525e-3*s3j8*s2j3-5.236e-3*cj7*c2j3-7.736e-3*c2j7*c2j3- 7.528e-3*c3j8*c2j3; *dml = degrad(*dml); *ds = (-7927+(2548+91*j1)*j1)*sj5+(13381+(1226-253*j1)*j1)*cj5+ (248-121*j1)*s2j5-(305+91*j1)*c2j5+412*s2j7+12415*sj3+ (390-617*j1)*sj7*sj3+(165-204*j1)*s2j7*sj3+26599*cj7*sj3- 4687*c2j7*sj3-1870*c3j7*sj3-821*c4j7*sj3- 377*c5j7*sj3+497*c2j8*sj3+(163-611*j1)*cj3; *ds += -12696*sj7*cj3-4200*s2j7*cj3-1503*s3j7*cj3-619*s4j7*cj3- 268*s5j7*cj3-(282+1306*j1)*cj7*cj3+(-86+230*j1)*c2j7*cj3+ 461*s2j8*cj3-350*s2j3+(2211-286*j1)*sj7*s2j3- 2208*s2j7*s2j3-568*s3j7*s2j3-346*s4j7*s2j3- (2780+222*j1)*cj7*s2j3+(2022+263*j1)*c2j7*s2j3+248*c3j7*s2j3+ 242*s3j8*s2j3+467*c3j8*s2j3-490*c2j3-(2842+279*j1)*sj7*c2j3; *ds += (128+226*j1)*s2j7*c2j3+224*s3j7*c2j3+ (-1594+282*j1)*cj7*c2j3+(2162-207*j1)*c2j7*c2j3+ 561*c3j7*c2j3+343*c4j7*c2j3+469*s3j8*c2j3-242*c3j8*c2j3- 205*sj7*s3j3+262*s3j7*s3j3+208*cj7*c3j3-271*c3j7*c3j3- 382*c3j7*s4j3-376*s3j7*c4j3; *ds *= 1e-7; dp = (7.7108e-2+(7.186e-3-1.533e-3*j1)*j1)*sj5-7.075e-3*sj7+ (4.5803e-2-(1.4766e-2+5.36e-4*j1)*j1)*cj5-7.2586e-2*cj3- 7.5825e-2*sj7*sj3-2.4839e-2*s2j7*sj3-8.631e-3*s3j7*sj3- 1.50383e-1*cj7*cj3+2.6897e-2*c2j7*cj3+1.0053e-2*c3j7*cj3- (1.3597e-2+1.719e-3*j1)*sj7*s2j3+1.1981e-2*s2j7*c2j3; dp += -(7.742e-3-1.517e-3*j1)*cj7*s2j3+ (1.3586e-2-1.375e-3*j1)*c2j7*c2j3- (1.3667e-2-1.239e-3*j1)*sj7*c2j3+ (1.4861e-2+1.136e-3*j1)*cj7*c2j3- (1.3064e-2+1.628e-3*j1)*c2j7*c2j3; *dm = *dml-(degrad(dp)/s); *da = 572*sj5-1590*s2j7*cj3+2933*cj5-647*s3j7*cj3+33629*cj7- 344*s4j7*cj3-3081*c2j7+2885*cj7*cj3-1423*c3j7+ (2172+102*j1)*c2j7*cj3-671*c4j7+296*c3j7*cj3-320*c5j7- 267*s2j7*s2j3+1098*sj3-778*cj7*s2j3-2812*sj7*sj3; *da += 495*c2j7*s2j3+688*s2j7*sj3+250*c3j7*s2j3-393*s3j7*sj3- 856*sj7*c2j3-228*s4j7*sj3+441*s2j7*c2j3+2138*cj7*sj3+ 296*c2j7*c2j3-999*c2j7*sj3+211*c3j7*c2j3-642*c3j7*sj3- 427*sj7*s3j3-325*c4j7*sj3+398*s3j7*s3j3-890*cj3+ 344*cj7*c3j3+2206*sj7*cj3-427*c3j7*c3j3; *da *= 1e-6; *dhl = 7.47e-4*cj7*sj3+1.069e-3*cj7*cj3+2.108e-3*s2j7*s2j3+ 1.261e-3*c2j7*s2j3+1.236e-3*s2j7*c2j3-2.075e-3*c2j7*c2j3; *dhl = degrad(*dhl); } /* ....uranus */ static p_uranus (t, s, dl, dr, dml, ds, dm, da, dhl) double t, s; double *dl, *dr, *dml, *ds, *dm, *da, *dhl; { double dp; double j1, j2, j3, j4, j5, j6; double j8, j9, j10, j11, j12; double sj4, cj4, s2j4, c2j4; double sj9, cj9, s2j9, c2j9; double sj11, cj11; aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6); j8 = mod2PI(1.46205+3.81337*t); j9 = 2*j8-j4; sj9 = sin(j9); cj9 = cos(j9); s2j9 = sin(2*j9); c2j9 = cos(2*j9); j10 = j4-j2; j11 = j4-j3; j12 = j8-j4; *dml = (8.64319e-1-1.583e-3*j1)*sj9+(8.2222e-2-6.833e-3*j1)*cj9+ 3.6017e-2*s2j9-3.019e-3*c2j9+8.122e-3*sin(j6); *dml = degrad(*dml); dp = 1.20303e-1*sj9+6.197e-3*s2j9+(1.9472e-2-9.47e-4*j1)*cj9; *dm = *dml-(degrad(dp)/s); *ds = (163*j1-3349)*sj9+20981*cj9+1311*c2j9; *ds *= 1e-7; *da = -3.825e-3*cj9; *dl = (1.0122e-2-9.88e-4*j1)*sin(j4+j11)+ (-3.8581e-2+(2.031e-3-1.91e-3*j1)*j1)*cos(j4+j11)+ (3.4964e-2-(1.038e-3-8.68e-4*j1)*j1)*cos(2*j4+j11)+ 5.594e-3*sin(j4+3*j12)-1.4808e-2*sin(j10)- 5.794e-3*sin(j11)+2.347e-3*cos(j11)+9.872e-3*sin(j12)+ 8.803e-3*sin(2*j12)-4.308e-3*sin(3*j12); sj11 = sin(j11); cj11 = cos(j11); sj4 = sin(j4); cj4 = cos(j4); s2j4 = sin(2*j4); c2j4 = cos(2*j4); *dhl = (4.58e-4*sj11-6.42e-4*cj11-5.17e-4*cos(4*j12))*sj4- (3.47e-4*sj11+8.53e-4*cj11+5.17e-4*sin(4*j11))*cj4+ 4.03e-4*(cos(2*j12)*s2j4+sin(2*j12)*c2j4); *dhl = degrad(*dhl); *dr = -25948+4985*cos(j10)-1230*cj4+3354*cos(j11)+904*cos(2*j12)+ 894*(cos(j12)-cos(3*j12))+(5795*cj4-1165*sj4+1388*c2j4)*sj11+ (1351*cj4+5702*sj4+1388*s2j4)*cos(j11); *dr *= 1e-6; } /* ....neptune */ static p_neptune (t, s, dl, dr, dml, ds, dm, da, dhl) double t, s; double *dl, *dr, *dml, *ds, *dm, *da, *dhl; { double dp; double j1, j2, j3, j4, j5, j6; double j8, j9, j10, j11, j12; double sj8, cj8; double sj9, cj9, s2j9, c2j9; double s2j12, c2j12; aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6); j8 = mod2PI(1.46205+3.81337*t); j9 = 2*j8-j4; sj9 = sin(j9); cj9 = cos(j9); s2j9 = sin(2*j9); c2j9 = cos(2*j9); j10 = j8-j2; j11 = j8-j3; j12 = j8-j4; *dml = (1.089e-3*j1-5.89833e-1)*sj9+(4.658e-3*j1-5.6094e-2)*cj9- 2.4286e-2*s2j9; *dml = degrad(*dml); dp = 2.4039e-2*sj9-2.5303e-2*cj9+6.206e-3*s2j9-5.992e-3*c2j9; *dm = *dml-(degrad(dp)/s); *ds = 4389*sj9+1129*s2j9+4262*cj9+1089*c2j9; *ds *= 1e-7; *da = 8189*cj9-817*sj9+781*c2j9; *da *= 1e-6; s2j12 = sin(2*j12); c2j12 = cos(2*j12); sj8 = sin(j8); cj8 = cos(j8); *dl = -9.556e-3*sin(j10)-5.178e-3*sin(j11)+2.572e-3*s2j12- 2.972e-3*c2j12*sj8-2.833e-3*s2j12*cj8; *dhl = 3.36e-4*c2j12*sj8+3.64e-4*s2j12*cj8; *dhl = degrad(*dhl); *dr = -40596+4992*cos(j10)+2744*cos(j11)+2044*cos(j12)+1051*c2j12; *dr *= 1e-6; } xXx echo x plot.c cat > plot.c << 'xXx' /* code to support the plotting capabilities. * idea is to let the operator name a plot file and mark some fields for * logging. then after each screen update, the logged fields are written to * the plot file. later, the file may be plotted (very simplistically by * ephem, for now anyway, or by some other program entirely.). * * format of the plot file is one line per coordinate: label,x,y * if z was specified, it is a fourth field. * x,y,z are plotted using %g format. */ #include <stdio.h> #include <math.h> #include "screen.h" extern errno; extern char *sys_errlist[]; #define errsys (sys_errlist[errno]) #define TRACE(x) {FILE *fp = fopen("trace","a"); fprintf x; fclose(fp);} #define MAXPLTLINES 10 /* max number of labeled lines we can track. * note we can't store more than NFLOGS fields * anyway (see flog.c). */ #define FNLEN (14+1) /* longest filename; plus 1 for \0 */ static char plt_filename[FNLEN] = "ephem.plt"; /* default plot file name */ static FILE *plt_fp; /* the plot file; == 0 means don't plot */ /* store the label and rcfpack()s for each line to track. */ typedef struct { char pl_label; int pl_rcpx, pl_rcpy, pl_rcpz; } PltLine; static PltLine pltlines[MAXPLTLINES]; static int npltlines; /* number of pltlines[] in actual use */ static int plt_in_polar; /*if true plot in polar coords, else cartesian*/ /* picked the Plot label: * if on, just turn it off. * if off, turn on, define fields or select name of file to plot and do it. * TODO: more flexability, more relevance. */ plot_setup() { if (plt_fp) { plt_turn_off(); plot_prstate (0); } else { static char *chcs[4] = { "Select fields", "Display a plot file", (char *)0, "Begin plotting" }; int ff = 0; ask: chcs[2] = plt_in_polar ? "Polar coords" : "Cartesian coords"; switch (popup(chcs, ff, npltlines > 0 ? 4 : 3)) { case 0: plt_select_fields(); break; case 1: plt_file(); break; case 2: plt_in_polar ^= 1; ff = 2; goto ask; case 3: plt_turn_on(); break; } } } /* write the active plotfields to the current plot file, if one is open. */ plot() { if (plt_fp) { PltLine *plp; double x, y, z; for (plp = &pltlines[npltlines]; --plp >= pltlines; ) { if (flog_get (plp->pl_rcpx, &x) == 0 && flog_get (plp->pl_rcpy, &y) == 0) { fprintf (plt_fp, "%c,%.12g,%.12g", plp->pl_label, x, y); if (flog_get (plp->pl_rcpz, &z) == 0) fprintf (plt_fp, ",%.12g", z); fprintf (plt_fp, "\n"); } } } } plot_prstate (force) int force; { static last; int this = plt_fp != 0; if (force || this != last) { f_string (R_PLOT, C_PLOTV, this ? " on" : "off"); last = this; } } plot_ison() { return (plt_fp != 0); } static plt_reset() { PltLine *plp; for (plp = &pltlines[npltlines]; --plp >= pltlines; ) { (void) flog_delete (plp->pl_rcpx); (void) flog_delete (plp->pl_rcpy); (void) flog_delete (plp->pl_rcpz); plp->pl_rcpx = plp->pl_rcpy = plp->pl_rcpz = 0; } npltlines = 0; } /* let operator select the fields he wants to plot. * register them with flog and keep rcfpack() in pltlines[] array. */ static plt_select_fields() { static char hlp[] = "move and RETURN to select a field, or q to quit"; static char sry[] = "Sorry; can not log any more fields."; int r = R_UT, c = C_UTV; /* TODO: start where main was? */ char buf[64]; int rcp; int i; plt_reset(); for (i = 0; i < MAXPLTLINES; i++) { sprintf (buf, "select x field for line %d", i+1); rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp); if (!rcp) break; pltlines[i].pl_rcpx = rcp; if (flog_add (rcp) < 0) { f_msg (sry); break; } sprintf (buf, "select y field for line %d", i+1); r = unpackr (rcp); c = unpackc (rcp); rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp); if (!rcp) { (void) flog_delete (pltlines[i].pl_rcpx); break; } if (flog_add (rcp) < 0) { (void) flog_delete (pltlines[i].pl_rcpx); f_msg (sry); break; } pltlines[i].pl_rcpy = rcp; sprintf (buf, "select z field for line %d", i+1); r = unpackr (rcp); c = unpackc (rcp); rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp); if (rcp) { if (flog_add (rcp) < 0) { (void) flog_delete (pltlines[i].pl_rcpx); (void) flog_delete (pltlines[i].pl_rcpy); f_msg (sry); break; } pltlines[i].pl_rcpz = rcp; r = unpackr (rcp); c = unpackc (rcp); } do { sprintf (buf, "enter a one-character label for line %d: ", i+1); f_prompt (buf); } while (read_line (buf, 1) != 1); pltlines[i].pl_label = *buf; } npltlines = i; } static plt_turn_off () { fclose (plt_fp); plt_fp = 0; plot_prstate(0); } /* turn on plotting. * establish a file to use (and thereby set plt_fp, the plotting_is_on flag). * also check that there is a srch function if it is being plotted. */ static plt_turn_on () { int sf = rcfpack(R_SRCH, C_SRCH, 0); char fn[FNLEN], fnq[64]; char *optype; int n; PltLine *plp; /* insure there is a valid srch function if we are to plot it */ for (plp = &pltlines[npltlines]; --plp >= pltlines; ) if ((plp->pl_rcpx == sf || plp->pl_rcpy == sf || plp->pl_rcpz == sf) && !prog_isgood()) { f_msg ("Plotting search function but it is not defined."); return; } /* prompt for file name, giving current as default */ sprintf (fnq, "file to write <%s>: ", plt_filename); f_prompt (fnq); n = read_line (fn, sizeof(fn)-1); /* leave plotting off if type END. * reuse same fn if just type \n */ if (n < 0) return; if (n > 0) strcpy (plt_filename, fn); /* give option to append if file already exists */ optype = "w"; if (access (plt_filename, 2) == 0) { while (1) { f_prompt ("files exists; append or overwrite (a/o)?: "); n = read_char(); if (n == 'a') { optype = "a"; break; } if (n == 'o') break; } } /* plotting is on if file opens ok */ plt_fp = fopen (plt_filename, optype); if (!plt_fp) { char buf[NC]; sprintf (buf, "can not open %s: %s", plt_filename, errsys); f_prompt (buf); (void)read_char(); } plot_prstate (0); } /* ask operator for a file to plot. if it's ok, do it. */ static plt_file () { char fn[FNLEN], fnq[64]; FILE *pfp; int n; /* prompt for file name, giving current as default */ sprintf (fnq, "file to read <%s>: ", plt_filename); f_prompt (fnq); n = read_line (fn, sizeof(fn)-1); /* forget it if type END. * reuse same fn if just type \n */ if (n < 0) return; if (n > 0) strcpy (plt_filename, fn); /* do the plot if file opens ok */ pfp = fopen (plt_filename, "r"); if (pfp) { if (plt_in_polar) plot_polar (pfp); else plot_cartesian (pfp); fclose (pfp); } else { char buf[NC]; sprintf (buf, "can not open %s: %s", plt_filename, errsys); f_prompt (buf); (void)read_char(); } } /* plot the given file on the screen in cartesian coords. * TODO: add z tags somehow * N.B. do whatever you like but redraw the screen when done. */ static plot_cartesian (pfp) FILE *pfp; { static char fmt[] = "%c,%F,%F"; double x, y; /* N.B. be sure these match what your scanf's %F wants*/ double minx, maxx, miny, maxy; char buf[128]; int npts = 0; char c; /* find ranges and number of points */ while (fgets (buf, sizeof(buf), pfp)) { sscanf (buf, fmt, &c, &x, &y); if (npts++ == 0) { maxx = minx = x; maxy = miny = y; } else { if (x > maxx) maxx = x; else if (x < minx) minx = x; if (y > maxy) maxy = y; else if (y < miny) miny = y; } } #define SMALL (1e-10) if (npts < 2 || fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL) f_prompt ("At least two different points required to plot."); else { /* read file again, this time plotting */ rewind (pfp); c_erase(); while (fgets (buf, sizeof(buf), pfp)) { int row, col; sscanf (buf, fmt, &c, &x, &y); row = NR-(int)((NR-1)*(y-miny)/(maxy-miny)+0.5); col = 1+(int)((NC-1)*(x-minx)/(maxx-minx)+0.5); if (row == NR && col == NC) col--; /* avoid lower right scrolling corner */ f_char (row, col, c); } /* label axes */ f_double (1, 1, "%.2g", maxy); f_double (NR-1, 1, "%.2g", miny); f_double (NR, 1, "%.2g", minx); f_double (NR, NC-10, "%.2g", maxx); } /* hit any key to resume... */ (void) read_char(); redraw_screen (2); /* full redraw */ } /* plot the given file on the screen in polar coords. * first numberic field in plot file is r, second is theta in degrees. * TODO: add z tags somehow * N.B. do whatever you like but redraw the screen when done. */ static plot_polar (pfp) FILE *pfp; { static char fmt[] = "%c,%F,%F"; double r, th; /* N.B. be sure these match what your scanf's %F wants*/ double maxr; char buf[128]; int npts = 0; char c; /* find ranges and number of points */ while (fgets (buf, sizeof(buf), pfp)) { sscanf (buf, fmt, &c, &r, &th); if (npts++ == 0) maxr = r; else if (r > maxr) maxr = r; } if (npts < 2) f_prompt ("At least two points required to plot."); else { /* read file again, this time plotting */ rewind (pfp); c_erase(); while (fgets (buf, sizeof(buf), pfp)) { int row, col; double x, y; sscanf (buf, fmt, &c, &r, &th); x = r * cos(th/57.2958); /* degs to rads */ y = r * sin(th/57.2958); row = NR-(int)((NR-1)*(y+maxr)/(2.0*maxr)+0.5); col = 1+(int)((NC-1)*(x+maxr)/(2.0*maxr)/ASPECT+0.5); if (row == NR && col == NC) col--; /* avoid lower right scrolling corner */ f_char (row, col, c); } /* label radius */ f_double (NR/2, NC-10, "%.4g", maxr); } /* hit any key to resume... */ (void) read_char(); redraw_screen (2); /* full redraw */ } xXx echo x popup.c cat > popup.c << 'xXx' /* put up a one-line menu consisting of the given fields and let op move * between them with the same methods as sel_fld(). * return index of which he picked, or -1 if hit END. */ #include <stdio.h> #include "screen.h" #define FLDGAP 2 /* inter-field gap */ #define MAXFLDS 32 /* max number of fields we can handle */ static char pup[] = "Select: "; /* put up an array of strings on prompt line and let op pick one. * start with field fn. * N.B. we do not do much error/bounds checking. */ popup (fields, fn, nfields) char *fields[]; int fn; int nfields; { int fcols[MAXFLDS]; /* column to use for each field */ int i; if (nfields > MAXFLDS) return (-1); again: /* erase the prompt line; we are going to take it over */ c_pos (R_PROMPT, C_PROMPT); c_eol(); /* compute starting column for each field */ fcols[0] = sizeof(pup); for (i = 1; i < nfields; i++) fcols[i] = fcols[i-1] + strlen (fields[i-1]) + FLDGAP; /* draw each field, with comma after all but last */ c_pos (R_PROMPT, 1); fputs (pup, stdout); for (i = 0; i < nfields; i++) { c_pos (R_PROMPT, fcols[i]); printf (i < nfields-1 ? "%s," : "%s", fields[i]); } /* let op choose one now; begin at fn. */ i = fn; while (1) { c_pos (R_PROMPT, fcols[i]); switch (read_char()) { case END: return (-1); case REDRAW: redraw_screen(2); goto again; case VERSION: version(); goto again; case '\r': return (i); case 'h': if (--i < 0) i = nfields - 1; break; case 'l': if (++i >= nfields) i = 0; break; } } } xXx echo x precess.c cat > precess.c << 'xXx' #include <stdio.h> #include <math.h> #include "astro.h" /* corrects ra and dec, both in radians, for precession from epoch 1 to epoch 2. * the epochs are given by their modified JDs, mjd1 and mjd2, respectively. * N.B. ra and dec are modifed IN PLACE. */ precess (mjd1, mjd2, ra, dec) double mjd1, mjd2; /* initial and final epoch modified JDs */ double *ra, *dec; /* ra/dec for mjd1 in, for mjd2 out */ { static double lastmjd1, lastmjd2; static double m, n, nyrs; double dra, ddec; /* ra and dec corrections */ if (mjd1 != lastmjd1 || mjd2 != lastmjd2) { double t1, t2; /* Julian centuries of 36525 days since Jan .5 1900 */ double m1, n1; /* "constants" for t1 */ double m2, n2; /* "constants" for t2 */ t1 = mjd1/36525.; t2 = mjd2/36525.; m1 = 3.07234+(1.86e-3*t1); n1 = 20.0468-(8.5e-3*t1); m2 = 3.07234+(1.86e-3*t2); n2 = 20.0468-(8.5e-3*t2); m = (m1+m2)/2; /* average m for the two epochs */ n = (n1+n2)/2; /* average n for the two epochs */ nyrs = (mjd2-mjd1)/365.2425; lastmjd1 = mjd1; lastmjd2 = mjd2; } dra = (m+(n*sin(*ra)*tan(*dec)/15))*7.272205e-5*nyrs; ddec = n*cos(*ra)*4.848137e-6*nyrs; *ra += dra; *dec += ddec; range (ra, 2*PI); } xXx echo x refract.c cat > refract.c << 'xXx' #include <stdio.h> #include <math.h> #include "astro.h" /* correct the true altitude, ta, for refraction to the apparent altitude, aa, * each in radians, given the local atmospheric pressure, pr, in mbars, and * the temperature, tr, in degrees C. */ refract (pr, tr, ta, aa) double pr, tr; double ta; double *aa; { double r; /* refraction correction*/ if (ta >= degrad(15.)) { /* model for altitudes at least 15 degrees above horizon */ r = 7.888888e-5*pr/((273+tr)*tan(ta)); } else if (ta > degrad(-5.)) { /* hairier model for altitudes at least -5 and below 15 degrees */ double a, b, tadeg = raddeg(ta); a = ((2e-5*tadeg+1.96e-2)*tadeg+1.594e-1)*pr; b = (273+tr)*((8.45e-2*tadeg+5.05e-1)*tadeg+1); r = degrad(a/b); } else { /* do nothing if more than 5 degrees below horizon. */ r = 0; } *aa = ta + r; } /* correct the apparent altitude, aa, for refraction to the true altitude, ta, * each in radians, given the local atmospheric pressure, pr, in mbars, and * the temperature, tr, in degrees C. */ unrefract (pr, tr, aa, ta) double pr, tr; double aa; double *ta; { double err; double appar; double true; /* iterative solution: search for the true that refracts to the * given apparent. * since refract() is discontinuous at -5 degrees, there is a range * of apparent altitudes between about -4.5 and -5 degrees that are * not invertable (the graph of ap vs. true has a vertical step at * true = -5). thus, the iteration just oscillates if it gets into * this region. if this happens the iteration is forced to abort. * of course, this makes unrefract() discontinuous too. */ true = aa; do { refract (pr, tr, true, &appar); err = appar - aa; true -= err; } while (fabs(err) >= 1e-6 && true > degrad(-5)); *ta = true; } xXx echo x riset.c cat > riset.c << 'xXx' #include <stdio.h> #include <math.h> #include "astro.h" /* given the true geocentric ra and dec of an object, in radians, the observer's * latitude in radians, and a horizon displacement correction, dis, in radians * find the local sidereal times and azimuths of rising and setting, lstr/s * and azr/s, in radians, respectively. * dis is the vertical displacement from the true position of the horizon. it * is positive if the apparent position is higher than the true position. * said another way, it is positive if the shift causes the object to spend * longer above the horizon. for example, atmospheric refraction is typically * assumed to produce a vertical shift of 34 arc minutes at the horizon; dis * would then take on the value +9.89e-3 (radians). On the other hand, if * your horizon has hills such that your apparent horizon is, say, 1 degree * above sea level, you would allow for this by setting dis to -1.75e-2 * (radians). * status: 0: normal; 1: never rises; -1: circumpolar; 2: trouble. */ riset (ra, dec, lat, dis, lstr, lsts, azr, azs, status) double ra, dec; double lat, dis; double *lstr, *lsts; double *azr, *azs; int *status; { static double lastlat = 0, slat = 0, clat = 1.0; double dec1, sdec, cdec, tdec; double psi, spsi, cpsi; double h, dh, ch; /* hr angle, delta and cos */ /* avoid needless sin/cos since latitude doesn't change often */ if (lat != lastlat) { clat = cos(lat); slat = sin(lat); lastlat = lat; } /* can't cope with objects very near the celestial pole nor if we * are located very near the earth's poles. */ cdec = cos(dec); if (fabs(cdec*clat) < 1e-10) { /* trouble */ *status = 2; return; } cpsi = slat/cdec; if (cpsi>1.0) cpsi = 1.0; else if (cpsi<-1.0) cpsi = -1.0; psi = acos(cpsi); spsi = sin(psi); dh = dis*spsi; dec1 = dec + (dis*cpsi); sdec = sin(dec1); tdec = tan(dec1); ch = (-1*slat*tdec)/clat; if (ch < -1) { /* circumpolar */ *status = -1; return; } if (ch > 1) { /* never rises */ *status = 1; return; } *status = 0; h = acos(ch)+dh; *lstr = 24+radhr(ra-h); *lsts = radhr(ra+h); range (lstr, 24.0); range (lsts, 24.0); *azr = acos(sdec/clat); range (azr, 2*PI); *azs = 2*PI - *azr; } xXx echo x riset_c.c cat > riset_c.c << 'xXx' /* find rise and set circumstances, ie, riset_cir() and related functions. */ #include <stdio.h> #include <math.h> #include "astro.h" #include "circum.h" #include "screen.h" /* just for SUN and MOON */ #define TRACE(x) {FILE *fp = fopen("trace","a"); fprintf x; fclose(fp);} #define STDREF degrad(34./60.) /* nominal horizon refraction amount */ #define TWIREF degrad(18.) /* twilight horizon displacement */ /* find where and when a body, p, will rise and set and * its transit circumstances. all times are local, angles rads e of n. * return 0 if just returned same stuff as previous call, else 1 if new. * status is set from the RS_* #defines in circum.h. * also used to find astro twilight by calling with dis of 18 degrees. */ riset_cir (p, np, hzn, ltr, lts, ltt, azr, azs, altt, status) int p; /* one of the body defines in astro.h or screen.h */ Now *np; int hzn; /* STDHZN or ADPHZN or TWILIGHT */ double *ltr, *lts; /* local rise and set times */ double *ltt; /* local transit time */ double *azr, *azs; /* local rise and set azimuths, rads e of n */ double *altt; /* local altitude at transit */ int *status; /* one or more of the RS_* defines */ { typedef struct { Now l_now; double l_ltr, l_lts, l_ltt, l_azr, l_azs, l_altt; int l_hzn; int l_status; } Last; /* must be in same order as the astro.h/screen.h #define's */ static Last last[NOBJ]; Last *lp; int new; lp = last + p; if (same_cir (np, &lp->l_now) && same_lday (np, &lp->l_now) && lp->l_hzn == hzn) { *ltr = lp->l_ltr; *lts = lp->l_lts; *ltt = lp->l_ltt; *azr = lp->l_azr; *azs = lp->l_azs; *altt = lp->l_altt; *status = lp->l_status; new = 0; } else { *status = 0; iterative_riset (p, np, hzn, ltr, lts, ltt, azr, azs, altt, status); lp->l_ltr = *ltr; lp->l_lts = *lts; lp->l_ltt = *ltt; lp->l_azr = *azr; lp->l_azs = *azs; lp->l_altt = *altt; lp->l_status = *status; lp->l_hzn = hzn; lp->l_now = *np; new = 1; } return (new); } static iterative_riset (p, np, hzn, ltr, lts, ltt, azr, azs, altt, status) int p; Now *np; int hzn; double *ltr, *lts, *ltt; /* local times of rise, set and transit */ double *azr, *azs, *altt;/* local azimuths of rise, set and transit altitude */ int *status; { #define MAXPASSES 6 double lstr, lsts, lstt; /* local sidereal times of rising/setting */ double mjd0; /* mjd estimates of rise/set event */ double lnoon; /* mjd of local noon */ double x; /* discarded tmp value */ Now n; /* just used to call now_lst() */ double lst; /* lst at local noon */ double diff, lastdiff; /* iterative improvement to mjd0 */ int pass; int rss; /* first approximation is to find rise/set times of a fixed object * in its position at local noon. */ lnoon = mjd_day(mjd - tz/24.0) + (12.0 + tz)/24.0; /*mjd of local noon*/ n.n_mjd = lnoon; n.n_lng = lng; now_lst (&n, &lst); /* lst at local noon */ mjd0 = lnoon; stationary_riset (p,mjd0,np,hzn,&lstr,&lsts,&lstt,&x,&x,&x,&rss); chkrss: switch (rss) { case 0: break; case 1: *status = RS_NEVERUP; return; case -1: *status = RS_CIRCUMPOLAR; goto transit; default: *status = RS_ERROR; return; } /* find a better approximation to the rising circumstances based on * more passes, each using a "fixed" object at the location at * previous approximation of the rise time. */ lastdiff = 1000.0; for (pass = 1; pass < MAXPASSES; pass++) { diff = (lstr - lst)*SIDRATE; /* next guess at rise time wrt noon */ if (diff > 12.0) diff -= 24.0*SIDRATE; /* not tomorrow, today */ else if (diff < -12.0) diff += 24.0*SIDRATE; /* not yesterday, today */ mjd0 = lnoon + diff/24.0; /* next guess at mjd of rise */ stationary_riset (p,mjd0,np,hzn,&lstr,&x,&x,azr,&x,&x,&rss); if (rss != 0) goto chkrss; if (fabs (diff - lastdiff) < 0.25/60.0) break; /* converged to better than 15 secs */ lastdiff = diff; } if (pass == MAXPASSES) *status |= RS_NORISE; /* didn't converge - no rise today */ else { *ltr = 12.0 + diff; if (p != MOON && (*ltr <= 24.0*(1.0-SIDRATE) || *ltr >= 24.0*SIDRATE)) *status |= RS_2RISES; } /* find a better approximation to the setting circumstances based on * more passes, each using a "fixed" object at the location at * previous approximation of the set time. */ lastdiff = 1000.0; for (pass = 1; pass < MAXPASSES; pass++) { diff = (lsts - lst)*SIDRATE; /* next guess at set time wrt noon */ if (diff > 12.0) diff -= 24.0*SIDRATE; /* not tomorrow, today */ else if (diff < -12.0) diff += 24.0*SIDRATE; /* not yesterday, today */ mjd0 = lnoon + diff/24.0; /* next guess at mjd of set */ stationary_riset (p,mjd0,np,hzn,&x,&lsts,&x,&x,azs,&x,&rss); if (rss != 0) goto chkrss; if (fabs (diff - lastdiff) < 0.25/60.0) break; /* converged to better than 15 secs */ lastdiff = diff; } if (pass == MAXPASSES) *status |= RS_NOSET; /* didn't converge - no set today */ else { *lts = 12.0 + diff; if (p != MOON && (*lts <= 24.0*(1.0-SIDRATE) || *lts >= 24.0*SIDRATE)) *status |= RS_2SETS; } transit: /* find a better approximation to the transit circumstances based on * more passes, each using a "fixed" object at the location at * previous approximation of the transit time. */ lastdiff = 1000.0; for (pass = 1; pass < MAXPASSES; pass++) { diff = (lstt - lst)*SIDRATE; /*next guess at transit time wrt noon*/ if (diff > 12.0) diff -= 24.0*SIDRATE; /* not tomorrow, today */ else if (diff < -12.0) diff += 24.0*SIDRATE; /* not yesterday, today */ mjd0 = lnoon + diff/24.0; /* next guess at mjd of set */ stationary_riset (p,mjd0,np,hzn,&x,&x,&lstt,&x,&x,altt,&rss); if (fabs (diff - lastdiff) < 0.25/60.0) break; /* converged to better than 15 secs */ lastdiff = diff; } if (pass == MAXPASSES || rss != 0) *status |= RS_NOTRANS; /* didn't converge - no transit today */ else { *ltt = 12.0 + diff; if (p != MOON && (*ltt <= 24.0*(1.0-SIDRATE) || *ltt >= 24.0*SIDRATE)) *status |= RS_2TRANS; } } static stationary_riset (p, mjd0, np, hzn, lstr, lsts, lstt, azr, azs, altt, status) int p; double mjd0; Now *np; int hzn; double *lstr, *lsts, *lstt; double *azr, *azs, *altt; int *status; { double dis; Now n; Sky s; switch (hzn) { case STDHZN: /* nominal atmospheric refraction. * then add nominal moon or sun semi-diameter, as appropriate. */ dis = STDREF; break; case TWILIGHT: if (p != SUN) { c_erase(); printf ("BUG 1!\n\r"); exit(1); } dis = TWIREF; break; default: /* horizon displacement is refraction plus object's semi-diameter */ unrefract (pressure, temp, 0.0, &dis); dis = -dis; n = *np; n.n_mjd = mjd0; (void) body_cir (p, 0.0, &n, &s); dis += degrad(s.s_size/3600./2.0); } switch (p) { case SUN: if (hzn == STDHZN) dis += degrad (32./60./2.); fixedsunriset (mjd0,np,dis,lstr,lsts,lstt,azr,azs,altt,status); break; case MOON: if (hzn == STDHZN) dis += degrad (32./60./2.); fixedmoonriset (mjd0,np,dis,lstr,lsts,lstt,azr,azs,altt,status); break; default: if (hzn == STDHZN) { /* assume planets have negligible diameters. * also, need to set s if hzn was STDHZN. */ n = *np; n.n_mjd = mjd0; (void) body_cir (p, 0.0, &n, &s); } riset (s.s_ra, s.s_dec, lat, dis, lstr, lsts, azr, azs, status); transit (s.s_ra, s.s_dec, np, lstt, altt); } } /* find the local rise/set sidereal times and azimuths of an object fixed * at the ra/dec of the sun on the given mjd time as seen from lat. * times are for the upper limb. dis should account for refraction and * sun's semi-diameter; we add corrections for nutation and aberration. */ static fixedsunriset (mjd0, np, dis, lstr, lsts, lstt, azr, azs, altt, status) double mjd0; Now *np; double dis; double *lstr, *lsts, *lstt; double *azr, *azs, *altt; int *status; { double lsn, rsn; double deps, dpsi; double r, d; /* find ecliptic position of sun at mjd */ sunpos (mjd0, &lsn, &rsn); /* allow for 20.4" aberation and nutation */ nutation (mjd0, &deps, &dpsi); lsn += dpsi - degrad(20.4/3600.0); /* convert ecliptic to equatorial coords */ ecl_eq (mjd0, 0.0, lsn, &r, &d); /* find circumstances for given horizon displacement */ riset (r, d, lat, dis, lstr, lsts, azr, azs, status); transit (r, d, np, lstt, altt); } /* find the local sidereal rise/set times and azimuths of an object fixed * at the ra/dec of the moon on the given mjd time as seen from lat. * times are for the upper limb. dis should account for refraction and moon's * semi-diameter; we add corrections for parallax, and nutation. * accuracy is to nearest minute. */ static fixedmoonriset (mjd0, np, dis, lstr, lsts, lstt, azr, azs, altt, status) double mjd0; Now *np; double dis; double *lstr, *lsts, *lstt; double *azr, *azs, *altt; int *status; { double lam, bet, hp; double deps, dpsi; double r, d; double ha; /* find geocentric ecliptic location and equatorial horizontal parallax * of moon at mjd. */ moon (mjd0, &lam, &bet, &hp); /* allow for nutation */ nutation (mjd0, &deps, &dpsi); lam += dpsi; /* convert ecliptic to equatorial coords */ ecl_eq (mjd0, bet, lam, &r, &d); /* find local sidereal times of rise/set times/azimuths for given * equatorial coords, allowing for * .27249*sin(hp) parallax (hp is radius of earth from moon; * .27249 is radius of moon from earth where * the ratio is the dia_moon/dia_earth). * hp nominal angular earth radius. subtract because * tangential line-of-sight makes moon appear lower * as move out from center of earth. */ dis += .27249*sin(hp) - hp; riset (r, d, lat, dis, lstr, lsts, azr, azs, status); /* account for parallax on the meridian (0 hour-angle). * TODO: is this really right? other stuff too? better way?? help! */ ta_par (0.0, d, lat, height, hp, &ha, &d); transit (r+ha, d, np, lstt, altt); } /* find when and how hi object at (r,d) is when it transits. */ static transit (r, d, np, lstt, altt) double r, d; /* ra and dec, rads */ Now *np; /* for refraction info */ double *lstt; /* local sidereal time of transit */ double *altt; /* local, refracted, altitude at time of transit */ { *lstt = radhr(r); *altt = PI/2 - lat + d; if (*altt > PI/2) *altt = PI - *altt; refract (pressure, temp, *altt, altt); } xXx