Beispiel #1
0
def _pixel_scale_angle_at_skycoord(skycoord, wcs, offset=1. * u.arcsec):
    """
    Calculate the pixel scale and WCS rotation angle at the position of
    a SkyCoord coordinate.

    Parameters
    ----------
    skycoord : `~astropy.coordinates.SkyCoord`
        The SkyCoord coordinate.
    wcs : `~astropy.wcs.WCS`
        The world coordinate system (WCS) transformation to use.
    offset : `~astropy.units.Quantity`
        A small angular offset to use to compute the pixel scale and
        position angle.

    Returns
    -------
    scale : `~astropy.units.Quantity`
        The pixel scale in arcsec/pixel.
    angle : `~astropy.units.Quantity`
        The angle (in degrees) measured counterclockwise from the
        positive x axis to the "North" axis of the celestial coordinate
        system.

    Notes
    -----
    If distortions are present in the image, the x and y pixel scales
    likely differ.  This function computes a single pixel scale along
    the North/South axis.
    """

    # We take a point directly "above" (in latitude) the input position
    # and convert it to pixel coordinates, then we use the pixel deltas
    # between the input and offset point to calculate the pixel scale and
    # angle.

    # Find the coordinates as a representation object
    coord = skycoord.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle)
    coord_new = UnitSphericalRepresentation(coord.lon, coord.lat + offset)
    coord_offset = skycoord.realize_frame(coord_new)

    # Find pixel coordinates of offset coordinates and pixel deltas
    x_offset, y_offset = skycoord_to_pixel(coord_offset, wcs, mode='all')
    x, y = skycoord_to_pixel(skycoord, wcs, mode='all')
    dx = x_offset - x
    dy = y_offset - y

    scale = offset.to(u.arcsec) / (np.hypot(dx, dy) * u.pixel)
    angle = (np.arctan2(dy, dx) * u.radian).to(u.deg)

    return scale, angle
Beispiel #2
0
def skycoord_to_pixel_scale_angle(coords, wcs):
    """
    Convert a set of SkyCoord coordinates into pixel coordinates, pixel
    scales, and position angles.

    Parameters
    ----------
    coords : `~astropy.coordinates.SkyCoord`
        The coordinates to convert
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use

    Returns
    -------
    x, y : `~numpy.ndarray`
        The x and y pixel coordinates corresponding to the input coordinates
    scale : `~astropy.units.Quantity`
        The pixel scale at each location, in degrees/pixel
    angle : `~astropy.units.Quantity`
        The position angle of the celestial coordinate system in pixel space.
    """

    # Convert to pixel coordinates
    x, y = skycoord_to_pixel(coords, wcs, mode=skycoord_to_pixel_mode)

    # We take a point directly 'above' (in latitude) the position requested
    # and convert it to pixel coordinates, then we use that to figure out the
    # scale and position angle of the coordinate system at the location of
    # the points.

    # Find the coordinates as a representation object
    r_old = coords.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle).
    dlat = 1 * u.arcsec
    r_new = UnitSphericalRepresentation(r_old.lon, r_old.lat + dlat)
    coords_offset = coords.realize_frame(r_new)

    # Find pixel coordinates of offset coordinates
    x_offset, y_offset = skycoord_to_pixel(coords_offset, wcs,
                                           mode=skycoord_to_pixel_mode)

    # Find vector
    dx = x_offset - x
    dy = y_offset - y

    # Find the length of the vector
    scale = np.hypot(dx, dy) * u.pixel / dlat

    # Find the position angle
    angle = np.arctan2(dy, dx) * u.radian

    return x, y, scale, angle
Beispiel #3
0
def test_cirs_altaz_nodist(testframe):
    """
    Check that a UnitSphericalRepresentation coordinate round-trips for the
    CIRS<->AltAz transformation.
    """
    coo0 = CIRS(UnitSphericalRepresentation(10 * u.deg, 20 * u.deg),
                obstime=testframe.obstime)

    # check that it round-trips
    coo1 = coo0.transform_to(testframe).transform_to(coo0)
    assert_allclose(coo0.cartesian.xyz, coo1.cartesian.xyz)
