Beispiel #1
0
def test_wrap_at_without_new():
    """
    Regression test for subtle bugs from situations where an Angle is
    created via numpy channels that don't do the standard __new__ but instead
    depend on array_finalize to set state.  Longitude is used because the
    bug was in its _wrap_angle not getting initialized correctly
    """
    l1 = Longitude([1] * u.deg)
    l2 = Longitude([2] * u.deg)

    l = np.concatenate([l1, l2])
    assert l._wrap_angle is not None
Beispiel #2
0
def test_angle_repr():
    assert 'Angle' in repr(Angle(0, u.deg))
    assert 'Longitude' in repr(Longitude(0, u.deg))
    assert 'Latitude' in repr(Latitude(0, u.deg))

    a = Angle(0, u.deg)
    repr(a)
Beispiel #3
0
    def to_selenodetic(self):
        """Convert to selenodetic coordinates (lat, lon, height).

        Height is in reference to a sphere with radius `_lunar_radius`,
        centered at the center of mass.

        Returns
        -------
        (lon, lat, height) : tuple
            The tuple contains instances of `~astropy.coordinates.Longitude`,
            `~astropy.coordinates.Latitude`, and `~astropy.units.Quantity`

        """
        self_xyz = self.to(u.meter).view(self._array_dtype, np.ndarray)
        self_xyz = np.atleast_2d(self_xyz)
        gps_p = np.sqrt(self_xyz[:, 0]**2 + self_xyz[:, 1]**2)
        lat = np.arctan2(self_xyz[:, 2], gps_p)
        lon = np.arctan2(self_xyz[:, 1], self_xyz[:, 0])
        height = np.linalg.norm(self_xyz, axis=1) - self._lunar_radius

        return GeodeticLocation(
            Longitude(lon * u.radian,
                      u.degree,
                      wrap_angle=180. * u.degree,
                      copy=False),
            Latitude(lat * u.radian, u.degree, copy=False),
            u.Quantity(height * u.meter, self.unit, copy=False))
Beispiel #4
0
 def setup(self):
     self.lon = Longitude([0., 45., 90., 135., 180., -180, -90, -45], u.deg,
                          wrap_angle=180*u.deg)
     self.lat = Latitude([+0., 30., 60., +90., -90., -60., -30., 0.], u.deg)
     self.h = u.Quantity([0.1, 0.5, 1.0, -0.5, -1.0, +4.2, -11., -.1], u.m)
     self.location = EarthLocation.from_geodetic(self.lon, self.lat, self.h)
     self.x, self.y, self.z = self.location.to_geocentric()
Beispiel #5
0
    def from_selenodetic(cls, lon, lat, height=0.):
        """
        Location on the Moon, from latitude and longitude.

        Parameters
        ----------
        lon : `~astropy.coordinates.Longitude` or float
            Lunar East longitude.  Can be anything that initialises an
            `~astropy.coordinates.Angle` object (if float, in degrees).
        lat : `~astropy.coordinates.Latitude` or float
            Lunar latitude.  Can be anything that initialises an
            `~astropy.coordinates.Latitude` object (if float, in degrees).
        height : `~astropy.units.Quantity` or float, optional
            Height above reference sphere (if float, in meters; default: 0).
            The reference sphere is a sphere of radius 1737.1 kilometers,
            from the center of mass of the Moon.

        Raises
        ------
        astropy.units.UnitsError
            If the units on ``lon`` and ``lat`` are inconsistent with angular
            ones, or that on ``height`` with a length.
        ValueError
            If ``lon``, ``lat``, and ``height`` do not have the same shape, or

        Notes
        -----

        latitude is defined relative to an equator 90 degrees
        off from the mean rotation axis. Longitude is defined
        relative to a prime meridian, which is itself given by
        the mean position of the "sub-Earth" point on the lunar surface.

        """
        lon = Longitude(lon, u.degree, wrap_angle=180 * u.degree, copy=False)
        lat = Latitude(lat, u.degree, copy=False)
        # don't convert to m by default, so we can use the height unit below.
        if not isinstance(height, u.Quantity):
            height = u.Quantity(height, u.m, copy=False)

        if not lon.shape == lat.shape:
            raise ValueError("Inconsistent quantity shapes: {}, {}".format(
                str(lon.shape), str(lat.shape)))
        # get selenocentric coordinates. Have to give one-dimensional array.

        lunar_radius = u.Quantity(cls._lunar_radius, u.m, copy=False)

        Npts = lon.size
        xyz = np.zeros((Npts, 3))
        xyz[:, 0] = ((lunar_radius + height) * np.cos(lat) * np.cos(lon))
        xyz[:, 1] = ((lunar_radius + height) * np.cos(lat) * np.sin(lon))
        xyz[:, 2] = ((lunar_radius + height) * np.sin(lat))

        xyz = np.squeeze(xyz)

        self = xyz.ravel().view(cls._location_dtype,
                                cls).reshape(xyz.shape[:-1])
        self._unit = u.meter
        return self.to(height.unit)
