def cross(a, b): """ Compute cross product of two CartesianRepresentations. Parameters ---------- a : `CartesianRepresentation` First CartesianRepresentation, e.g directions to earth b : `CartesianRepresentation` Second CartesianRepresentation, e.g directions of tiles Returns ------- cross_product : `CartesianRepresentation` array of cross products. If `a` has shape (N, M) and `b` has shape (K,L) returned Quantity has shape (N, M, K, L) """ # since the data can be n-dimensional, reshape # to a 2-d (3, N) array xyz_a, xyz_b = a.xyz, b.xyz orig_shape_a = xyz_a.shape orig_shape_b = xyz_b.shape xyz_a = xyz_a.reshape((3, xyz_a.size // 3)) xyz_b = xyz_b.reshape((3, xyz_b.size // 3)) # take the cross product cross_product = np.cross(xyz_a[:, :, np.newaxis], xyz_b, axisa=0, axisb=0, axisc=0) cross_product_unit = xyz_a.unit * xyz_b.unit cross_product = u.Quantity(cross_product, unit=cross_product_unit) cartrep = CartesianRepresentation(cross_product) return cartrep.reshape(orig_shape_a[1:] + orig_shape_b[1:])
def test_creation_cartesian(): rep = CartesianRepresentation([10, 0., 0.]*u.pc) dif = CartesianDifferential([0, 100, 0.]*u.pc/u.Myr) rep = rep.with_differentials(dif) c = SkyCoord(rep) sdif = dif.represent_as(SphericalCosLatDifferential, rep) assert_quantity_allclose(c.pm_ra_cosdec, sdif.d_lon_coslat)
def setup(self): # Avoid top-level module import to make sure that the benchmarks are # compatible with versions of astropy that did not have this functionality. from astropy.coordinates import CartesianDifferential self.scalar_rep = CartesianRepresentation([1., 2, 3] * u.kpc) self.scalar_dif = CartesianDifferential([1, 2, 3.] * u.km/u.s) self.array_rep = CartesianRepresentation(np.ones((3, 1000)) * u.kpc) self.array_dif = CartesianDifferential(np.ones((3, 1000)) * u.km/u.s)
def test_plot_ephem_different_plane_raises_error(): unused_epochs = Time.now().reshape(-1) unused_coordinates = CartesianRepresentation( [(1, 0, 0)] * u.au, xyz_axis=1, differentials=CartesianDifferential([(0, 1, 0)] * (u.au / u.day), xyz_axis=1), ) op = StaticOrbitPlotter(plane=Planes.EARTH_ECLIPTIC) op.set_attractor(Sun) op.set_body_frame(Earth) with pytest.raises(ValueError) as excinfo: op.plot_ephem( Ephem(unused_epochs, unused_coordinates, Planes.EARTH_EQUATOR)) assert ( "sample the ephemerides using a different plane or create a new plotter" in excinfo.exconly())
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 = interp1d(t, xyz.x)(t_new) y_new = interp1d(t, xyz.y)(t_new) z_new = interp1d(t, xyz.z)(t_new) xyz_new = CartesianRepresentation(x_new, y_new, z_new) altaz_frame = AltAz(obstime=time, location=self.location) # FIXME: an API change in Astropy in 3.1 broke this # See https://github.com/gammapy/gammapy/pull/1906 if astropy_version >= "3.1": kwargs = {"representation_type": "unitspherical"} else: kwargs = {"representation": "unitspherical"} return SkyCoord(xyz_new, frame=altaz_frame, unit="deg", **kwargs)
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.coordinates.SkyCoord` A cloud of points Returns ------- frame : `EigenFrame` A new coordinate frame """ 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_hgs_hcc_sunspice(): # Compare our HGS->HCC transformation against SunSPICE # "HEQ" is another name for HEEQ, which is equivalent to Heliographic Stonyhurst # "HGRTN" is equivalent to our Heliocentric, but with the axes permuted # SunSPICE, like us, assumes an Earth observer if not explicitly specified # # IDL> coord = [7d5, 8d5, 9d5] # IDL> convert_sunspice_coord, '2019-06-01', coord, 'HEQ', 'HGRTN' # Assuming Earth observation # IDL> print, coord # 688539.32 800000.00 908797.89 old = SkyCoord(CartesianRepresentation([7e5, 8e5, 9e5]*u.km), frame=HeliographicStonyhurst(obstime='2019-06-01')) new = old.heliocentric assert_quantity_allclose(new.x, 800000.00*u.km, atol=1e-2*u.km) assert_quantity_allclose(new.y, 908797.89*u.km, atol=1e-2*u.km) assert_quantity_allclose(new.z, 688539.32*u.km, atol=1e-2*u.km)
def __call__(self, t): """ Computes the interpolated coordinates at the given time(s). Parameters ---------- t : Time Time or list of times where an interpolated coordinate is required Returns ------- coords : SkyCoord A `SkyCoord` object with the requested coordinate(s), in the original frame Raises ------ ValueError If the requested `t` value is out of bounds for the interpolator """ if not self._interpolators_initialised: # Lazy init interpolators only when required self._init_interpolators() # **** get coords at requested time **** # compute raw r and v vectors and # fill Astropy cartesian vectors (with velocities if available) if t.isscalar: # there is a single time instance coords = CartesianRepresentation(self._compute_pos(t), copy=False) if self._has_velocity: v = CartesianDifferential(self._compute_vel(t), copy=False) coords = coords.with_differentials(v) else: # there is more than one time instance r = [self._compute_pos(time) for time in t] coords = CartesianRepresentation( np.asarray(r), unit=r[0].unit, copy=False, xyz_axis=1 ) if self._has_velocity: v = [self._compute_vel(time) for time in t] v = CartesianDifferential( np.asarray(v), unit=v[0].unit, copy=False, xyz_axis=1 ) coords = coords.with_differentials(v) return init_pvt(self._frame_name, t, coords)
def represent_as(self, representation): """Converts the orbit to a specific representation. .. versionadded:: 0.11.0 Parameters ---------- representation : ~astropy.coordinates.BaseRepresentation Representation object to use. It must be a class, not an instance. Examples -------- >>> from poliastro.examples import iss >>> from astropy.coordinates import CartesianRepresentation, SphericalRepresentation >>> iss.represent_as(CartesianRepresentation) <CartesianRepresentation (x, y, z) in km (859.07256, -4137.20368, 5295.56871) (has differentials w.r.t.: 's')> >>> iss.represent_as(CartesianRepresentation).xyz <Quantity [ 859.07256, -4137.20368, 5295.56871] km> >>> iss.represent_as(CartesianRepresentation).differentials['s'] <CartesianDifferential (d_x, d_y, d_z) in km / s (7.37289205, 2.08223573, 0.43999979)> >>> iss.represent_as(CartesianRepresentation).differentials['s'].d_xyz <Quantity [7.37289205, 2.08223573, 0.43999979] km / s> >>> iss.represent_as(SphericalRepresentation) <SphericalRepresentation (lon, lat, distance) in (rad, rad, km) (4.91712525, 0.89732339, 6774.76995296) (has differentials w.r.t.: 's')> """ # As we do not know the differentials, we first convert to cartesian, # then let the frame represent_as do the rest # TODO: Perhaps this should be public API as well? cartesian = CartesianRepresentation( *self.r, differentials=CartesianDifferential(*self.v)) # See the propagate function for reasoning about the usage of a # protected method coords = self.frame._replicate(cartesian, representation_type="cartesian") return coords.represent_as(representation)
def _interpolate_sinc(epochs, reference_epochs, coordinates): def _interp_1d(arr): return _sinc_interp(arr, reference_epochs.jd, epochs.jd) xyz_unit = coordinates.xyz.unit d_xyz_unit = coordinates.differentials["s"].d_xyz.unit x = _interp_1d(coordinates.x.value) * xyz_unit y = _interp_1d(coordinates.y.value) * xyz_unit z = _interp_1d(coordinates.z.value) * xyz_unit d_x = _interp_1d(coordinates.differentials["s"].d_x.value) * d_xyz_unit d_y = _interp_1d(coordinates.differentials["s"].d_y.value) * d_xyz_unit d_z = _interp_1d(coordinates.differentials["s"].d_z.value) * d_xyz_unit return CartesianRepresentation(x, y, z, differentials=CartesianDifferential( d_x, d_y, d_z))
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()
def _create_coord_from_offset(observer, radial_velocity): """ Generates a default target or observer from a provided observer or target with an offset defined such as to create the provided radial velocity. Parameters ---------- observer : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord` Observer frame off which to base the target frame. radial_velocity : `~astropy.units.Quantity` Radial velocity used to calculate appropriate offsets between provided observer and generated target. Returns ------- target : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord` Generated target frame. """ # The generated observer or target will be set up along the same y and z # coordinates as the target or observer, but offset along the x direction observer_icrs = observer.transform_to(ICRS) d = observer_icrs.cartesian.norm() drep = CartesianRepresentation( [DEFAULT_DISTANCE.to(d.unit), 0 * d.unit, 0 * d.unit]) obs_vel = observer_icrs.cartesian.differentials['s'] target = (observer_icrs.cartesian.without_differentials() + drep).with_differentials( CartesianDifferential([ _relativistic_velocity_addition( obs_vel.d_x, radial_velocity), obs_vel.d_y.to(radial_velocity.unit), obs_vel.d_z.to(radial_velocity.unit) ])) return observer_icrs.realize_frame(target)
def teme_to_tirs(teme_coord, tirs_frame): # TEME to TIRS basic rotation matrix teme_to_pef_mat = rotation_matrix(_gmst82_angle(teme_coord.obstime), axis='z') # rotate position vector: TEME to TIRS r_tirs = teme_coord.cartesian.transform(teme_to_pef_mat) # prepare rotation offset: w x r_TIRS wxr = CartesianRepresentation(_w).cross(r_tirs) # do the velocity rotation and then add rotation offset v_tirs = teme_coord.velocity.to_cartesian().transform( teme_to_pef_mat) - wxr v_tirs = CartesianDifferential.from_cartesian(v_tirs) # Prepare final coord vector with velocity tirs_coord = r_tirs.with_differentials(v_tirs) # Add coord data to the existing frame return tirs_frame.realize_frame(tirs_coord)
def translate(cls, translation_vector): """ Apply a coordinate translation. Parameters ---------- cls : astropy.coordinates.CartesianRepresentation Equivalent to the 'self' argument for methods. translation_vector : astropy.units.Quantity, with dimensions of length 3-vector by which to translate. Returns ------- out : astropy.coordinates.CartesianRepresentation A new CartesianRepresentation instance with translation applied. """ return CartesianRepresentation(cls.__class__.get_xyz(cls) + translation_vector.reshape(3, 1), differentials=cls.differentials)
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 _sample(self, time_values, method=mean_motion): positions = method(self, time_values.to(u.s).value) data = CartesianRepresentation(positions[0] * u.km, xyz_axis=1) # If the frame supports obstime, set the time values kwargs = {} if "obstime" in self.frame.frame_attributes: kwargs["obstime"] = self.epoch + time_values else: warn( "Frame {} does not support 'obstime', time values were not returned".format( self.frame.__class__ ) ) # Use of a protected method instead of frame.realize_frame # because the latter does not let the user choose the representation type # in one line despite its parameter names, see # https://github.com/astropy/astropy/issues/7784 return self.frame._replicate(data, representation_type="cartesian", **kwargs)
def test_from_orbit_has_desired_properties(method, rtol): epochs = Time( [ "2020-02-01 12:00:00", "2020-02-13 12:00:00", "2020-03-04 12:00:00", "2020-03-17 12:00:00", ] ) expected_coordinates = CartesianRepresentation( [ (336.77109079, -1447.38211842, -743.72094119), (-1133.43957703, 449.41297342, 3129.10416554), (201.42480053, -1978.64139325, -287.25776291), (-1084.94556884, -1713.5357774, 3298.72284309), ] * u.km, xyz_axis=1, differentials=CartesianDifferential( [ (-2.68502706, -14.85798508, 9.66683585), (1.36841306, 7.30080155, -4.88822441), (-3.46999908, -10.04899184, 11.19715233), (-1.46069855, 5.88696886, 3.28112281), ] * (u.km / u.s), xyz_axis=1, ), ) r = [-1000, -2000, 3100] * u.km v = [-1.836, 5.218, 4.433] * u.km / u.s orb = Orbit.from_vectors(Earth, r, v) unused_plane = Planes.EARTH_EQUATOR ephem = Ephem.from_orbit(orbit=orb, epochs=epochs, plane=unused_plane) coordinates = ephem.sample() assert ephem.epochs is epochs assert_coordinates_allclose(coordinates, expected_coordinates, rtol=rtol)
def tirs_to_teme(tirs_coord, teme_frame): # TIRS to TEME basic rotation matrix teme_to_pef_mat = rotation_matrix(_gmst82_angle(tirs_coord.obstime), axis='z') pef_to_teme_mat = teme_to_pef_mat.transpose() # rotate position vector: TIRS to TEME r_teme = tirs_coord.cartesian.transform(pef_to_teme_mat) # prepare rotation offset: w x r_TIRS wxr = CartesianRepresentation(_w).cross(tirs_coord.cartesian) # add rotation offset and then do the velocity rotation v_teme = (tirs_coord.velocity.to_cartesian() + wxr).transform(pef_to_teme_mat) v_teme = CartesianDifferential.from_cartesian(v_teme) # Prepare final coord vector with velocity teme_coord = r_teme.with_differentials(v_teme) # Add coord data to the existing frame return teme_frame.realize_frame(teme_coord)
def _target_from_observer(observer, radial_velocity): """ Generates a default target from a provided observer with an offset defined such as to create the provided radial velocity. Parameters ---------- observer : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord` Observer frame off which to base the target frame. radial_velocity : `~astropy.units.Quantity` Radial velocity used to calculate appropriate offsets between provided observer and generated target. Returns ------- target : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord` Generated target frame. """ observer = SpectralCoord._validate_coordinate(observer) observer_icrs = observer.transform_to(ICRS) d = observer_icrs.cartesian.norm() drep = CartesianRepresentation( [DEFAULT_DISTANCE.to(d.unit), 0 * d.unit, 0 * d.unit]) obs_vel = observer_icrs.cartesian.differentials['s'] tot_rv = radial_velocity # + observer_icrs.radial_velocity target = (observer_icrs.cartesian.without_differentials() + drep).with_differentials( CartesianDifferential([ obs_vel.d_x + tot_rv, obs_vel.d_y.to(tot_rv.unit), obs_vel.d_z.to(tot_rv.unit) ])) target = observer_icrs.realize_frame(target) return target
def nominal_to_altaz(altaz_coord,norm_coord): """ Transformation from astropy AltAz system to nominal system Parameters ---------- altaz_coord: AltAz system norm_coord: nominal system Returns ------- nominal Coordinates """ alt_norm,az_norm = norm_coord.array_direction az = altaz_coord.az alt = altaz_coord.alt x,y = altaz_to_offset(az,alt,az_norm,alt_norm) x=x*u.rad y=y*u.rad representation = CartesianRepresentation(x.to(u.deg),y.to(u.deg),0*u.deg) return norm_coord.realize_frame(representation)
def rotate(self, angle): """ Rotate the star, by moving the spots. Parameters ---------- angle : `~astropy.units.Quantity` """ remove_is = rotation_matrix(-self.inclination, axis='x') rotate = rotation_matrix(angle, axis='z') add_is = rotation_matrix(self.inclination, axis='x') transform_matrix = matrix_product(remove_is, rotate, add_is) for spot in self.spots: cartesian = CartesianRepresentation( x=spot.x, y=spot.y, z=spot.z).transform(transform_matrix) spot.x = cartesian.x.value spot.y = cartesian.y.value spot.z = cartesian.z.value self.rotations_applied += angle
def select_tidal_annulus(w0,\ ann_low = 0.0,\ ann_high = 0.5,\ sat_mass=1e8,\ mw_mass=130.0075e10,\ mw_c=32.089): com_p, com_v, com_index = calc_com(w0) distances_to_com =\ np.linalg.norm((w0.pos - CartesianRepresentation(com_p)).xyz, axis=0) tidal_radius = r_tidal(sat_mass, mw_mass, mw_c, np.linalg.norm(com_p)) selected_indices = [] for p_index in range(len(distances_to_com)): curr_dist = distances_to_com[p_index] if (ann_low * tidal_radius) <= curr_dist < (ann_high * tidal_radius): selected_indices.append(p_index) return w0[selected_indices]
def telescope_to_camera(telescope_coord, camera_frame): ''' Transformation between TelescopeFrame and CameraFrame Is called when a SkyCoord is transformed from TelescopeFrame into CameraFrame ''' x_pos = telescope_coord.delta_alt y_pos = telescope_coord.delta_az # reverse the rotation applied to get to this system rot = -camera_frame.rotation if rot.value == 0.0: # if no rotation applied save a few cycles x_rotated = x_pos y_rotated = y_pos else: # or else rotate all positions around the camera centre cosrot = np.cos(rot) sinrot = np.sin(rot) x_rotated = x_pos * cosrot - y_pos * sinrot y_rotated = x_pos * sinrot + y_pos * cosrot focal_length = camera_frame.focal_length # this assumes an equidistant mapping function of the telescope optics # or a small angle approximation of most other mapping functions # this could be replaced by actually defining the mapping function # as an Attribute of `CameraFrame` that maps f(theta, focal_length) -> r, # where theta is the angle to the optical axis and r is the distance # to the camera center in the focal plane x_rotated = x_rotated.to_value(u.rad) * focal_length y_rotated = y_rotated.to_value(u.rad) * focal_length representation = CartesianRepresentation( x_rotated, y_rotated, 0 * u.m ) return camera_frame.realize_frame(representation)
def interpolate(self, epochs, reference_epochs, coordinates): xyz_unit = coordinates.xyz.unit d_xyz_unit = coordinates.differentials["s"].d_xyz.unit result_xyz = ( spline_interp( coordinates.xyz.value, reference_epochs.jd, epochs.jd, kind=self._kind ) << xyz_unit ) result_d_xyz = ( spline_interp( coordinates.differentials["s"].d_xyz.value, reference_epochs.jd, epochs.jd, kind=self._kind, ) << d_xyz_unit ) return CartesianRepresentation( result_xyz, differentials=CartesianDifferential(result_d_xyz) )
def propagation_engine(line1, line2, time_list): """Tests the interpolation accuracy for a given TLE.""" # Init satellite object from the TLE sat = Satrec.twoline2rv(line1, line2) # ****** Generate the pos, vel vectors for each time instant ****** # Run the propagation and init pos and vel vectors in TEME e, r_list, v_list = sat.sgp4_array(time_list.jd1, time_list.jd2) # Load the time, pos, vel info into astropy objects (shallow copied) vel_list = CartesianDifferential(v_list, unit=u.km / u.s, xyz_axis=1) pos_list = CartesianRepresentation(r_list, unit=u.km, xyz_axis=1).with_differentials(vel_list) # trajectory in astropy traj_astropy = init_pvt(TEME, time_list, pos_list) # Init trajectory in Trajectory object trajectory = Trajectory(traj_astropy) return {"traj": trajectory, "sat": sat}
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)
def test_regression_6300(): """Check that importing old frame attribute names from astropy.coordinates still works. See comments at end of #6300 """ from astropy.utils.exceptions import AstropyDeprecationWarning from astropy.coordinates import CartesianRepresentation from astropy.coordinates import (TimeFrameAttribute, QuantityFrameAttribute, CartesianRepresentationFrameAttribute) with catch_warnings() as found_warnings: attr = TimeFrameAttribute(default=Time("J2000")) for w in found_warnings: if issubclass(w.category, AstropyDeprecationWarning): break else: assert False, "Deprecation warning not raised" with catch_warnings() as found_warnings: attr = QuantityFrameAttribute(default=5 * u.km) for w in found_warnings: if issubclass(w.category, AstropyDeprecationWarning): break else: assert False, "Deprecation warning not raised" with catch_warnings() as found_warnings: attr = CartesianRepresentationFrameAttribute( default=CartesianRepresentation([5, 6, 7] * u.kpc)) for w in found_warnings: if issubclass(w.category, AstropyDeprecationWarning): break else: assert False, "Deprecation warning not raised"
def _interpolate_splines(epochs, reference_epochs, coordinates, *, kind="cubic"): xyz_unit = coordinates.xyz.unit d_xyz_unit = coordinates.differentials["s"].d_xyz.unit # TODO: Avoid building interpolant every time? # Does it have a performance impact? interpolant_xyz = interp1d(reference_epochs.jd, coordinates.xyz.value, kind=kind) interpolant_d_xyz = interp1d( reference_epochs.jd, coordinates.differentials["s"].d_xyz.value, kind=kind, ) result_xyz = interpolant_xyz(epochs.jd) * xyz_unit result_d_xyz = interpolant_d_xyz(epochs.jd) * d_xyz_unit return CartesianRepresentation( result_xyz, differentials=CartesianDifferential(result_d_xyz))
def test_array_coordinates_creation(): """ Test creating coordinates from arrays. """ c = ICRS(np.array([1, 2])*u.deg, np.array([3, 4])*u.deg) assert not c.ra.isscalar with pytest.raises(ValueError): c = ICRS(np.array([1, 2])*u.deg, np.array([3, 4, 5])*u.deg) with pytest.raises(ValueError): c = ICRS(np.array([1, 2, 4, 5])*u.deg, np.array([[3, 4], [5, 6]])*u.deg) # make sure cartesian initialization also works cart = CartesianRepresentation(x=[1., 2.]*u.kpc, y=[3., 4.]*u.kpc, z=[5., 6.]*u.kpc) c = ICRS(cart) # also ensure strings can be arrays c = SkyCoord(['1d0m0s', '2h02m00.3s'], ['3d', '4d']) # but invalid strings cannot with pytest.raises(ValueError): c = SkyCoord(Angle(['10m0s', '2h02m00.3s']), Angle(['3d', '4d'])) with pytest.raises(ValueError): c = SkyCoord(Angle(['1d0m0s', '2h02m00.3s']), Angle(['3x', '4d']))
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 telescope_to_nominal(tel_coord,norm_frame): """ Coordinate transformation from telescope frame to nominal frame Parameters ---------- tel_coord: TelescopeFrame system norm_frame: NominalFrame system Returns ------- NominalFrame coordinates """ alt_tel,az_tel = tel_coord.pointing_direction alt_norm,az_norm = norm_frame.array_direction alt_trans,az_trans = offset_to_altaz(tel_coord.x,tel_coord.y,az_tel,alt_tel) x,y = altaz_to_offset(az_trans,alt_trans,az_norm,alt_norm) x = x*u.rad y = y*u.rad representation = CartesianRepresentation(x.to(tel_coord.x.unit),y.to(tel_coord.x.unit),0*tel_coord.x.unit) return norm_frame.realize_frame(representation)
def test_ephem_from_horizons_calls_horizons_with_correct_parameters( horizons_mock, attractor, location_str, plane, refplane_str): unused_name = "Strange Object" unused_id_type = "id_type" epochs = Time(["2020-03-01 12:00:00"], scale="tdb") horizons_mock().vectors.return_value = { "x": [1] * u.au, "y": [0] * u.au, "z": [0] * u.au, "vx": [0] * (u.au / u.day), "vy": [1] * (u.au / u.day), "vz": [0] * (u.au / u.day), } expected_coordinates = CartesianRepresentation( [(1, 0, 0)] * u.au, xyz_axis=1, differentials=CartesianDifferential([(0, 1, 0)] * (u.au / u.day), xyz_axis=1), ) ephem = Ephem.from_horizons(unused_name, epochs, attractor=attractor, plane=plane, id_type=unused_id_type) horizons_mock.assert_called_with(id=unused_name, location=location_str, epochs=epochs.jd, id_type=unused_id_type) horizons_mock().vectors.assert_called_once_with(refplane=refplane_str) coordinates = ephem.sample() assert_coordinates_allclose(coordinates, expected_coordinates)
def telescope_to_camera(telescope_coord, camera_frame): """ Transformation between TelescopeFrame and CameraFrame Parameters ---------- telescope_coord: `astropy.coordinates.SkyCoord` TelescopeFrame system camera_frame: `astropy.coordinates.SkyCoord` CameraFrame system Returns ------- CameraFrame Coordinates """ x_pos = telescope_coord.cartesian.x y_pos = telescope_coord.cartesian.y # reverse the rotation applied to get to this system rot = camera_frame.rotation * -1 if rot == 0: # if no rotation applied save a few cycles x_rotated = x_pos y_rotated = y_pos else: # or else rotate all positions around the camera centre x_rotated = x_pos * cos(rot) - y_pos * sin(rot) y_rotated = x_pos * sin(rot) + y_pos * cos(rot) focal_length = camera_frame.focal_length # Remove distance units here as we are using small angle approx x_rotated = x_rotated.to(u.rad) * (focal_length / u.m) y_rotated = y_rotated.to(u.rad) * (focal_length / u.m) representation = CartesianRepresentation(x_rotated.value * u.m, y_rotated.value * u.m, 0 * u.m) return camera_frame.realize_frame(representation)
def add_oriented_radecs(elvis_tab, hostidx=0, targetidx=1, target_coord=SkyCoord(0*u.deg, 0*u.deg), earth_distance=8.5*u.kpc, earth_vrot=220*u.km/u.s, roll_angle=0*u.deg): """ Computes a spherical coordinate system centered on the `hostidx` halo, re-oriented so that `targetidx` is at the `target_coord` coordinate location. Note that this adds columns 'host<n>_*' to `elvis_tab`, and will *overwrite* them if they already exist. """ if hasattr(target_coord, 'spherical'): target_lat = target_coord.spherical.lat target_lon = target_coord.spherical.lon else: target_lat = target_coord.lat target_lon = target_coord.lon def offset_repr(rep, vector, newrep=None): if newrep is None: newrep = rep.__class__ newxyz = rep.to_cartesian().xyz + vector.reshape(3, 1) return CartesianRepresentation(newxyz).represent_as(newrep) def rotate_repr(rep, matrix, newrep=None): if newrep is None: newrep = rep.__class__ newxyz = np.dot(matrix.view(np.ndarray), rep.to_cartesian().xyz) return CartesianRepresentation(newxyz).represent_as(newrep) rep = CartesianRepresentation(elvis_tab['X'], elvis_tab['Y'], elvis_tab['Z']) # first we offset the catalog to have its origin at host rep = offset_repr(rep, -rep.xyz[:, hostidx]) # now rotate so that host1 is along the z-axis, and apply the arbitrary roll angle usph = rep.represent_as(UnitSphericalRepresentation) M1 = rotation_matrix(usph.lon[targetidx], 'z') M2 = rotation_matrix(90*u.deg-usph.lat[targetidx], 'y') M3 = rotation_matrix(roll_angle, 'z') Mfirst = M3*M2*M1 rep = rotate_repr(rep, Mfirst) # now determine the location of the earth in this system # need diagram to explain this, but it uses SSA formula theta = target_coord.separation(galactic_center) # target to GC angle D = rep.z[targetidx] # distance to the target host R = earth_distance # srho = (R/D) * np.sin(theta) # sdelta_p = (srho * np.cos(theta) + (1 - srho**2)**0.5) # sdelta_m = (srho * np.cos(theta) - (1 - srho**2)**0.5) d1, d2 = R * np.cos(theta), (D**2 - (R * np.sin(theta))**2)**0.5 dp, dm = d1 + d2, d1 - d2 sdelta = (dp/D) * np.sin(theta) x = R * sdelta z = R * (1-sdelta**2)**0.5 earth_location = u.Quantity([x, 0*u.kpc, z]) # now offset to put earth at the origin rep = offset_repr(rep, -earth_location) sph = rep.represent_as(SphericalRepresentation) # rotate to put the target at its correct spot # first sent the target host to 0,0 M1 = rotation_matrix(sph[targetidx].lon, 'z') M2 = rotation_matrix(-sph[targetidx].lat, 'y') # now rotate from origin to target lat,lon M3 = rotation_matrix(target_lat, 'y') M4 = rotation_matrix(-target_lon, 'z') Mmiddle = M4*M3*M2*M1 rep = rotate_repr(rep, Mmiddle) # now one more rotation about the target to stick the GC in the right place def tomin(ang, inrep=rep[hostidx], axis=rep[targetidx].xyz, target=galactic_center.icrs): newr = rotate_repr(inrep, rotation_matrix(ang[0]*u.deg, axis)) return ICRS(newr).separation(target).radian rot_angle = optimize.minimize(tomin, np.array(0).ravel(), method='Nelder-Mead')['x'][0] Mlast = rotation_matrix(rot_angle*u.deg, rep[targetidx].xyz) rep = rotate_repr(rep, Mlast) sph = rep.represent_as(SphericalRepresentation) elvis_tab['host{}_lat'.format(hostidx)] = sph.lat.to(u.deg) elvis_tab['host{}_lon'.format(hostidx)] = sph.lon.to(u.deg) elvis_tab['host{}_dist'.format(hostidx)] = sph.distance # now compute velocities # host galactocentric dvxg = u.Quantity((elvis_tab['Vx'])-elvis_tab['Vx'][hostidx]) dvyg = u.Quantity((elvis_tab['Vy'])-elvis_tab['Vy'][hostidx]) dvzg = u.Quantity((elvis_tab['Vz'])-elvis_tab['Vz'][hostidx]) earth_location_in_xyz = np.dot(Mfirst.T, earth_location) dxg = elvis_tab['X'] - elvis_tab['X'][0] - earth_location_in_xyz[0] dyg = elvis_tab['Y'] - elvis_tab['Y'][0] - earth_location_in_xyz[0] dzg = elvis_tab['Z'] - elvis_tab['Z'][0] - earth_location_in_xyz[0] vrg = (dvxg*dxg + dvyg*dyg + dvzg*dzg) * (dxg**2+dyg**2+dzg**2)**-0.5 elvis_tab['host{}_galvr'.format(hostidx)] = vrg.to(u.km/u.s) # "vLSR-like" # first figure out the rotation direction earth_rotdir = SkyCoord(90*u.deg, 0*u.deg, frame='galactic').icrs #now apply the component from that everywhere offset_angle = earth_rotdir.separation(ICRS(sph)) vrlsr = vrg - earth_vrot*np.cos(offset_angle) elvis_tab['host{}_vrlsr'.format(hostidx)] = vrlsr.to(u.km/u.s)