def prepare_earth_position_vel(time): """ Get barycentric position and velocity, and heliocentric position of Earth Parameters ----------- time : `~astropy.time.Time` time at which to calculate position and velocity of Earth Returns -------- earth_pv : `np.ndarray` Barycentric position and velocity of Earth, in au and au/day earth_helio : `np.ndarray` Heliocentric position of Earth in au """ # this goes here to avoid circular import errors from astropy.coordinates.solar_system import (get_body_barycentric, get_body_barycentric_posvel) # get barycentric position and velocity of earth earth_p, earth_v = get_body_barycentric_posvel('earth', time) # get heliocentric position of earth, preparing it for passing to erfa. sun = get_body_barycentric('sun', time) earth_heliocentric = (earth_p - sun).get_xyz(xyz_axis=-1).to_value(u.au) # Also prepare earth_pv for passing to erfa, which wants it as # a structured dtype. earth_pv = erfa.pav2pv( earth_p.get_xyz(xyz_axis=-1).to_value(u.au), earth_v.get_xyz(xyz_axis=-1).to_value(u.au / u.d)) return earth_pv, earth_heliocentric
def prepare_earth_position_vel(time): """ Get barycentric position and velocity, and heliocentric position of Earth Parameters ----------- time : `~astropy.time.Time` time at which to calculate position and velocity of Earth Returns -------- earth_pv : `np.ndarray` Barycentric position and velocity of Earth, in au and au/day earth_helio : `np.ndarray` Heliocentric position of Earth in au """ # this goes here to avoid circular import errors from astropy.coordinates.solar_system import (get_body_barycentric, get_body_barycentric_posvel) # get barycentric position and velocity of earth earth_p, earth_v = get_body_barycentric_posvel('earth', time) # get heliocentric position of earth, preparing it for passing to erfa. sun = get_body_barycentric('sun', time) earth_heliocentric = (earth_p - sun).get_xyz(xyz_axis=-1).to_value(u.au) # Also prepare earth_pv for passing to erfa, which wants it as # a structured dtype. earth_pv = erfa.pav2pv( earth_p.get_xyz(xyz_axis=-1).to_value(u.au), earth_v.get_xyz(xyz_axis=-1).to_value(u.au/u.d)) return earth_pv, earth_heliocentric
def icrs_to_gcrs(icrs_coo, gcrs_frame): # first set up the astrometry context for ICRS<->GCRS. There are a few steps... # get the position and velocity arrays for the observatory. Need to # have xyz in last dimension, and pos/vel in one-but-last. # (Note could use np.stack once our minimum numpy version is >=1.10.) obs_pv = erfa.pav2pv( gcrs_frame.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m), gcrs_frame.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m / u.s)) # find the position and velocity of earth jd1, jd2 = get_jd12(gcrs_frame.obstime, 'tdb') earth_pv, earth_heliocentric = prepare_earth_position_vel( gcrs_frame.obstime) # get astrometry context object, astrom. astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric) if icrs_coo.data.get_name( ) == 'unitspherical' or icrs_coo.data.to_cartesian().x.unit == u.one: # if no distance, just do the infinite-distance/no parallax calculation usrepr = icrs_coo.represent_as(UnitSphericalRepresentation) i_ra = usrepr.lon.to_value(u.radian) i_dec = usrepr.lat.to_value(u.radian) gcrs_ra, gcrs_dec = atciqz(i_ra, i_dec, astrom) newrep = UnitSphericalRepresentation(lat=u.Quantity(gcrs_dec, u.radian, copy=False), lon=u.Quantity(gcrs_ra, u.radian, copy=False), copy=False) else: # When there is a distance, we first offset for parallax to get the # BCRS coordinate direction and *then* run the ERFA transform for no # parallax/PM. This ensures reversibility and is more sensible for # inside solar system objects astrom_eb = CartesianRepresentation(astrom['eb'], unit=u.au, xyz_axis=-1, copy=False) newcart = icrs_coo.cartesian - astrom_eb srepr = newcart.represent_as(SphericalRepresentation) i_ra = srepr.lon.to_value(u.radian) i_dec = srepr.lat.to_value(u.radian) gcrs_ra, gcrs_dec = atciqz(i_ra, i_dec, astrom) newrep = SphericalRepresentation(lat=u.Quantity(gcrs_dec, u.radian, copy=False), lon=u.Quantity(gcrs_ra, u.radian, copy=False), distance=srepr.distance, copy=False) return gcrs_frame.realize_frame(newrep)
def gcrs_to_hcrs(gcrs_coo, hcrs_frame): if np.any(gcrs_coo.obstime != hcrs_frame.obstime): # if they GCRS obstime and HCRS obstime are not the same, we first # have to move to a GCRS where they are. frameattrs = gcrs_coo.get_frame_attr_names() frameattrs['obstime'] = hcrs_frame.obstime gcrs_coo = gcrs_coo.transform_to(GCRS(**frameattrs)) srepr = gcrs_coo.represent_as(SphericalRepresentation) gcrs_ra = srepr.lon.to_value(u.radian) gcrs_dec = srepr.lat.to_value(u.radian) # set up the astrometry context for ICRS<->GCRS and then convert to ICRS # coordinate direction obs_pv = erfa.pav2pv( gcrs_coo.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m), gcrs_coo.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m / u.s)) jd1, jd2 = get_jd12(hcrs_frame.obstime, 'tdb') earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_coo.obstime) astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric) i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom) # convert to Quantity objects i_ra = u.Quantity(i_ra, u.radian, copy=False) i_dec = u.Quantity(i_dec, u.radian, copy=False) if gcrs_coo.data.get_name( ) == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one: # if no distance, just use the coordinate direction to yield the # infinite-distance/no parallax answer newrep = UnitSphericalRepresentation(lat=i_dec, lon=i_ra, copy=False) else: # When there is a distance, apply the parallax/offset to the # Heliocentre as the last step to ensure round-tripping with the # hcrs_to_gcrs transform # Note that the distance in intermedrep is *not* a real distance as it # does not include the offset back to the Heliocentre intermedrep = SphericalRepresentation(lat=i_dec, lon=i_ra, distance=srepr.distance, copy=False) # astrom['eh'] and astrom['em'] contain Sun to observer unit vector, # and distance, respectively. Shapes are (X) and (X,3), where (X) is the # shape resulting from broadcasting the shape of the times object # against the shape of the pv array. # broadcast em to eh and scale eh eh = astrom['eh'] * astrom['em'][..., np.newaxis] eh = CartesianRepresentation(eh, unit=u.au, xyz_axis=-1, copy=False) newrep = intermedrep.to_cartesian() + eh return hcrs_frame.realize_frame(newrep)
def gcrs_to_hcrs(gcrs_coo, hcrs_frame): if np.any(gcrs_coo.obstime != hcrs_frame.obstime): # if they GCRS obstime and HCRS obstime are not the same, we first # have to move to a GCRS where they are. frameattrs = gcrs_coo.get_frame_attr_names() frameattrs['obstime'] = hcrs_frame.obstime gcrs_coo = gcrs_coo.transform_to(GCRS(**frameattrs)) srepr = gcrs_coo.represent_as(SphericalRepresentation) gcrs_ra = srepr.lon.to_value(u.radian) gcrs_dec = srepr.lat.to_value(u.radian) # set up the astrometry context for ICRS<->GCRS and then convert to ICRS # coordinate direction obs_pv = erfa.pav2pv( gcrs_coo.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m), gcrs_coo.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m/u.s)) jd1, jd2 = get_jd12(hcrs_frame.obstime, 'tdb') earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_coo.obstime) astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric) i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom) # convert to Quantity objects i_ra = u.Quantity(i_ra, u.radian, copy=False) i_dec = u.Quantity(i_dec, u.radian, copy=False) if gcrs_coo.data.get_name() == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one: # if no distance, just use the coordinate direction to yield the # infinite-distance/no parallax answer newrep = UnitSphericalRepresentation(lat=i_dec, lon=i_ra, copy=False) else: # When there is a distance, apply the parallax/offset to the # Heliocentre as the last step to ensure round-tripping with the # hcrs_to_gcrs transform # Note that the distance in intermedrep is *not* a real distance as it # does not include the offset back to the Heliocentre intermedrep = SphericalRepresentation(lat=i_dec, lon=i_ra, distance=srepr.distance, copy=False) # astrom['eh'] and astrom['em'] contain Sun to observer unit vector, # and distance, respectively. Shapes are (X) and (X,3), where (X) is the # shape resulting from broadcasting the shape of the times object # against the shape of the pv array. # broadcast em to eh and scale eh eh = astrom['eh'] * astrom['em'][..., np.newaxis] eh = CartesianRepresentation(eh, unit=u.au, xyz_axis=-1, copy=False) newrep = intermedrep.to_cartesian() + eh return hcrs_frame.realize_frame(newrep)
def gcrs_to_icrs(gcrs_coo, icrs_frame): srepr = gcrs_coo.represent_as(SphericalRepresentation) gcrs_ra = srepr.lon.to_value(u.radian) gcrs_dec = srepr.lat.to_value(u.radian) # set up the astrometry context for ICRS<->GCRS and then convert to BCRS # coordinate direction obs_pv = erfa.pav2pv( gcrs_coo.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m), gcrs_coo.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m / u.s)) jd1, jd2 = get_jd12(gcrs_coo.obstime, 'tdb') earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_coo.obstime) astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric) i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom) if gcrs_coo.data.get_name( ) == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one: # if no distance, just use the coordinate direction to yield the # infinite-distance/no parallax answer newrep = UnitSphericalRepresentation(lat=u.Quantity(i_dec, u.radian, copy=False), lon=u.Quantity(i_ra, u.radian, copy=False), copy=False) else: # When there is a distance, apply the parallax/offset to the SSB as the # last step - ensures round-tripping with the icrs_to_gcrs transform # the distance in intermedrep is *not* a real distance as it does not # include the offset back to the SSB intermedrep = SphericalRepresentation(lat=u.Quantity(i_dec, u.radian, copy=False), lon=u.Quantity(i_ra, u.radian, copy=False), distance=srepr.distance, copy=False) astrom_eb = CartesianRepresentation(astrom['eb'], unit=u.au, xyz_axis=-1, copy=False) newrep = intermedrep + astrom_eb return icrs_frame.realize_frame(newrep)
def icrs_to_gcrs(icrs_coo, gcrs_frame): # first set up the astrometry context for ICRS<->GCRS. There are a few steps... # get the position and velocity arrays for the observatory. Need to # have xyz in last dimension, and pos/vel in one-but-last. # (Note could use np.stack once our minimum numpy version is >=1.10.) obs_pv = erfa.pav2pv( gcrs_frame.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m), gcrs_frame.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m/u.s)) # find the position and velocity of earth jd1, jd2 = get_jd12(gcrs_frame.obstime, 'tdb') earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_frame.obstime) # get astrometry context object, astrom. astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric) if icrs_coo.data.get_name() == 'unitspherical' or icrs_coo.data.to_cartesian().x.unit == u.one: # if no distance, just do the infinite-distance/no parallax calculation usrepr = icrs_coo.represent_as(UnitSphericalRepresentation) i_ra = usrepr.lon.to_value(u.radian) i_dec = usrepr.lat.to_value(u.radian) gcrs_ra, gcrs_dec = atciqz(i_ra, i_dec, astrom) newrep = UnitSphericalRepresentation(lat=u.Quantity(gcrs_dec, u.radian, copy=False), lon=u.Quantity(gcrs_ra, u.radian, copy=False), copy=False) else: # When there is a distance, we first offset for parallax to get the # BCRS coordinate direction and *then* run the ERFA transform for no # parallax/PM. This ensures reversibility and is more sensible for # inside solar system objects astrom_eb = CartesianRepresentation(astrom['eb'], unit=u.au, xyz_axis=-1, copy=False) newcart = icrs_coo.cartesian - astrom_eb srepr = newcart.represent_as(SphericalRepresentation) i_ra = srepr.lon.to_value(u.radian) i_dec = srepr.lat.to_value(u.radian) gcrs_ra, gcrs_dec = atciqz(i_ra, i_dec, astrom) newrep = SphericalRepresentation(lat=u.Quantity(gcrs_dec, u.radian, copy=False), lon=u.Quantity(gcrs_ra, u.radian, copy=False), distance=srepr.distance, copy=False) return gcrs_frame.realize_frame(newrep)
def gcrs_to_icrs(gcrs_coo, icrs_frame): srepr = gcrs_coo.represent_as(SphericalRepresentation) gcrs_ra = srepr.lon.to_value(u.radian) gcrs_dec = srepr.lat.to_value(u.radian) # set up the astrometry context for ICRS<->GCRS and then convert to BCRS # coordinate direction obs_pv = erfa.pav2pv( gcrs_coo.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m), gcrs_coo.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m/u.s)) jd1, jd2 = get_jd12(gcrs_coo.obstime, 'tdb') earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_coo.obstime) astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric) i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom) if gcrs_coo.data.get_name() == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one: # if no distance, just use the coordinate direction to yield the # infinite-distance/no parallax answer newrep = UnitSphericalRepresentation(lat=u.Quantity(i_dec, u.radian, copy=False), lon=u.Quantity(i_ra, u.radian, copy=False), copy=False) else: # When there is a distance, apply the parallax/offset to the SSB as the # last step - ensures round-tripping with the icrs_to_gcrs transform # the distance in intermedrep is *not* a real distance as it does not # include the offset back to the SSB intermedrep = SphericalRepresentation(lat=u.Quantity(i_dec, u.radian, copy=False), lon=u.Quantity(i_ra, u.radian, copy=False), distance=srepr.distance, copy=False) astrom_eb = CartesianRepresentation(astrom['eb'], unit=u.au, xyz_axis=-1, copy=False) newrep = intermedrep + astrom_eb return icrs_frame.realize_frame(newrep)