def test_url_ephemeris_wrong_input(): # Try loading a non-existing URL: time = Time('1960-01-12 00:00') with pytest.raises(HTTPError): get_body( 'earth', time, ephemeris='http://data.astropy.org/path/to/nonexisting/file.bsp')
def test_file_ephemeris_wrong_input(): time = Time('1960-01-12 00:00') # Try loading a non-existing file: with pytest.raises(ValueError): get_body('earth', time, ephemeris='/path/to/nonexisting/file.bsp') # Try loading a file that does exist, but is not an ephemeris file: with pytest.raises(ValueError): get_body('earth', time, ephemeris=__file__)
def test_url_ephemeris_wrong_input(): # Try loading a non-existing URL: time = Time('1960-01-12 00:00') with pytest.raises((HTTPError, URLError)): get_body( 'earth', time, ephemeris=get_pkg_data_filename('path/to/nonexisting/file.bsp'))
def test_custom_kernel_spec_body(self, bodyname): """ Checks that giving a kernel specifier instead of a body name works """ coord_by_name = get_body(bodyname, self.t, ephemeris='de432s') kspec = BODY_NAME_TO_KERNEL_SPEC[bodyname] coord_by_kspec = get_body(kspec, self.t, ephemeris='de432s') assert_quantity_allclose(coord_by_name.ra, coord_by_kspec.ra) assert_quantity_allclose(coord_by_name.dec, coord_by_kspec.dec) assert_quantity_allclose(coord_by_name.distance, coord_by_kspec.distance)
def test_file_ephemeris_wrong_input(): time = Time('1960-01-12 00:00') # Try loading a non-existing file: with pytest.raises(ValueError): get_body('earth', time, ephemeris='/path/to/nonexisting/file.bsp') # NOTE: This test currently leaves the file open (ResourceWarning). # To fix this issue, an upstream fix is required in jplephem # package. # Try loading a file that does exist, but is not an ephemeris file: with pytest.warns(ResourceWarning), pytest.raises(ValueError): get_body('earth', time, ephemeris=__file__)
def print_planet_position(name, observer, time): """ Print information about the planets position Parameters ---------- name : str String name of planet (e.g. 'mercury' or 'jupiter') observer : astropy.coordinates.EarthLocation Observer object time : astropy.time.Time Time of the observation """ # Compute the observed coordinates of the object planet = solar_system.get_body(body=name, time=time) aa = AltAz(location=observer, obstime=time) obs = planet.transform_to(aa) icrs = planet.transform_to('icrs') cirs = planet.transform_to('cirs') # Compute the position/velocity of the object pos, vel = solar_system.get_body_barycentric_posvel(body=name, time=time) print( f"{name:8}: obs=({obs.az:20.16f},{obs.zen:20.16f}) | icrs=({icrs.ra:20.16f},{icrs.dec:20.16f})" ) print(f" cirs=({cirs.ra:20.16f},{cirs.dec:20.16f})") print(f" pos={pos}, vel={vel}")
def test_horizons_consistency_with_precision(): """ A test to compare at high precision against output of JPL horizons. Tests ephemerides, and conversions from ICRS to GCRS to TETE. We are aiming for better than 2 milli-arcsecond precision. We use the Moon since it is nearby, and moves fast in the sky so we are testing for parallax, proper handling of light deflection and aberration. """ # JPL Horizon values for 2020_04_06 00:00 to 23:00 in 1 hour steps # JPL Horizons has a known offset (frame bias) of 51.02 mas in RA. We correct that here ra_apparent_horizons = [ 170.167332531, 170.560688674, 170.923834838, 171.271663481, 171.620188972, 171.985340827, 172.381766539, 172.821772139, 173.314502650, 173.865422398, 174.476108551, 175.144332386, 175.864375310, 176.627519827, 177.422655853, 178.236955730, 179.056584831, 179.867427392, 180.655815385, 181.409252074, 182.117113814, 182.771311578, 183.366872837, 183.902395443 ] * u.deg + 51.02376467 * u.mas dec_apparent_horizons = [ 10.269112037, 10.058820647, 9.837152044, 9.603724551, 9.358956528, 9.104012390, 8.840674927, 8.571162442, 8.297917326, 8.023394488, 7.749873882, 7.479312991, 7.213246666, 6.952732614, 6.698336823, 6.450150213, 6.207828142, 5.970645962, 5.737565957, 5.507313851, 5.278462034, 5.049521497, 4.819038911, 4.585696512 ] * u.deg with solar_system_ephemeris.set('de430'): loc = EarthLocation.from_geodetic(-67.787260*u.deg, -22.959748*u.deg, 5186*u.m) times = Time('2020-04-06 00:00') + np.arange(0, 24, 1)*u.hour astropy = get_body('moon', times, loc) apparent_frame = TETE(obstime=times, location=loc) astropy = astropy.transform_to(apparent_frame) usrepr = UnitSphericalRepresentation(ra_apparent_horizons, dec_apparent_horizons) horizons = apparent_frame.realize_frame(usrepr) assert_quantity_allclose(astropy.separation(horizons), 0*u.mas, atol=1.5*u.mas)
def test_aa_high_precision(): """ These tests are provided by @mkbrewer - see issue #10356. The code that produces them agrees very well (<0.5 mas) with SkyField once Polar motion is turned off, but SkyField does not include polar motion, so a comparison to Skyfield or JPL Horizons will be ~1" off. The absence of polar motion within Skyfield and the disagreement between Skyfield and Horizons make high precision comparisons to those codes difficult. """ lat = -22.959748 * u.deg lon = -67.787260 * u.deg elev = 5186 * u.m loc = EarthLocation.from_geodetic(lon, lat, elev) t = Time('2017-04-06T00:00:00.0') with solar_system_ephemeris.set('de430'): moon = get_body('moon', t, loc) moon_aa = moon.transform_to(AltAz(obstime=t, location=loc)) TARGET_AZ, TARGET_EL = 15.0326735105 * u.deg, 50.3031101339 * u.deg TARGET_DISTANCE = 376252883.2473 * u.m assert_allclose(moon_aa.az, TARGET_AZ, atol=2 * u.uas, rtol=0) assert_allclose(moon_aa.alt, TARGET_EL, atol=2 * u.uas, rtol=0) assert_allclose(moon_aa.distance, TARGET_DISTANCE, atol=2 * u.mm, rtol=0)
def test_get_sun_consistency(time): """ Test that the sun from JPL and the builtin get_sun match """ sun_jpl_gcrs = get_body('sun', time, ephemeris='de432s') builtin_get_sun = get_sun(time) sep = builtin_get_sun.separation(sun_jpl_gcrs) assert sep < 0.1 * u.arcsec
def test_get_sun_consistency(time): """ Test that the sun from JPL and the builtin get_sun match """ sun_jpl_gcrs = get_body('sun', time, ephemeris='de432s') builtin_get_sun = get_sun(time) sep = builtin_get_sun.separation(sun_jpl_gcrs) assert sep < 0.1*u.arcsec
def test_url_or_file_ephemeris(time): # URL for ephemeris de432s used for testing: url = 'http://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/de432s.bsp' # Pass the ephemeris directly as a URL. coord_by_url = get_body('earth', time, ephemeris=url) # Translate the URL to the cached location on the filesystem. # Since we just used the url above, it should already have been downloaded. filepath = download_file(url, cache=True) # Get the coordinates using the file path directly: coord_by_filepath = get_body('earth', time, ephemeris=filepath) # Using the URL or filepath should give exactly the same results: assert_quantity_allclose(coord_by_url.ra, coord_by_filepath.ra) assert_quantity_allclose(coord_by_url.dec, coord_by_filepath.dec) assert_quantity_allclose(coord_by_url.distance, coord_by_filepath.distance)
def test_de432s_planet(self, body): astropy = get_body(body, self.t, ephemeris='de432s') horizons = self.horizons[body] # convert to true equator and equinox astropy = _apparent_position_in_true_coordinates(astropy) # Assert sky coordinates are close. assert (astropy.separation(horizons) < de432s_separation_tolerance_planets) # Assert distances are close. assert_quantity_allclose(astropy.distance, horizons.distance, atol=de432s_distance_tolerance)
def test_de432s_planet(self, body): astropy = get_body(body, self.t, ephemeris='de432s') horizons = self.horizons[body] # convert to true equator and equinox astropy = astropy.transform_to(self.apparent_frame) # Assert sky coordinates are close. assert (astropy.separation(horizons) < de432s_separation_tolerance_planets) # Assert distances are close. assert_quantity_allclose(astropy.distance, horizons.distance, atol=de432s_distance_tolerance)
def test_aa_hd_high_precision(): """These tests are provided by @mkbrewer - see issue #10356. The code that produces them agrees very well (<0.5 mas) with SkyField once Polar motion is turned off, but SkyField does not include polar motion, so a comparison to Skyfield or JPL Horizons will be ~1" off. The absence of polar motion within Skyfield and the disagreement between Skyfield and Horizons make high precision comparisons to those codes difficult. Updated 2020-11-29, after the comparison between codes became even better, down to 100 nas. NOTE: the agreement reflects consistency in approach between two codes, not necessarily absolute precision. If this test starts failing, the tolerance can and should be weakened *if* it is clear that the change is due to an improvement (e.g., a new IAU precession model). """ lat = -22.959748 * u.deg lon = -67.787260 * u.deg elev = 5186 * u.m loc = EarthLocation.from_geodetic(lon, lat, elev) # Note: at this level of precision for the comparison, we have to include # the location in the time, as it influences the transformation to TDB. t = Time('2017-04-06T00:00:00.0', location=loc) with solar_system_ephemeris.set('de430'): moon = get_body('moon', t, loc) moon_aa = moon.transform_to(AltAz(obstime=t, location=loc)) moon_hd = moon.transform_to(HADec(obstime=t, location=loc)) # Numbers from # https://github.com/astropy/astropy/pull/11073#issuecomment-735486271 # updated in https://github.com/astropy/astropy/issues/11683 TARGET_AZ, TARGET_EL = 15.032673509956 * u.deg, 50.303110133923 * u.deg TARGET_DISTANCE = 376252883.247239 * u.m assert_allclose(moon_aa.az, TARGET_AZ, atol=0.1 * u.uas, rtol=0) assert_allclose(moon_aa.alt, TARGET_EL, atol=0.1 * u.uas, rtol=0) assert_allclose(moon_aa.distance, TARGET_DISTANCE, atol=0.1 * u.mm, rtol=0) ha, dec = erfa.ae2hd(moon_aa.az.to_value(u.radian), moon_aa.alt.to_value(u.radian), lat.to_value(u.radian)) ha = u.Quantity(ha, u.radian, copy=False) dec = u.Quantity(dec, u.radian, copy=False) assert_allclose(moon_hd.ha, ha, atol=0.1 * u.uas, rtol=0) assert_allclose(moon_hd.dec, dec, atol=0.1 * u.uas, rtol=0)
def test_erfa_planet(self, body, sep_tol, dist_tol): """Test predictions using erfa/plan94. Accuracies are maximum deviations listed in erfa/plan94.c, for Jupiter and Mercury, and that quoted in Meeus "Astronomical Algorithms" (1998) for the Moon. """ astropy = get_body(body, self.t, ephemeris='builtin') horizons = self.horizons[body] # convert to true equator and equinox astropy = astropy.transform_to(self.apparent_frame) # Assert sky coordinates are close. assert astropy.separation(horizons) < sep_tol # Assert distances are close. assert_quantity_allclose(astropy.distance, horizons.distance, atol=dist_tol)
def test_erfa_planet(self, body, sep_tol, dist_tol): """Test predictions using erfa/plan94. Accuracies are maximum deviations listed in erfa/plan94.c, for Jupiter and Mercury, and that quoted in Meeus "Astronomical Algorithms" (1998) for the Moon. """ astropy = get_body(body, self.t, ephemeris='builtin') horizons = self.horizons[body] # convert to true equator and equinox astropy = _apparent_position_in_true_coordinates(astropy) # Assert sky coordinates are close. assert astropy.separation(horizons) < sep_tol # Assert distances are close. assert_quantity_allclose(astropy.distance, horizons.distance, atol=dist_tol)
def test_aa_high_precision_nodata(): """ These tests are designed to ensure high precision alt-az transforms. They are a slight fudge since the target values come from astropy itself. They are generated with a version of the code that passes the tests above, but for the internal solar system ephemerides to avoid the use of remote data. """ TARGET_AZ, TARGET_EL = 15.0321908 * u.deg, 50.30263625 * u.deg lat = -22.959748 * u.deg lon = -67.787260 * u.deg elev = 5186 * u.m loc = EarthLocation.from_geodetic(lon, lat, elev) t = Time('2017-04-06T00:00:00.0') moon = get_body('moon', t, loc) moon_aa = moon.transform_to(AltAz(obstime=t, location=loc)) assert_allclose(moon_aa.az - TARGET_AZ, 0 * u.mas, atol=0.5 * u.mas) assert_allclose(moon_aa.alt - TARGET_EL, 0 * u.mas, atol=0.5 * u.mas)
def test_erfa_planet(self, body, sep_tol, dist_tol): """Test predictions using erfa/plan94. Accuracies are maximum deviations listed in erfa/plan94.c. """ # Add uncertainty in position of Earth dist_tol = dist_tol + 1300 * u.km astropy = get_body(body, self.t, ephemeris='builtin') horizons = self.horizons[body] # convert to true equator and equinox astropy = _apparent_position_in_true_coordinates(astropy) # Assert sky coordinates are close. assert astropy.separation(horizons) < sep_tol # Assert distances are close. assert_quantity_allclose(astropy.distance, horizons.distance, atol=dist_tol)
def test_erfa_planet(self, body, sep_tol, dist_tol): """Test predictions using erfa/plan94. Accuracies are maximum deviations listed in erfa/plan94.c. """ # Add uncertainty in position of Earth dist_tol = dist_tol + 1300 * u.km astropy = get_body(body, self.t, ephemeris='builtin') horizons = self.horizons[body] # convert to true equator and equinox astropy = astropy.transform_to(self.apparent_frame) # Assert sky coordinates are close. assert astropy.separation(horizons) < sep_tol # Assert distances are close. assert_quantity_allclose(astropy.distance, horizons.distance, atol=dist_tol)
def test_url_ephemeris_wrong_input(): time = Time('1960-01-12 00:00') with pytest.raises((HTTPError, URLError)): # A non-existent URL get_body( 'earth', time, ephemeris=get_pkg_data_filename('path/to/nonexisting/file.bsp')) with pytest.raises(HTTPError): # A non-existent version of the JPL ephemeris get_body('earth', time, ephemeris='de001') with pytest.raises(ValueError): # An invalid string get_body('earth', time, ephemeris='not_an_ephemeris')
def test_positions_skyfield(tmpdir): """ Test positions against those generated by skyfield. """ load = Loader(tmpdir) t = Time('1980-03-25 00:00') location = None # skyfield ephemeris try: planets = load('de421.bsp') ts = load.timescale() except OSError as e: if os.environ.get('CI', False) and 'timed out' in str(e): pytest.xfail('Timed out in CI') else: raise mercury, jupiter, moon = planets['mercury'], planets[ 'jupiter barycenter'], planets['moon'] earth = planets['earth'] skyfield_t = ts.from_astropy(t) if location is not None: earth = earth + Topos(latitude_degrees=location.lat.to_value(u.deg), longitude_degrees=location.lon.to_value(u.deg), elevation_m=location.height.to_value(u.m)) skyfield_mercury = earth.at(skyfield_t).observe(mercury).apparent() skyfield_jupiter = earth.at(skyfield_t).observe(jupiter).apparent() skyfield_moon = earth.at(skyfield_t).observe(moon).apparent() if location is not None: frame = TETE(obstime=t, location=location) else: frame = TETE(obstime=t) ra, dec, dist = skyfield_mercury.radec(epoch='date') skyfield_mercury = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_jupiter.radec(epoch='date') skyfield_jupiter = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_moon.radec(epoch='date') skyfield_moon = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) # planet positions w.r.t true equator and equinox moon_astropy = get_moon(t, location, ephemeris='de430').transform_to(frame) mercury_astropy = get_body('mercury', t, location, ephemeris='de430').transform_to(frame) jupiter_astropy = get_body('jupiter', t, location, ephemeris='de430').transform_to(frame) assert (moon_astropy.separation(skyfield_moon) < skyfield_angular_separation_tolerance) assert (moon_astropy.separation_3d(skyfield_moon) < skyfield_separation_tolerance) assert (jupiter_astropy.separation(skyfield_jupiter) < skyfield_angular_separation_tolerance) assert (jupiter_astropy.separation_3d(skyfield_jupiter) < skyfield_separation_tolerance) assert (mercury_astropy.separation(skyfield_mercury) < skyfield_angular_separation_tolerance) assert (mercury_astropy.separation_3d(skyfield_mercury) < skyfield_separation_tolerance) planets.close()
def test_positions_skyfield(): """ Test positions against those generated by skyfield. """ t = Time('1980-03-25 00:00') location = None # skyfield ephemeris planets = load('de421.bsp') ts = load.timescale() mercury, jupiter, moon = planets['mercury'], planets[ 'jupiter barycenter'], planets['moon'] earth = planets['earth'] skyfield_t = ts.from_astropy(t) if location is not None: earth = earth.topos(latitude_degrees=location.lat.to_value(u.deg), longitude_degrees=location.lon.to_value(u.deg), elevation_m=location.height.to_value(u.m)) skyfield_mercury = earth.at(skyfield_t).observe(mercury).apparent() skyfield_jupiter = earth.at(skyfield_t).observe(jupiter).apparent() skyfield_moon = earth.at(skyfield_t).observe(moon).apparent() if location is not None: obsgeoloc, obsgeovel = location.get_gcrs_posvel(t) frame = GCRS(obstime=t, obsgeoloc=obsgeoloc, obsgeovel=obsgeovel) else: frame = GCRS(obstime=t) ra, dec, dist = skyfield_mercury.radec(epoch='date') skyfield_mercury = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_jupiter.radec(epoch='date') skyfield_jupiter = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_moon.radec(epoch='date') skyfield_moon = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) moon_astropy = get_moon(t, location, ephemeris='de430') mercury_astropy = get_body('mercury', t, location, ephemeris='de430') jupiter_astropy = get_body('jupiter', t, location, ephemeris='de430') # convert to true equator and equinox jupiter_astropy = _apparent_position_in_true_coordinates(jupiter_astropy) mercury_astropy = _apparent_position_in_true_coordinates(mercury_astropy) moon_astropy = _apparent_position_in_true_coordinates(moon_astropy) assert (moon_astropy.separation(skyfield_moon) < skyfield_angular_separation_tolerance) assert (moon_astropy.separation_3d(skyfield_moon) < skyfield_separation_tolerance) assert (jupiter_astropy.separation(skyfield_jupiter) < skyfield_angular_separation_tolerance) assert (jupiter_astropy.separation_3d(skyfield_jupiter) < skyfield_separation_tolerance) assert (mercury_astropy.separation(skyfield_mercury) < skyfield_angular_separation_tolerance) assert (mercury_astropy.separation_3d(skyfield_mercury) < skyfield_separation_tolerance)
def test_positions_skyfield(): """ Test positions against those generated by skyfield. """ t = Time('1980-03-25 00:00') location = None # skyfield ephemeris planets = load('de421.bsp') ts = load.timescale() mercury, jupiter, moon = planets['mercury'], planets['jupiter barycenter'], planets['moon'] earth = planets['earth'] skyfield_t = ts.from_astropy(t) if location is not None: earth = earth.topos(latitude_degrees=location.lat.to_value(u.deg), longitude_degrees=location.lon.to_value(u.deg), elevation_m=location.height.to_value(u.m)) skyfield_mercury = earth.at(skyfield_t).observe(mercury).apparent() skyfield_jupiter = earth.at(skyfield_t).observe(jupiter).apparent() skyfield_moon = earth.at(skyfield_t).observe(moon).apparent() if location is not None: obsgeoloc, obsgeovel = location.get_gcrs_posvel(t) frame = GCRS(obstime=t, obsgeoloc=obsgeoloc, obsgeovel=obsgeovel) else: frame = GCRS(obstime=t) ra, dec, dist = skyfield_mercury.radec(epoch='date') skyfield_mercury = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_jupiter.radec(epoch='date') skyfield_jupiter = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) ra, dec, dist = skyfield_moon.radec(epoch='date') skyfield_moon = SkyCoord(ra.to(u.deg), dec.to(u.deg), distance=dist.to(u.km), frame=frame) moon_astropy = get_moon(t, location, ephemeris='de430') mercury_astropy = get_body('mercury', t, location, ephemeris='de430') jupiter_astropy = get_body('jupiter', t, location, ephemeris='de430') # convert to true equator and equinox jupiter_astropy = _apparent_position_in_true_coordinates(jupiter_astropy) mercury_astropy = _apparent_position_in_true_coordinates(mercury_astropy) moon_astropy = _apparent_position_in_true_coordinates(moon_astropy) assert (moon_astropy.separation(skyfield_moon) < skyfield_angular_separation_tolerance) assert (moon_astropy.separation_3d(skyfield_moon) < skyfield_separation_tolerance) assert (jupiter_astropy.separation(skyfield_jupiter) < skyfield_angular_separation_tolerance) assert (jupiter_astropy.separation_3d(skyfield_jupiter) < skyfield_separation_tolerance) assert (mercury_astropy.separation(skyfield_mercury) < skyfield_angular_separation_tolerance) assert (mercury_astropy.separation_3d(skyfield_mercury) < skyfield_separation_tolerance)