Beispiel #6
0
def position():

    lon = Longitude([0., 45., 90., 135., 180., -180, -90, -45], u.deg,
                    wrap_angle=180*u.deg)
    lat = Latitude([+0., 30., 60., +90., -90., -60., -30., 0.], u.deg)
    h = u.Quantity([0.1, 0.5, 1.0, -0.5, -1.0, +4.2, -11., -.1], u.m)

    return lon, lat, h
Beispiel #7
0
def test_angle_format_roundtripping():
    """
    Ensures that the string representation of an angle can be used to create a
    new valid Angle.
    """

    a1 = Angle(0, unit=u.radian)
    a2 = Angle(10, unit=u.degree)
    a3 = Angle(0.543, unit=u.degree)
    a4 = Angle('1d2m3.4s')

    assert Angle(str(a1)).degree == a1.degree
    assert Angle(str(a2)).degree == a2.degree
    assert Angle(str(a3)).degree == a3.degree
    assert Angle(str(a4)).degree == a4.degree

    # also check Longitude/Latitude
    ra = Longitude('1h2m3.4s')
    dec = Latitude('1d2m3.4s')

    assert_allclose(Angle(str(ra)).degree, ra.degree)
    assert_allclose(Angle(str(dec)).degree, dec.degree)
Beispiel #8
0
def test_longitude():
    # Default wrapping at 360d with an array input
    lon = Longitude(['370d', '88d'])
    assert np.all(lon == Longitude(['10d', '88d']))
    assert np.all(lon == Angle(['10d', '88d']))

    # conserve type on unit change and keep wrap_angle (closes #1423)
    angle = lon.to('hourangle')
    assert type(angle) is Longitude
    assert angle.wrap_angle == lon.wrap_angle
    angle = lon[0]
    assert type(angle) is Longitude
    assert angle.wrap_angle == lon.wrap_angle
    angle = lon[1:]
    assert type(angle) is Longitude
    assert angle.wrap_angle == lon.wrap_angle

    # but not on calculations
    angle = lon / 2.
    assert np.all(angle == Angle(['5d', '44d']))
    assert type(angle) is Angle
    assert not hasattr(angle, 'wrap_angle')

    angle = lon * 2. + 400 * u.deg
    assert np.all(angle == Angle(['420d', '576d']))
    assert type(angle) is Angle

    # Test setting a mutable value and having it wrap
    lon[1] = -10 * u.deg
    assert np.all(lon == Angle(['10d', '350d']))

    # Test wrapping and try hitting some edge cases
    lon = Longitude(np.array([0, 0.5, 1.0, 1.5, 2.0]) * np.pi, unit=u.radian)
    assert np.all(lon.degree == np.array([0., 90, 180, 270, 0]))

    lon = Longitude(np.array([0, 0.5, 1.0, 1.5, 2.0]) * np.pi,
                    unit=u.radian,
                    wrap_angle='180d')
    assert np.all(lon.degree == np.array([0., 90, -180, -90, 0]))

    # Wrap on setting wrap_angle property (also test auto-conversion of wrap_angle to an Angle)
    lon = Longitude(np.array([0, 0.5, 1.0, 1.5, 2.0]) * np.pi, unit=u.radian)
    lon.wrap_angle = '180d'
    assert np.all(lon.degree == np.array([0., 90, -180, -90, 0]))

    lon = Longitude('460d')
    assert lon == Angle('100d')
    lon.wrap_angle = '90d'
    assert lon == Angle('-260d')

    # check that if we initialize a longitude with another longitude,
    # wrap_angle is kept by default
    lon2 = Longitude(lon)
    assert lon2.wrap_angle == lon.wrap_angle
    # but not if we explicitly set it
    lon3 = Longitude(lon, wrap_angle='180d')
    assert lon3.wrap_angle == 180 * u.deg

    # check for problem reported in #2037 about Longitude initializing to -0
    lon = Longitude(0, u.deg)
    lonstr = lon.to_string()
    assert not lonstr.startswith('-')

    # also make sure dtype is correctly conserved
    assert Longitude(0, u.deg, dtype=float).dtype == np.dtype(float)
    assert Longitude(0, u.deg, dtype=int).dtype == np.dtype(int)

    # Test errors when trying to interoperate with latitudes.
    with pytest.raises(TypeError) as excinfo:
        lat = Latitude(10, 'deg')
        lon = Longitude(lat)
    assert "A Longitude angle cannot be created from a Latitude angle" in str(
        excinfo.value)

    with pytest.raises(TypeError) as excinfo:
        lat = Latitude(10, 'deg')
        lon = Longitude([20], 'deg')
        lon[0] = lat
    assert "A Latitude angle cannot be assigned to a Longitude angle" in str(
        excinfo.value)

    # Check we can work around the Lat vs Long checks by casting explicitly to Angle.
    lat = Latitude(10, 'deg')
    lon = Longitude(Angle(lat))
    assert lon.value == 10.0
    # Check setitem.
    lat = Latitude(10, 'deg')
    lon = Longitude([20], 'deg')
    lon[0] = Angle(lat)
    assert lon.value[0] == 10.0