Beispiel #4
0
def convert_world_coordinates(lon_in, lat_in, wcs_in, wcs_out):
    """
    Convert longitude/latitude coordinates from an input frame to an output
    frame.

    Parameters
    ----------
    lon_in, lat_in : `~numpy.ndarray`
        The longitude and latitude to convert
    wcs_in, wcs_out : tuple or `~astropy.wcs.WCS`
        The input and output frames, which can be passed either as a tuple of
        ``(frame, lon_unit, lat_unit)`` or as a `~astropy.wcs.WCS` instance.

    Returns
    -------
    lon_out, lat_out : `~numpy.ndarray`
        The output longitude and latitude
    """

    if isinstance(wcs_in, WCS):
        # Extract the celestial component of the WCS in (lon, lat) order
        wcs_in = wcs_in.celestial
        frame_in = wcs_to_celestial_frame(wcs_in)
        lon_in_unit = u.Unit(wcs_in.wcs.cunit[0])
        lat_in_unit = u.Unit(wcs_in.wcs.cunit[1])
    else:
        frame_in, lon_in_unit, lat_in_unit = wcs_in

    if isinstance(wcs_out, WCS):
        # Extract the celestial component of the WCS in (lon, lat) order
        wcs_out = wcs_out.celestial
        frame_out = wcs_to_celestial_frame(wcs_out)
        lon_out_unit = u.Unit(wcs_out.wcs.cunit[0])
        lat_out_unit = u.Unit(wcs_out.wcs.cunit[1])
    else:
        frame_out, lon_out_unit, lat_out_unit = wcs_out

    data = UnitSphericalRepresentation(lon_in * lon_in_unit,
                                       lat_in * lat_in_unit)

    coords_in = frame_in.realize_frame(data)
    coords_out = coords_in.transform_to(frame_out)

    lon_out = coords_out.represent_as('unitspherical').lon.to(
        lon_out_unit).value
    lat_out = coords_out.represent_as('unitspherical').lat.to(
        lat_out_unit).value

    return lon_out, lat_out
Beispiel #5
0
    def setup(self):

        self.coord_scalar = SkyCoord(1, 2, unit='deg', frame='icrs')

        lon, lat = np.ones((2, 1000))
        self.coord_array_1e3 = SkyCoord(lon, lat, unit='deg', frame='icrs')

        self.lon_1e6, self.lat_1e6 = np.ones((2, int(1e6)))
        self.coord_array_1e6 = SkyCoord(self.lon_1e6,
                                        self.lat_1e6,
                                        unit='deg',
                                        frame='icrs')

        self.scalar_q_ra = 1 * u.deg
        self.scalar_q_dec = 2 * u.deg

        np.random.seed(12345)
        self.array_q_ra = np.random.rand(int(1e6)) * 360 * u.deg
        self.array_q_dec = (np.random.rand(int(1e6)) * 180 - 90) * u.deg

        self.scalar_repr = UnitSphericalRepresentation(lat=self.scalar_q_dec,
                                                       lon=self.scalar_q_ra)
        self.array_repr = UnitSphericalRepresentation(lat=self.array_q_dec,
                                                      lon=self.array_q_ra)
Beispiel #6
0
def camera_to_telescope(camera_coord, telescope_frame):
    """
    Transformation between CameraFrame and TelescopeFrame.
    Is called when a SkyCoord is transformed from CameraFrame into TelescopeFrame
    """
    x_pos = camera_coord.cartesian.x
    y_pos = camera_coord.cartesian.y

    rot = camera_coord.rotation
    if rot == 0:  # if no rotation applied save a few cycles
        x_rotated = x_pos
        y_rotated = y_pos
    else:
        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_coord.focal_length
    if focal_length.shape == () and focal_length.value == 0:
        raise ValueError(
            "Coordinate in CameraFrame is missing focal_length information")

    # 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(r, focal_length) -> theta,
    # where theta is the angle to the optical axis and r is the distance
    # to the camera center in the focal plane
    fov_lat = u.Quantity(
        (x_rotated / focal_length).to_value(u.dimensionless_unscaled),
        u.rad,
        copy=False)
    fov_lon = u.Quantity(
        (y_rotated / focal_length).to_value(u.dimensionless_unscaled),
        u.rad,
        copy=False)

    representation = UnitSphericalRepresentation(lat=fov_lat, lon=fov_lon)

    return telescope_frame.realize_frame(representation)
