def inclination(self, new_inclination): previous_inclination = self._inclination rot_new_inc = rotation_matrix(previous_inclination - new_inclination, axis='x') for spot in self.spots: cartesian = CartesianRepresentation( x=spot.x, y=spot.y, z=spot.z).transform(rot_new_inc) spot.x = cartesian.x.value spot.y = cartesian.y.value spot.z = cartesian.z.value self._inclination = new_inclination
def test_from_coord_fails_if_no_time_differential(): pos = [30000, 0, 0] * u.km cartrep = CartesianRepresentation(*pos) # Method fails if coordinate instance doesn't contain a differential with # respect to time with pytest.raises(ValueError) as excinfo: Orbit.from_coords(Earth, SkyCoord(cartrep)) assert ( "ValueError: Coordinate instance doesn't have a differential with respect to time" in excinfo.exconly())
def _sample(self, time_values, method=mean_motion): # if use cowell, propagate to max_time and use other values as intermediate (dense output) if method == cowell: values, _ = cowell(self, (time_values - self.epoch).to(u.s).value) values = values * u.km else: values = np.zeros((len(time_values), 3)) * self.r.unit for ii, epoch in enumerate(time_values): rr = self.propagate(epoch, method).r values[ii] = rr return CartesianRepresentation(values, xyz_axis=1)
def test_from_coord_if_coord_is_not_of_shape_zero(): pos = [0, 1, 0] vel = [1, 0, 0] cartdiff = CartesianDifferential([vel] * u.km / u.s, xyz_axis=1) cartrep = CartesianRepresentation([pos] * u.km, differentials=cartdiff, xyz_axis=1) coords = GCRS(cartrep, representation_type=CartesianRepresentation, obstime=J2000) ss = Orbit.from_coords(Earth, coords) assert_quantity_allclose(ss.r, pos * u.km, rtol=1e-5) assert_quantity_allclose(ss.v, vel * u.km / u.s, rtol=1e-5)
def goto(self, x, y=None): if isinstance(x, CartesianRepresentation): self._position3D = x x_km = self._position3D.x.to(units.kilometer).value y_km = self._position3D.y.to(units.kilometer).value super().goto(x_km, y_km) else: super().goto(x, y) x_km = super().xcor() * units.kilometer y_km = super().ycor() * units.kilometer self._position3D = CartesianRepresentation(x_km, y_km, self._position3D.z)
def propagate(orbit, time_of_flight, *, method=farnocchia, rtol=1e-10, **kwargs): """Propagate an orbit some time and return the result. Parameters ---------- orbit : ~poliastro.twobody.Orbit Orbit object to propagate. time_of_flight : ~astropy.time.TimeDelta Time of propagation. method : callable, optional Propagation method, default to farnocchia. rtol : float, optional Relative tolerance, default to 1e-10. **kwargs Extra kwargs for propagation method. Returns ------- astropy.coordinates.CartesianRepresentation Propagation coordinates. """ # Check if propagator fulfills orbit requirements if orbit.ecc < 1.0 and method not in ELLIPTIC_PROPAGATORS: raise ValueError( "Can not use an parabolic/hyperbolic propagator for elliptical/circular orbits." ) elif orbit.ecc == 1.0 and method not in PARABOLIC_PROPAGATORS: raise ValueError( "Can not use an elliptic/hyperbolic propagator for parabolic orbits." ) elif orbit.ecc > 1.0 and method not in HYPERBOLIC_PROPAGATORS: raise ValueError( "Can not use an elliptic/parabolic propagator for hyperbolic orbits." ) rr, vv = method(orbit.attractor.k, orbit.r, orbit.v, time_of_flight.reshape(-1).to(u.s), rtol=rtol, **kwargs) cartesian = CartesianRepresentation(rr, differentials=CartesianDifferential( vv, xyz_axis=1), xyz_axis=1) return cartesian
def __init__(self, surface_area, radiance, mass): self.radiance = radiance # power / area / solid angle self.surface_area = surface_area self.mass = mass self.t = 0*u.second try: self.loc = CartesianRepresentation([0, 0, 0]*u.m) except AttributeError: pass # this is OK, because it's when a read-only loc is present
def test_planetary_icrs_frame_is_just_translation(body, frame): with solar_system_ephemeris.set("builtin"): epoch = J2000 vector = CartesianRepresentation(x=100 * u.km, y=100 * u.km, z=100 * u.km) vector_result = (frame(vector, obstime=epoch).transform_to( ICRS).represent_as(CartesianRepresentation)) expected_result = get_body_barycentric(body.name, epoch) + vector assert_quantity_allclose(vector_result.xyz, expected_result.xyz)
def __getarray__(rotate=True, representation='Cylindrical', **kwargs): """ This function will create a 2D/3D array from the requested shape in kwargs['shape']. It can either return this array into cartesian, polar/cylindrical or spherical coordinates. Using the optional rotate keyword the array can also be rotated into the plane of the sky. This requires the position angle, 'PA', and the inclinatio, 'Incl'. Parameters ---------- rotate : 'True' | 'False' This will either return the rotated or non-rotated array. representation : 'Cylindrical' | 'Cartesian' | 'Spherical' Representation to use for the returned array. Returns ------- 2 or 3 numpy arrays corresponding to the rho, phi, (z) array, the x, y, (z) array or the rho, lon, (lat array). """ # create x, y ,and z arrays tshape = np.array(kwargs['shape']) shape = (tshape[-1], tshape[-2], np.max(tshape)) Indices = np.indices(shape, dtype=float) # translate the array Indices[0] = Indices[0] - kwargs['par']['Xcen'] Indices[1] = Indices[1] - kwargs['par']['Ycen'] Indices[2] = Indices[2] - int(kwargs['shape'][2] / 2.) # make a cartesian representation for matrix rotation CarRep = CartesianRepresentation(Indices, unit=u.pix) if rotate: # rotation due to PA (NOTE different axis definition) CarRep = CarRep.transform( rm(kwargs['par']['PA'] + np.pi / 2, axis='z', unit=u.rad)) # rotation due to inclination (NOTE different axis definition) CarRep = CarRep.transform( rm(kwargs['par']['Incl'], axis='x', unit=u.rad)) else: # rotate by 90 degrees because of definition of PA CarRep = CarRep.transform(rm(np.pi / 2, axis='z', unit=u.rad)) # the representation to use and the return values if representation is 'Cartesian': return CarRep.x.value, CarRep.y.value, CarRep.z.value elif representation is 'Cylindrical': Rep = CylindricalRepresentation.from_cartesian(CarRep) return Rep.rho.value, Rep.phi.value, Rep.z.value elif representation is 'Spherical': Rep = SphericalRepresentation.from_cartesian(CarRep) return Rep.distance.value, Rep.lon.value, Rep.lat.value
def obsgeo_to_frame(obsgeo, obstime): """ Convert a WCS obsgeo property into an `~builtin_frames.ITRS` coordinate frame. Parameters ---------- obsgeo : array-like A shape ``(6, )`` array representing ``OBSGEO-[XYZ], OBSGEO-[BLH]`` as returned by ``WCS.wcs.obsgeo``. obstime : time-like The time assiociated with the coordinate, will be passed to `~.builtin_frames.ITRS` as the obstime keyword. Returns ------- `~.builtin_frames.ITRS` An `~.builtin_frames.ITRS` coordinate frame representing the coordinates. Notes ----- The obsgeo array as accessed on a `.WCS` object is a length 6 numpy array where the first three elements are the coordinate in a cartesian representation and the second 3 are the coordinate in a spherical representation. This function priorities reading the cartesian coordinates, and will only read the spherical coordinates if the cartesian coordinates are either all zero or any of the cartesian coordinates are non-finite. In the case where both the spherical and cartesian coordinates have some non-finite values the spherical coordinates will be returned with the non-finite values included. """ if (obsgeo is None or len(obsgeo) != 6 or np.all(np.array(obsgeo) == 0) or np.all(~np.isfinite(obsgeo))): # NOQA raise ValueError( f"Can not parse the 'obsgeo' location ({obsgeo}). " "obsgeo should be a length 6 non-zero, finite numpy array") # If the cartesian coords are zero or have NaNs in them use the spherical ones if np.all(obsgeo[:3] == 0) or np.any(~np.isfinite(obsgeo[:3])): data = SphericalRepresentation(*(obsgeo[3:] * (u.deg, u.deg, u.m))) # Otherwise we assume the cartesian ones are valid else: data = CartesianRepresentation(*obsgeo[:3] * u.m) return ITRS(data, obstime=obstime)
def to_cartesian(self): """Generate a Cartesian representation from a Geodetic one Returns ------- CartesianRepresentation The Cartesian coordinates corresponding to this representation """ d1, m1 = 1 / u.deg, 1 / u.m ecef = turtle.ecef_from_geodetic(self.latitude * d1, self.longitude * d1, self.height * m1) if ecef.size == 3: return CartesianRepresentation(ecef[0] * u.m, ecef[1] * u.m, ecef[2] * u.m, copy=False) else: return CartesianRepresentation(ecef[:, 0] * u.m, ecef[:, 1] * u.m, ecef[:, 2] * u.m, copy=False)
def altaz_interpolate(self, time): """Interpolate pointing for a given time.""" t_new = time.mjd t = self.time.mjd xyz = self.altaz.cartesian x_new = scipy.interpolate.interp1d(t, xyz.x)(t_new) y_new = scipy.interpolate.interp1d(t, xyz.y)(t_new) z_new = scipy.interpolate.interp1d(t, xyz.z)(t_new) xyz_new = CartesianRepresentation(x_new, y_new, z_new) altaz_frame = AltAz(obstime=time, location=self.location) return SkyCoord( xyz_new, frame=altaz_frame, unit="deg", representation_type="unitspherical" )
def from_equatorial(equatorial_coo, fixed_frame): # TODO replace w/ something smart (Sun/Earth special cased) # assert equatorial_coo.body == fixed_frame.body r = equatorial_coo.cartesian.xyz ra, dec, W = fixed_frame.rot_elements_at_epoch(equatorial_coo.obstime) r_trans2 = transform_vector(r, (90 * u.deg + ra), "z") r_f = transform_vector(r_trans2, (90 * u.deg - dec), "x") r_f = transform_vector(r_f, W, "z") if equatorial_coo.data.differentials: v = equatorial_coo.data.differentials["s"].d_xyz v_trans1 = transform_vector(v, (90 * u.deg + ra), "z") v_f = transform_vector(v_trans1, (90 * u.deg - dec), "x") v_f = transform_vector(v_f, W, "z") data = CartesianRepresentation( r_f, differentials=CartesianDifferential(v_f)) else: data = CartesianRepresentation(r_f) return fixed_frame.realize_frame(data)
def test_observer_init_rv_behavior(): """ Test basic initialization behavior or observer/target and redshift/rv """ # Start off by specifying the radial velocity only sc_init = SpectralCoord([4000, 5000] * u.AA, radial_velocity=100 * u.km / u.s) assert sc_init.observer is None assert sc_init.target is None assert_quantity_allclose(sc_init.radial_velocity, 100 * u.km / u.s) # Next, set the observer, and check that the radial velocity hasn't changed with pytest.warns(AstropyUserWarning, match='No velocity defined on frame'): sc_init.observer = ICRS( CartesianRepresentation([0 * u.km, 0 * u.km, 0 * u.km])) assert sc_init.observer is not None assert_quantity_allclose(sc_init.radial_velocity, 100 * u.km / u.s) # Setting the target should now cause the original radial velocity to be # dropped in favor of the automatically computed one sc_init.target = SkyCoord(CartesianRepresentation( [1 * u.km, 0 * u.km, 0 * u.km]), frame='icrs', radial_velocity=30 * u.km / u.s) assert sc_init.target is not None assert_quantity_allclose(sc_init.radial_velocity, 30 * u.km / u.s) # The observer can only be set if originally None - now that it isn't # setting it again should fail with pytest.raises(ValueError, match='observer has already been set'): sc_init.observer = GCRS( CartesianRepresentation([0 * u.km, 1 * u.km, 0 * u.km])) # And similarly, changing the target should not be possible with pytest.raises(ValueError, match='target has already been set'): sc_init.target = GCRS( CartesianRepresentation([0 * u.km, 1 * u.km, 0 * u.km]))
def test_regression_6697(): """ Test for regression of a bug in get_gcrs_posvel that introduced errors at the 1m/s level. Comparison data is derived from calculation in PINT https://github.com/nanograv/PINT/blob/master/pint/erfautils.py """ pint_vels = CartesianRepresentation(*(348.63632871, -212.31704928, -0.60154936), unit=u.m/u.s) location = EarthLocation(*(5327448.9957829, -1718665.73869569, 3051566.90295403), unit=u.m) t = Time(2458036.161966612, format='jd') obsgeopos, obsgeovel = location.get_gcrs_posvel(t) delta = (obsgeovel-pint_vels).norm() assert delta < 1*u.cm/u.s
def test_regression_8924(): """This checks that the ValueError in BaseRepresentation._re_represent_differentials is raised properly """ # A case where the representation has a 's' differential, but we try to # re-represent only with an 's2' differential rep = CartesianRepresentation(1, 2, 3, unit=u.kpc) dif = CartesianDifferential(4, 5, 6, u.km/u.s) rep = rep.with_differentials(dif) with pytest.raises(ValueError): rep._re_represent_differentials(CylindricalRepresentation, {'s2': CylindricalDifferential})
def ecef_to_eci(r: np.ndarray, time: Time) -> np.ndarray: """ Converts coordinates in Earth Centered Earth Initial frame to Earth Centered Initial. :param r: position of satellite in ECEF frame. Units [km] :param time: Time of observation """ itrs = ITRS(CartesianRepresentation(r[0] * u.km, r[1] * u.km, r[2] * u.km), obstime=time) gcrs = itrs.transform_to(GCRS(obstime=time)) x_eci = gcrs.cartesian.x.value y_eci = gcrs.cartesian.y.value z_eci = gcrs.cartesian.z.value return np.array([x_eci, y_eci, z_eci])
def setup(self): self.t1 = Time("2013-02-02T23:00") self.t2 = Time("2013-08-02T23:00") self.tarr = Time(["2013-02-02T23:00", "2013-08-02T23:00"]) self.sun_icrs_scalar = ICRS(ra=244.52984668 * u.deg, dec=-22.36943723 * u.deg, distance=406615.66347377 * u.km) # array of positions corresponds to times in `tarr` self.sun_icrs_arr = ICRS(ra=[244.52989062, 271.40976248] * u.deg, dec=[-22.36943605, -25.07431079] * u.deg, distance=[406615.66347377, 375484.13558956] * u.km) # corresponding HCRS positions self.sun_hcrs_t1 = HCRS(CartesianRepresentation([0.0, 0.0, 0.0] * u.km), obstime=self.t1) twod_rep = CartesianRepresentation( [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] * u.km) self.sun_hcrs_tarr = HCRS(twod_rep, obstime=self.tarr) self.tolerance = 5 * u.km
def eci_to_ecef(r: np.ndarray, time: Time) -> np.ndarray: """ Converts coordinates in Earth Centered Inertial frame to Earth Centered Earth Fixed. :param r: position of satellite in ECI frame. Units [km] :param time: Time of observation """ gcrs = GCRS(CartesianRepresentation(r[0] * u.km, r[1] * u.km, r[2] * u.km), obstime=time) itrs = gcrs.transform_to(ITRS(obstime=time)) x_ecef = itrs.x.value y_ecef = itrs.y.value z_ecef = itrs.z.value return np.array([x_ecef, y_ecef, z_ecef])
def __init__(self, spots=None, u1=0.4987, u2=0.1772, r=1, radius_threshold=0.1, rotation_period=25 * u.day): """ The star is assumed to have stellar inclination 90 deg (equator-on). Parameters ---------- u1 : float (optional) Quadratic limb-darkening parameter, linear term u2 : float (optional) Quadratic limb-darkening parameter, quadratic term r : float (optional) Stellar radius (default is unity) radius_threshold : float (optional) If all spots are smaller than this radius, use the analytic solution to compute the stellar centroid, otherwise use the numerical solution. spots : list (optional) List of spots on this star. rotation_period : `~astropy.units.Quantity` Stellar rotation period [default = 25 d]. contrast : float (optional) Spot contrast relative to photosphere. Default is ``c=0.7`` """ if spots is None: spots = [] self.spots = spots self.spots_cartesian = CartesianRepresentation( x=[spot.cartesian.x for spot in spots], y=[spot.cartesian.y for spot in spots], z=[spot.cartesian.z for spot in spots]) self.spots_r = np.array([spot.r for spot in spots]) self.spot_contrasts = np.array([spot.contrast for spot in spots]) self.x = 0 self.y = 0 self.r = r self.u1 = u1 self.u2 = u2 self.radius_threshold = radius_threshold self.rotations_applied = 0 * u.deg self.rotation_period = rotation_period self.inclination = 90 * u.deg self.unspotted_flux = ( 2 * np.pi * quad(lambda r: r * self.limb_darkening_normed(r), 0, self.r)[0])
def gen_trajectory(self, tle, interval, **kwargs): """ 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 kwargs No keywords defined 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_icrs_altaz_moonish(testframe): """ Check that something expressed in *ICRS* as being moon-like goes to the right AltAz distance """ # we use epv00 instead of get_sun because get_sun includes aberration earth_pv_helio, earth_pv_bary = erfa.epv00(*get_jd12(testframe.obstime, 'tdb')) earth_icrs_xyz = earth_pv_bary[0]*u.au moonoffset = [0, 0, MOONDIST.value]*MOONDIST.unit moonish_icrs = ICRS(CartesianRepresentation(earth_icrs_xyz + moonoffset)) moonaa = moonish_icrs.transform_to(testframe) # now check that the distance change is similar to earth radius assert 1000*u.km < np.abs(moonaa.distance - MOONDIST).to(u.au) < 7000*u.km
def test_teme_itrf(): """ Test case transform from TEME to ITRF. Test case derives from example on appendix C of Vallado, Crawford, Hujsak & Kelso (2006). See https://celestrak.com/publications/AIAA/2006-6753/AIAA-2006-6753-Rev2.pdf """ v_itrf = CartesianDifferential(-3.225636520, -2.872451450, 5.531924446, unit=u.km/u.s) p_itrf = CartesianRepresentation(-1033.479383, 7901.2952740, 6380.35659580, unit=u.km, differentials={'s': v_itrf}) t = Time("2004-04-06T07:51:28.386") teme = ITRS(p_itrf, obstime=t).transform_to(TEME(obstime=t)) v_teme = CartesianDifferential(-4.746131487, 0.785818041, 5.531931288, unit=u.km/u.s) p_teme = CartesianRepresentation(5094.18016210, 6127.64465050, 6380.34453270, unit=u.km, differentials={'s': v_teme}) assert_allclose(teme.cartesian.without_differentials().xyz, p_teme.without_differentials().xyz, atol=30*u.cm) assert_allclose(teme.cartesian.differentials['s'].d_xyz, p_teme.differentials['s'].d_xyz, atol=1.0*u.cm/u.s) # test round trip itrf = teme.transform_to(ITRS(obstime=t)) assert_allclose( itrf.cartesian.without_differentials().xyz, p_itrf.without_differentials().xyz, atol=100*u.cm ) assert_allclose( itrf.cartesian.differentials['s'].d_xyz, p_itrf.differentials['s'].d_xyz, atol=1*u.cm/u.s )
class EigenFrame(BaseCoordinateFrame): """A coordinate frame that has its axes aligned with the principal components of a cloud of points.""" e_x = CartesianRepresentationAttribute(default=CartesianRepresentation( 1, 0, 0, unit=dimensionless_unscaled), unit=dimensionless_unscaled) e_y = CartesianRepresentationAttribute(default=CartesianRepresentation( 0, 1, 0, unit=dimensionless_unscaled), unit=dimensionless_unscaled) e_z = CartesianRepresentationAttribute(default=CartesianRepresentation( 0, 0, 1, unit=dimensionless_unscaled), unit=dimensionless_unscaled) default_representation = CartesianRepresentation @classmethod def for_coords(cls, coords): """Create a coordinate frame that has its axes aligned with the principal components of a cloud of points. Parameters ---------- coords : astropy.cordinates.SkyCoord A cloud of points Returns ------- frame : EigenFrame A new coordinate frame """ obj = cls() v = coords.icrs.cartesian.xyz.value _, R = np.linalg.eigh(np.dot(v, v.T)) R = R[:, ::-1] # Order by descending eigenvalue e_x, e_y, e_z = CartesianRepresentation(R, unit=dimensionless_unscaled) return cls(e_x=e_x, e_y=e_y, e_z=e_z)
def test_shift_to_rest_star_withobserver(): rv = -8.3283011 * u.km / u.s rest_line_wls = [5007, 6563] * u.AA obstime = time.Time('2018-12-13 9:00') eloc = get_greenwich_earthlocation() obs = eloc.get_gcrs(obstime) # always built-in, no download required acen = SkyCoord(ra=219.90085 * u.deg, dec=-60.83562 * u.deg, frame='icrs', distance=4.37 * u.lightyear) # Note that above the rv is missing from the SkyCoord. # That's intended, as it will instead be set in the `SpectralCoord`. But # the SpectralCoord machinery should yield something comparable to test_ # spectral_coord_alphacen with pytest.warns(AstropyUserWarning, match='No velocity defined on frame'): observed_spc = SpectralCoord(rest_line_wls * (rv / c + 1), observer=obs, target=acen) rest_spc = observed_spc.to_rest() assert_quantity_allclose(rest_spc, rest_line_wls) with pytest.warns(AstropyUserWarning, match='No velocity defined on frame'): barycentric_spc = observed_spc._change_observer_to( ICRS(CartesianRepresentation([0, 0, 0] * u.au))) baryrest_spc = barycentric_spc.to_rest() assert quantity_allclose(baryrest_spc, rest_line_wls) # now make sure the change the barycentric shift did is comparable to the # offset rv_correction produces # barytarg = SkyCoord(barycentric_spc.target.frame) # should be this but that doesn't work for unclear reasons barytarg = SkyCoord(barycentric_spc.target.data.without_differentials(), frame=barycentric_spc.target.realize_frame(None)) vcorr = barytarg.radial_velocity_correction(kind='barycentric', obstime=obstime, location=eloc) drv = baryrest_spc.radial_velocity - observed_spc.radial_velocity # note this probably will not work on the first try, but it's ok if this is # "good enough", where good enough is estimated below. But that could be # adjusted if we think that's too agressive of a precision target for what # the machinery can handle # with pytest.raises(AssertionError): assert_quantity_allclose(vcorr, drv, atol=10 * u.m / u.s)
def validate_GCRF_to_ITRF(r_vec, v_vec): # Compute for the norm of position and velocity vectors r_norm, v_norm = [norm(vec) for vec in [r_vec, v_vec]] R = Earth_poliastro.R.to(u.m).value # Correction factor to normalize position and velocity vectors k_r = R / r_norm if r_norm != 0 else 1.00 k_v = 1 / v_norm if v_norm != 0 else 1.00 # Make a position vector who's norm is equal to the body's radius. Make a # unitary velocity vector. Units are in [m] and [m / s]. rx, ry, rz = [float(k_r * r_i) for r_i in r_vec] vx, vy, vz = [float(k_v * v_i) for v_i in v_vec] # orekit: build r_vec and v_vec wrt inertial body frame xyz_orekit = Vector3D(rx, ry, rz) uvw_orekit = Vector3D(vx, vy, vz) coords_GCRF_orekit = TimeStampedPVCoordinates(J2000_OREKIT, xyz_orekit, uvw_orekit) # orekit: build conversion between GCRF and ITRF GCRF_TO_ITRF_OREKIT = GCRF_FRAME_OREKIT.getTransformTo( ITRF_FRAME_OREKIT, J2000_OREKIT, ) # orekit: convert from GCRF to ITRF using previous built conversion coords_ITRF_orekit = (GCRF_TO_ITRF_OREKIT.transformPVCoordinates( coords_GCRF_orekit).getPosition().toArray()) coords_ITRF_orekit = np.asarray(coords_ITRF_orekit) * u.m # poliastro: build r_vec and v_vec wrt GCRF xyz_poliastro = CartesianRepresentation(rx * u.m, ry * u.m, rz * u.m) coords_GCRS_poliastro = GCRS_poliastro(xyz_poliastro) # poliastro: convert from inertial to fixed frame at given epoch coords_ITRS_poliastro = (coords_GCRS_poliastro.transform_to( ITRS_poliastro( obstime=J2000_POLIASTRO)).represent_as(CartesianRepresentation).xyz ) # Check position conversion assert_quantity_allclose( coords_ITRS_poliastro, coords_ITRF_orekit, atol=1e-3 * u.m, rtol=1e-2, )
def test_orbit_represent_as_produces_correct_data(): r = [1e09, -4e09, -1e09] * u.km v = [5e00, -1e01, -4e00] * u.km / u.s ss = Orbit.from_vectors(Sun, r, v) expected_result = CartesianRepresentation( *r, differentials=CartesianDifferential(*v)) result = ss.represent_as(CartesianRepresentation) # We can't directly compare the objects, see https://github.com/astropy/astropy/issues/7793 assert (result.xyz == expected_result.xyz).all() assert (result.differentials["s"].d_xyz == expected_result.differentials["s"].d_xyz).all()
def test_velocity_hgs_hgc(): # Construct a simple HGS coordinate with zero velocity obstime = Time(['2019-01-01', '2019-04-01', '2019-07-01', '2019-10-01']) pos = CartesianRepresentation(1, 0, 0)*u.AU vel = CartesianDifferential(0, 0, 0)*u.km/u.s loc = (pos.with_differentials(vel))._apply('repeat', obstime.size) coord = SkyCoord(HeliographicStonyhurst(loc, obstime=obstime)) # The induced velocity in HGC should be entirely longitudinal, and approximately equal to one # full rotation every mean synodic period (27.2753 days) new = coord.heliographic_carrington new_vel = new.data.differentials['s'].represent_as(SphericalDifferential, new.data) assert_quantity_allclose(new_vel.d_lon, -360*u.deg / (27.27253*u.day), rtol=1e-2) assert_quantity_allclose(new_vel.d_lat, 0*u.deg/u.s) assert_quantity_allclose(new_vel.d_distance, 0*u.km/u.s, atol=1e-7*u.km/u.s)
def test_from_coord_fails_for_multiple_positions(obstime): cartdiff = CartesianDifferential([[0, 1, 0], [-0.1, 0.9, 0]] * u.km / u.s, xyz_axis=1) cartrep = CartesianRepresentation([[1, 0, 0], [0.9, 0.1, 0]] * u.km, differentials=cartdiff, xyz_axis=1) coords = GCRS(cartrep, representation_type=CartesianRepresentation, obstime=obstime) with pytest.raises(ValueError) as excinfo: Orbit.from_coords(Earth, coords) assert ( "ValueError: Coordinate instance must represents exactly 1 position, found: 2" in excinfo.exconly())
def test_galactocentric_loopback(to_frame): xyz = CartesianRepresentation(1, 2, 3) * u.pc from_coo = Galactocentric(xyz) explicit_coo = from_coo.transform_to(ICRS()).transform_to(to_frame) implicit_coo = from_coo.transform_to(to_frame) # Confirm that the explicit transformation changes the position assert not allclose( explicit_coo.cartesian.xyz, from_coo.cartesian.xyz, rtol=1e-10) # Confirm that the loopback matches the explicit transformation assert allclose(explicit_coo.cartesian.xyz, implicit_coo.cartesian.xyz, rtol=1e-10)