Ejemplo n.º 1
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()
Ejemplo n.º 2
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
Ejemplo n.º 3
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)
Ejemplo n.º 4
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))
Ejemplo n.º 5
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()
Ejemplo n.º 6
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)
Ejemplo n.º 7
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
Ejemplo n.º 8
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)
Ejemplo n.º 9
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
Ejemplo n.º 10
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
Ejemplo n.º 11
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
Ejemplo n.º 12
0
def test_longitude_nan():
    # Check that passing a NaN to Longitude doesn't raise a warning
    Longitude([0, np.nan, 1] * u.deg)
Ejemplo n.º 13
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)

    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)

    # 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
Ejemplo n.º 14
0
class TestInput():
    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()

    def test_default_ellipsoid(self):
        assert self.location.ellipsoid == EarthLocation._ellipsoid

    def test_geo_attributes(self):
        assert all(np.all(_1 == _2)
                   for _1, _2 in zip(self.location.geodetic,
                                     self.location.to_geodetic()))
        assert all(np.all(_1 == _2)
                   for _1, _2 in zip(self.location.geocentric,
                                     self.location.to_geocentric()))

    def test_attribute_classes(self):
        """Test that attribute classes are correct (and not EarthLocation)"""
        assert type(self.location.x) is u.Quantity
        assert type(self.location.y) is u.Quantity
        assert type(self.location.z) is u.Quantity
        assert type(self.location.lon) is Longitude
        assert type(self.location.lat) is Latitude
        assert type(self.location.height) is u.Quantity

    def test_input(self):
        """Check input is parsed correctly"""

        # units of length should be assumed geocentric
        geocentric = EarthLocation(self.x, self.y, self.z)
        assert np.all(geocentric == self.location)
        geocentric2 = EarthLocation(self.x.value, self.y.value, self.z.value,
                                    self.x.unit)
        assert np.all(geocentric2 == self.location)
        geodetic = EarthLocation(self.lon, self.lat, self.h)
        assert np.all(geodetic == self.location)
        geodetic2 = EarthLocation(self.lon.to_value(u.degree),
                                  self.lat.to_value(u.degree),
                                  self.h.to_value(u.m))
        assert np.all(geodetic2 == self.location)
        geodetic3 = EarthLocation(self.lon, self.lat)
        assert allclose_m14(geodetic3.lon.value,
                            self.location.lon.value)
        assert allclose_m14(geodetic3.lat.value,
                            self.location.lat.value)
        assert not np.any(isclose_m14(geodetic3.height.value,
                                      self.location.height.value))
        geodetic4 = EarthLocation(self.lon, self.lat, self.h[-1])
        assert allclose_m14(geodetic4.lon.value,
                            self.location.lon.value)
        assert allclose_m14(geodetic4.lat.value,
                            self.location.lat.value)
        assert allclose_m14(geodetic4.height[-1].value,
                            self.location.height[-1].value)
        assert not np.any(isclose_m14(geodetic4.height[:-1].value,
                                      self.location.height[:-1].value))
        # check length unit preservation
        geocentric5 = EarthLocation(self.x, self.y, self.z, u.pc)
        assert geocentric5.unit is u.pc
        assert geocentric5.x.unit is u.pc
        assert geocentric5.height.unit is u.pc
        assert allclose_m14(geocentric5.x.to_value(self.x.unit), self.x.value)
        geodetic5 = EarthLocation(self.lon, self.lat, self.h.to(u.pc))
        assert geodetic5.unit is u.pc
        assert geodetic5.x.unit is u.pc
        assert geodetic5.height.unit is u.pc
        assert allclose_m14(geodetic5.x.to_value(self.x.unit), self.x.value)

    def test_invalid_input(self):
        """Check invalid input raises exception"""
        # incomprehensible by either raises TypeError
        with pytest.raises(TypeError):
            EarthLocation(self.lon, self.y, self.z)

        # wrong units
        with pytest.raises(u.UnitsError):
            EarthLocation.from_geocentric(self.lon, self.lat, self.lat)
        # inconsistent units
        with pytest.raises(u.UnitsError):
            EarthLocation.from_geocentric(self.h, self.lon, self.lat)
        # floats without a unit
        with pytest.raises(TypeError):
            EarthLocation.from_geocentric(self.x.value, self.y.value,
                                          self.z.value)
        # inconsistent shape
        with pytest.raises(ValueError):
            EarthLocation.from_geocentric(self.x, self.y, self.z[:5])

        # inconsistent units
        with pytest.raises(u.UnitsError):
            EarthLocation.from_geodetic(self.x, self.y, self.z)
        # inconsistent shape
        with pytest.raises(ValueError):
            EarthLocation.from_geodetic(self.lon, self.lat, self.h[:5])

    def test_slicing(self):
        # test on WGS72 location, so we can check the ellipsoid is passed on
        locwgs72 = EarthLocation.from_geodetic(self.lon, self.lat, self.h,
                                               ellipsoid='WGS72')
        loc_slice1 = locwgs72[4]
        assert isinstance(loc_slice1, EarthLocation)
        assert loc_slice1.unit is locwgs72.unit
        assert loc_slice1.ellipsoid == locwgs72.ellipsoid == 'WGS72'
        assert not loc_slice1.shape
        with pytest.raises(TypeError):
            loc_slice1[0]
        with pytest.raises(IndexError):
            len(loc_slice1)

        loc_slice2 = locwgs72[4:6]
        assert isinstance(loc_slice2, EarthLocation)
        assert len(loc_slice2) == 2
        assert loc_slice2.unit is locwgs72.unit
        assert loc_slice2.ellipsoid == locwgs72.ellipsoid
        assert loc_slice2.shape == (2,)
        loc_x = locwgs72['x']
        assert type(loc_x) is u.Quantity
        assert loc_x.shape == locwgs72.shape
        assert loc_x.unit is locwgs72.unit

    def test_invalid_ellipsoid(self):
        # unknown ellipsoid
        with pytest.raises(ValueError):
            EarthLocation.from_geodetic(self.lon, self.lat, self.h,
                                        ellipsoid='foo')
        with pytest.raises(TypeError):
            EarthLocation(self.lon, self.lat, self.h, ellipsoid='foo')

        with pytest.raises(ValueError):
            self.location.ellipsoid = 'foo'

        with pytest.raises(ValueError):
            self.location.to_geodetic('foo')

    @pytest.mark.parametrize('ellipsoid', ELLIPSOIDS)
    def test_ellipsoid(self, ellipsoid):
        """Test that different ellipsoids are understood, and differ"""
        # check that heights differ for different ellipsoids
        # need different tolerance, since heights are relative to ~6000 km
        lon, lat, h = self.location.to_geodetic(ellipsoid)
        if ellipsoid == self.location.ellipsoid:
            assert allclose_m8(h.value, self.h.value)
        else:
            # Some heights are very similar for some; some lon, lat identical.
            assert not np.all(isclose_m8(h.value, self.h.value))

        # given lon, lat, height, check that x,y,z differ
        location = EarthLocation.from_geodetic(self.lon, self.lat, self.h,
                                               ellipsoid=ellipsoid)
        if ellipsoid == self.location.ellipsoid:
            assert allclose_m14(location.z.value, self.z.value)
        else:
            assert not np.all(isclose_m14(location.z.value, self.z.value))

        def test_to_value(self):
            loc = self.location
            loc_ndarray = loc.view(np.ndarray)
            assert np.all(loc.value == loc_ndarray)
            loc2 = self.location.to(u.km)
            loc2_ndarray = np.empty_like(loc_ndarray)
            for coo in 'x', 'y', 'z':
                loc2_ndarray[coo] = loc_ndarray[coo] / 1000.
            assert np.all(loc2.value == loc2_ndarray)
            loc2_value = self.location.to_value(u.km)
            assert np.all(loc2_value == loc2_ndarray)