Beispiel #7
0
def _convert_world_coordinates(lon_in, lat_in, wcs_in, wcs_out):

    frame_in, lon_in_unit, lat_in_unit = wcs_in

    wcs_out = wcs_out.celestial
    frame_out = wcs_to_celestial_frame(wcs_out)
    lon_out_unit = u.Unit(wcs_out.wcs.cunit[0])
    lat_out_unit = u.Unit(wcs_out.wcs.cunit[1])

    data = UnitSphericalRepresentation(lon_in * lon_in_unit,
                                       lat_in * lat_in_unit)

    coords_in = frame_in.realize_frame(data)
    coords_out = coords_in.transform_to(frame_out)

    lon_out = coords_out.represent_as('unitspherical').lon.to(
        lon_out_unit).value
    lat_out = coords_out.represent_as('unitspherical').lat.to(
        lat_out_unit).value

    return lon_out, lat_out
Beispiel #8
0
    def transform(self, input_coords):
        """
        Transform one set of coordinates to another
        """
        if self.same_frames:
            return input_coords

        input_coords = input_coords * u.deg
        x_in, y_in = input_coords[:, 0], input_coords[:, 1]

        c_in = SkyCoord(UnitSphericalRepresentation(x_in, y_in),
                        frame=self.input_system)

        # We often need to transform arrays that contain NaN values, and filtering
        # out the NaN values would have a performance hit, so instead we just pass
        # on all values and just ignore Numpy warnings
        with np.errstate(all='ignore'):
            c_out = c_in.transform_to(self.output_system)

        lon = c_out.spherical.lon.deg
        lat = c_out.spherical.lat.deg

        return np.concatenate((lon[:, np.newaxis], lat[:, np.newaxis]), axis=1)
Beispiel #9
0
    def test_camera_tilt_unreachable(self):
        """Remove, then apply camera tilt for unreachable positions and check separation"""

        param_set = ModelParamSet(None, None, None, None)
        model = MountModel(param_set)

        for _ in range(20):

            tilt = Angle(np.random.uniform(-90.0, 90.0) * u.deg)

            params = ModelParameters(
                axis_0_offset=Angle(
                    0 * u.deg),  # does not affect the method under test
                axis_1_offset=Angle(
                    0 * u.deg),  # does not affect the method under test
                pole_rot_axis_az=Angle(
                    0 * u.deg),  # does not affect the method under test
                pole_rot_angle=Angle(
                    0 * u.deg),  # does not affect the method under test
                camera_tilt=tilt,
            )
            model.model_params = params

            coord = UnitSphericalRepresentation(
                np.random.uniform(0.0, 360.0) * u.deg,
                random.choice((-1, +1)) *
                np.random.uniform(90.0 - abs(tilt.deg), 90.0) * u.deg)
            meridian_side = random.choice(
                (MeridianSide.WEST, MeridianSide.EAST))
            untilted_coord = model.remove_camera_tilt(coord, meridian_side)
            final_coord = model.apply_camera_tilt(untilted_coord,
                                                  meridian_side)

            separation = SkyCoord(coord).separation(SkyCoord(final_coord))
            expected_separation = np.abs(tilt) - (90 * u.deg -
                                                  np.abs(coord.lat))
            assert_allclose(separation.deg, expected_separation.deg)
Beispiel #10
0
def latlon_to_cartesian(latitude, longitude, stellar_inclination):
    """
    Convert coordinates in latitude/longitude for a star with a given
    stellar inclination into cartesian coordinates.

    The X-Y plane is the sky plane: x is aligned with the stellar equator, y is
    aligned with the stellar rotation axis.

    Parameters
    ----------
    latitude : float or `~astropy.units.Quantity`
        Spot latitude. Will assume unit=deg if none is specified.
    longitude : float or `~astropy.units.Quantity`
        Spot longitude. Will assume unit=deg if none is specified.
    stellar_inclination : float
        Stellar inclination angle, measured away from the line of sight,
        in [deg].

    Returns
    -------
    cartesian : `~astropy.coordinates.CartesianRepresentation`
        Cartesian representation in the frame described above.
    """

    if not hasattr(longitude, 'unit') and not hasattr(latitude, 'unit'):
        longitude *= u.deg
        latitude *= u.deg

    c = UnitSphericalRepresentation(longitude, latitude)
    cartesian = c.to_cartesian()

    rotate_about_z = rotation_matrix(90 * u.deg, axis='z')
    rotate_is = rotation_matrix(stellar_inclination * u.deg, axis='y')
    transform_matrix = matrix_product(rotate_about_z, rotate_is)
    cartesian = cartesian.transform(transform_matrix)
    return cartesian
