def test_orbit_creation_using_frame_obj(attractor, frame, obstime): vel = [0, 2, 0] * u.km / u.s cartdiff = CartesianDifferential(*vel) pos = [30_000, 0, 0] * u.km cartrep = CartesianRepresentation(*pos, differentials=cartdiff) coord = frame(cartrep, obstime=obstime) o = Orbit.from_coords(attractor, coord) inertial_frame_at_body_centre = get_frame(attractor, Planes.EARTH_EQUATOR, obstime=coord.obstime) coord_transformed_to_irf = coord.transform_to( inertial_frame_at_body_centre) pos_transformed_to_irf = coord_transformed_to_irf.cartesian.xyz vel_transformed_to_irf = coord_transformed_to_irf.cartesian.differentials[ "s"].d_xyz assert_quantity_allclose(o.r, pos_transformed_to_irf, atol=1e-5 * u.km) assert_quantity_allclose(o.v, vel_transformed_to_irf, atol=1e-5 * u.km / u.s)
def get_frame(self): """Get equivalent reference frame of the orbit. .. versionadded:: 0.14.0 """ return get_frame(self.attractor, self.plane, self.epoch)
def change_attractor(self, new_attractor, force=False): """Changes orbit attractor. Only changes from attractor to parent or the other way around are allowed. Parameters ---------- new_attractor : poliastro.bodies.Body Desired new attractor. force : bool If `True`, changes attractor even if physically has no-sense. Returns ------- ss: poliastro.twobody.orbit.Orbit Orbit with new attractor """ if self.attractor == new_attractor: return self elif self.attractor == new_attractor.parent: # "Sun -> Earth" r_soi = laplace_radius(new_attractor) barycentric_position = get_body_barycentric(new_attractor.name, self.epoch) # Transforming new_attractor's frame into frame of attractor new_attractor_r = ( ICRS(barycentric_position) .transform_to(self.get_frame()) .represent_as(CartesianRepresentation) .xyz ) distance = norm(self.r - new_attractor_r) elif self.attractor.parent == new_attractor: # "Earth -> Sun" r_soi = laplace_radius(self.attractor) distance = norm(self.r) else: raise ValueError("Cannot change to unrelated attractor") if distance > r_soi and not force: raise ValueError( "Orbit is out of new attractor's SOI. If required, use 'force=True'." ) elif self.ecc < 1.0 and not force: raise ValueError("Orbit will never leave the SOI of its current attractor") else: warn( "Leaving the SOI of the current attractor", PatchedConicsWarning, stacklevel=2, ) new_frame = get_frame(new_attractor, self.plane, obstime=self.epoch) coords = self.get_frame().realize_frame( self.represent_as(CartesianRepresentation, CartesianDifferential) ) ss = Orbit.from_coords(new_attractor, coords.transform_to(new_frame)) return ss
def _get_destination_frame(attractor, plane, epochs): if attractor is not None: destination_frame = get_frame(attractor, plane, epochs) elif plane is Planes.EARTH_ECLIPTIC: destination_frame = BarycentricMeanEcliptic() else: destination_frame = None return destination_frame
def get_frame(self): """Get equivalent reference frame of the orbit. .. versionadded:: 0.14.0 """ # HACK: Only needed for Orbit.from_body_ephem if self._frame is not None: return self._frame return get_frame(self.attractor, self.plane, self.epoch)
def from_coords(cls, attractor, coord, plane=Planes.EARTH_EQUATOR): """Creates an `Orbit` from an attractor and astropy `SkyCoord` or `BaseCoordinateFrame` instance. This method accepts position and velocity in any reference frame unlike `Orbit.from_vector` which can accept inputs in only inertial reference frame centred at attractor. Also note that the frame information is lost after creation of the orbit and only the inertial reference frame at body centre will be used for all purposes. Parameters ---------- attractor : Body Main attractor coord : ~astropy.coordinates.SkyCoord or ~astropy.coordinates.BaseCoordinateFrame Position and velocity vectors in any reference frame. Note that coord must have a representation and its differential with respect to time. plane : ~poliastro.frames.Planes, optional Final orbit plane, default to Earth Equator. """ if "s" not in coord.cartesian.differentials: raise ValueError( "Coordinate instance doesn't have a differential with respect to time" ) if coord.size != 1: raise ValueError( "Coordinate instance must represents exactly 1 position, found: %d" % coord.size) # Reshape coordinate to 0 dimension if it is not already dimensionless. coord = coord.reshape(()) # Get an inertial reference frame parallel to ICRS and centered at # attractor inertial_frame_at_body_centre = get_frame(attractor, plane, coord.obstime) if not coord.is_equivalent_frame(inertial_frame_at_body_centre): coord_in_irf = coord.transform_to(inertial_frame_at_body_centre) else: coord_in_irf = coord pos = coord_in_irf.cartesian.xyz vel = coord_in_irf.cartesian.differentials["s"].d_xyz return cls.from_vectors(attractor, pos, vel, epoch=coord.obstime, plane=plane)
def change_plane(self, plane): """Changes fundamental plane. Parameters ---------- plane : ~poliastro.frames.Planes Fundamental plane of the frame. """ coords_orig = self.get_frame().realize_frame( self.represent_as(CartesianRepresentation, CartesianDifferential)) dest_frame = get_frame(self.attractor, plane, obstime=self.epoch) coords_dest = coords_orig.transform_to(dest_frame) coords_dest.representation_type = CartesianRepresentation return Orbit.from_coords(self.attractor, coords_dest, plane=plane)
def test_orbit_creation_using_skycoord(attractor): vel = [0, 2, 0] * u.km / u.s cartdiff = CartesianDifferential(*vel) pos = [30_000, 0, 0] * u.km cartrep = CartesianRepresentation(*pos, differentials=cartdiff) coord = SkyCoord(cartrep, frame="icrs") o = Orbit.from_coords(attractor, coord) inertial_frame_at_body_centre = get_frame( attractor, Planes.EARTH_EQUATOR, obstime=coord.obstime ) coord_transformed_to_irf = coord.transform_to(inertial_frame_at_body_centre) pos_transformed_to_irf = coord_transformed_to_irf.cartesian.xyz vel_transformed_to_irf = coord_transformed_to_irf.cartesian.differentials["s"].d_xyz assert (o.r == pos_transformed_to_irf).all() assert (o.v == vel_transformed_to_irf).all()