def reference_plane(self, time): """Compute the orbit at specified times in the two-body barycentric frame aligned with the reference plane coordinate system (XYZ). Parameters ---------- time : array_like, `astropy.time.Time` Array of times as barycentric MJD values, or an Astropy `~astropy.time.Time` object containing the times to evaluate at. """ xyz = self.orbital_plane(time) vxyz = xyz.differentials['s'] xyz = xyz.without_differentials() # Construct rotation matrix to take the orbit from the orbital plane # system (xyz) to the reference plane system (XYZ): R1 = rotation_matrix(-self.omega, axis='z') R2 = rotation_matrix(self.i, axis='x') R3 = rotation_matrix(self.Omega, axis='z') Rot = matrix_product(R3, R2, R1) # Rotate to the reference plane system XYZ = coord.CartesianRepresentation(matrix_product(Rot, xyz.xyz)) VXYZ = coord.CartesianDifferential(matrix_product(Rot, vxyz.d_xyz)) XYZ = XYZ.with_differentials(VXYZ) kw = dict() if self.barycenter is not None: kw['origin'] = self.barycenter.origin return ReferencePlaneFrame(XYZ, **kw)
def reference_to_greatcircle(reference_frame, greatcircle_frame): """Convert a reference coordinate to a great circle frame.""" # Define rotation matrices along the position angle vector, and # relative to the origin. pole = greatcircle_frame.pole.transform_to(coord.ICRS) ra0 = greatcircle_frame.ra0 R_rot = rotation_matrix(greatcircle_frame.rotation, 'z') if np.isnan(ra0): R2 = rotation_matrix(pole.dec, 'y') R1 = rotation_matrix(pole.ra, 'z') R = matrix_product(R2, R1) else: xaxis = np.array([np.cos(ra0), np.sin(ra0), 0.]) zaxis = pole.cartesian.xyz.value xaxis[2] = -(zaxis[0] * xaxis[0] + zaxis[1] * xaxis[1]) / zaxis[2] # what? xaxis = xaxis / np.sqrt(np.sum(xaxis**2)) yaxis = np.cross(zaxis, xaxis) R = np.stack((xaxis, yaxis, zaxis)) return matrix_product(R_rot, R)
def _get_matrix_vectors(gal_frame, inverse=False): """ Utility function: use the ``inverse`` argument to get the inverse transformation, matrix and offsets to go from external galaxy frame to ICRS. """ # this is based on the astropy Galactocentric class code # shorthand gcf = gal_frame # rotation matrix to align x(ICRS) with the vector to the galaxy center mat0 = np.array([[0., 1., 0.], [0., 0., 1.], [1., 0., 0.]]) # relabel axes so x points in RA, y in dec, z away from us mat1 = rotation_matrix(-gcf.gal_coord.dec, 'y') mat2 = rotation_matrix(gcf.gal_coord.ra, 'z') # construct transformation matrix and use it R = matrix_product(mat0, mat1, mat2) # Now define translation by distance to galaxy center - best defined in current sky coord system defined by R translation = r.CartesianRepresentation(gcf.gal_distance * [0., 0., 1.]) # Now rotate galaxy to right orientation pa_rot = rotation_matrix(-gcf.PA, 'z') inc_rot = rotation_matrix(gcf.inclination, 'y') H = matrix_product(inc_rot, pa_rot) # compute total matrices A = matrix_product(H, R) # Now we transform the translation vector between sky-aligned and galaxy-aligned frames offset = -translation.transform(H) if inverse: # the inverse of a rotation matrix is a transpose, which is much faster # and more stable to compute A = matrix_transpose(A) offset = (-offset).transform(A) # galvel is given in sky-aligned coords, need to transform to ICRS, so use R transpose R = matrix_transpose(R) offset_v = r.CartesianDifferential.from_cartesian( (gcf.galvel_heliocentric).to_cartesian().transform(R)) offset = offset.with_differentials(offset_v) else: # galvel is given in sky-aligned coords, need to transform to gal frame, so use H offset_v = r.CartesianDifferential.from_cartesian( (-gcf.galvel_heliocentric).to_cartesian().transform(H)) offset = offset.with_differentials(offset_v) return A, offset
def fk4_to_gal(fk4coords, galframe): mat1 = rotation_matrix(180 - Galactic._lon0_B1950.degree, 'z') mat2 = rotation_matrix(90 - Galactic._ngp_B1950.dec.degree, 'y') mat3 = rotation_matrix(Galactic._ngp_B1950.ra.degree, 'z') matprec = fk4coords._precession_matrix(fk4coords.equinox, EQUINOX_B1950) return matrix_product(mat1, mat2, mat3, matprec)
def fk4_to_gal(fk4coords, galframe): mat1 = rotation_matrix(180 - Galactic._lon0_B1950.degree, 'z') mat2 = rotation_matrix(90 - Galactic._ngp_B1950.dec.degree, 'y') mat3 = rotation_matrix(Galactic._ngp_B1950.ra.degree, 'z') matprec = fk4coords._precession_matrix(fk4coords.equinox, EQUINOX_B1950) return matrix_product(mat1, mat2, mat3, matprec)
def hcrs_to_hgs(hcrscoord, hgsframe): """ Convert from HCRS to Heliographic Stonyhurst (HGS). HGS shares the same origin (the Sun) as HCRS, but has its Z axis aligned with the Sun's rotation axis and its X axis aligned with the projection of the Sun-Earth vector onto the Sun's equatorial plane (i.e., the component of the Sun-Earth vector perpendicular to the Z axis). Thus, the transformation matrix is the product of the matrix to align the Z axis (by de-tilting the Sun's rotation axis) and the matrix to align the X axis. The first matrix is independent of time and is pre-computed, while the second matrix depends on the time-varying Sun-Earth vector. """ if hgsframe.obstime is None: raise ValueError("To perform this transformation the coordinate" " Frame needs an obstime Attribute") # Determine the Sun-Earth vector in ICRS # Since HCRS is ICRS with an origin shift, this is also the Sun-Earth vector in HCRS sun_pos_icrs = get_body_barycentric('sun', hgsframe.obstime) earth_pos_icrs = get_body_barycentric('earth', hgsframe.obstime) sun_earth = earth_pos_icrs - sun_pos_icrs # De-tilt the Sun-Earth vector to the frame with the Sun's rotation axis parallel to the Z axis sun_earth_detilt = sun_earth.transform(_SUN_DETILT_MATRIX) # Remove the component of the Sun-Earth vector that is parallel to the Sun's north pole hgs_x_axis_detilt = CartesianRepresentation(sun_earth_detilt.xyz * [1, 1, 0]) # The above vector, which is in the Sun's equatorial plane, is also the X axis of HGS x_axis = CartesianRepresentation(1, 0, 0) rot_matrix = _make_rotation_matrix_from_reprs(hgs_x_axis_detilt, x_axis) return matrix_product(rot_matrix, _SUN_DETILT_MATRIX)
def reference_to_skyoffset_matrix(skyoffset_frame): """Make rotation matrix from reference frame and a skyoffset frame. this function is useful after using astropy to make a rotation matrix *modified from reference_to_skyoffset function in astropy Parameters ---------- skyoffset_frame : SkyCoord frame the rotated frame note: SkyCoords are compatible Returns ------- R : numpy array a 3d rotation matrix """ origin = skyoffset_frame.origin.spherical mat1 = rotation_matrix(-skyoffset_frame.rotation, "x") mat2 = rotation_matrix(-origin.lat, "y") mat3 = rotation_matrix(origin.lon, "z") R = matrix_product(mat1, mat2, mat3) return R
def gcrs_to_geosolarecliptic(gcrs_coo, to_frame): if not to_frame.obstime.isscalar: raise ValueError( "To perform this transformation the obstime Attribute must be a scalar." ) _earth_orbit_perpen_point_gcrs = UnitSphericalRepresentation( lon=0 * u.deg, lat=(90 * u.deg - _obliquity_rotation_value(to_frame.obstime))) _earth_detilt_matrix = _make_rotation_matrix_from_reprs( _earth_orbit_perpen_point_gcrs, CartesianRepresentation(0, 0, 1)) sun_pos_gcrs = get_body("sun", to_frame.obstime).cartesian earth_pos_gcrs = get_body("earth", to_frame.obstime).cartesian sun_earth = sun_pos_gcrs - earth_pos_gcrs sun_earth_detilt = sun_earth.transform(_earth_detilt_matrix) # Earth-Sun Line in Geocentric Solar Ecliptic Frame x_axis = CartesianRepresentation(1, 0, 0) rot_matrix = _make_rotation_matrix_from_reprs(sun_earth_detilt, x_axis) return matrix_product(rot_matrix, _earth_detilt_matrix)
def hcrs_to_hgs(hcrscoord, hgsframe): """ Convert from HCRS to Heliographic Stonyhurst (HGS). HGS shares the same origin (the Sun) as HCRS, but has its Z axis aligned with the Sun's rotation axis and its X axis aligned with the projection of the Sun-Earth vector onto the Sun's equatorial plane (i.e., the component of the Sun-Earth vector perpendicular to the Z axis). Thus, the transformation matrix is the product of the matrix to align the Z axis (by de-tilting the Sun's rotation axis) and the matrix to align the X axis. The first matrix is independent of time and is pre-computed, while the second matrix depends on the time-varying Sun-Earth vector. """ if hgsframe.obstime is None: raise ValueError("To perform this transformation the coordinate" " Frame needs an obstime Attribute") # Determine the Sun-Earth vector in ICRS # Since HCRS is ICRS with an origin shift, this is also the Sun-Earth vector in HCRS sun_pos_icrs = get_body_barycentric('sun', hgsframe.obstime) earth_pos_icrs = get_body_barycentric('earth', hgsframe.obstime) sun_earth = earth_pos_icrs - sun_pos_icrs # De-tilt the Sun-Earth vector to the frame with the Sun's rotation axis parallel to the Z axis sun_earth_detilt = sun_earth.transform(_SUN_DETILT_MATRIX) # Remove the component of the Sun-Earth vector that is parallel to the Sun's north pole hgs_x_axis_detilt = CartesianRepresentation(sun_earth_detilt.xyz * [1, 1, 0]) # The above vector, which is in the Sun's equatorial plane, is also the X axis of HGS x_axis = CartesianRepresentation(1, 0, 0) rot_matrix = _make_rotation_matrix_from_reprs(hgs_x_axis_detilt, x_axis) return matrix_product(rot_matrix, _SUN_DETILT_MATRIX)
def gcrs_to_geosolarecliptic(gcrs_coo, to_frame): if not to_frame.obstime.isscalar: raise ValueError( "To perform this transformation the obstime Attribute must be a scalar." ) _earth_orbit_perpen_point_gcrs = UnitSphericalRepresentation( lon=0 * u.deg, lat=(90 * u.deg - _obliquity_rotation_value(to_frame.obstime)) ) _earth_detilt_matrix = _make_rotation_matrix_from_reprs( _earth_orbit_perpen_point_gcrs, CartesianRepresentation(0, 0, 1) ) sun_pos_gcrs = get_body("sun", to_frame.obstime).cartesian earth_pos_gcrs = get_body("earth", to_frame.obstime).cartesian sun_earth = sun_pos_gcrs - earth_pos_gcrs sun_earth_detilt = sun_earth.transform(_earth_detilt_matrix) # Earth-Sun Line in Geocentric Solar Ecliptic Frame x_axis = CartesianRepresentation(1, 0, 0) rot_matrix = _make_rotation_matrix_from_reprs(sun_earth_detilt, x_axis) return matrix_product(rot_matrix, _earth_detilt_matrix)
def get_transform_matrix(from_frame, to_frame): """Compose sequential matrix transformations (static or dynamic) to get a single transformation matrix from a given path through the Astropy transformation machinery. Parameters ---------- from_frame : `~astropy.coordinates.BaseCoordinateFrame` subclass The *class* or instance of the frame you're transforming from. to_frame : `~astropy.coordinates.BaseCoordinateFrame` subclass The class or instance of the frame you're transforming to. """ if isinstance(from_frame, coord.BaseCoordinateFrame): from_frame_cls = from_frame.__class__ else: from_frame_cls = from_frame if isinstance(to_frame, coord.BaseCoordinateFrame): to_frame_cls = to_frame.__class__ else: to_frame_cls = to_frame path, distance = coord.frame_transform_graph.find_shortest_path( from_frame_cls, to_frame_cls) matrices = [] currsys = from_frame for p in path[1:]: # first element is fromsys so we skip it if isinstance(currsys, coord.BaseCoordinateFrame): currsys_cls = currsys.__class__ else: currsys_cls = currsys currsys = currsys_cls() trans = coord.frame_transform_graph._graph[currsys_cls][p] if isinstance(to_frame, p): p = to_frame if isinstance(trans, coord.DynamicMatrixTransform): M = trans.matrix_func(currsys, p) elif isinstance(trans, coord.StaticMatrixTransform): M = trans.matrix else: raise ValueError("Transform path contains a '{0}': cannot " "be composed into a single transformation " "matrix.".format(trans.__class__.__name__)) matrices.append(M) currsys = p M = None for Mi in reversed(matrices): if M is None: M = Mi else: M = matrix_product(M, Mi) return M
def fk5_to_gal(fk5coord, galframe): # need precess to J2000 first pmat = fk5coord._precession_matrix(fk5coord.equinox, EQUINOX_J2000) mat1 = rotation_matrix(180 - Galactic._lon0_J2000.degree, 'z') mat2 = rotation_matrix(90 - Galactic._ngp_J2000.dec.degree, 'y') mat3 = rotation_matrix(Galactic._ngp_J2000.ra.degree, 'z') return matrix_product(mat1, mat2, mat3, pmat)
def fk5_to_gal(fk5coord, galframe): # need precess to J2000 first pmat = fk5coord._precession_matrix(fk5coord.equinox, EQUINOX_J2000) mat1 = rotation_matrix(180 - Galactic._lon0_J2000.degree, 'z') mat2 = rotation_matrix(90 - Galactic._ngp_J2000.dec.degree, 'y') mat3 = rotation_matrix(Galactic._ngp_J2000.ra.degree, 'z') return matrix_product(mat1, mat2, mat3, pmat)
def reference_to_skyoffset_matrix( lon: T.Union[float, u.Quantity], lat: T.Union[float, u.Quantity], rotation: T.Union[float, u.Quantity], ) -> T.Sequence: """Convert a reference coordinate to an sky offset frame [astropy]. Cartesian to Cartesian matrix transform. Parameters ---------- lon : float or |AngleType| or |Quantity| instance For ICRS, the right ascension. If float, assumed degrees. lat : |AngleType| or |Quantity| instance For ICRS, the declination. If float, assumed degrees. rotation : |AngleType| or |Quantity| instance The final rotation of the frame about the ``origin``. The sign of the rotation is the left-hand rule. That is, an object at a particular position angle in the un-rotated system will be sent to the positive latitude (z) direction in the final frame. If float, assumed degrees. Returns ------- ndarray (3x3) matrix. rotates reference Cartesian to skyoffset Cartesian. See Also -------- :func:`~astropy.coordinates.builtin.skyoffset.reference_to_skyoffset` References ---------- .. [astropy] Astropy Collaboration, Robitaille, T., Tollerud, E., Greenfield, P., Droettboom, M., Bray, E., Aldcroft, T., Davis, M., Ginsburg, A., Price-Whelan, A., Kerzendorf, W., Conley, A., Crighton, N., Barbary, K., Muna, D., Ferguson, H., Grollier, F., Parikh, M., Nair, P., Unther, H., Deil, C., Woillez, J., Conseil, S., Kramer, R., Turner, J., Singer, L., Fox, R., Weaver, B., Zabalza, V., Edwards, Z., Azalee Bostroem, K., Burke, D., Casey, A., Crawford, S., Dencheva, N., Ely, J., Jenness, T., Labrie, K., Lim, P., Pierfederici, F., Pontzen, A., Ptak, A., Refsdal, B., Servillat, M., & Streicher, O. (2013). Astropy: A community Python package for astronomy. Astronomy and Astrophysics, 558, A33. """ # Define rotation matrices along the position angle vector, and # relative to the origin. mat1 = rotation_matrix(-rotation, "x") mat2 = rotation_matrix(-lat, "y") mat3 = rotation_matrix(lon, "z") M = matrix_product(mat1, mat2, mat3) return M
def _create_matrix(self, phi, theta, psi, axes_order): matrices = [] for angle, axis in zip([phi, theta, psi], axes_order): if isinstance(angle, u.Quantity): angle = angle.value angle = angle.item() matrices.append(rotation_matrix(angle, axis, unit=u.rad)) result = matrix_product(*matrices[::-1]) return result
def reference_to_skyoffset(reference_frame, telescope_frame): """Convert a reference coordinate to an sky offset frame.""" # Define rotation matrices along the position angle vector, and # relative to the origin. origin = telescope_frame.origin.spherical mat1 = rotation_matrix(-origin.lat, 'y') mat2 = rotation_matrix(origin.lon, 'z') return matrix_product(mat1, mat2)
def _create_matrix(self, phi, theta, psi, axes_order): matrices = [] for angle, axis in zip([phi, theta, psi], axes_order): if isinstance(angle, u.Quantity): angle = angle.value angle = angle.item() matrices.append(rotation_matrix(angle, axis, unit=u.rad)) result = matrix_product(*matrices[::-1]) return result
def _true_ecliptic_rotation_matrix(equinox): # This code calls pnm06a from ERFA, which retrieves the precession # matrix (including frame bias) according to the IAU 2006 model, and # including the nutation. This family of systems is less popular # (see https://github.com/astropy/astropy/pull/6508). jd1, jd2 = get_jd12(equinox, 'tt') rnpb = erfa.pnm06a(jd1, jd2) obl = erfa.obl06(jd1, jd2)*u.radian return matrix_product(rotation_matrix(obl, 'x'), rnpb)
def reference_to_skyoffset(reference_frame, telescope_frame): """Convert a reference coordinate to an sky offset frame.""" # Define rotation matrices along the position angle vector, and # relative to the origin. origin = telescope_frame.origin.spherical mat1 = rotation_matrix(-origin.lat, "y") mat2 = rotation_matrix(origin.lon, "z") return matrix_product(mat1, mat2)
def reference_to_skyoffset(reference_frame, telescope_frame): '''Convert a reference coordinate to an sky offset frame.''' # Define rotation matrices along the position angle vector, and # relative to the telescope_pointing. telescope_pointing = telescope_frame.telescope_pointing.spherical mat1 = rotation_matrix(-telescope_pointing.lat, 'y') mat2 = rotation_matrix(telescope_pointing.lon, 'z') return matrix_product(mat1, mat2)
def reference_to_greatcircle(reference_frame, greatcircle_frame): """Convert a reference coordinate to a great circle frame.""" # Define rotation matrices along the position angle vector, and # relative to the origin. pole = greatcircle_frame.pole.transform_to(coord.ICRS()) ra0 = greatcircle_frame.ra0 center = greatcircle_frame.center R_rot = rotation_matrix(greatcircle_frame.rotation, 'z') if not np.isnan(ra0) and np.abs(pole.dec.value) > 1e-15: zaxis = pole.cartesian.xyz.value xaxis = np.array([np.cos(ra0), np.sin(ra0), 0.]) if np.abs(zaxis[2]) >= 1e-15: xaxis[2] = -(zaxis[0] * xaxis[0] + zaxis[1] * xaxis[1]) / zaxis[2] else: xaxis[2] = 0. xaxis = xaxis / np.sqrt(np.sum(xaxis**2)) yaxis = np.cross(zaxis, xaxis) yaxis = yaxis / np.sqrt(np.sum(yaxis**2)) R = np.stack((xaxis, yaxis, zaxis)) elif center is not None: R1 = rotation_matrix(pole.ra, 'z') R2 = rotation_matrix(90 * u.deg - pole.dec, 'y') Rtmp = matrix_product(R2, R1) rot = center.cartesian.transform(Rtmp) rot_lon = rot.represent_as(coord.UnitSphericalRepresentation).lon R3 = rotation_matrix(rot_lon, 'z') R = matrix_product(R3, R2, R1) else: if not np.isnan(ra0) and np.abs(pole.dec.value) < 1e-15: warn("Ignoring input ra0 because the pole is along dec=0", RuntimeWarning) R1 = rotation_matrix(pole.ra, 'z') R2 = rotation_matrix(90 * u.deg - pole.dec, 'y') R = matrix_product(R2, R1) return matrix_product(R_rot, R)
def get_matrix_vectors(galactocentric_frame, inverse=False): """ Use the ``inverse`` argument to get the inverse transformation, matrix and offsets to go from Galactocentric to ICRS. """ # shorthand gcf = galactocentric_frame # rotation matrix to align x(ICRS) with the vector to the Galactic center mat1 = rotation_matrix(-gcf.galcen_coord.dec, 'y') mat2 = rotation_matrix(gcf.galcen_coord.ra, 'z') # extra roll away from the Galactic x-z plane mat0 = rotation_matrix(gcf.get_roll0() - gcf.roll, 'x') # construct transformation matrix and use it R = matrix_product(mat0, mat1, mat2) # Now need to translate by Sun-Galactic center distance around x' and # rotate about y' to account for tilt due to Sun's height above the plane translation = r.CartesianRepresentation(gcf.galcen_distance * [1., 0., 0.]) z_d = gcf.z_sun / gcf.galcen_distance H = rotation_matrix(-np.arcsin(z_d), 'y') # compute total matrices A = matrix_product(H, R) # Now we re-align the translation vector to account for the Sun's height # above the midplane offset = -translation.transform(H) if inverse: # the inverse of a rotation matrix is a transpose, which is much faster # and more stable to compute A = matrix_transpose(A) offset = (-offset).transform(A) offset_v = r.CartesianDifferential.from_cartesian( (-gcf.galcen_v_sun).to_cartesian().transform(A)) offset = offset.with_differentials(offset_v) else: offset = offset.with_differentials(gcf.galcen_v_sun) return A, offset
def reference_to_skyoffset(reference_frame, skyoffset_frame): """Convert a reference coordinate to an sky offset frame.""" # Define rotation matrices along the position angle vector, and # relative to the origin. origin = skyoffset_frame.origin.spherical mat1 = rotation_matrix(-skyoffset_frame.rotation, 'x') mat2 = rotation_matrix(-origin.lat, 'y') mat3 = rotation_matrix(origin.lon, 'z') return matrix_product(mat1, mat2, mat3)
def aligned3D_to_projected(X, Y, Z, inc): XYZ = np.array([X.to('pc').value, Y.to('pc').value, Z.to('pc').value]) * u.pc M = rotate(inc) xyz = matrix_product(M, XYZ) x = xyz[0, :] y = xyz[1, :] z = xyz[2, :] return x, y, z
def fk4_no_e_to_fk5(fk4noecoord, fk5frame): # Correction terms for FK4 being a rotating system B = _fk4_B_matrix(fk4noecoord.obstime) # construct both precession matricies - if the equinoxes are B1950 and # J2000, these are just identity matricies pmat1 = fk4noecoord._precession_matrix(fk4noecoord.equinox, EQUINOX_B1950) pmat2 = fk5frame._precession_matrix(EQUINOX_J2000, fk5frame.equinox) return matrix_product(pmat2, B, pmat1)
def cylin_to_aligned3D_vels(vR, vphi, vz, phi): M = np.array([[np.cos(phi), -np.sin(phi), 0], [np.sin(phi), np.cos(phi), 0], [0, 0, 1]]) vR, vphi, vz = np.atleast_1d(vR), np.atleast_1d(vphi), np.atleast_1d(vz) v_cylin = np.array( [vR.to('km/s').value, vphi.to('km/s').value, vz.to('km/s').value]) v_cartesian = matrix_product(M, v_cylin) return v_cartesian * u.km / u.s
def fk4_no_e_to_fk5(fk4noecoord, fk5frame): # Correction terms for FK4 being a rotating system B = _fk4_B_matrix(fk4noecoord.obstime) # construct both precession matricies - if the equinoxes are B1950 and # J2000, these are just identity matricies pmat1 = fk4noecoord._precession_matrix(fk4noecoord.equinox, EQUINOX_B1950) pmat2 = fk5frame._precession_matrix(EQUINOX_J2000, fk5frame.equinox) return matrix_product(pmat2, B, pmat1)
def _mean_ecliptic_rotation_matrix(equinox): # This code calls pmat06 from ERFA, which retrieves the precession # matrix (including frame bias) according to the IAU 2006 model, but # leaves out the nutation. This matches what ERFA does in the ecm06 # function and also brings the results closer to what other libraries # give (see https://github.com/astropy/astropy/pull/6508). jd1, jd2 = get_jd12(equinox, 'tt') rbp = erfa.pmat06(jd1, jd2) obl = erfa.obl06(jd1, jd2)*u.radian return matrix_product(rotation_matrix(obl, 'x'), rbp)
def get_matrix_vectors(galactocentric_frame, inverse=False): """ Use the ``inverse`` argument to get the inverse transformation, matrix and offsets to go from Galactocentric to ICRS. """ # shorthand gcf = galactocentric_frame # rotation matrix to align x(ICRS) with the vector to the Galactic center mat1 = rotation_matrix(-gcf.galcen_coord.dec, 'y') mat2 = rotation_matrix(gcf.galcen_coord.ra, 'z') # extra roll away from the Galactic x-z plane mat0 = rotation_matrix(gcf.get_roll0() - gcf.roll, 'x') # construct transformation matrix and use it R = matrix_product(mat0, mat1, mat2) # Now need to translate by Sun-Galactic center distance around x' and # rotate about y' to account for tilt due to Sun's height above the plane translation = r.CartesianRepresentation(gcf.galcen_distance * [1., 0., 0.]) z_d = gcf.z_sun / gcf.galcen_distance H = rotation_matrix(-np.arcsin(z_d), 'y') # compute total matrices A = matrix_product(H, R) # Now we re-align the translation vector to account for the Sun's height # above the midplane offset = -translation.transform(H) if inverse: # the inverse of a rotation matrix is a transpose, which is much faster # and more stable to compute A = matrix_transpose(A) offset = (-offset).transform(A) offset_v = r.CartesianDifferential.from_cartesian( (-gcf.galcen_v_sun).to_cartesian().transform(A)) offset = offset.with_differentials(offset_v) else: offset = offset.with_differentials(gcf.galcen_v_sun) return A, offset
def cb_crs_to_cb_j2000_eq(cb_crs_coord, _): """Conversion from Celestial Reference System of a Central Body to its Local Equatorial at J2000 Epoch Reference System.""" ra, dec, w = celestial_body_rot_params(None, cb_crs_coord.body_name) body_crs_to_body_eq = matrix_product( rotation_matrix(90 * u.deg - dec, "x"), rotation_matrix(90 * u.deg + ra, "z")) return body_crs_to_body_eq
def fk5_to_fk4_no_e(fk5coord, fk4noeframe): # Get transposed version of the rotating correction terms... so with the # transpose this takes us from FK5/J200 to FK4/B1950 B = matrix_transpose(_fk4_B_matrix(fk4noeframe.obstime)) # construct both precession matricies - if the equinoxes are B1950 and # J2000, these are just identity matricies pmat1 = fk5coord._precession_matrix(fk5coord.equinox, EQUINOX_J2000) pmat2 = fk4noeframe._precession_matrix(EQUINOX_B1950, fk4noeframe.equinox) return matrix_product(pmat2, B, pmat1)
def body_crs_to_body_eq_matrix(obstime, body_name): """Computes the rotation matrix from Celestial Body CRS to Local Equatorial True-of-Date Reference System.""" ra, dec, w = celestial_body_rot_params(obstime, body_name) body_crs_to_body_eq = matrix_product( rotation_matrix(90 * u.deg - dec, "x"), rotation_matrix(90 * u.deg + ra, "z"), ) return body_crs_to_body_eq
def fk5_to_fk4_no_e(fk5coord, fk4noeframe): # Get transposed version of the rotating correction terms... so with the # transpose this takes us from FK5/J200 to FK4/B1950 B = matrix_transpose(_fk4_B_matrix(fk4noeframe.obstime)) # construct both precession matricies - if the equinoxes are B1950 and # J2000, these are just identity matricies pmat1 = fk5coord._precession_matrix(fk5coord.equinox, EQUINOX_J2000) pmat2 = fk4noeframe._precession_matrix(EQUINOX_B1950, fk4noeframe.equinox) return matrix_product(pmat2, B, pmat1)
def _ecliptic_rotation_matrix(equinox): # This code calls pmat06 from ERFA, which retrieves the precession # matrix (including frame bias) according to the IAU 2006 model, but # leaves out the nutation. This matches what ERFA does in the ecm06 # function and also brings the results closer to what other libraries # give (see https://github.com/astropy/astropy/pull/6508). However, # notice that this makes the name "TrueEcliptic" misleading, and might # be changed in the future (discussion in the same pull request) jd1, jd2 = get_jd12(equinox, 'tt') rbp = erfa.pmat06(jd1, jd2) obl = erfa.obl06(jd1, jd2) * u.radian return matrix_product(rotation_matrix(obl, 'x'), rbp)
def _ecliptic_rotation_matrix(equinox): # This code calls pmat06 from ERFA, which retrieves the precession # matrix (including frame bias) according to the IAU 2006 model, but # leaves out the nutation. This matches what ERFA does in the ecm06 # function and also brings the results closer to what other libraries # give (see https://github.com/astropy/astropy/pull/6508). However, # notice that this makes the name "TrueEcliptic" misleading, and might # be changed in the future (discussion in the same pull request) jd1, jd2 = get_jd12(equinox, 'tt') rbp = erfa.pmat06(jd1, jd2) obl = erfa.obl06(jd1, jd2)*u.radian return matrix_product(rotation_matrix(obl, 'x'), rbp)
def body_crs_to_body_fixed_matrix(obstime, body_name): """Computes the rotation matrix from Celestial Body CRS to Body Fixed Reference System.""" ra, dec, w = celestial_body_rot_params(obstime, body_name) body_crs_to_body_fixed = matrix_product( rotation_matrix(w, "z"), rotation_matrix(90 * u.deg - dec, "x"), rotation_matrix(90 * u.deg + ra, "z"), ) return body_crs_to_body_fixed
def projected_to_aligned3D(x, y, z, inc): unit = x.unit x = x.to(unit) y = y.to(unit) z = z.to(unit) xyz = np.array([x.value, y.value, z.value]) * unit M = rotate(inc).T XYZ = matrix_product(M, xyz) X = XYZ[0, :] Y = XYZ[1, :] Z = XYZ[2, :] return X, Y, Z
def icrs_to_arbpole(icrs_coord, arbpole_frame): roll = arbpole_frame.roll pole = arbpole_frame.pole # Align z(new) with direction to M31 mat1 = rotation_matrix(-pole.dec, 'y') mat2 = rotation_matrix(pole.ra, 'z') mat3 = rotation_matrix(roll, 'z') mat4 = rotation_matrix(90 * u.degree, 'y') R = matrix_product(mat4, mat1, mat2, mat3) return R
def _icrs_to_fk5_matrix(): """ B-matrix from USNO circular 179. Used by the ICRS->FK5 transformation functions. """ eta0 = -19.9 / 3600000. xi0 = 9.1 / 3600000. da0 = -22.9 / 3600000. m1 = rotation_matrix(-eta0, 'x') m2 = rotation_matrix(xi0, 'y') m3 = rotation_matrix(da0, 'z') return matrix_product(m1, m2, m3)
def _rotation_matrix_hme_to_hee(hmeframe): """ Return the rotation matrix from HME to HEE at the same observation time """ # Get the Sun-Earth vector sun_earth = HCRS(_sun_earth_icrf(hmeframe.obstime), obstime=hmeframe.obstime) sun_earth_hme = sun_earth.transform_to(hmeframe).cartesian # Rotate the Sun-Earth vector about the Z axis so that it lies in the XZ plane rot_matrix = _rotation_matrix_reprs_to_xz_about_z(sun_earth_hme) # Tilt the rotated Sun-Earth vector so that it is aligned with the X axis tilt_matrix = _rotation_matrix_reprs_to_reprs(sun_earth_hme.transform(rot_matrix), CartesianRepresentation(1, 0, 0)) return matrix_product(tilt_matrix, rot_matrix)
def get_transform_matrix(from_frame, to_frame): """Compose sequential matrix transformations (static or dynamic) to get a single transformation matrix from a given path through the Astropy transformation machinery. Parameters ---------- from_frame : `~astropy.coordinates.BaseCoordinateFrame` subclass The *class* of the frame you're transforming from. to_frame : `~astropy.coordinates.BaseCoordinateFrame` subclass The *class* of the frame you're transfrorming to. """ path, distance = coord.frame_transform_graph.find_shortest_path( from_frame, to_frame) matrices = [] currsys = from_frame for p in path[1:]: # first element is fromsys so we skip it trans = coord.frame_transform_graph._graph[currsys][p] if isinstance(trans, coord.DynamicMatrixTransform): M = trans.matrix_func(currsys(), p) elif isinstance(trans, coord.StaticMatrixTransform): M = trans.matrix else: raise ValueError("Transform path contains a '{0}': cannot " "be composed into a single transformation " "matrix.".format(trans.__class__.__name__)) matrices.append(M) currsys = p M = None for Mi in reversed(matrices): if M is None: M = Mi else: M = matrix_product(M, Mi) return M
def _rotate_polygon(lon, lat, lon0, lat0): """ Given a polygon with vertices defined by (lon, lat), rotate the polygon such that the North pole of the spherical coordinates is now at (lon0, lat0). Therefore, to end up with a polygon centered on (lon0, lat0), the polygon should initially be drawn around the North pole. """ # Create a representation object polygon = UnitSphericalRepresentation(lon=lon, lat=lat) # Determine rotation matrix to make it so that the circle is centered # on the correct longitude/latitude. m1 = rotation_matrix(-(0.5 * np.pi * u.radian - lat0), axis='y') m2 = rotation_matrix(-lon0, axis='z') transform_matrix = matrix_product(m2, m1) # Apply 3D rotation polygon = polygon.to_cartesian() polygon = polygon.transform(transform_matrix) polygon = UnitSphericalRepresentation.from_cartesian(polygon) return polygon.lon, polygon.lat
r = super().represent_as(base, s=s, in_frame_units=in_frame_units) r.lon.wrap_angle = self._default_wrap_angle return r represent_as.__doc__ = coord.BaseCoordinateFrame.represent_as.__doc__ # Define the Euler angles (from Law & Majewski 2010) phi = (180+3.75) * u.degree theta = (90-13.46) * u.degree psi = (180+14.111534) * u.degree # Generate the rotation matrix using the x-convention (see Goldstein) D = rotation_matrix(phi, "z") C = rotation_matrix(theta, "x") B = rotation_matrix(psi, "z") A = np.diag([1.,1.,-1.]) R = matrix_product(A, B, C, D) # Galactic to Sgr coordinates @frame_transform_graph.transform(coord.StaticMatrixTransform, coord.Galactic, SagittariusLaw10) def galactic_to_sgr(): """ Compute the transformation from Galactic spherical to heliocentric Sagittarius coordinates. """ return R # Sgr to Galactic coordinates @frame_transform_graph.transform(coord.StaticMatrixTransform, SagittariusLaw10, coord.Galactic) def sgr_to_galactic(): """ Compute the transformation from heliocentric Sagittarius coordinates to
r = super().represent_as(base, s=s, in_frame_units=in_frame_units) r.lon.wrap_angle = self._default_wrap_angle return r represent_as.__doc__ = coord.BaseCoordinateFrame.represent_as.__doc__ # Define the Euler angles phi = 128.79 * u.degree theta = 54.39 * u.degree psi = 90.70 * u.degree # Generate the rotation matrix using the x-convention (see Goldstein) D = rotation_matrix(phi, "z") C = rotation_matrix(theta, "x") B = rotation_matrix(psi, "z") R = matrix_product(B, C, D) @frame_transform_graph.transform(coord.StaticMatrixTransform, coord.Galactic, OrphanNewberg10) def galactic_to_orp(): """ Compute the transformation from Galactic spherical to heliocentric Orphan coordinates. """ return R # Oph to Galactic coordinates @frame_transform_graph.transform(coord.StaticMatrixTransform, OrphanNewberg10, coord.Galactic) def oph_to_galactic(): """ Compute the transformation from heliocentric Orphan coordinates to spherical Galactic.
def gal_to_mag(): mat1 = rotation_matrix(57.275785782128686*u.deg, 'z') mat2 = rotation_matrix(90*u.deg - MagellanicStreamNidever08._ngp.b, 'y') mat3 = rotation_matrix(MagellanicStreamNidever08._ngp.l, 'z') return matrix_product(mat1, mat2, mat3)
# the new system. Because the transformation to the Sagittarius coordinate # system is just a spherical rotation from Galactic coordinates, we'll just # define a function that returns this matrix. We'll start by constructing the # transformation matrix using pre-deteremined Euler angles and the # ``rotation_matrix`` helper function: SGR_PHI = (180 + 3.75) * u.degree # Euler angles (from Law & Majewski 2010) SGR_THETA = (90 - 13.46) * u.degree SGR_PSI = (180 + 14.111534) * u.degree # Generate the rotation matrix using the x-convention (see Goldstein) D = rotation_matrix(SGR_PHI, "z") C = rotation_matrix(SGR_THETA, "x") B = rotation_matrix(SGR_PSI, "z") A = np.diag([1.,1.,-1.]) SGR_MATRIX = matrix_product(A, B, C, D) ############################################################################## # Since we already constructed the transformation (rotation) matrix above, and # the inverse of a rotation matrix is just its transpose, the required # transformation functions are very simple: @frame_transform_graph.transform(coord.StaticMatrixTransform, coord.Galactic, Sagittarius) def galactic_to_sgr(): """ Compute the transformation matrix from Galactic spherical to heliocentric Sgr coordinates. """ return SGR_MATRIX ############################################################################## # The decorator ``@frame_transform_graph.transform(coord.StaticMatrixTransform,
def gal_to_supergal(): mat1 = rotation_matrix(90, 'z') mat2 = rotation_matrix(90 - Supergalactic._nsgp_gal.b.degree, 'y') mat3 = rotation_matrix(Supergalactic._nsgp_gal.l.degree, 'z') return matrix_product(mat1, mat2, mat3)