Beispiel #11
0
def convert_world_coordinates(xw_in, yw_in, wcs_in, wcs_out):
    """
    Convert world coordinates from an input frame to an output frame.

    Parameters
    ----------
    xw_in, yw_in : `~numpy.ndarray`
        The input coordinates to convert
    wcs_in, wcs_out : tuple or `~astropy.wcs.WCS`
        The input and output frames, which can be passed either as a tuple of
        ``(frame, x_unit, y_unit)`` or as a `~astropy.wcs.WCS` instance.
    """

    if isinstance(wcs_in, WCS):
        frame_in = wcs_to_celestial_frame(wcs_in)
        xw_in_unit = u.Unit(wcs_in.wcs.cunit[0])
        yw_in_unit = u.Unit(wcs_in.wcs.cunit[1])
    else:
        frame_in, xw_in_unit, yw_in_unit = wcs_in

    if isinstance(wcs_out, WCS):
        frame_out = wcs_to_celestial_frame(wcs_out)
        xw_out_unit = u.Unit(wcs_out.wcs.cunit[0])
        yw_out_unit = u.Unit(wcs_out.wcs.cunit[1])
    else:
        frame_out, xw_out_unit, yw_out_unit = wcs_out

    data = UnitSphericalRepresentation(xw_in * xw_in_unit, yw_in * yw_in_unit)

    coords_in = frame_in.realize_frame(data)
    coords_out = coords_in.transform_to(frame_out)

    xw_out = coords_out.spherical.lon.to(xw_out_unit).value
    yw_out = coords_out.spherical.lat.to(yw_out_unit).value

    return xw_out, yw_out
Beispiel #12
0
def init_frame(frame, args, kwargs):
    if args and kwargs:
        return frame(*args, **kwargs)
    elif args:
        return frame(*args)
    elif kwargs:
        return frame(**kwargs)


"""
These are common 2D params, kwargs are frame specific
"""
two_D_parameters = [
    ([0 * u.deg, 0 * u.arcsec], None),
    ([0 * u.deg, 0 * u.arcsec], {'obstime': '2011/01/01T00:00:00'}),
    ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], None),
    ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], {'obstime': '2011/01/01T00:00:00'}),
    ([0 * u.deg, 0 * u.arcsec], {'representation_type': 'unitspherical'})
]
"""
These are common 3D params, kwargs are frame specific
"""
three_D_parameters = [
    ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], None),
    ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], {'obstime': '2011/01/01T00:00:00'}),
    ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], {'representation_type': 'spherical'}),
    ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)],
     None),
    ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)], None), (
        [SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)],
        {'obstime': '2011/01/01T00:00:00'})
Beispiel #13
0
        return frame(*args)
    elif kwargs:
        return frame(**kwargs)


"""
These are common 2D params, kwargs are frame specific
"""
two_D_parameters = [([0 * u.deg, 0 * u.arcsec], None),
                    ([0 * u.deg, 0 * u.arcsec], {
                        'obstime': '2011/01/01T00:00:00'
                    }),
                    ([0 * u.deg, 0 * u.arcsec], {
                        'representation': 'unitspherical'
                    }),
                    ([UnitSphericalRepresentation(0 * u.deg,
                                                  0 * u.arcsec)], None),
                    ([UnitSphericalRepresentation(0 * u.deg,
                                                  0 * u.arcsec)], None),
                    ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], {
                        'obstime': '2011/01/01T00:00:00'
                    })]
"""
These are common 3D params, kwargs are frame specific
"""
three_D_parameters = [
    ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], None),
    ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], {
        'obstime': '2011/01/01T00:00:00'
    }), ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], {
        'representation': 'spherical'
    }), ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)], None),
