def test_gcrs_altaz(): """ Check GCRS<->AltAz transforms for round-tripping. Has multiple paths """ from astropy.coordinates import EarthLocation ra, dec, _ = randomly_sample_sphere(1) gcrs = GCRS(ra=ra[0], dec=dec[0], obstime='J2000') # check array times sure N-d arrays work times = Time(np.linspace(2456293.25, 2456657.25, 51) * u.day, format='jd', scale='utc') loc = EarthLocation(lon=10 * u.deg, lat=80. * u.deg) aaframe = AltAz(obstime=times, location=loc) aa1 = gcrs.transform_to(aaframe) aa2 = gcrs.transform_to(ICRS).transform_to(CIRS).transform_to(aaframe) aa3 = gcrs.transform_to(ITRS).transform_to(CIRS).transform_to(aaframe) # make sure they're all consistent assert_allclose(aa1.alt, aa2.alt) assert_allclose(aa1.az, aa2.az) assert_allclose(aa1.alt, aa3.alt) assert_allclose(aa1.az, aa3.az)
def eci2el(x,y,z,dt): """ Convert Earth-Centered Inertial (ECI) cartesian coordinates to ITRS for astropy EarthLocation object. Inputs : x = ECI X-coordinate y = ECI Y-coordinate z = ECI Z-coordinate dt = UTC time (datetime object) """ from astropy.coordinates import GCRS, ITRS, EarthLocation, CartesianRepresentation import astropy.units as u # convert datetime object to astropy time object tt=Time(dt,format='datetime') # Read the coordinates in the Geocentric Celestial Reference System gcrs = GCRS(CartesianRepresentation(x=x, y=y,z=z), obstime=tt) # Convert it to an Earth-fixed frame itrs = gcrs.transform_to(ITRS(obstime=tt)) el = EarthLocation.from_geocentric(itrs.x, itrs.y, itrs.z) return el
def earth_location_itrf(self, time=None): '''Return Fermi spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('none'): log.warning('Using location=None for TT to TDB conversion') return None elif self.tt2tdb_mode.lower().startswith('geo'): log.warning('Using location geocenter for TT to TDB conversion') return EarthLocation.from_geocentric(0.0*u.m,0.0*u.m,0.0*u.m) elif self.tt2tdb_mode.lower().startswith('spacecraft'): # First, interpolate Earth-Centered Inertial (ECI) geocentric # location from orbit file. # These are inertial coordinates aligned with ICRS, called GCRS # <http://docs.astropy.org/en/stable/api/astropy.coordinates.GCRS.html> pos_gcrs = GCRS(CartesianRepresentation(self.X(time.tt.mjd)*u.m, self.Y(time.tt.mjd)*u.m, self.Z(time.tt.mjd)*u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None', self.tt2tdb_mode) return None
def test_gcrs_icrs_moonish(testframe): """ check that something like the moon goes to about the right distance from the ICRS origin when starting from GCRS """ moonish = GCRS(MOONDIST_CART, obstime=testframe.obstime) moonicrs = moonish.transform_to(ICRS) assert 0.97*u.au < moonicrs.distance < 1.03*u.au
def test_gcrs_altaz_moonish(testframe): """ Sanity-check that an object resembling the moon goes to the right place with a GCRS->AltAz transformation """ moon = GCRS(MOONDIST_CART, obstime=testframe.obstime) moonaa = moon.transform_to(testframe) # now check that the distance change is similar to earth radius assert 1000*u.km < np.abs(moonaa.distance - moon.distance).to(u.au) < 7000*u.km # now check that it round-trips moon2 = moonaa.transform_to(moon) assert_allclose(moon.cartesian.xyz, moon2.cartesian.xyz)
def test_gcrs_altaz_bothroutes(testframe): """ Repeat of both the moonish and sunish tests above to make sure the two routes through the coordinate graph are consistent with each other """ sun = get_sun(testframe.obstime) sunaa_viaicrs = sun.transform_to(ICRS).transform_to(testframe) sunaa_viaitrs = sun.transform_to(ITRS(obstime=testframe.obstime)).transform_to(testframe) moon = GCRS(MOONDIST_CART, obstime=testframe.obstime) moonaa_viaicrs = moon.transform_to(ICRS).transform_to(testframe) moonaa_viaitrs = moon.transform_to(ITRS(obstime=testframe.obstime)).transform_to(testframe) assert_allclose(sunaa_viaicrs.cartesian.xyz, sunaa_viaitrs.cartesian.xyz) assert_allclose(moonaa_viaicrs.cartesian.xyz, moonaa_viaitrs.cartesian.xyz)
def test_gcrs_cirs(): """ Check GCRS<->CIRS transforms for round-tripping. More complicated than the above two because it's multi-hop """ ra, dec, _ = randomly_sample_sphere(200) gcrs = GCRS(ra=ra, dec=dec, obstime='J2000') gcrs6 = GCRS(ra=ra, dec=dec, obstime='J2006') gcrs2 = gcrs.transform_to(CIRS).transform_to(gcrs) gcrs6_2 = gcrs6.transform_to(CIRS).transform_to(gcrs) assert_allclose(gcrs.ra, gcrs2.ra) assert_allclose(gcrs.dec, gcrs2.dec) assert not allclose(gcrs.ra, gcrs6_2.ra) assert not allclose(gcrs.dec, gcrs6_2.dec) # now try explicit intermediate pathways and ensure they're all consistent gcrs3 = gcrs.transform_to(ITRS).transform_to(CIRS).transform_to(ITRS).transform_to(gcrs) assert_allclose(gcrs.ra, gcrs3.ra) assert_allclose(gcrs.dec, gcrs3.dec) gcrs4 = gcrs.transform_to(ICRS).transform_to(CIRS).transform_to(ICRS).transform_to(gcrs) assert_allclose(gcrs.ra, gcrs4.ra) assert_allclose(gcrs.dec, gcrs4.dec)
def test_gcrs_itrs(): """ Check basic GCRS<->ITRS transforms for round-tripping. """ ra, dec, _ = randomly_sample_sphere(200) gcrs = GCRS(ra=ra, dec=dec, obstime='J2000') gcrs6 = GCRS(ra=ra, dec=dec, obstime='J2006') gcrs2 = gcrs.transform_to(ITRS).transform_to(gcrs) gcrs6_2 = gcrs6.transform_to(ITRS).transform_to(gcrs) assert_allclose(gcrs.ra, gcrs2.ra) assert_allclose(gcrs.dec, gcrs2.dec) assert not allclose(gcrs.ra, gcrs6_2.ra) assert not allclose(gcrs.dec, gcrs6_2.dec) # also try with the cartesian representation gcrsc = gcrs.realize_frame(gcrs.data) gcrsc.representation_type = CartesianRepresentation gcrsc2 = gcrsc.transform_to(ITRS).transform_to(gcrsc) assert_allclose(gcrsc.spherical.lon.deg, gcrsc2.ra.deg) assert_allclose(gcrsc.spherical.lat, gcrsc2.dec)
def test_precessed_geocentric(): assert PrecessedGeocentric().equinox.jd == Time('J2000', scale='utc').jd gcrs_coo = GCRS(180*u.deg, 2*u.deg, distance=10000*u.km) pgeo_coo = gcrs_coo.transform_to(PrecessedGeocentric) assert np.abs(gcrs_coo.ra - pgeo_coo.ra) > 10*u.marcsec assert np.abs(gcrs_coo.dec - pgeo_coo.dec) > 10*u.marcsec assert_allclose(gcrs_coo.distance, pgeo_coo.distance) gcrs_roundtrip = pgeo_coo.transform_to(GCRS) assert_allclose(gcrs_coo.ra, gcrs_roundtrip.ra) assert_allclose(gcrs_coo.dec, gcrs_roundtrip.dec) assert_allclose(gcrs_coo.distance, gcrs_roundtrip.distance) pgeo_coo2 = gcrs_coo.transform_to(PrecessedGeocentric(equinox='B1850')) assert np.abs(gcrs_coo.ra - pgeo_coo2.ra) > 1.5*u.deg assert np.abs(gcrs_coo.dec - pgeo_coo2.dec) > 0.5*u.deg assert_allclose(gcrs_coo.distance, pgeo_coo2.distance) gcrs2_roundtrip = pgeo_coo2.transform_to(GCRS) assert_allclose(gcrs_coo.ra, gcrs2_roundtrip.ra) assert_allclose(gcrs_coo.dec, gcrs2_roundtrip.dec) assert_allclose(gcrs_coo.distance, gcrs2_roundtrip.distance)
def gen_trajectory(self, tle, interval): """ Generates the trajectory (time and coordinate information) for the given interval with the internal stepsize. Parameters ---------- tle : TLE Two-Line-Element initial orbit information (TEME mean orbital elements) interval : TimeInterval Time interval for which the ephemeris will be generated Returns ------- Trajectory The output trajectory (in `GCRS`) """ # ****** Generate the pos, vel vectors for each time instant ****** # generate the output timelist time_list = self._generate_time_list(interval) # Run the propagation and init pos and vel vectors in TEME e, r_list, v_list = tle.satrec.sgp4_array(time_list.jd1, time_list.jd2) # Load the time, pos, vel info into astropy objects (shallow copied) rv_list_teme = CartesianRepresentation( r_list, unit=u.km, xyz_axis=1 ).with_differentials(CartesianDifferential(v_list, unit=u.km / u.s, xyz_axis=1)) rv_list_gcrs = TEME( rv_list_teme, obstime=time_list, representation_type="cartesian", differential_type="cartesian", ).transform_to(GCRS(obstime=time_list)) # trajectory in astropy traj_astropy = SkyCoord( rv_list_gcrs, obstime=time_list, frame="gcrs", representation_type="cartesian", differential_type="cartesian", ) # Init trajectory in Trajectory object trajectory = Trajectory(traj_astropy) return trajectory
def test_horizontal(self): """Test `Coordinate.horizontal`. Notes ----- Test cases generated using the `Astropy` Python package. """ from astropy.coordinates import SkyCoord, ITRS, GCRS, EarthLocation, AltAz from astropy import units as u from astropy import time # Set up observer location. lat, lon = 52.1579, -106.6702 loc = EarthLocation.from_geodetic(lon * u.deg, lat * u.deg) # Prepare time and position information. times = time.Time(self.times + self.offset, format="jd") x, y, z = self.GCRS.T # Define coordinate frames. gcrs = GCRS(obstime=times) itrs = ITRS(obstime=times) altaz = AltAz(obstime=times, location=loc) # Convert between frames. gcrsCoor = SkyCoord(x=x, y=y, z=z, unit='km', frame=gcrs, representation_type='cartesian') itrsCoor = gcrsCoor.transform_to(itrs) altazCoor = itrsCoor.transform_to(altaz) # Get validation data. itrsData = np.transpose(np.array([itrsCoor.x, itrsCoor.y, itrsCoor.z])) alt = altazCoor.alt.degree az = altazCoor.az.degree # Get Celest results. coor = Coordinate(itrsData, "itrs", self.times, self.offset) groundPos = GroundPosition(lat, lon) calc_alt, calc_az = coor.horizontal(groundPos) for i in range(calc_alt.size): with self.subTest(i=i): self.assertAlmostEqual(alt[i], calc_alt[i], delta=0.25) self.assertAlmostEqual(az[i], calc_az[i], delta=7.5)
def earth_location_itrf(self, time=None): '''Return NICER spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('none'): return None elif self.tt2tdb_mode.lower().startswith('geo'): return EarthLocation.from_geocentric(0.0*u.m,0.0*u.m,0.0*u.m) elif self.tt2tdb_mode.lower().startswith('spacecraft'): # First, interpolate ECI geocentric location from orbit file. # These are inertial coorinates aligned with ICRF pos_gcrs = GCRS(CartesianRepresentation(self.X(time.tt.mjd)*u.m, self.Y(time.tt.mjd)*u.m, self.Z(time.tt.mjd)*u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None', self.tt2tdb_mode) return None
def ecef2eci(time, r_ecef, v_ecef, init_gps_weeknum): """Returns a tuple of position and velocity in ECI""" coord_ecef = ITRS(x=r_ecef[0] * u.m, y=r_ecef[1] * u.m, z=r_ecef[2] * u.m, v_x=v_ecef[0] * u.m / u.s, v_y=v_ecef[1] * u.m / u.s, v_z=v_ecef[2] * u.m / u.s, representation_type=CartesianRepresentation, differential_type=CartesianDifferential, obstime=time2astropyTime(time, init_gps_weeknum)) coord_eci = coord_ecef.transform_to( GCRS(obstime=time2astropyTime(time, init_gps_weeknum))) return (coord_eci.cartesian.xyz.to_value(u.m), coord_eci.velocity.d_xyz.to_value(u.m / u.s))
def earth_location_itrf(self, time=None): '''Return NuSTAR spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('pint'): # log.warning('Using location=None for TT to TDB conversion') return None elif self.tt2tdb_mode.lower().startswith('astropy'): # First, interpolate ECI geocentric location from orbit file. # These are inertial coorinates aligned with ICRF log.warning('Performing GCRS to ITRS transformation') pos_gcrs = GCRS(CartesianRepresentation(self.X(time.tt.mjd)*u.m, self.Y(time.tt.mjd)*u.m, self.Z(time.tt.mjd)*u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None' % self.tt2tdb_mode) return None
def _from_raw_to_ITRS(self, raw_xyz, raw_obstime): """Converts raw coordinates to ITRS ones Parameters ---------- raw_xyz: array A collection of rwa position coordinates raw_obstime: array Associated observation time Returns ------- itrs_xyz: ~astropy.coordinates.ITRS A collection of coordinates in ITRS frame """ # Build GCRS and ITRS coordinates gcrs_xyz = GCRS(raw_xyz, obstime=raw_obstime, representation_type=CartesianRepresentation) itrs_xyz = gcrs_xyz.transform_to(ITRS(obstime=raw_obstime)) return itrs_xyz
def test_gcrs_altaz(): """ Check GCRS<->AltAz transforms for round-tripping. Has multiple paths """ from astropy.coordinates import EarthLocation ra, dec, _ = randomly_sample_sphere(1) gcrs = GCRS(ra=ra[0], dec=dec[0], obstime='J2000') # check array times sure N-d arrays work times = Time(np.linspace(2456293.25, 2456657.25, 51) * u.day, format='jd') loc = EarthLocation(lon=10 * u.deg, lat=80. * u.deg) aaframe = AltAz(obstime=times, location=loc) aa1 = gcrs.transform_to(aaframe) aa2 = gcrs.transform_to(ICRS()).transform_to(CIRS()).transform_to(aaframe) aa3 = gcrs.transform_to(ITRS()).transform_to(CIRS()).transform_to(aaframe) # make sure they're all consistent assert_allclose(aa1.alt, aa2.alt) assert_allclose(aa1.az, aa2.az) assert_allclose(aa1.alt, aa3.alt) assert_allclose(aa1.az, aa3.az)
def setup_class(cls): cls.loc = loc = EarthLocation.from_geodetic( np.linspace(0, 360, 6) * u.deg, np.linspace(-90, 90, 6) * u.deg, 100 * u.m) cls.obstime = obstime = Time(np.linspace(2000, 2010, 6), format='jyear') # Get comparison via a full transformation. We do not use any methods # of EarthLocation, since those depend on the fast transform. loc_itrs = ITRS(loc.x, loc.y, loc.z, obstime=obstime) zeros = np.broadcast_to(0. * (u.km / u.s), (3, ) + loc_itrs.shape, subok=True) loc_itrs.data.differentials['s'] = CartesianDifferential(zeros) loc_gcrs_cart = loc_itrs.transform_to(GCRS(obstime=obstime)).cartesian cls.obsgeoloc = loc_gcrs_cart.without_differentials() cls.obsgeovel = loc_gcrs_cart.differentials['s'].to_cartesian()
def geoTopoVector(longitude, latitude, elevation, jd): loc = EarthLocation(longitude, latitude, elevation) time = Time(jd, scale='utc', format='jd') itrs = loc.get_itrs(obstime=time) gcrs = itrs.transform_to(GCRS(obstime=time)) r = gcrs.cartesian # convert from m to km x = r.x.value / 1000.0 y = r.y.value / 1000.0 z = r.z.value / 1000.0 return x, y, z
def test_icrs_gcrscirs_sunish(testframe): """ check that the ICRS barycenter goes to about the right distance from various ~geocentric frames (other than testframe) """ # slight offset to avoid divide-by-zero errors icrs = ICRS(0*u.deg, 0*u.deg, distance=10*u.km) gcrs = icrs.transform_to(GCRS(obstime=testframe.obstime)) assert (EARTHECC - 1)*u.au < gcrs.distance.to(u.au) < (EARTHECC + 1)*u.au cirs = icrs.transform_to(CIRS(obstime=testframe.obstime)) assert (EARTHECC - 1)*u.au < cirs.distance.to(u.au) < (EARTHECC + 1)*u.au itrs = icrs.transform_to(ITRS(obstime=testframe.obstime)) assert (EARTHECC - 1)*u.au < itrs.spherical.distance.to(u.au) < (EARTHECC + 1)*u.au
def test_j2000_to_gcrs(): """Check the coordinate transform accuracy.""" # test_frame = "GCRS" allowable_pos_diff = 800 * u.mm allowable_vel_diff = 0.36 * u.mm / u.s rv_gcrs = rv_j2000_true.transform_to(GCRS(obstime=time)) r_diff = pos_err(rv_gcrs, rv_gcrs_true) v_diff = vel_err(rv_gcrs, rv_gcrs_true) # print(f"r {test_frame} diff : {r_diff}") # print(f"v {test_frame} diff : {v_diff}") assert approx(r_diff.value, abs=allowable_pos_diff.value) == 0.0 assert approx(v_diff.value, abs=allowable_vel_diff.value) == 0.0
def TEME2ECI_pos(Pos_TEME, t): T = Time(t, format='jd', scale='utc') dist_vect = norm(Pos_TEME, axis=0) ra_vect = np.arctan2(Pos_TEME[1], Pos_TEME[0]) dec_vect = np.arcsin(Pos_TEME[2] / dist_vect) Pos_TEME_SC = PrecessedGeocentric(ra=ra_vect * u.rad, dec=dec_vect * u.rad, distance=dist_vect * u.m, equinox=T, obstime=T) Pos_ECI_SC = Pos_TEME_SC.transform_to(GCRS(obstime=T)) Pos_ECI = np.vstack(Pos_ECI_SC.cartesian.xyz.value) return Pos_ECI
def ecef2eci(x, y, z, dt): """This function takes a position in the ECEF coordinate system [m] and datetime.object [utc] and returns it in ECI-J2000 [m].""" # # Input # x = ECEF X-coordinate (m) # y = ECEF Y-coordinate (m) # z = ECEF Z-coordinate (m) # dt = UTC time (datetime object) # # # Output # # convert datetime object to astropy time object tt = time.Time(dt, format="datetime") # Read the coordinates in the Earth-fixed frame itrs = ITRS( CartesianRepresentation(x=x * units.m, y=y * units.m, z=z * units.m), obstime=tt ) # Convert it to Geocentric Celestial Reference System # gcrs = itrs.transform_to(itrs(obstime=tt)) gcrs = itrs.transform_to(GCRS(obstime=tt)) x = gcrs.cartesian.x.to_value() y = gcrs.cartesian.y.to_value() z = gcrs.cartesian.z.to_value() return x, y, z
def test_skycoord_transforms(): # An EarthLocation object should still get copied over # under transformations. eloc = EarthLocation.from_geodetic(0.0, 10.0) coords = ltest.get_catalog() altaz = coords.transform_to(AltAz(location=eloc, obstime=Time.now())) assert altaz.location == eloc gcrs = altaz.transform_to(GCRS()) assert gcrs.location == eloc icrs = altaz.transform_to(ICRS()) assert icrs.location == eloc
def HCI2ECI_pos(Pos_HCI, t): # Position & velocity relative to the sun T = Time(t, format='jd', scale='utc') Pos_HCRS = HCI2HCRS(Pos_HCI) # TODO. HARD: had to remove it #Vel_HCRS_rel = HCI2HCRS(Vel_HCI - EarthVelocity(t)) Pos_HCRS_SC = HCRS(x=Pos_HCRS[0] * u.m, y=Pos_HCRS[1] * u.m, z=Pos_HCRS[2] * u.m, representation='cartesian', obstime=T) Pos_ECI = np.vstack( Pos_HCRS_SC.transform_to(GCRS(obstime=T)).cartesian.xyz.value) return Pos_ECI
def test_j2000_roundtrip(): """Check whether transforming to a coord and then transforming back yields the same output.""" # test_frame = "J2000" allowable_pos_diff = 1.5e-6 * u.mm allowable_vel_diff = 1.0e-9 * u.mm / u.s rv_gcrs = rv_j2000_true.transform_to(GCRS(obstime=time)) rv_j2000_from_gcrs = rv_gcrs.transform_to(J2000(obstime=time)) r_diff = pos_err(rv_j2000_from_gcrs, rv_j2000_true) v_diff = vel_err(rv_j2000_from_gcrs, rv_j2000_true) # print(f"r {test_frame} diff : {r_diff}") # print(f"v {test_frame} diff : {v_diff}") assert approx(r_diff.value, abs=allowable_pos_diff.value) == 0.0 assert approx(v_diff.value, abs=allowable_vel_diff.value) == 0.0
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ # TODO: https://github.com/poliastro/poliastro/issues/445 if not epoch: epoch = time.Time.now().tdb elif epoch.scale != "tdb": epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " f"{epoch.tdb.value}. Use Time(..., scale='tdb') instead.", TimeScaleWarning, ) try: r, v = get_body_barycentric_posvel(body.name, epoch) except KeyError: raise RuntimeError( """To compute the position and velocity of the Moon and Pluto use the JPL ephemeris: >>> from astropy.coordinates import solar_system_ephemeris >>> solar_system_ephemeris.set('jpl') """) if body == Moon: # TODO: The attractor is in fact the Earth-Moon Barycenter icrs_cart = r.with_differentials( v.represent_as(CartesianDifferential)) gcrs_cart = (ICRS(icrs_cart).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) ss = cls.from_vectors( Earth, gcrs_cart.xyz.to(u.km), gcrs_cart.differentials["s"].d_xyz.to(u.km / u.day), epoch, ) else: # TODO: The attractor is not really the Sun, but the Solar System # Barycenter ss = cls.from_vectors(Sun, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch) ss._frame = ICRS() # Hack! return ss
def build_ephem_interpolant(body, period, t_span, rtol=1e-5): """Interpolates ephemerides data Parameters ---------- body : Body Source body. period : ~astropy.units.Quantity Orbital period. t_span : list(~astropy.units.Quantity) Initial and final epochs. rtol : float, optional Relative tolerance. Controls the number of sampled data points, defaults to 1e-5. Returns ------- intrp : ~scipy.interpolate.interpolate.interp1d Interpolated function. """ h = (period * rtol).to(u.day).value t_span = (t_span[0].to(u.day).value, t_span[1].to(u.day).value + 0.01) t_values = np.linspace(*t_span, int( (t_span[1] - t_span[0]) / h)) # type: ignore r_values = np.zeros((t_values.shape[0], 3)) for i, t in enumerate(t_values): epoch = Time(t, format="jd", scale="tdb") r = get_body_barycentric(body.name, epoch) r = (ICRS( x=r.x, y=r.y, z=r.z, representation_type=CartesianRepresentation).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) r_values[i] = r.xyz.to(u.km) t_values = ((t_values - t_span[0]) * u.day).to(u.s).value return interp1d(t_values, r_values, kind="cubic", axis=0, assume_sorted=True)
def test_icrs_gcrs(icoo): """ Check ICRS<->GCRS for consistency """ gcrscoo = icoo.transform_to(gcrs_frames[0]) # uses the default time # first do a round-tripping test icoo2 = gcrscoo.transform_to(ICRS()) assert_allclose(icoo.distance, icoo2.distance) assert_allclose(icoo.ra, icoo2.ra) assert_allclose(icoo.dec, icoo2.dec) assert isinstance(icoo2.data, icoo.data.__class__) # now check that a different time yields different answers gcrscoo2 = icoo.transform_to(gcrs_frames[1]) assert not allclose(gcrscoo.ra, gcrscoo2.ra, rtol=1e-8, atol=1e-10 * u.deg) assert not allclose( gcrscoo.dec, gcrscoo2.dec, rtol=1e-8, atol=1e-10 * u.deg) # now check that the cirs self-transform works as expected gcrscoo3 = gcrscoo.transform_to(gcrs_frames[0]) # should be a no-op assert_allclose(gcrscoo.ra, gcrscoo3.ra) assert_allclose(gcrscoo.dec, gcrscoo3.dec) gcrscoo4 = gcrscoo.transform_to(gcrs_frames[1]) # should be different assert not allclose(gcrscoo4.ra, gcrscoo.ra, rtol=1e-8, atol=1e-10 * u.deg) assert not allclose( gcrscoo4.dec, gcrscoo.dec, rtol=1e-8, atol=1e-10 * u.deg) gcrscoo5 = gcrscoo4.transform_to( gcrs_frames[0]) # should be back to the same assert_allclose(gcrscoo.ra, gcrscoo5.ra, rtol=1e-8, atol=1e-10 * u.deg) assert_allclose(gcrscoo.dec, gcrscoo5.dec, rtol=1e-8, atol=1e-10 * u.deg) # also make sure that a GCRS with a different geoloc/geovel gets a different answer # roughly a moon-like frame gframe3 = GCRS(obsgeoloc=[385000., 0, 0] * u.km, obsgeovel=[1, 0, 0] * u.km / u.s) gcrscoo6 = icoo.transform_to(gframe3) # should be different assert not allclose(gcrscoo.ra, gcrscoo6.ra, rtol=1e-8, atol=1e-10 * u.deg) assert not allclose( gcrscoo.dec, gcrscoo6.dec, rtol=1e-8, atol=1e-10 * u.deg) icooviag3 = gcrscoo6.transform_to(ICRS()) # and now back to the original assert_allclose(icoo.ra, icooviag3.ra) assert_allclose(icoo.dec, icooviag3.dec)
def test_ephemerides(): """ We test that using different ephemerides gives very similar results for transformations """ t = Time("2014-12-25T07:00") moon = SkyCoord( GCRS(318.10579159 * u.deg, -11.65281165 * u.deg, 365042.64880308 * u.km, obstime=t)) icrs_frame = ICRS() hcrs_frame = HCRS(obstime=t) ecl_frame = HeliocentricMeanEcliptic(equinox=t) cirs_frame = CIRS(obstime=t) moon_icrs_builtin = moon.transform_to(icrs_frame) moon_hcrs_builtin = moon.transform_to(hcrs_frame) moon_helioecl_builtin = moon.transform_to(ecl_frame) moon_cirs_builtin = moon.transform_to(cirs_frame) with solar_system_ephemeris.set('jpl'): moon_icrs_jpl = moon.transform_to(icrs_frame) moon_hcrs_jpl = moon.transform_to(hcrs_frame) moon_helioecl_jpl = moon.transform_to(ecl_frame) moon_cirs_jpl = moon.transform_to(cirs_frame) # most transformations should differ by an amount which is # non-zero but of order milliarcsecs sep_icrs = moon_icrs_builtin.separation(moon_icrs_jpl) sep_hcrs = moon_hcrs_builtin.separation(moon_hcrs_jpl) sep_helioecl = moon_helioecl_builtin.separation(moon_helioecl_jpl) sep_cirs = moon_cirs_builtin.separation(moon_cirs_jpl) assert_allclose([sep_icrs, sep_hcrs, sep_helioecl], 0.0 * u.deg, atol=10 * u.mas) assert all(sep > 10 * u.microarcsecond for sep in (sep_icrs, sep_hcrs, sep_helioecl)) # CIRS should be the same assert_allclose(sep_cirs, 0.0 * u.deg, atol=1 * u.microarcsecond)
def test_propagation(init_tle_vgd): # init TLE tle = init_tle_vgd # init SGP4 sgp4 = SGP4Propagator() # Propagate 3 days into future time = tle.epoch + 3.0 * u.day rv_gcrs = sgp4.propagate(tle, time) # print(rv_gcrs) # Generate truth values # Vallado IAU-76/FK5 - pg.234 v_j2000_true = CartesianDifferential( [-2.233348094, -4.110136162, -3.157394074], unit=u.km / u.s ) r_j2000_true = CartesianRepresentation( [-9059.9413786, 4659.6972000, 813.9588875], unit=u.km ) rv_j2000_true = J2000( r_j2000_true.with_differentials(v_j2000_true), obstime=time, representation_type="cartesian", differential_type="cartesian", ) rv_gcrs_true = SkyCoord( rv_j2000_true.transform_to(GCRS(obstime=time)), representation_type="cartesian", differential_type="cartesian", ) r_diff, v_diff = rv_diff(rv_gcrs, rv_gcrs_true) # print(r_diff.to(u.mm)) # print(v_diff.to(u.mm / u.s)) assert r_diff.to(u.mm) < 1700 * u.mm assert v_diff.to(u.mm / u.s) < 0.88 * u.mm / u.s
def test_tete_transforms(): """ We test the TETE transforms for proper behaviour here. The TETE transforms are tested for accuracy against JPL Horizons in test_solar_system.py. Here we are looking to check for consistency and errors in the self transform. """ loc = EarthLocation.from_geodetic("-22°57'35.1", "-67°47'14.1", 5186*u.m) time = Time('2020-04-06T00:00') p, v = loc.get_gcrs_posvel(time) gcrs_frame = GCRS(obstime=time, obsgeoloc=p, obsgeovel=v) moon = SkyCoord(169.24113968*u.deg, 10.86086666*u.deg, 358549.25381755*u.km, frame=gcrs_frame) tete_frame = TETE(obstime=time, location=loc) # need to set obsgeoloc/vel explicity or skycoord behaviour over-writes tete_geo = TETE(obstime=time, location=EarthLocation(*([0, 0, 0]*u.km))) # test self-transform by comparing to GCRS-TETE-ITRS-TETE route tete_coo1 = moon.transform_to(tete_frame) tete_coo2 = moon.transform_to(tete_geo) assert_allclose(tete_coo1.separation_3d(tete_coo2), 0*u.mm, atol=1*u.mm) # test TETE-ITRS transform by comparing GCRS-CIRS-ITRS to GCRS-TETE-ITRS itrs1 = moon.transform_to(CIRS()).transform_to(ITRS()) itrs2 = moon.transform_to(TETE()).transform_to(ITRS()) assert_allclose(itrs1.separation_3d(itrs2), 0*u.mm, atol=1*u.mm) # test round trip GCRS->TETE->GCRS new_moon = moon.transform_to(TETE()).transform_to(moon) assert_allclose(new_moon.separation_3d(moon), 0*u.mm, atol=1*u.mm) # test round trip via ITRS tete_rt = tete_coo1.transform_to(ITRS(obstime=time)).transform_to(tete_coo1) assert_allclose(tete_rt.separation_3d(tete_coo1), 0*u.mm, atol=1*u.mm) # ensure deprecated routine remains consistent # make sure test raises warning! with pytest.warns(AstropyDeprecationWarning, match='The use of'): tete_alt = _apparent_position_in_true_coordinates(moon) assert_allclose(tete_coo1.separation_3d(tete_alt), 0*u.mm, atol=100*u.mm)
def propagate(tle, time): """ Computes the coordinates at the target `time` using the source `TLE` mean orbital elements. Parameters ---------- tle : TLE Mean orbital elements (Two-Line-Element) time : Time Target time for propagation Returns ------- coords : SkyCoord Coordinates at target time (in `GCRS`) Raises ------ SGP4GeneralError Errors in SGP4 propagation SGP4SatDecayedError Satellite coordinates at required coordinates are below decay altitude. """ # compute coords at time e, r, v = tle.satrec.sgp4(time.utc.jd1, time.utc.jd2) # check error code SGP4Propagator.__handle_err_code(e) v_teme = CartesianDifferential(np.asarray(v), unit=u.km / u.s) r_teme = CartesianRepresentation(np.asarray(r), unit=u.km) rv_gcrs = TEME(r_teme.with_differentials(v_teme), obstime=time).transform_to(GCRS(obstime=time)) return SkyCoord( rv_gcrs, representation_type="cartesian", differential_type="cartesian", )
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ # TODO: https://github.com/poliastro/poliastro/issues/445 if not epoch: epoch = time.Time.now().tdb elif epoch.scale != "tdb": epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " "{}. Use Time(..., scale='tdb') instead.".format( epoch.tdb.value), TimeScaleWarning, ) r, v = get_body_barycentric_posvel(body.name, epoch) if body == Moon: # TODO: The attractor is in fact the Earth-Moon Barycenter icrs_cart = r.with_differentials( v.represent_as(CartesianDifferential)) gcrs_cart = (ICRS(icrs_cart).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) ss = cls.from_vectors( Earth, gcrs_cart.xyz.to(u.km), gcrs_cart.differentials["s"].d_xyz.to(u.km / u.day), epoch, ) else: # TODO: The attractor is not really the Sun, but the Solar System # Barycenter ss = cls.from_vectors(Sun, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch) ss._frame = ICRS() # Hack! return ss
def test_get_skycoord(): m31 = SkyCoord(10.6847083 * u.deg, 41.26875 * u.deg) m31_with_distance = SkyCoord(10.6847083 * u.deg, 41.26875 * u.deg, 780 * u.kpc) subaru = Observer.at_site('subaru') time = Time("2016-01-22 12:00") pos, vel = subaru.location.get_gcrs_posvel(time) gcrs_frame = GCRS(obstime=Time("2016-01-22 12:00"), obsgeoloc=pos, obsgeovel=vel) m31_gcrs = m31.transform_to(gcrs_frame) m31_gcrs_with_distance = m31_with_distance.transform_to(gcrs_frame) coo = get_skycoord(m31) assert coo.is_equivalent_frame(ICRS()) with pytest.raises(TypeError) as exc_info: len(coo) coo = get_skycoord([m31]) assert coo.is_equivalent_frame(ICRS()) assert len(coo) == 1 coo = get_skycoord([m31, m31_gcrs]) assert coo.is_equivalent_frame(ICRS()) assert len(coo) == 2 coo = get_skycoord([m31_with_distance, m31_gcrs_with_distance]) assert coo.is_equivalent_frame(ICRS()) assert len(coo) == 2 coo = get_skycoord( [m31, m31_gcrs, m31_gcrs_with_distance, m31_with_distance]) assert coo.is_equivalent_frame(ICRS()) assert len(coo) == 4 coo = get_skycoord([m31_gcrs, m31_gcrs_with_distance]) assert coo.is_equivalent_frame(m31_gcrs.frame) assert len(coo) == 2
def test_init_cart(): """Tests the cartesian initialisation convenience method.""" rv_gcrs_true_sky = SkyCoord(rv_gcrs_true) # easy init rv_gcrs_0 = init_pvt(GCRS, time, r_gcrs_true, v_gcrs_true) # init with str frame name (should be lowercase letters) rv_gcrs_1 = init_pvt("GCRS", time, r_gcrs_true, v_gcrs_true) # init without velocity rv_gcrs_2 = init_pvt(GCRS, time, r_gcrs_true, copy=False) assert rv_gcrs_0 == rv_gcrs_true_sky assert rv_gcrs_1 == rv_gcrs_true_sky assert rv_gcrs_2 == SkyCoord( GCRS( r_gcrs_true, obstime=time, representation_type="cartesian", differential_type="cartesian", ))
def build_ephem_interpolant(body, period, t_span, rtol=1e-5): h = (period * rtol).to(u.day).value t_span = (t_span[0].to(u.day).value, t_span[1].to(u.day).value + 0.01) t_values = np.linspace(*t_span, int((t_span[1] - t_span[0]) / h)) r_values = np.zeros((t_values.shape[0], 3)) for i, t in enumerate(t_values): epoch = Time(t, format="jd", scale="tdb") r = get_body_barycentric(body.name, epoch) r = (ICRS( x=r.x, y=r.y, z=r.z, representation_type=CartesianRepresentation).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) r_values[i] = r.xyz.to(u.km) t_values = ((t_values - t_span[0]) * u.day).to(u.s).value return interp1d(t_values, r_values, kind="cubic", axis=0, assume_sorted=True)
def test_gcrs_itrs(): """ Check basic GCRS<->ITRS transforms for round-tripping. """ ra, dec, _ = randomly_sample_sphere(200) gcrs = GCRS(ra=ra, dec=dec, obstime='J2000') gcrs6 = GCRS(ra=ra, dec=dec, obstime='J2006') gcrs2 = gcrs.transform_to(ITRS).transform_to(gcrs) gcrs6_2 = gcrs6.transform_to(ITRS).transform_to(gcrs) assert_allclose(gcrs.ra, gcrs2.ra) assert_allclose(gcrs.dec, gcrs2.dec) assert not allclose(gcrs.ra, gcrs6_2.ra) assert not allclose(gcrs.dec, gcrs6_2.dec) # also try with the cartesian representation gcrsc = gcrs.realize_frame(gcrs.data) gcrsc.representation_type = CartesianRepresentation gcrsc2 = gcrsc.transform_to(ITRS).transform_to(gcrsc) assert_allclose(gcrsc.spherical.lon.deg, gcrsc2.ra.deg) assert_allclose(gcrsc.spherical.lat, gcrsc2.dec)
def test_gcrs_itrs(): """ Check basic GCRS<->ITRS transforms for round-tripping. """ usph = golden_spiral_grid(200) gcrs = GCRS(usph, obstime='J2000') gcrs6 = GCRS(usph, obstime='J2006') gcrs2 = gcrs.transform_to(ITRS()).transform_to(gcrs) gcrs6_2 = gcrs6.transform_to(ITRS()).transform_to(gcrs) assert_allclose(gcrs.ra, gcrs2.ra) assert_allclose(gcrs.dec, gcrs2.dec) # these should be different: assert not allclose(gcrs.ra, gcrs6_2.ra, rtol=1e-8) assert not allclose(gcrs.dec, gcrs6_2.dec, rtol=1e-8) # also try with the cartesian representation gcrsc = gcrs.realize_frame(gcrs.data) gcrsc.representation_type = CartesianRepresentation gcrsc2 = gcrsc.transform_to(ITRS()).transform_to(gcrsc) assert_allclose(gcrsc.spherical.lon, gcrsc2.ra) assert_allclose(gcrsc.spherical.lat, gcrsc2.dec)
def test_precessed_geocentric(): assert PrecessedGeocentric().equinox.jd == Time('J2000').jd gcrs_coo = GCRS(180 * u.deg, 2 * u.deg, distance=10000 * u.km) pgeo_coo = gcrs_coo.transform_to(PrecessedGeocentric()) assert np.abs(gcrs_coo.ra - pgeo_coo.ra) > 10 * u.marcsec assert np.abs(gcrs_coo.dec - pgeo_coo.dec) > 10 * u.marcsec assert_allclose(gcrs_coo.distance, pgeo_coo.distance) gcrs_roundtrip = pgeo_coo.transform_to(GCRS()) assert_allclose(gcrs_coo.ra, gcrs_roundtrip.ra) assert_allclose(gcrs_coo.dec, gcrs_roundtrip.dec) assert_allclose(gcrs_coo.distance, gcrs_roundtrip.distance) pgeo_coo2 = gcrs_coo.transform_to(PrecessedGeocentric(equinox='B1850')) assert np.abs(gcrs_coo.ra - pgeo_coo2.ra) > 1.5 * u.deg assert np.abs(gcrs_coo.dec - pgeo_coo2.dec) > 0.5 * u.deg assert_allclose(gcrs_coo.distance, pgeo_coo2.distance) gcrs2_roundtrip = pgeo_coo2.transform_to(GCRS()) assert_allclose(gcrs_coo.ra, gcrs2_roundtrip.ra) assert_allclose(gcrs_coo.dec, gcrs2_roundtrip.dec) assert_allclose(gcrs_coo.distance, gcrs2_roundtrip.distance)
assert_allclose(cirsnod.ra, cirsnod3.ra) assert_allclose(cirsnod.dec, cirsnod3.dec) cirsnod4 = cirsnod.transform_to(cframe2) # should be different assert not allclose(cirsnod4.ra, cirsnod.ra, rtol=1e-8) assert not allclose(cirsnod4.dec, cirsnod.dec, rtol=1e-8) cirsnod5 = cirsnod4.transform_to(cframe1) # should be back to the same assert_allclose(cirsnod.ra, cirsnod5.ra) assert_allclose(cirsnod.dec, cirsnod5.dec) usph = golden_spiral_grid(200) dist = np.linspace(0.5, 1, len(usph)) * u.pc icrs_coords = [ICRS(usph), ICRS(usph.lon, usph.lat, distance=dist)] gcrs_frames = [GCRS(), GCRS(obstime=Time('J2005'))] @pytest.mark.parametrize('icoo', icrs_coords) def test_icrs_gcrs(icoo): """ Check ICRS<->GCRS for consistency """ gcrscoo = icoo.transform_to(gcrs_frames[0]) # uses the default time # first do a round-tripping test icoo2 = gcrscoo.transform_to(ICRS()) assert_allclose(icoo.distance, icoo2.distance) assert_allclose(icoo.ra, icoo2.ra) assert_allclose(icoo.dec, icoo2.dec) assert isinstance(icoo2.data, icoo.data.__class__)
def test_gcrs_itrs_cartesian_repr(): # issue 6436: transformation failed if coordinate representation was # Cartesian gcrs = GCRS(CartesianRepresentation((859.07256, -4137.20368, 5295.56871), unit='km'), representation_type='cartesian') gcrs.transform_to(ITRS)
def test_regression_8138(): sc = SkyCoord(1*u.deg, 2*u.deg) newframe = GCRS() sc2 = sc.transform_to(newframe) assert newframe.is_equivalent_frame(sc2.frame)