Beispiel #9
0
def test_latitude():
    with pytest.raises(ValueError):
        lat = Latitude(['91d', '89d'])
    with pytest.raises(ValueError):
        lat = Latitude('-91d')

    lat = Latitude(['90d', '89d'])
    # check that one can get items
    assert lat[0] == 90 * u.deg
    assert lat[1] == 89 * u.deg
    # and that comparison with angles works
    assert np.all(lat == Angle(['90d', '89d']))
    # check setitem works
    lat[1] = 45. * u.deg
    assert np.all(lat == Angle(['90d', '45d']))
    # but not with values out of range
    with pytest.raises(ValueError):
        lat[0] = 90.001 * u.deg
    with pytest.raises(ValueError):
        lat[0] = -90.001 * u.deg
    # these should also not destroy input (#1851)
    assert np.all(lat == Angle(['90d', '45d']))

    # conserve type on unit change (closes #1423)
    angle = lat.to('radian')
    assert type(angle) is Latitude
    # but not on calculations
    angle = lat - 190 * u.deg
    assert type(angle) is Angle
    assert angle[0] == -100 * u.deg

    lat = Latitude('80d')
    angle = lat / 2.
    assert type(angle) is Angle
    assert angle == 40 * u.deg

    angle = lat * 2.
    assert type(angle) is Angle
    assert angle == 160 * u.deg

    angle = -lat
    assert type(angle) is Angle
    assert angle == -80 * u.deg

    # Test errors when trying to interoperate with longitudes.
    with pytest.raises(TypeError) as excinfo:
        lon = Longitude(10, 'deg')
        lat = Latitude(lon)
    assert "A Latitude angle cannot be created from a Longitude angle" in str(
        excinfo.value)

    with pytest.raises(TypeError) as excinfo:
        lon = Longitude(10, 'deg')
        lat = Latitude([20], 'deg')
        lat[0] = lon
    assert "A Longitude angle cannot be assigned to a Latitude angle" in str(
        excinfo.value)

    # Check we can work around the Lat vs Long checks by casting explicitly to Angle.
    lon = Longitude(10, 'deg')
    lat = Latitude(Angle(lon))
    assert lat.value == 10.0
    # Check setitem.
    lon = Longitude(10, 'deg')
    lat = Latitude([20], 'deg')
    lat[0] = Angle(lon)
    assert lat.value[0] == 10.0
Beispiel #10
0
def test_radec():
    """
    Tests creation/operations of Longitude and Latitude objects
    """
    '''
    Longitude and Latitude are objects that are subclassed from Angle. As with Angle, Longitude
    and Latitude can parse any unambiguous format (tuples, formatted strings, etc.).

    The intention is not to create an Angle subclass for every possible
    coordinate object (e.g. galactic l, galactic b). However, equatorial Longitude/Latitude
    are so prevalent in astronomy that it's worth creating ones for these
    units. They will be noted as "special" in the docs and use of the just the
    Angle class is to be used for other coordinate systems.
    '''

    with pytest.raises(u.UnitsError):
        ra = Longitude("4:08:15.162342")  # error - hours or degrees?
    with pytest.raises(u.UnitsError):
        ra = Longitude("-4:08:15.162342")

    # the "smart" initializer allows >24 to automatically do degrees, but the
    # Angle-based one does not
    # TODO: adjust in 0.3 for whatever behavior is decided on

    # ra = Longitude("26:34:15.345634")  # unambiguous b/c hours don't go past 24
    # assert_allclose(ra.degree, 26.570929342)
    with pytest.raises(u.UnitsError):
        ra = Longitude("26:34:15.345634")

    # ra = Longitude(68)
    with pytest.raises(u.UnitsError):
        ra = Longitude(68)

    with pytest.raises(u.UnitsError):
        ra = Longitude(12)

    with pytest.raises(ValueError):
        ra = Longitude("garbage containing a d and no units")

    ra = Longitude("12h43m23s")
    assert_allclose(ra.hour, 12.7230555556)

    ra = Longitude((56, 14, 52.52), unit=u.degree)  # can accept tuples
    # TODO: again, fix based on >24 behavior
    # ra = Longitude((56,14,52.52))
    with pytest.raises(u.UnitsError):
        ra = Longitude((56, 14, 52.52))
    with pytest.raises(u.UnitsError):
        ra = Longitude((12, 14, 52))  # ambiguous w/o units
    ra = Longitude((12, 14, 52), unit=u.hour)

    ra = Longitude([56, 64, 52.2], unit=u.degree)  # ...but not arrays (yet)

    # Units can be specified
    ra = Longitude("4:08:15.162342", unit=u.hour)

    # TODO: this was the "smart" initializer behavior - adjust in 0.3 appropriately
    # Where Longitude values are commonly found in hours or degrees, declination is
    # nearly always specified in degrees, so this is the default.
    # dec = Latitude("-41:08:15.162342")
    with pytest.raises(u.UnitsError):
        dec = Latitude("-41:08:15.162342")
    dec = Latitude("-41:08:15.162342", unit=u.degree)  # same as above
Beispiel #11
0
def test_longitude_nan():
    # Check that passing a NaN to Longitude doesn't raise a warning
    Longitude([0, np.nan, 1] * u.deg)