Beispiel #14
0
    def spherical_to_cartesian(self,
                               spot_lons,
                               spot_lats,
                               inc_stellar,
                               times=None,
                               planet=None,
                               time_ref=None):
        """
        Convert spot parameter matrices in the original stellar coordinates to
        rotated and tilted cartesian coordinates.

        Parameters
        ----------
        spot_lons : `~astropy.units.Quantity`
            Spot longitudes
        spot_lats : `~astropy.units.Quantity`
            Spot latitudes
        inc_stellar : `~astropy.units.Quantity`
            Stellar inclination
        times : `~numpy.ndarray`
            Times at which evaluate the stellar rotation
        planet : `~batman.TransitParams`
            Planet parameters
        time_ref : float
            Reference time used as the initial rotational phase of the star,
            such that the sub-observer point is at zero longitude at
            ``time_ref``.

        Returns
        -------
        tilted_spots : `~numpy.ndarray`
            Rotated and tilted spot positions in cartesian coordinates
        """
        # Spots by default are given in unit spherical representation (lat, lon)
        usr = UnitSphericalRepresentation(spot_lons, spot_lats)

        # Represent those spots with cartesian coordinates (x, y, z)
        # In this coordinate system, the observer is at positive x->inf,
        # the star is at the origin, and (y, z) is the sky plane.
        cartesian = usr.represent_as(CartesianRepresentation)

        # Generate array of rotation matrices to rotate the spots about the
        # stellar rotation axis
        if times is None or (hasattr(times, '__len__') and times[0] is None):
            rotate = rotation_matrix(self.phases[:, np.newaxis, np.newaxis],
                                     axis='z')
        else:
            if time_ref is None:
                time_ref = 0
            rotational_phase = 2 * np.pi * (
                (times - time_ref) / self.rotation_period) * u.rad
            rotate = rotation_matrix(rotational_phase[:, np.newaxis,
                                                      np.newaxis],
                                     axis='z')

        rotated_spots = cartesian.transform(rotate)

        if planet is not None and hasattr(planet, 'lam'):
            lam = planet.lam * u.deg
        else:
            lam = 0 * u.deg

        # Generate array of rotation matrices to rotate the spots so that the
        # star is observed from the correct stellar inclination
        stellar_inclination = rotation_matrix(inc_stellar - 90 * u.deg,
                                              axis='y')
        inclined_spots = rotated_spots.transform(stellar_inclination)

        # Generate array of rotation matrices to rotate the spots so that the
        # planet's orbit normal is tilted with respect to stellar spin
        tilt = rotation_matrix(-lam, axis='x')
        tilted_spots = inclined_spots.transform(tilt)

        return tilted_spots
Beispiel #15
0
 def surface_normal(self, lat, lon):
     usr = UnitSphericalRepresentation(lon=lon+self.rotation_angle, lat=lat)
     rotm = matrix_utilities.rotation_matrix(self.obliquity, axis='x')
     return usr.to_cartesian().transform(rotm)
Beispiel #16
0
def test_skycoord(frame):

    c = SkyCoord([[1, 2], [3, 4]], [[5, 6], [7, 8]],
                 unit='deg', frame=frame,
                 obstime=Time('2016-01-02'),
                 location=EarthLocation(1000, 2000, 3000, unit=u.km))
    cy = load(dump(c))
    compare_coord(c, cy)


@pytest.mark.parametrize('rep', [
    CartesianRepresentation(1*u.m, 2.*u.m, 3.*u.m),
    SphericalRepresentation([[1, 2], [3, 4]]*u.deg,
                            [[5, 6], [7, 8]]*u.deg,
                            10*u.pc),
    UnitSphericalRepresentation(0*u.deg, 10*u.deg),
    SphericalCosLatDifferential([[1.], [2.]]*u.mas/u.yr,
                                [4., 5.]*u.mas/u.yr,
                                [[[10]], [[20]]]*u.km/u.s),
    CartesianDifferential([10, 20, 30]*u.km/u.s),
    CartesianRepresentation(
        [1, 2, 3]*u.m,
        differentials=CartesianDifferential([10, 20, 30]*u.km/u.s)),
    SphericalRepresentation(
        [[1, 2], [3, 4]]*u.deg, [[5, 6], [7, 8]]*u.deg, 10*u.pc,
        differentials={
            's': SphericalDifferential([[0., 1.], [2., 3.]]*u.mas/u.yr,
                                       [[4., 5.], [6., 7.]]*u.mas/u.yr,
                                       10*u.km/u.s)})])
def test_representations(rep):
    rrep = load(dump(rep))