Ejemplo n.º 15
0
class TestInput():
    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()

    def test_default_ellipsoid(self):
        assert self.location.ellipsoid == EarthLocation._ellipsoid

    def test_geo_attributes(self):
        assert all(np.all(_1 == _2)
                   for _1, _2 in zip(self.location.geodetic,
                                     self.location.to_geodetic()))
        assert all(np.all(_1 == _2)
                   for _1, _2 in zip(self.location.geocentric,
                                     self.location.to_geocentric()))

    def test_attribute_classes(self):
        """Test that attribute classes are correct (and not EarthLocation)"""
        assert type(self.location.x) is u.Quantity
        assert type(self.location.y) is u.Quantity
        assert type(self.location.z) is u.Quantity
        assert type(self.location.lon) is Longitude
        assert type(self.location.lat) is Latitude
        assert type(self.location.height) is u.Quantity

    def test_input(self):
        """Check input is parsed correctly"""

        # units of length should be assumed geocentric
        geocentric = EarthLocation(self.x, self.y, self.z)
        assert np.all(geocentric == self.location)
        geocentric2 = EarthLocation(self.x.value, self.y.value, self.z.value,
                                    self.x.unit)
        assert np.all(geocentric2 == self.location)
        geodetic = EarthLocation(self.lon, self.lat, self.h)
        assert np.all(geodetic == self.location)
        geodetic2 = EarthLocation(self.lon.to_value(u.degree),
                                  self.lat.to_value(u.degree),
                                  self.h.to_value(u.m))
        assert np.all(geodetic2 == self.location)
        geodetic3 = EarthLocation(self.lon, self.lat)
        assert allclose_m14(geodetic3.lon.value,
                            self.location.lon.value)
        assert allclose_m14(geodetic3.lat.value,
                            self.location.lat.value)
        assert not np.any(isclose_m14(geodetic3.height.value,
                                      self.location.height.value))
        geodetic4 = EarthLocation(self.lon, self.lat, self.h[-1])
        assert allclose_m14(geodetic4.lon.value,
                            self.location.lon.value)
        assert allclose_m14(geodetic4.lat.value,
                            self.location.lat.value)
        assert allclose_m14(geodetic4.height[-1].value,
                            self.location.height[-1].value)
        assert not np.any(isclose_m14(geodetic4.height[:-1].value,
                                      self.location.height[:-1].value))
        # check length unit preservation
        geocentric5 = EarthLocation(self.x, self.y, self.z, u.pc)
        assert geocentric5.unit is u.pc
        assert geocentric5.x.unit is u.pc
        assert geocentric5.height.unit is u.pc
        assert allclose_m14(geocentric5.x.to_value(self.x.unit), self.x.value)
        geodetic5 = EarthLocation(self.lon, self.lat, self.h.to(u.pc))
        assert geodetic5.unit is u.pc
        assert geodetic5.x.unit is u.pc
        assert geodetic5.height.unit is u.pc
        assert allclose_m14(geodetic5.x.to_value(self.x.unit), self.x.value)

    def test_invalid_input(self):
        """Check invalid input raises exception"""
        # incomprehensible by either raises TypeError
        with pytest.raises(TypeError):
            EarthLocation(self.lon, self.y, self.z)

        # wrong units
        with pytest.raises(u.UnitsError):
            EarthLocation.from_geocentric(self.lon, self.lat, self.lat)
        # inconsistent units
        with pytest.raises(u.UnitsError):
            EarthLocation.from_geocentric(self.h, self.lon, self.lat)
        # floats without a unit
        with pytest.raises(TypeError):
            EarthLocation.from_geocentric(self.x.value, self.y.value,
                                          self.z.value)
        # inconsistent shape
        with pytest.raises(ValueError):
            EarthLocation.from_geocentric(self.x, self.y, self.z[:5])

        # inconsistent units
        with pytest.raises(u.UnitsError):
            EarthLocation.from_geodetic(self.x, self.y, self.z)
        # inconsistent shape
        with pytest.raises(ValueError):
            EarthLocation.from_geodetic(self.lon, self.lat, self.h[:5])

    def test_slicing(self):
        # test on WGS72 location, so we can check the ellipsoid is passed on
        locwgs72 = EarthLocation.from_geodetic(self.lon, self.lat, self.h,
                                               ellipsoid='WGS72')
        loc_slice1 = locwgs72[4]
        assert isinstance(loc_slice1, EarthLocation)
        assert loc_slice1.unit is locwgs72.unit
        assert loc_slice1.ellipsoid == locwgs72.ellipsoid == 'WGS72'
        assert not loc_slice1.shape
        with pytest.raises(TypeError):
            loc_slice1[0]
        with pytest.raises(IndexError):
            len(loc_slice1)

        loc_slice2 = locwgs72[4:6]
        assert isinstance(loc_slice2, EarthLocation)
        assert len(loc_slice2) == 2
        assert loc_slice2.unit is locwgs72.unit
        assert loc_slice2.ellipsoid == locwgs72.ellipsoid
        assert loc_slice2.shape == (2,)
        loc_x = locwgs72['x']
        assert type(loc_x) is u.Quantity
        assert loc_x.shape == locwgs72.shape
        assert loc_x.unit is locwgs72.unit

    def test_invalid_ellipsoid(self):
        # unknown ellipsoid
        with pytest.raises(ValueError):
            EarthLocation.from_geodetic(self.lon, self.lat, self.h,
                                        ellipsoid='foo')
        with pytest.raises(TypeError):
            EarthLocation(self.lon, self.lat, self.h, ellipsoid='foo')

        with pytest.raises(ValueError):
            self.location.ellipsoid = 'foo'

        with pytest.raises(ValueError):
            self.location.to_geodetic('foo')

    @pytest.mark.parametrize('ellipsoid', ELLIPSOIDS)
    def test_ellipsoid(self, ellipsoid):
        """Test that different ellipsoids are understood, and differ"""
        # check that heights differ for different ellipsoids
        # need different tolerance, since heights are relative to ~6000 km
        lon, lat, h = self.location.to_geodetic(ellipsoid)
        if ellipsoid == self.location.ellipsoid:
            assert allclose_m8(h.value, self.h.value)
        else:
            # Some heights are very similar for some; some lon, lat identical.
            assert not np.all(isclose_m8(h.value, self.h.value))

        # given lon, lat, height, check that x,y,z differ
        location = EarthLocation.from_geodetic(self.lon, self.lat, self.h,
                                               ellipsoid=ellipsoid)
        if ellipsoid == self.location.ellipsoid:
            assert allclose_m14(location.z.value, self.z.value)
        else:
            assert not np.all(isclose_m14(location.z.value, self.z.value))

        def test_to_value(self):
            loc = self.location
            loc_ndarray = loc.view(np.ndarray)
            assert np.all(loc.value == loc_ndarray)
            loc2 = self.location.to(u.km)
            loc2_ndarray = np.empty_like(loc_ndarray)
            for coo in 'x', 'y', 'z':
                loc2_ndarray[coo] = loc_ndarray[coo] / 1000.
            assert np.all(loc2.value == loc2_ndarray)
            loc2_value = self.location.to_value(u.km)
            assert np.all(loc2_value == loc2_ndarray)