Example #1
0
def get_moon(times):
    
    t = Table()
    
    earth = get_body(times, 'earth')
    moon = get_body(times, 'moon')

    em_x = moon['x']-earth['x']
    em_y = moon['y']-earth['y']
    em_z = moon['z']-earth['z']
    em_d = np.sqrt(em_x**2 + em_y**2 + em_z**2)
    em_vx = moon['vx']-earth['vx']
    em_vy = moon['vy']-earth['vy']
    em_vz = moon['vz']-earth['vz']
    em_v = np.sqrt(em_vx**2 + em_vy**2 + em_vz**2)
    t.add_column(moon['utc'])
    t.add_column(moon['jd'])
    t.add_column(em_x)
    t.add_column(em_y)
    t.add_column(em_z)
    t.add_column(em_d, name='d')
    t.add_column(em_vx)
    t.add_column(em_vy)
    t.add_column(em_vz)
    t.add_column(em_v, name='v')
    t.add_column(np.arcsin(em_z/em_d), name='dec')
    t.add_column(np.arctan2(em_y, em_x), name='RA')

    return t
Example #2
0
 def termtime(daytime,daytime2,code,unit='hour'):
     if unit=='hour':
         times=daytime+np.linspace(0.,1.,25)*(daytime2-daytime)
     elif unit=='minute':
         times=daytime+np.linspace(0.,1.,61)*(daytime2-daytime)
     else:
         times=daytime+np.linspace(0.,1.,61)*(daytime2-daytime)
     gmttimes=times-eighthours
     if type=='jieqi':
         diflongitudes=get_body('sun', gmttimes,  ephemeris='jpl').\
             transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
     else:
         sunlongitudes=get_body('sun', gmttimes,  ephemeris='jpl').\
             transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
         moonlongitudes=get_body('moon', gmttimes,  ephemeris='jpl').\
             transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
         diflongitudes=(moonlongitudes-sunlongitudes)%360
     difcode=diflongitudes // sec
     difcode=[int(difcode[i]) for i in range(len(difcode))]
     for i in range(len(difcode)-1):
       if difcode[i+1]!=code:
         if unit=='hour':
           return termtime(times[i],times[i+1],code,"minute")
         else:
           if unit=='minute':
             return termtime(times[i],times[i+1],code,"second")
           else:
             return ((code+1) % (360//sec),(times[i]+0.5*(times[i+1]-times[i])).value)
     return (-1,"")
Example #3
0
def gcrs_to_geosolarecliptic(gcrs_coo, to_frame):

    if not to_frame.obstime.isscalar:
        raise ValueError(
            "To perform this transformation the obstime Attribute must be a scalar."
        )

    _earth_orbit_perpen_point_gcrs = UnitSphericalRepresentation(
        lon=0 * u.deg,
        lat=(90 * u.deg - _obliquity_rotation_value(to_frame.obstime)))

    _earth_detilt_matrix = _make_rotation_matrix_from_reprs(
        _earth_orbit_perpen_point_gcrs, CartesianRepresentation(0, 0, 1))

    sun_pos_gcrs = get_body("sun", to_frame.obstime).cartesian
    earth_pos_gcrs = get_body("earth", to_frame.obstime).cartesian
    sun_earth = sun_pos_gcrs - earth_pos_gcrs

    sun_earth_detilt = sun_earth.transform(_earth_detilt_matrix)

    # Earth-Sun Line in Geocentric Solar Ecliptic Frame
    x_axis = CartesianRepresentation(1, 0, 0)

    rot_matrix = _make_rotation_matrix_from_reprs(sun_earth_detilt, x_axis)

    return matrix_product(rot_matrix, _earth_detilt_matrix)
Example #4
0
    def __init__(self, observer, body_name, t):
        """Calculate properties of the geometry of the observer, the body and
        the Sun."""
        self.observer = observer
        self.body_name = body_name
        self.t = t

        # Position of the Sun
        self.sun = get_body('sun', self.t)

        # Position of the body
        self.body = get_body(body_name, self.t)

        # The location of the observer in HPC co-ordinates.
        self.observer_hpc = coordinates.Helioprojective(
            observer=observer, obstime=observer.obstime)

        # The location of the body as seen by the observer, following the
        # SunPy example
        self.body_hpc = self.body.transform_to(
            frames.Helioprojective).transform_to(self.observer_hpc)

        # The body and the observer in HCC for ease of distance calculation.
        self.body_hcc = self.body.transform_to(frames.Heliocentric)
        self.observer_hcc = self.observer.transform_to(frames.Heliocentric)
Example #5
0
def gcrs_to_geosolarecliptic(gcrs_coo, to_frame):

    if not to_frame.obstime.isscalar:
        raise ValueError(
            "To perform this transformation the obstime Attribute must be a scalar."
        )

    _earth_orbit_perpen_point_gcrs = UnitSphericalRepresentation(
        lon=0 * u.deg, lat=(90 * u.deg - _obliquity_rotation_value(to_frame.obstime))
    )

    _earth_detilt_matrix = _make_rotation_matrix_from_reprs(
        _earth_orbit_perpen_point_gcrs, CartesianRepresentation(0, 0, 1)
    )

    sun_pos_gcrs = get_body("sun", to_frame.obstime).cartesian
    earth_pos_gcrs = get_body("earth", to_frame.obstime).cartesian
    sun_earth = sun_pos_gcrs - earth_pos_gcrs

    sun_earth_detilt = sun_earth.transform(_earth_detilt_matrix)

    # Earth-Sun Line in Geocentric Solar Ecliptic Frame
    x_axis = CartesianRepresentation(1, 0, 0)

    rot_matrix = _make_rotation_matrix_from_reprs(sun_earth_detilt, x_axis)

    return matrix_product(rot_matrix, _earth_detilt_matrix)
Example #6
0
def galactic(tstart=None, tend=None, tstep=None, time=None):
    if time is not None and (tstart is not None or tend is not None
                             or tstep is not None):
        raise AssertionError(
            'Must enter one time, or a start time, end time, and time step')

    elif time is not None:
        with solar_system_ephemeris.set('jpl'):
            jup_ephem = get_body('sun', time).galactic

    elif time is None and (tstart is None or tend is None or tstep is None):
        raise AssertionError('Must enter start time, end time, and time step')

    elif time is None and (tstart is not None and tend is not None
                           and tstep is not None):
        #        tstart = tstart.mjd + (tstep/2)  #use this line if you want times in the center of timeranges, dont use if you want coordinates at the time intervals themselves
        tstart = tstart.mjd  # use if you want coordinates at time intervals not at center of intervals
        tend = tend.mjd
        times = np.arange(tstart, tend, tstep, dtype=float)
        times_list = Time(times, format='mjd').fits
        times_list = Time(times_list, format='fits')

        jup_ephem = list()

        for date in times_list:
            with solar_system_ephemeris.set('jpl'):
                jup = get_body('sun', date).galactic
                jup_ephem.append(jup)

    return jup_ephem
Example #7
0
def CCTerm(start,end,type):
    eighthours=TimeDelta(8*3600,format='sec')
    def termtime(daytime,daytime2,code,unit='hour'):
        if unit=='hour':
            times=daytime+np.linspace(0.,1.,25)*(daytime2-daytime)
        elif unit=='minute':
            times=daytime+np.linspace(0.,1.,61)*(daytime2-daytime)
        else:
            times=daytime+np.linspace(0.,1.,61)*(daytime2-daytime)
        gmttimes=times-eighthours
        if type=='jieqi':
            diflongitudes=get_body('sun', gmttimes,  ephemeris='jpl').\
                transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
        else:
            sunlongitudes=get_body('sun', gmttimes,  ephemeris='jpl').\
                transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
            moonlongitudes=get_body('moon', gmttimes,  ephemeris='jpl').\
                transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
            diflongitudes=(moonlongitudes-sunlongitudes)%360
        difcode=diflongitudes // sec
        difcode=[int(difcode[i]) for i in range(len(difcode))]
        for i in range(len(difcode)-1):
          if difcode[i+1]!=code:
            if unit=='hour':
              return termtime(times[i],times[i+1],code,"minute")
            else:
              if unit=='minute':
                return termtime(times[i],times[i+1],code,"second")
              else:
                return ((code+1) % (360//sec),(times[i]+0.5*(times[i+1]-times[i])).value)
        return (-1,"")

    start=Time(Time(start,out_subfmt='date').iso)
    end=Time(Time(end,out_subfmt='date').iso)
    daycount=int(round((Time(end)-Time(start)).value))
    # print(start,end,daycount)
    # print(daycount)
    times=Time(start)+np.linspace(0.,1.,daycount+1)*(end-start+TimeDelta(3,format='sec')) # 考量潤秒,故加上3秒
    times=Time(Time(times,out_subfmt='date').iso)
    gmttimes=times-TimeDelta(8*3600,format='sec')
    if type=='jieqi':
        diflongitudes= get_body('sun', gmttimes,  ephemeris='jpl').\
            transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
        sec=15
    else:
        sunlongitudes=get_body('sun', gmttimes,  ephemeris='jpl').\
            transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
        moonlongitudes=get_body('moon', gmttimes,  ephemeris='jpl').\
            transform_to(GeocentricTrueEcliptic(equinox=gmttimes)).lon.deg
        diflongitudes=(moonlongitudes-sunlongitudes)%360
        sec=90
    res=[]
    difcode=diflongitudes // sec
    difcode=[int(difcode[i]) for i in range(len(difcode))]
    for i in range(len(difcode)-1):
      if difcode[i]!=difcode[i+1]:
        res.append(termtime(times[i],times[i+1],difcode[i],'hour'))
    return res
Example #8
0
def get_position(body_name, time, observer=None):
    """
    Get the position of one of the supported bodies.  If an observer is given then light travel time from the body
    to the observer is taken in to account.

    Parameters
    ----------
    body_name : `str`
        The body whose position will be calculated

    time : `~astropy.time.Time`
        The time at which the body position is calculated.  If the observer is not None, then the time is the
        time at the observer.

    observer : None, `~astropy.coordinate.SkyCoord`
        If None, the position of the body is returned.  If not none, the position of the body as seen from the
        observer takes into account the light travel time from the body to the observer.

    Returns
    -------
    `~astropy.coordinate.SkyCoord`
        The position of the body.  If the observer is not none, the position of the body as seen from the
        observer takes into account the light travel time from the body to the observer.
    """
    _body_name = body_name.lower()

    if observer is None:
        if _body_name in spice_spacecraft:
            spice_target = get_spice_target(_body_name)
            if _body_name == 'soho':
                # Use the SPICE kernels if available, otherwise estimate the position of SOHO.
                try:
                    coordinate = spice_target.coordinate(time)
                except:  # SpiceyError:
                    earth = get_body('earth', time).transform_to(frames.HeliographicStonyhurst)
                    coordinate = SkyCoord(lat=earth.lat, lon=earth.lon, radius=0.99 * earth.radius, obstime=time, frame=frames.HeliographicStonyhurst)
            else:
                coordinate = spice_target.coordinate(time)
        elif _body_name in solar_system_objects:
            coordinate = get_body(_body_name, time)
        else:
            raise ValueError('The body name is not recognized.')
    else:
        if _body_name in spice_spacecraft:
            #log.warning('Light travel time corrected locations of spacecraft are not yet supported ({:s} seen from observer).'.format(body_name))
            spice_target = get_spice_target(_body_name)
            coordinate = spice_target.coordinate(time)
        elif _body_name in solar_system_objects:
            body_frame = get_body_heliographic_stonyhurst(_body_name, observer=observer, time=time)
            # Explicitly convert the returned body frame in to a SkyCoord.
            coordinate = SkyCoord(lat=body_frame.lat, lon=body_frame.lon, radius=body_frame.radius, obstime=time, frame=frames.HeliographicStonyhurst)
        else:
            raise ValueError('The body name is not recognized.')
    return coordinate.transform_to(frames.HeliographicStonyhurst)
Example #9
0
def get_observer(observer_name, t):
    """ Get the location of the observer given the name of the observer."""
    # TODO understand LASCO and helioviewer image processing steps
    if observer_name.lower() == 'soho':
        earth = get_body('earth', t).transform_to(frames.Heliocentric)
        return SkyCoord(earth.x,
                        earth.y,
                        0.99 * earth.z,
                        frame=frames.Heliocentric,
                        obstime=t)
    else:
        return get_body(observer_name, t)
Example #10
0
    def find_parallax(self, date):
        '''Find the maximum parallax of self.planet on the given date
           from self.observer's location -- in other words, the difference
           in Mars' position between the observer's position and an
           observer at the same latitude but opposite longitude:
           this tells you you how much difference you would see from
           your position if Mars didn't move between your sunrise and sunset.
        '''
        # To calculate from a point on the equator, set lat to 0.
        observer_loc = EarthLocation.from_geodetic(self.location.lon,
                                                   self.location.lat,
                                                   self.location.height)

        # Specify the anti-point.
        # This isn't really an antipode unless lat == 0.
        antipode_loc = EarthLocation.from_geodetic(-observer.lon,
                                                   observer.lat,
                                                   observer.height)

        # XXX Oops, astropy doesn't offer next_rising etc.
        # so we'll need a function to find that before this
        # function can be implemented since it only works
        # when the planet is on the horizon so both the observer
        # and the anti-observer can see it.
        risetime = find_next_rising(planetname, date)

        obs_planet = get_body(planetname, risetime, observer_loc)
        ant_planet = get_body(planetname, risetime, antipode_loc)

        # First, calculate it the straightforward way using the arctan:
        print()
        mars_dist_miles = mars.distance.km / 1.609344
        print("Miles to Mars:", mars_dist_miles)
        earth_mean_radius = 3958.8    # in miles
        half_dist = earth_mean_radius * math.cos(observer_loc.lat)
        print("Distance between observers:", 2. * half_dist)
        par = 2. * math.atan(half_dist / mars_dist_miles) \
              * 180. / math.pi * 3600.
        print("Calculated parallax (arcsec):", par)

        # See what astropy calculates as the difference between observations:
        print()
        print("parallax on %s: RA %f, dec %f" % (antipode.date,
                                                 obs_planet.ra - ant_planet.ra,
                                             obs_planet.dec - ant_planet.dec))
        total_par = (math.sqrt((obs_planet.ra.radians
                                - ant_planet.ra.radians)**2
                               + (obs_planet.dec.radians
                                - ant_planet.dec.radians)**2)
                     * 180. * 3600. / math.pi)
        print("Total parallax (sum of squares): %f arcseconds" % total_par)
        print()
def test_regression_10291():
    """
    According to https://eclipse.gsfc.nasa.gov/OH/transit12.html,
    the minimum separation between Venus and the Sun during the 2012
    transit is 554 arcseconds for an observer at the Geocenter.

    If light deflection from the Sun is incorrectly applied, this increases
    to 557 arcseconds.
    """
    t = Time('2012-06-06 01:29:36')
    sun = get_body('sun', t)
    venus = get_body('venus', t)
    assert_quantity_allclose(venus.separation(sun),
                             554.427*u.arcsecond, atol=0.001*u.arcsecond)
Example #12
0
    def find_parallax(self, date):
        '''Find the maximum parallax of self.planet on the given date
           from self.observer's location -- in other words, the difference
           in Mars' position between the observer's position and an
           observer at the same latitude but opposite longitude:
           this tells you you how much difference you would see from
           your position if Mars didn't move between your sunrise and sunset.
        '''
        # To calculate from a point on the equator, set lat to 0.
        observer_loc = EarthLocation.from_geodetic(self.location.lon,
                                                   self.location.lat,
                                                   self.location.height)

        # Specify the anti-point.
        # This isn't really an antipode unless lat == 0.
        antipode_loc = EarthLocation.from_geodetic(-observer.lon, observer.lat,
                                                   observer.height)

        # XXX Oops, astropy doesn't offer next_rising etc.
        # so we'll need a function to find that before this
        # function can be implemented since it only works
        # when the planet is on the horizon so both the observer
        # and the anti-observer can see it.
        risetime = find_next_rising(planetname, date)

        obs_planet = get_body(planetname, risetime, observer_loc)
        ant_planet = get_body(planetname, risetime, antipode_loc)

        # First, calculate it the straightforward way using the arctan:
        print()
        mars_dist_miles = mars.distance.km / 1.609344
        print("Miles to Mars:", mars_dist_miles)
        earth_mean_radius = 3958.8  # in miles
        half_dist = earth_mean_radius * math.cos(observer_loc.lat)
        print("Distance between observers:", 2. * half_dist)
        par = 2. * math.atan(half_dist / mars_dist_miles) \
              * 180. / math.pi * 3600.
        print("Calculated parallax (arcsec):", par)

        # See what astropy calculates as the difference between observations:
        print()
        print("parallax on %s: RA %f, dec %f" %
              (antipode.date, obs_planet.ra - ant_planet.ra,
               obs_planet.dec - ant_planet.dec))
        total_par = (
            math.sqrt((obs_planet.ra.radians - ant_planet.ra.radians)**2 +
                      (obs_planet.dec.radians - ant_planet.dec.radians)**2) *
            180. * 3600. / math.pi)
        print("Total parallax (sum of squares): %f arcseconds" % total_par)
        print()
Example #13
0
def main():

    # MeerKAT
    obs_lat = -30.71323598930457
    obs_lon = 21.443001467965008
    loc = EarthLocation.from_geodetic(obs_lat,
                                      obs_lon)  #,obs_height,ellipsoid)

    myms = sys.argv[1].rstrip('/')
    maintab = table(myms, ack=False)
    scans = list(numpy.unique(maintab.getcol('SCAN_NUMBER')))
    ids, names, dirs = get_fields(myms)

    print(myms + ' | ' + str(len(ids)) + ' fields | ' + str(len(scans)) +
          ' scans')
    #header = 'Scan  Field        ID    t[iso]                    t[s]                 t0[s]                t1[s]                int0    int1    Duration[m]  N_int'
    header = 't[iso]                       Scan  Field Name         SunRA[deg]   SunDec[deg]  SunRA[hms]       SunDec[dms]      SunSep[deg]  MoonRA[deg]  MoonDec[deg] MoonRA[hms]      MoonDec[dms]     MoonSep[deg]'
    print('-' * len(header))
    print(header)
    print('-' * len(header))
    for scan in scans:
        subtab = maintab.query(query='SCAN_NUMBER==' + str(scan))
        field = numpy.unique(subtab.getcol('FIELD_ID'))[0]
        name, field_ra, field_dec = match_field(ids, names, dirs, field)
        field_hms, field_dms = format_coords(field_ra, field_dec)
        t_scan = numpy.mean(subtab.getcol('TIME'))
        t = Time(t_scan / 86400.0, format='mjd')
        with solar_system_ephemeris.set('builtin'):
            sun = get_body('Sun', t, loc)
            moon = get_body('Moon', t, loc)
        sun_ra = sun.ra.value
        sun_dec = sun.dec.value
        moon_ra = moon.ra.value
        moon_dec = moon.dec.value
        sun_hms, sun_dms = format_coords(sun_ra, sun_dec)
        moon_hms, moon_dms = format_coords(moon_ra, moon_dec)
        delta_ra_sun = field_ra - sun_ra
        delta_dec_sun = field_dec - sun_dec
        delta_ra_moon = field_ra - moon_ra
        delta_dec_moon = field_dec - moon_dec
        sun_sep = calcsep(field_ra, field_dec, sun_ra, sun_dec)
        moon_sep = calcsep(field_ra, field_dec, moon_ra, moon_dec)
        #	print field,name,sun_sep
        print(
            '%-28s %-5i %-5i %-12s %-12f %-12f %-16s %-16s %-12f %-12f %-12f %-16s %-16s %-12f'
            % (t.iso, scan, field, name, sun_ra, sun_dec, sun_hms, sun_dms,
               sun_sep, moon_ra, moon_dec, moon_hms, moon_dms, moon_sep))

    print('-' * len(header))
Example #14
0
def EarthRegion(times):
    gmttimes=times-eighthours
    sun=get_body('sun', gmttimes,  ephemeris='jpl')
    moon=get_body('moon', gmttimes,  ephemeris='jpl')
    earth=get_body('earth', gmttimes,  ephemeris='jpl')
    rs=const.R_sun.to('km').value
    re=const.R_earth.to('km').value
    ro=1737.1
    sunpos=np.transpose(np.array([sun.cartesian.x.value,
                                  sun.cartesian.y.value,sun.cartesian.z.value]))
    moonpos=np.transpose(np.array([moon.cartesian.x.value,
                                  moon.cartesian.y.value,moon.cartesian.z.value]))
    earthpos=np.zeros((len(sunpos),3))
    Ucenter,Pcenter,uarc,parc,SOdir=ShadowCone(sunpos,rs,moonpos,ro)
    return(Region(sunpos,moonpos,earthpos,re,Ucenter,Pcenter,uarc,parc,SOdir))
Example #15
0
    def _select_solar_system(self, body: str) -> None:
        """Set RA/Dec for selected solar system body."""
        from astropy.coordinates import solar_system_ephemeris, get_body

        # nothing?
        if body == "":
            return

        # clear simbad and JPL
        self.textSimbadName.clear()
        self.textJplHorizonsName.clear()

        QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        with solar_system_ephemeris.set("builtin"):
            # get coordinates
            body = get_body(body, Time.now(), self.observer.location)
        QtWidgets.QApplication.restoreOverrideCursor()

        # set them
        self.textMoveRA.setText(
            body.ra.to_string(unit=u.hour, sep=" ", precision=2))
        self.textMoveDec.setText(body.dec.to_string(sep=" ", precision=2))

        # update destination
        self._calc_dest_equatorial(clear=False)
Example #16
0
def solarbody_to_radec(
        body,
        location,
        timestamp,
        # default output in degrees
        as_radians=False,
        as_string=False):
    """Calculate equatorial (ra, dec) for solar body ephemerides

    Parameters
    ----------
    body: Name of solar body, Astropy convention
    location: Telescope geocentric position, `Astropy.EarthLocaton`
    timestamp: Unix timestamp

    Returns
    -------
    tuple: (ra, dec) equatorial coordinates in degrees
    """
    obs_time = timestamp2datetime(timestamp)
    obs_time = obs_time.strftime("%Y-%m-%d %H:%M:%S")
    obs_time = Time(obs_time)

    with solar_system_ephemeris.set('builtin'):
        solar_gcrs = get_body(body, obs_time, location)
    return radec_from_pointing_object(solar_gcrs,
                                      as_radians=as_radians,
                                      as_string=as_string)
Example #17
0
def planet(body, obs_loc, t=None):

    if t is None:
        t = datetime.utcnow()

    body = body.lower()
    if not body in solar_system_ephemeris.bodies:
        raise Exception("Body not available!")

    if type(obs_loc) == str and obs_loc in cities.keys():
        lon, lat = cities[obs_loc][:-1]
    elif isinstance(obs_loc, tuple):
        if len(obs_loc) == 2:
            lon, lat = obs_loc
        else:
            raise Exception("obs_loc should be in the format: (lon, lat)")
    else:
        raise Exception(
            "obs_loc should be a city name or geographic coordiantes.")

    loc = EarthLocation(lon=lon, lat=lat)

    with solar_system_ephemeris.set('jpl'):
        crd = get_body(body, Time(t), loc)

    ra = crd.ra.value
    dec = crd.dec.value
    r = crd.distance.value

    x, y, z = radec_to_cartesian(ra, dec, r)
    alt, az = radec_to_altaz(lon=lon, lat=lat, ra=ra, dec=dec, t=t)

    return (x, y, z), (ra, dec, r), (az, alt)
Example #18
0
def get_planet_info():
    planet_info = []

    with solar_system_ephemeris.set('de432s'):
        for planet_name in planets:
            planet = get_body(planet_name, current_time, location)

            planet_info.append({
                "name":
                planet_name,
                "lightMinutes":
                to_light_minutes(planet.distance),
                "xyz":
                get_xyz(planet)
            })

        sun = get_sun(current_time)
        planet_info.append({
            "name": "The Sun",
            "lightMinutes": to_light_minutes(sun.distance),
            "xyz": get_xyz(sun)
        })

        moon = get_moon(current_time)
        planet_info.append({
            "name": "The Moon",
            "lightMinutes": to_light_minutes(moon.distance),
            "xyz": get_xyz(moon)
        })

    return json.dumps(planet_info)
    def plot_solarsystem(self, obs_time):
        """
        Put planets of Solar System on a given Axes instance. Designation of the
        each planet is its roman symbol
        """

        # for Uranus must be another symbol, but at Unicode U+2645, which renders as ♅ (Wiki)
        planets = OrderedDict([('Mercury', '☿'), ('Venus', '♀'), ('Mars', '♂'),
                               ('Jupiter', '♃'), ('Saturn', '♄'),
                               ('Uranus', '♅'), ('Neptune', '♆')])

        planets_coords = [
            get_body(planet, obs_time, location=self.obs_loc)
            for planet in planets.keys()
        ]
        for coords, (name, symbol) in zip(planets_coords, planets.items()):
            planet = SkyCoord(coords.ra, coords.dec,
                              frame='gcrs').transform_to('icrs')
            self.ax.plot([planet.ra.radian], [-planet.dec.value + 45],
                         label=name,
                         linestyle='',
                         color='violet',
                         marker='$' + symbol + '$',
                         markersize=markers['planet'])

        print("planets are plotted")
def sun_position(obs_time):
    location = EarthLocation(lon=115.2505 * u.deg,
                             lat=42.211833333 * u.deg,
                             height=1365.0 * u.m)

    solar_system_ephemeris.set('de432s')

    # GCRS
    phasecentre = get_body('sun', obs_time, location, ephemeris='jpl')
    print('SUN: RA:{} Dec:{}'.format(phasecentre.ra.value,
                                     phasecentre.dec.value))
    # convert phasecentre into ITRS coordinate

    # ITRF - Alta
    cAltAz = phasecentre.transform_to(
        AltAz(obstime=obs_time, location=location))
    newAltAzcoordiantes = SkyCoord(alt=cAltAz.alt,
                                   az=cAltAz.az,
                                   obstime=obs_time,
                                   frame='altaz')

    new_ra_dec = newAltAzcoordiantes.transform_to('icrs')
    print(new_ra_dec)

    c_ITRS = phasecentre.transform_to(ITRS(obstime=obs_time,
                                           location=location))
    local_ha = location.lon - c_ITRS.spherical.lon
    local_ha.wrap_at(24 * u.hourangle, inplace=True)

    print("UTC: {} Local Hour Angle: {}".format(obs_time,
                                                local_ha.to('deg').value))
    obs_time1 = Time(obs_time, scale='utc', location=location)
    lst = obs_time1.sidereal_time('mean')
    local_ha1 = lst.to('deg').value - phasecentre.ra.value
    print("UTC: {} Local Hour Angle: {}".format(obs_time, local_ha1 * u.deg))
Example #21
0
def moon_coordinates(time, cam):
    """This function searches for the moon position at a given time.

    Parameters
    -----------
    time: 'astropy.time.core.Time'
        Time the image was taken.
    cam: 'str'
        Camera
    Returns
    -------
    moon_altitude:  'float'
        Altitude of the moon at the time the image was taken [radians]
    """
    observer = cam.location
    object = 'moon'
    with solar_system_ephemeris.set('builtin'):
        coordinates = get_body(object, time, observer)

    ra = coordinates.ra
    dec = coordinates.dec
    moon_position = SkyCoord(ra=ra, dec=dec, frame='icrs', unit='deg')
    moon_position_altaz = moon_position.transform_to(
        AltAz(obstime=time, location=observer))
    moon_altitude = moon_position_altaz.alt.radian
    print('time', type(time))
    return moon_altitude
Example #22
0
    def Get_Sun_Coordinates(self, cg, ctime):
        #
        #  Get_Sun_Coordinates
        #
        #     This method obtains the Sun Coordinates both in (Ra,Dec) and (Alt, Az)
        #     While astropy may use very accurate calculations and corrections from
        #     IERS, for some reason it cannot download the data. So, I decided to
        #     work off-line with a lesser precision, although enoug for us.
        #
        #
        #  @guiguesp - 2020-04-05
        #            - 2020-05-30 : Now using sunpy 1.1
        #_____________________________________________________________________________

        t = Time(ctime)

        with solar_system_ephemeris.set('builtin'):
            sun_radec = get_body('sun', t, cg)

        aa = AltAz(location=cg, obstime=t)
        sun_altaz = sun_radec.transform_to(aa)

        L0 = Sun_Coordinates.sun.L0(ctime)
        B0 = Sun_Coordinates.sun.B0(ctime)
        P = Sun_Coordinates.sun.P(ctime)
        R_Sun = Sun_Coordinates.sun.angular_radius(ctime)
        Carrington = Sun_Coordinates.sun.carrington_rotation_number(ctime)

        return sun_radec, sun_altaz, L0, B0, P, R_Sun, Carrington
Example #23
0
    def rm_celestial_bodies(
            self,
            radius=10.0,
            bodies=['moon', 'venus', 'mars', 'mercury', 'jupiter', 'saturn']):
        """Removes stars in the vicinity of bright celestial bodies from the
        image.

        Parameters
        ----------
        radius : float
            Radius in pixels
        bodies : list(str)
            List of names of celestial bodies. For allowed values see
            astropy.coordinates.get_body.
        """
        altaz_cs = AltAz(obstime=self.time, location=self.camera.location)
        objects = [
            get_body(p, self.time, self.camera.location).transform_to(altaz_cs)
            for p in bodies
        ]
        px_pos = np.array([
            np.array(self.camera.__project_stars__(p.az, p.alt))
            for p in objects
        ])
        D = distance_matrix(self.star_pos, px_pos)
        choice = np.all(D > radius, axis=1)
        self.star_pos = self.star_pos[choice, :]
        self.star_mag = self.star_mag[choice]
def stentime(plot=False):
    gravity = EarthLocation(lat=31.78135 * u.deg,
                            lon=76.99313 * u.deg,
                            height=1000 * u.m)
    time = Time(datetime(2020, 6, 8, 20, 18, 37, 274634))
    deluni = np.linspace(0, 12, 1440)
    delta = deluni * u.hour
    utcoffset = 5.5 * u.hour
    time = time - utcoffset
    saturn = get_body('Saturn', time=time, location=gravity)
    frame = AltAz(obstime=time + delta, location=gravity)
    range1 = saturn.transform_to(frame)
    alts = range1.alt.value
    list20 = []
    for i in range(1440):
        if (alts[i] >= 20):
            list20.append(i)
    first20delta = deluni[list20[0]]
    last20delta = deluni[list20[len(list20) - 1]]
    st = first20delta * u.hour
    ls = last20delta * u.hour
    if plot:
        plt.plot(delta, range1.alt.value)
        plt.xlim(0, 12)
        plt.xlabel('Hours from 8 PM IST')
        plt.ylabel('Saturn Alt at Gravity')
        plt.show()
    rise = time + st + utcoffset
    set = time + ls + utcoffset
    rised = rise.to_datetime()
    setd = set.to_datetime()
    print(rise.to_datetime())
    print(set.to_datetime())
    return rised, setd
Example #25
0
 def check_sun_position(self):
     now = dt.utcnow()
     sun = get_body("sun", Time(now))
     sun.location = self.nanten2
     azel = sun.altaz
     sun_az = azel.az.deg
     if sun_az > 240.:
         sun_az -= 360.
     sun_el = azel.alt.deg
     stop_flag = False
     az_list = self.az_list
     el_list = self.el_list
     for i in range(len(az_list)):
         if sun_az + 15 > +240.:
             if (sun_az - 360. + 15 >= az_list[i] / 3600. >=
                     -120.) or (sun_az - 15 <= az_list[i] / 3600. <= +240.):
                 stop_flag = True
             else:
                 pass
         elif sun_az - 15 < -240.:
             if (sun_az + 360. - 15 <= az_list[i] / 3600. <=
                     +120.) or (sun_az + 15 >= az_list[i] / 3600. >= -240.):
                 stop_flag = True
             else:
                 pass
         elif sun_az - 15 <= az_list[i] / 3600. <= sun_az + 15:
             stop_flag = True
         else:
             pass
         if sun_el - 15 <= el_list[i] / 3600. <= sun_el + 15:
             stop_flag = True
     return stop_flag
Example #26
0
def get_object(objectName: str, earthPos: (float, float), time: str) -> dict:
    """Get the altitude and azimuth of an object at a given time and location

    :param objectName: Name of the target object
    :param earthPos:   Latitude and Longitude of the observation location
    :param time:       Time of observation
    :type objectName:  string
    :type earthPos:    (float, float)
    :type time:        string

    :return: A dict containing the altitude and azimuth of the object
    :rtype:  { 'alt': float, 'az': float }
    """

    (lat, long) = earthPos
    astroTime = Time(time)
    objectCoord = get_body(objectName, astroTime)
    earthCoord = EarthLocation(lat=lat * u.deg, lon=long * u.deg)

    observation_frame = AltAz(obstime=astroTime, location=earthCoord)
    object_alt_az = objectCoord.transform_to(observation_frame)

    return {
        'alt': round(object_alt_az.alt.deg, 2),
        'az': round(object_alt_az.az.deg, 2)
    }
Example #27
0
 def run(self):
     if self.target == "Home":
         self.telescope.goto_home()
     elif self.target == "Stop":
         self.telescope.tracking = False
     else:
         body = get_body(self.target.lower(), Time.now())
         self.telescope.goto(body.ra.hour, body.dec.degree)
Example #28
0
def get_mars_ephemeris(timedate):
    """
    Get the ephemeris of Mars given a particular julian date
    """
    t = Time(timedate)
    with solar_system_ephemeris.set('builtin'):
        mars = get_body('mars', t) 
    return mars 
Example #29
0
    def _get_bodies(self, time):
        """Get position of the solar system bodies from Astropy.

        """
        return [
            get_body(body, time, ephemeris=self.ephemeris).transform_to(ITRS)
            for body in self.bodies
        ]
    def set_beam_target(self,
                        target_or_ra,
                        dec=None,
                        load_time=None,
                        verbose=True):
        """
        Given the name of an astronomical target, 'sun', or 'zenith', compute the
        current topocentric position of the body and point the beam at it.  If
        the 'dec' keyword is not None, the target is intepreted to be a RA.
        """

        # Force to string
        target_or_ra = str(target_or_ra)
        if dec is not None:
            dec = str(dec)

        # Figure out what to do with the name
        if target_or_ra.lower() in ('z', 'zen', 'zenith'):
            ## Zenith is easy
            az, alt = 0.0, 90.0
        else:
            ## Load in where we are
            obs = EarthLocation.from_geocentric(*self.station.ecef, unit=u.m)

            ## Resolve the name into coordinates
            if dec is not None:
                ra = Angle(target_or_ra, unit='hourangle')
                dec = Angle(dec, unit='deg')
                sc = SkyCoord(ra, dec, frame='fk5')
                if verbose:
                    print(
                        f"Resolved '{target_or_ra}, {dec}' to RA {sc.ra}, Dec. {sc.dec}"
                    )

            elif target_or_ra.lower() in solar_system_ephemeris.bodies:
                if target_or_ra.lower().startswith('earth'):
                    raise ValueError(f"Invalid target: '{target_or_ra}'")

                sc = get_body(target_or_ra.lower(), Time.now(), location=obs)
                if verbose:
                    print(
                        f"Resolved '{target_or_ra}' to {target_or_ra.lower()}")
            else:
                sc = SkyCoord.from_name(target_or_ra)
                if verbose:
                    print(
                        f"Resolved '{target_or_ra}' to RA {sc.ra}, Dec. {sc.dec}"
                    )

            ## Figure out where it is right now
            aa = sc.transform_to(AltAz(obstime=Time.now(), location=obs))
            az = aa.az.deg
            alt = aa.alt.deg
            if verbose:
                print(f"Currently at azimuth {aa.az}, altitude {aa.alt}")

        # Point the beam
        self.set_beam_pointing(az, alt, degrees=True, load_time=load_time)
Example #31
0
    def check_sky_tonight(self, obj):
        if obj in self.planet_list:
            midnight = Time(self.date + ' 00:00:00')
            sky_obj = get_body(obj, midnight)
        else:
            sky_obj = SkyCoord.from_name(obj)
        sky_objaltazs_viewing_date = sky_obj.transform_to(self.viewing_frame)

        last_hour = 999
        for altaz in sky_objaltazs_viewing_date:  # need to parallelize this at some point
            altitude = altaz.alt
            (sign, d, m, s) = altitude.signed_dms
            (zsign, zd, zm, zs) = altaz.az.signed_dms
            zstr = zsign + zd
            ohour = str(altaz.obstime)[11:13]
            omin = str(altaz.obstime)[14:16]
            odate = str(altaz.obstime)[0:10]
            oday = str(altaz.obstime)[8:10]
            omon = str(altaz.obstime)[5:7]

            object_type = 'Planet'
            suggested_filters = ''
            finder_link = ''
            if obj not in self.planet_list:
                my_messier = Messier.MessierData()
                object_type = my_messier.object_type[obj]
                finder_link = "<a href=\"https://freestarcharts.com/images/Articles/Messier" \
                              "/Single/{0}_Finder_Chart.pdf\" target=\"_blank\">Finder Chart</a>".format(obj.upper())
                if obj in my_messier.messier_filters.keys():
                    suggested_filters = my_messier.messier_filters[obj]

            skip_print = True
            if 0 <= int(omin) < 5:
                if ohour == last_hour:
                    skip_print = True
                else:
                    skip_print = False
            else:
                skip_print = True
            last_hour = ohour
            if altitude.is_within_bounds(20 * u.deg,
                                         90 * u.deg) and not skip_print:
                obs_date, obs_hour = un_utc(odate, ohour)
                if int(ohour) % 2 == 0:
                    tr_bgclr = "#d5f5e3"
                else:
                    tr_bgclr = "#d6eaf8"
                compass = return_sector(zstr)
                direction = str(zstr) + " - {0}".format(compass)
                table_row = "<tr bgcolor={6}><td>{0}</td><td>{5}</td><td>{1}</td><td>{2}</td><td>{3}&#730;</td>" \
                            "<td>{4}&#730;</td><td>{8}</td><td>{7}</td></tr>\n" \
                    .format(obj.upper(), obs_date, obs_hour, d, direction, object_type, tr_bgclr, suggested_filters,
                            finder_link)
                key = int(omon) * 10000 + int(oday) * 100 + int(ohour)
                self.viewing_index[self.v_i_ctr] = key
                self.viewing_dictionary[self.v_i_ctr] = table_row
                self.v_i_ctr += 1
Example #32
0
def jupLoc(tt, dd, loc):
    ds = str(dd[0]) + '-' + str(dd[1]) + '-' + str(dd[2])
    ts = str(tt[0]) + ':' + str(tt[1]) + ':' + str(tt[2])
    t = Time(ds + ' ' + ts)
    # loc = EarthLocation.of_site('Kitt Peak')
    with solar_system_ephemeris.set('builtin'):
        jup_loc = get_body('jupiter', t, loc)

    return jup_loc.ra, jup_loc.dec
Example #33
0
    def compute_constraint(self, times, observer, targets):
        # use get_body rather than get sun here, since
        # it returns the Sun's coordinates in an observer
        # centred frame, so the separation is as-seen
        # by the observer.
        # 'get_sun' returns ICRS coords.
        sun = get_body('sun', times, location=observer.location)
        solar_separation = sun.separation(targets)

        if self.min is None and self.max is not None:
            mask = self.max >= solar_separation
        elif self.max is None and self.min is not None:
            mask = self.min <= solar_separation
        elif self.min is not None and self.max is not None:
            mask = ((self.min <= solar_separation) &
                    (solar_separation <= self.max))
        else:
            raise ValueError("No max and/or min specified in "
                             "SunSeparationConstraint.")
        return mask
Example #34
0
    def __init__(self, parent = None, arg = None, name = "mount", port="", connect = True, var = {}):
        self.arg = arg
        self.Autoconnect = connect
        self.port = port
        self.parent = parent
        self.name = name
        self.sname = self.name
        self.variables = var
        self.rate = 1

        self.mount = drive(profile = 'HEQ5', mode = "eq", connectMethod = 'pymlab',
            obs_lat = 48.986976, obs_lon = 14.467532, obs_alt = 300, port = '/dev/ttyUSB0')
        
        self.mount.run()
        self.mount.UnPark()

        #self.mount.Slew(SkyCoord(alt = 45, az = 10, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)

        rospy.Subscriber("/mount/controll", String, callback_btn)
        rospy.Subscriber("/arom/UI/buttons", String, callback_btn)
        self.pub_status = rospy.Publisher('/mount/status', String, queue_size=10)
        self.pub_radec  = rospy.Publisher('/mount/status/coordinates/RaDec', Float32MultiArray, queue_size=10)

        #rospy.init_node('AROM_mount')
        AromNode.__init__(self)
        print "zinicializovano"

        rate = rospy.Rate(self.rate)
        ra = 0
        dec = 90
        while not rospy.is_shutdown():
            try:
                if len(btn_data) > 0:
                    print btn_data[0], len(btn_data)
                    lastBtn = btn_data[0]
                    btn_data.pop(0)

                    if "name" in lastBtn:
                        split = lastBtn.split(" ")
                        self.mount.Slew(SkyCoord.from_name(split[1]))
                        #self.mount.Slew(SkyCoord(alt = float(split[1]), az = float(split[2]), obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                    elif "solar" in lastBtn:
                        split = lastBtn.split(" ")
                        self.mount.Slew(get_body(split[1], obstime = Time.now(), location = self.mount.getObs()).icrs)

                    elif "sun" in lastBtn:
                        self.mount.Slew(get_sun(Time.now()).icrs)
                    
                    elif "altaz" in lastBtn:
                        split = lastBtn.split(" ")
                        self.mount.Slew(SkyCoord(alt = float(split[1]), az = float(split[2]), obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                    
                    elif "radec" in lastBtn:
                        split = lastBtn.split(" ")
                        self.mount.Slew(SkyCoord(alt = float(split[1]), az = float(split[2]), obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                        
                    elif lastBtn == 'KEY_OK':
                        self.mount.Slew(SkyCoord(ra = float(split[1]), dec = float(split[2]), frame = 'icrs', unit="deg"))
                        
                        #now = Time.now()                                  
                        #altazframe = AltAz(obstime=now, location=self.mount.getObs())                                               
                        #sunaltaz = get_sun(now).transform_to(altazframe)  
                        #print sunaltaz, altazframe, now
                        #self.mount.Slew(SkyCoord(get_sun(Time.now()), location = self.mount.getObs()).icrs)

                    if lastBtn == 'KEY_UP':
                        dec += 10
                        self.mount.Slew(SkyCoord(ra = ra, dec=dec, unit="deg"))
                        #self.mount.Slew(SkyCoord(alt = 45, az = 181+90, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                        # mode: -90 - 0

                    if lastBtn == 'KEY_DOWN':
                        dec -= 10
                        self.mount.Slew(SkyCoord(ra = ra, dec=dec, unit="deg"))
                        #self.mount.Slew(SkyCoord(alt = 45, az = 181+45, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                        # mode: -180 - -90

                    if lastBtn == 'KEY_LEFT':
                        ra += 10
                        self.mount.Slew(SkyCoord(ra = ra, dec=dec, unit="deg"))
                        #self.mount.Slew(SkyCoord(alt = 45, az = 181, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                        #mode: -90 - 0

                    if lastBtn == 'KEY_RIGHT':
                        ra -= 10
                        self.mount.Slew(SkyCoord(ra = ra, dec=dec, unit="deg"))
                        #self.mount.Slew(SkyCoord(alt = 1, az = 181+90, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)
                        #mode: -180 - -90

                    if lastBtn == 'KEY_MENU':
                        self.mount.Slew(SkyCoord(alt = 1, az = 181+45, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)

                    if lastBtn == 'KEY_TAB':
                        self.mount.Slew(SkyCoord(alt = 1, az = 181, obstime = Time.now(), frame = 'altaz', unit="deg", location = self.mount.getObs()).icrs)

                    elif lastBtn == 'KEY_STOP' or lastBtn == 'home':
                        self.mount.GoPark()

                    elif lastBtn == 'KEY_PLAY':
                        self.mount.UnPark()
                else:
                    #(ra, dec) = self.mount.getCoordinates('RaDec')
                    #print ra, dec

                    #try:
                    #    mat = Float32MultiArray(data=[ra, dec])
                    #    self.pub_radec.publish(mat)

                    #except Exception, e:
                    #    print e
                    #mat = Float32MultiArray(data=[ra, dec])
                        #mat.layout.dim.append(MultiArrayDimension())
                        #mat.layout.dim[0].label = "RaDec"
                        #mat.layout.dim[0].size = 2
                        #mat.data.
                    #print mat
                    #self.pub_radec.publish(mat)
                    pass


            except Exception, e:
                rospy.logerr(e)
            rate.sleep()
Example #35
0
    def find_opp_and_retro(self, start_time):
        cur_time = Time(start_time)

        last_RA = 0.
        last_dist = Distance(999, unit=units.au)
        pre_closest = True
        self.retrograding = False
        retro_start = None
        retro_end = None
        opptime = None

        # Earth location to use for calculating Mars' position.
        # Setting it to None will (I think? docs aren't clear) calculate
        # from the center of the Earth; this is much faster, skips
        # calculations like parallax due to earth's rotation,
        # and avoids seeing a lot of spurious retrograde/direct
        # transitions due solely to the observer's position changing
        # as the earth rotates.
        location = None

        # A place to store the data points
        self.planettrack = []

        # When a planet is approaching opposition, its elongation is negative.
        # When it flips to positive (-180 to 180), it just passed opposition.
        # Can't check for exactly 180 if we're only checking time coarsely.
        last_elong = -1

        # We'll look for the end of retrograde then go a few days
        # past it; but first, put a limit on how far we can go.
        end_time = cur_time + TimeDelta(300, format='jd')

        # Initially, go one day at a time:
        coarsemode = TimeDelta(1, format='jd')
        # but in fine mode, we'll go one hour at a time:
        finemode = TimeDelta(60*60, format='sec')
        # and near opposition we'll go even finer for a few days:
        superfinemode = TimeDelta(60 * 5, format='sec')

        timeslice = coarsemode

        while cur_time < end_time:
            cur_time += timeslice

            mars = get_body(planetname, cur_time)

            flags = ''

            # Are we starting or stopping retrograde?
            if ( (mars.ra == last_RA) or
                 (mars.ra < last_RA and not self.retrograding) or
                 (mars.ra > last_RA and self.retrograding) ):
                # Are we still in coarse mode? If so, jump back
                # in time a few days and go to fine mode.
                if timeslice == coarsemode:
                    print("Switching to fine mode on", cur_time)
                    print("         RA", mars.ra.hour, ", dec", mars.dec.degree)
                    timeslice = finemode
                    cur_time -= TimeDelta(EXTRA_DAYS, format='jd')
                    continue

                # We're in fine mode. Record dates when the planet
                # starts or ends retrograde, hits opposition or makes
                # its closest approach.

                if self.retrograding:
                    flags += END_RETROGRADE
                    # Don't consider this the actual end of retrograde
                    # unless we're already past opposition.
                    # There are potentially a lot of false retrogrades.
                    # We can get them from parallax if we calculate
                    # Mars' position from a specific earth location;
                    # but even if we don't, pyastro gives us a lot
                    # of false little retrogrades and I don't know why.
                    if opptime:
                        retro_end = cur_time
                else:
                    flags += START_RETROGRADE
                    retro_start = cur_time

                if mars.ra == last_RA:
                    flags += STATIONARY

                self.retrograding = not self.retrograding

            # Calculate elongation to find the opposition time:
            sun = get_body('sun', cur_time)
            elongation = (mars.ra - sun.ra).degree
            # print(cur_time, "\n  RA",
            #       mars.ra.hour, "dec", mars.dec.degree,
            #       "elongation", elongation)
            if last_elong > 180. and elongation <= 180.:
                if timeslice == superfinemode:
                    flags += OPPOSITION
                    opptime = cur_time
                    timeslice = finemode
                    print("Opposition on", cur_time, ", switching back to fine")
                    # XXX it would be nice not to go back to finemode
                    # until after we've found closest approach.
                    # But astropy randomly finds a closest approach
                    # date weeks before the actual closest approach,
                    # at the start of retrograde.
                else:
                    # Looks like opposition. But let's go back a day and
                    # get a finer view of the time.
                    print("Switching to superfine mode on", cur_time)
                    timeslice = superfinemode
                    cur_time -= TimeDelta(1, format='jd')

            if mars.distance >= last_dist and pre_closest:
                flags += CLOSEST_APPROACH
                # self.find_parallax(cur_time)
                pre_closest = False

            elif mars.distance < last_dist:  # receding
                pre_closest = True

            if flags or self.save_all_points:
                self.planettrack.append([cur_time.datetime,
                                         mars.ra.radian, mars.dec.radian,
                                         mars.distance.km, flags])

            last_RA = mars.ra
            last_dist = mars.distance
            last_elong = elongation

            # If we've seen the opposition as well as retro_start and retro_end
            # then we're done. Switch back to coarse mode and record a
            # few more days.
            if timeslice == finemode and retro_start and retro_end and opptime:
                timeslice = coarsemode
                end_time = cur_time + TimeDelta(EXTRA_DAYS, format='jd')

        # We're done calculating all the points.
        # Now calculate the retrograde midpoint, if we have both start and end.
        if retro_start and retro_end:
            mid_retro_date = retro_start + (retro_end - retro_start) / 2
            mars = get_body(planetname, mid_retro_date)

            # Insert that into our planettrack list:
            for i, point in enumerate(self.planettrack):
                if point[IDATE] == mid_retro_date:
                    point[IFLAGS] += MIDPOINT_RETRO
                    break
                elif point[IDATE] > mid_retro_date:
                    self.planettrack.insert(i, [mid_retro_date.datetime,
                                                mars.ra.radian, mars.dec.radian,
                                                mars.distance.km,
                                                MIDPOINT_RETRO])
                    # We've just changed a list in the middle of looping
                    # over that list, but it's okay because we're breaking out.
                    break
        else:
            print("don't have both retro start and end")

        # Now print what we found.
        print("%20s %-19s  %-11s   %-10s %s" % ('', 'Date',
                                               'RA', 'Dec', 'Dist (mi)'))
        for point in self.planettrack:
            if point[IFLAGS]:
                # print("%20s %-19s  %-11s  %-10s %d" % \
                #       (self.flags_to_string(point[4]), str(point[0]),
                #        point[1], point[2],
                #        point[3] * 9.2956e7))
                print("%20s %-19s  %-11.7f  %-10.7f %d" % \
                      (self.flags_to_string(point[IFLAGS]), str(point[IDATE]),
                       self.rads_to_hours(point[IRA]),
                       self.rads_to_degrees(point[IDEC]),
                       point[IDIST] / 1.609344))