Beispiel #17
0
    def __init__(self, center, length=None, angle=None, sample=2, width=None):

        # Check input types

        if not isinstance(center, (SkyCoord, BaseCoordinateFrame)):
            raise TypeError(
                "The central position should be given as a SkyCoord object")

        if not isinstance(length, u.Quantity) or not length.unit.is_equivalent(
                u.deg):
            raise TypeError(
                "The length should be given as an angular Quantity")

        if not isinstance(angle, u.Quantity) or not angle.unit.is_equivalent(
                u.deg):
            raise TypeError("The angle should be given as an angular Quantity")

        # We set up the path by adding and removing half the length along the
        # declination axis, then rotate the resulting two points around the
        # center.

        # Convert the central position to cartesian coordinates
        c1, c2, c3 = center.cartesian.xyz.value

        # Find the end points of the path
        clon, clat = center.spherical.lon, center.spherical.lat
        try:
            plat = clat + np.linspace(-length * 0.5, length * 0.5, sample)
        except ValueError:  # Numpy 1.10+
            plat = clat + np.linspace(-length.value * 0.5, length.value * 0.5,
                                      sample) * length.unit

        x, y, z = UnitSphericalRepresentation(clon,
                                              plat).to_cartesian().xyz.value

        # Rotate around central point

        # Because longitude increases to the left, we have to take -angle
        angle = -angle

        # We rotate (x,y,z) around (c1,c2,c3) by making use of the following
        # equations:
        #
        # x' = x cos a + (1 - cos a)(c1c1x + c1c2y + c1c3z) + (c2z - c3y)sin a
        # y' = y cos a + (1 - cos a)(c2c1x + c2c2y + c2c3z) + (c3x - c1z)sin a
        # z' = z cos a + (1 - cos a)(c3c1x + c3c2y + c3c3z) + (c1y - c2x)sin a
        #
        # Source: https://www.uwgb.edu/dutchs/MATHALGO/sphere0.htm

        cosa = np.cos(angle)
        sina = np.sin(angle)

        xd = x * cosa + (1 - cosa) * (c1 * c1 * x + c1 * c2 * y +
                                      c1 * c3 * z) + (c2 * z - c3 * y) * sina
        yd = y * cosa + (1 - cosa) * (c2 * c1 * x + c2 * c2 * y +
                                      c2 * c3 * z) + (c3 * x - c1 * z) * sina
        zd = z * cosa + (1 - cosa) * (c3 * c1 * x + c3 * c2 * y +
                                      c3 * c3 * z) + (c1 * y - c2 * x) * sina

        # Construct representations
        points = center.realize_frame(CartesianRepresentation(x=xd, y=yd,
                                                              z=zd))

        super(PathFromCenter, self).__init__(points, width=width)
Beispiel #18
0
def pixel_to_skycoord(xp, yp, wcs, origin=0, mode='all', cls=None):
    """
    Convert a set of pixel coordinates into a `~astropy.coordinates.SkyCoord`
    coordinate.

    Parameters
    ----------
    xp, yp : float or `numpy.ndarray`
        The coordinates to convert.
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use.
    origin : int
        Whether to return 0 or 1-based pixel coordinates.
    mode : 'all' or 'wcs'
        Whether to do the transformation including distortions (``'all'``) or
        only including only the core WCS transformation (``'wcs'``).
    cls : class or None
        The class of object to create.  Should be a
        `~astropy.coordinates.SkyCoord` subclass.  If None, defaults to
        `~astropy.coordinates.SkyCoord`.

    Returns
    -------
    coords : Whatever ``cls`` is (a subclass of `~astropy.coordinates.SkyCoord`)
        The celestial coordinates

    See Also
    --------
    astropy.coordinates.SkyCoord.from_pixel
    """

    # Import astropy.coordinates here to avoid circular imports
    from astropy.coordinates import SkyCoord, UnitSphericalRepresentation

    # we have to do this instead of actually setting the default to SkyCoord
    # because importing SkyCoord at the module-level leads to circular
    # dependencies.
    if cls is None:
        cls = SkyCoord

    if _has_distortion(wcs) and wcs.naxis != 2:
        raise ValueError(
            "Can only handle WCS with distortions for 2-dimensional WCS")

    # Keep only the celestial part of the axes, also re-orders lon/lat
    wcs = wcs.sub([WCSSUB_LONGITUDE, WCSSUB_LATITUDE])

    if wcs.naxis != 2:
        raise ValueError("WCS should contain celestial component")

    # Check which frame the WCS uses
    frame = wcs_to_celestial_frame(wcs)

    # Check what unit the WCS gives
    lon_unit = u.Unit(wcs.wcs.cunit[0])
    lat_unit = u.Unit(wcs.wcs.cunit[1])

    # Convert pixel coordinates to celestial coordinates
    if mode == 'all':
        lon, lat = wcs.all_pix2world(xp, yp, origin)
    elif mode == 'wcs':
        lon, lat = wcs.wcs_pix2world(xp, yp, origin)
    else:
        raise ValueError("mode should be either 'all' or 'wcs'")

    # Add units to longitude/latitude
    lon = lon * lon_unit
    lat = lat * lat_unit

    # Create a SkyCoord-like object
    data = UnitSphericalRepresentation(lon=lon, lat=lat)
    coords = cls(frame.realize_frame(data))

    return coords
