/* find the chart number of Uranometria 2000.0 and return pointer to static * string describing location. * 0 <= ra < 24; -90 <= dec <= 90 */ char * u2k_atlas(double ra, double dec) { static char buf[512]; static char err[] = "???"; int band; /* index to array */ int south; /* flag for volume 2*/ int panel; /* panel number */ ra = radhr(ra); dec = raddeg(dec); buf[0] = 0; if (ra < 0.0 || 24.0 <= ra || dec < -90.0 || 90.0 < dec) { strcpy (buf, err); return (buf); /* range checking */ } if (dec < 0.0) { dec = -dec; south = 1; /* South is mirror of North */ } else south = 0; panel = 1; band = 0; /* scan u2k_zones for the correct band: */ while (u2k_zones[band].numZones != 0 && dec <= u2k_zones[band].lowDec ){ panel += u2k_zones[band].numZones; /*accumulate total panels */ band++ ; } if (!u2k_zones[band].numZones) { /* hit end of array with no match. */ strcpy (buf, err); return (buf); } ra -= 12.0 / u2k_zones[band].numZones; /*offset by half-width of panel*/ if (ra >= 24.0) /* reality check. shouldn't happen. */ ra -= 24.0; if (ra < 0.0) /* offset could give negative ra */ ra += 24.0; if (south && u2k_zones[band+1].numZones) panel = 222 - panel - u2k_zones[band].numZones; /* resultant panel number is accumulated panels in prior bands plus * ra's fraction of panels in dec's band. panel # goes up as ra goes * down. */ sprintf(buf, "V%d - P%3d", south+1, panel+(int)(u2k_zones[band].numZones*(24.0 - ra)/24.0)); return (buf); }
/* given a Now *, find the local apparent sidereal time, in hours. */ void now_lst (Now *np, double *lstp) { static double last_mjd = -23243, last_lng = 121212, last_lst; double eps, lst, deps, dpsi; if (last_mjd == mjd && last_lng == lng) { *lstp = last_lst; return; } utc_gst (mjd_day(mjd), mjd_hr(mjd), &lst); lst += radhr(lng); obliquity(mjd, &eps); nutation(mjd, &deps, &dpsi); lst += radhr(dpsi*cos(eps+deps)); range (&lst, 24.0); last_mjd = mjd; last_lng = lng; *lstp = last_lst = lst; }
/* * find the chart number of Uranometria first edition and return pointer to * static string describing location. * 0 <= ra < 24; -90 <= dec <= 90 */ char * um_atlas(double ra, double dec) { static char buf[512]; int band, south; int p; double w; ra = radhr(ra); dec = raddeg(dec); buf[0] = 0; if (ra < 0.0 || 24.0 <= ra || dec < -90.0 || 90.0 < dec) return (buf); p = 0; if (dec < 0.0) { dec = -dec; south = 1; } else south = 0; p = 1; for (band=0; um_zones[band].n; band++) { if (um_zones[band].l <= dec) break; p += um_zones[band].n; } if (!um_zones[band].n) return (buf); w = 24.0 / um_zones[band].n; if (band) { ra += w/2.0; if (ra >= 24.0) ra -= 24.0; } if (south && um_zones[band+1].n) p = 475 - p - um_zones[band].n; if (south && band == 0) { /* south pole part is mis-ordered! */ ra = 24.0 - ra; } sprintf(buf, "V%d - P%3d", south+1, p+(int)(ra/w)); return (buf); }
/* * find the chart number of Millennium Star Atlas and return pointer to static * string describing location. * 0 <= ra < 24; -90 <= dec <= 90 */ char * msa_atlas(double ra, double dec) { static char buf[512]; int zone, band; int i, p; ra = radhr(ra); dec = raddeg(dec); buf[0] = 0; if (ra < 0.0 || 24.0 <= ra || dec < -90.0 || 90.0 < dec) return (buf); zone = (int)(ra/8.0); band = -((int)(dec+((dec>=0)?3:-3))/6 - 15); for (p=0, i=0; i <= band; i++) p += msa_charts[i]; i = (int)((ra - 8.0*zone) / (8.0/msa_charts[band])); sprintf(buf, "V%d - P%3d", zone+1, p-i+zone*516); return (buf); }
/* find when the given object transits. start the search when LST matches the * object's RA at noon. * if ok, return 0 with np and op set to the transit conditions; if can't * converge return -1; if converges ok but not today return -2. * N.B. we assume np is passed set to local noon. */ static int find_transit (double dt, Now *np, Obj *op) { #define MAXLOOPS 10 #define MAXERR (0.25/60.) /* hours */ double mjdn = mjd; double lst; int i; /* insure initial guess is today -- if not, move by 24 hours */ if (dt < -12.0) dt += 24.0; if (dt > 12.0) dt -= 24.0; i = 0; do { mjd += dt/24.0; if (obj_cir (np, op) < 0) return (-1); now_lst (np, &lst); dt = (radhr(op->s_gaera) - lst); if (dt < -12.0) dt += 24.0; if (dt > 12.0) dt -= 24.0; } while (++i < MAXLOOPS && fabs(dt) > MAXERR); /* return codes */ if (i == MAXLOOPS) return (-1); return (fabs(mjd - mjdn) < 0.5 ? 0 : -2); #undef MAXLOOPS #undef MAXERR }
int main(int argc, char *argv[]) { Now *np; Now now; ObjF *op = NULL; char msg[256]; char *wfsroot, *filename, ra_hms[50], dec_dms[50]; double ra, dec, fov, mag, dra, ddec, dist, fo_ra, fo_dec; int nop = 0; int i; now.n_mjd = 0.0; now.n_lat = degrad(31.689); now.n_lng = degrad(-110.885); now.n_tz = 7.0; now.n_temp = 20.0; now.n_pressure = 700.0; now.n_elev = 2580.0/ERAD; now.n_dip = 0.0; now.n_epoch = EOD; sprintf(now.n_tznm, "UTC-7"); np = &now; time_fromsys(np); ra = hrrad(atof(argv[1])); dec = degrad(atof(argv[2])); fov = degrad(atof(argv[3])); mag = atof(argv[4]); /* precess(mjd, J2000, &ra, &dec); */ if (getenv("WFSROOT")) { wfsroot = getenv("WFSROOT"); filename = (char *) malloc(strlen(wfsroot) + 20); strcpy(filename, wfsroot); strcat(filename, "/wfscat/tycho.xe2"); } else { filename = "/mmt/shwfs/wfscat/tycho.xe2"; } nop = xe2fetch(filename, np, ra, dec, fov, mag, &op, msg); for (i=0; i<nop; i++) { dist = raddeg( acos( sin(op[i].fo_dec)*sin(dec) + cos(op[i].fo_dec)*cos(dec)*cos(ra-op[i].fo_ra) ) ); dist *= 60.0; fo_ra = radhr(op[i].fo_ra); fo_dec = raddeg(op[i].fo_dec); sprintf(ra_hms, "%02d:%02d:%05.2f", (int) fo_ra, (int) ((fo_ra - (int)fo_ra)*60.0), ( (fo_ra - (int)fo_ra)*60.0 - (int) ((fo_ra - (int)fo_ra)*60.0) )*60.0); if (fo_dec < 0.0 && (int)fo_dec >= 0) { sprintf(dec_dms, "-%02d:%02d:%06.3f", (int)fo_dec, abs( (int) ((fo_dec - (int)fo_dec)*60.0) ), fabs( ( (fo_dec - (int)fo_dec)*60.0 - (int) ((fo_dec - (int)fo_dec)*60.0) )*60.0) ); } else { sprintf(dec_dms, "%+03d:%02d:%06.3f", (int)fo_dec, abs( (int) ((fo_dec - (int)fo_dec)*60.0) ), fabs( ( (fo_dec - (int)fo_dec)*60.0 - (int) ((fo_dec - (int)fo_dec)*60.0) )*60.0) ); } printf("%15s %4.1f mag %2s %c %s %s %+07.3f %+07.2f %9.2f\n", op[i].co_name, op[i].co_mag/MAGSCALE, op[i].fo_spect, op[i].fo_class, ra_hms, dec_dms, 0.1*op[i].fo_pma/cos(op[i].fo_dec), 0.1*op[i].fo_pmd, dist); } return(0); }
/* given the true geocentric ra and dec of an object, the observer's latitude, * lt, and a horizon displacement correction, dis, all in radians, find the * local sidereal times and azimuths of rising and setting, lstr/s * and azr/s, also all 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). * * This version contributed by Konrad Bernloehr, Nov. 1996 * * status: 0=normal; 1=never rises; -1=circumpolar. * In case of non-zero status, all other returned variables are undefined. */ void riset (double ra, double dec, double lt, double dis, double *lstr, double *lsts, double *azr, double *azs, int *status) { #define EPS (1e-9) /* math rounding fudge - always the way, eh? */ double h; /* hour angle */ double cos_h; /* cos h */ double z; /* zenith angle */ double zmin, zmax; /* Minimum and maximum zenith angles */ double xaz, yaz; /* components of az */ int shemi; /* flag for southern hemisphere reflection */ /* reflect lt and dec if in southern hemisphere, then az back later */ if ((shemi= (lt < 0.)) != 0) { lt = -lt; dec = -dec; } /* establish zenith angle, and its extrema */ z = (PI/2.) + dis; zmin = fabs (dec - lt); zmax = PI - fabs(dec + lt); /* first consider special cases. * these also avoid any boundary problems in subsequent computations. */ if (zmax <= z + EPS) { *status = -1; /* never sets */ return; } if (zmin >= z - EPS) { *status = 1; /* never rises */ return; } /* compute rising hour angle -- beware found off */ cos_h = (cos(z)-sin(lt)*sin(dec))/(cos(lt)*cos(dec)); if (cos_h >= 1.) h = 0.; else if (cos_h <= -1.) h = PI; else h = acos (cos_h); /* compute setting azimuth -- beware found off */ xaz = sin(dec)*cos(lt)-cos(dec)*cos(h)*sin(lt); yaz = -1.*cos(dec)*sin(h); if (xaz == 0.) { if (yaz > 0) *azs = PI/2; else *azs = -PI/2; } else *azs = atan2 (yaz, xaz); /* reflect az back if southern */ if (shemi) *azs = PI - *azs; range(azs, 2.*PI); /* rising is just the opposite side */ *azr = 2.*PI - *azs; range(azr, 2.*PI); /* rise and set are just ha either side of ra */ *lstr = radhr(ra-h); range(lstr,24.0); *lsts = radhr(ra+h); range(lsts,24.0); /* OK */ *status = 0; }
/* find where and when an object, op, will rise and set and * it's transit circumstances. all times are utc mjd, angles rads e of n. * dis is the angle down from an ideal horizon, in rads (see riset()). * N.B. dis should NOT include refraction, we do that here. */ void riset_cir (Now *np, Obj *op, double dis, RiseSet *rp) { double mjdn; /* mjd of local noon */ double lstn; /* lst at local noon */ double lr, ls; /* lst rise/set times */ double ar, as; /* az of rise/set */ double ran; /* RA at noon */ Now n; /* copy to move time around */ Obj o; /* copy to get circumstances at n */ int rss; /* temp status */ /* work with local copies so we can move the time around */ (void) memcpy ((void *)&n, (void *)np, sizeof(n)); (void) memcpy ((void *)&o, (void *)op, sizeof(o)); /* fast Earth satellites need a different approach. * "fast" here is pretty arbitrary -- just too fast to work with the * iterative approach based on refining the times for a "fixed" object. */ if (op->o_type == EARTHSAT && op->es_n > FAST_SAT_RPD) { e_riset_cir (&n, &o, dis, rp); return; } /* assume no problems initially */ rp->rs_flags = 0; /* start the iteration at local noon */ mjdn = mjd_day(mjd - tz/24.0) + tz/24.0 + 0.5; n.n_mjd = mjdn; now_lst (&n, &lstn); /* first approximation is to find rise/set times of a fixed object * at the current epoch in its position at local noon. * N.B. add typical refraction if dis is above horizon for initial * go/no-go test. if it passes, real code does refraction rigorously. */ n.n_mjd = mjdn; if (obj_cir (&n, &o) < 0) { rp->rs_flags = RS_ERROR; return; } ran = o.s_gaera; riset (o.s_gaera, o.s_gaedec, lat, dis+(dis>.01 ? 0 : .01), &lr, &ls, &ar, &as, &rss); switch (rss) { case 0: break; case 1: rp->rs_flags = RS_NEVERUP; return; case -1: rp->rs_flags = RS_CIRCUMPOLAR; goto dotransit; default: rp->rs_flags = RS_ERROR; return; } /* iterate to find better rise time */ n.n_mjd = mjdn; switch (find_0alt ((lr - lstn)/SIDRATE, dis, &n, &o)) { case 0: /* ok */ rp->rs_risetm = n.n_mjd; rp->rs_riseaz = o.s_az; break; case -1: /* obj_cir error */ rp->rs_flags |= RS_RISERR; break; case -2: /* converged but not today, err but give times anyway */ rp->rs_risetm = n.n_mjd; rp->rs_riseaz = o.s_az; rp->rs_flags |= RS_NORISE; break; case -3: /* probably never up */ rp->rs_flags |= RS_NEVERUP; break; } /* iterate to find better set time */ n.n_mjd = mjdn; switch (find_0alt ((ls - lstn)/SIDRATE, dis, &n, &o)) { case 0: /* ok */ rp->rs_settm = n.n_mjd; rp->rs_setaz = o.s_az; break; case -1: /* obj_cir error */ rp->rs_flags |= RS_SETERR; break; case -2: /* converged but not today, err but give times anyway */ rp->rs_settm = n.n_mjd; rp->rs_setaz = o.s_az; rp->rs_flags |= RS_NOSET; break; case -3: /* probably circumpolar */ rp->rs_flags |= RS_CIRCUMPOLAR; break; } /* can try transit even if rise or set failed */ dotransit: n.n_mjd = mjdn; switch (find_transit ((radhr(ran) - lstn)/SIDRATE, &n, &o)) { case 0: /* ok */ rp->rs_trantm = n.n_mjd; rp->rs_tranalt = o.s_alt; break; case -1: /* did not converge */ rp->rs_flags |= RS_TRANSERR; break; case -2: /* converged but not today */ rp->rs_flags |= RS_NOTRANS; break; } }