Beispiel #19
0
def plot_reachable_zone(
        ax: matplotlib.axes.Axes,
        mount_model: MountModel,
        axis_0_west_limit: float = 110,
        axis_0_east_limit: float = 110,
    ) -> None:
    """Plot area(s) of sky reachable by the mount.

    This only accounts for what area of the sky is reachable. It does not take into account whether
    the mount can keep up with a specific target's trajectory. Some trajectories, especially
    those that pass near the mount pole, may require slew rates that exceed what the mount is
    capable of.

    This function assumes an equatorial mount with limits on the right ascension axis.

    Args:
        ax: Axes object this function will plot on. This should be generated by `make_sky_plot()`.
        mount_model: Mount model from which this plot will be generated.
        axis_0_west_limit: Western limit on axis 0 in degrees from the meridian.
        axis_0_east_limit: Eastern limit on axis 0 in degrees from the meridian.
    """
    if axis_0_west_limit < 90 or axis_0_east_limit < 90:
        # current logic would not shade the correct regions of the polar plot
        raise ValueError('Axis limits less than 90 degrees from meridian are not supported')

    # convert from arg values to encoder position angles
    axis_0_west_limit = 180 - axis_0_west_limit
    axis_0_east_limit = 180 + axis_0_east_limit

    # place a dot at the position of the mount pole
    mount_pole_topo = mount_model.spherical_to_topocentric(
        UnitSphericalRepresentation(
            lon=0*u.deg,
            lat=90*u.deg,
        )
    )
    ax.plot(np.radians(mount_pole_topo.az.deg), 90.0 - mount_pole_topo.alt.deg, 'k.')

    for meridian_side in MeridianSide:
        if meridian_side == MeridianSide.EAST:
            color = 'blue'
            legend_label = 'east of mount meridian'
            axis_1_range = np.linspace(0, 180, 100) + mount_model.model_params.axis_1_offset.deg
            az = np.linspace(mount_pole_topo.az.deg, mount_pole_topo.az.deg + 180, 100)
        else:
            axis_1_range = np.linspace(180, 360, 100) + mount_model.model_params.axis_1_offset.deg
            color = 'red'
            legend_label = 'west of mount meridian'
            az = np.linspace(mount_pole_topo.az.deg - 180, mount_pole_topo.az.deg, 100)

        # add a circle patch outside the visible area of the plot purely for the purpose of
        # generating an entry in the legend for this region
        ax.add_patch(Circle((0, 100), radius=0, color=color, alpha=0.2, label=legend_label))

        alt = 90*np.ones_like(az)
        fill_to_horizon(ax, az, alt, color=color)

        for axis_0 in (axis_0_west_limit, axis_0_east_limit):
            az = []
            alt = []
            for axis_1 in axis_1_range:
                topo = mount_model.encoders_to_topocentric(
                    MountEncoderPositions(
                        Longitude(axis_0*u.deg),
                        Longitude(axis_1*u.deg),
                    )
                )
                az.append(topo.az.deg)
                alt.append(topo.alt.deg)
            az = np.array(az)
            alt = np.array(alt)
            ax.plot(np.radians(az), 90.0 - alt, ':', color=color)

            if axis_0 == axis_0_east_limit and meridian_side == MeridianSide.EAST:
                fill_to_horizon(ax, az, alt, color=color)
            elif axis_0 == axis_0_west_limit and meridian_side == MeridianSide.EAST:
                fill_to_zenith(ax, az, alt, color=color)
            elif axis_0 == axis_0_east_limit and meridian_side == MeridianSide.WEST:
                fill_to_zenith(ax, az, alt, color=color)
            elif axis_0 == axis_0_west_limit and meridian_side == MeridianSide.WEST:
                fill_to_horizon(ax, az, alt, color=color)