def test_los_shift(sc_kwargs): wl = [4000, 5000] * u.AA with nullcontext( ) if 'observer' not in sc_kwargs and 'target' not in sc_kwargs else pytest.warns( AstropyUserWarning, match='No velocity defined on frame'): sc_init = SpectralCoord(wl, **sc_kwargs) # these should always work in *all* cases because it's unambiguous that # a target shift should behave this way new_sc1 = sc_init.with_radial_velocity_shift(.1) assert_quantity_allclose(new_sc1, wl * 1.1) new_sc2 = sc_init.with_radial_velocity_shift( .1 * u.dimensionless_unscaled) # interpret at redshift assert_quantity_allclose(new_sc1, new_sc2) new_sc3 = sc_init.with_radial_velocity_shift(-100 * u.km / u.s) assert_quantity_allclose(new_sc3, wl * (1 + (-100 * u.km / u.s / c))) # now try the cases where observer is specified as well/instead if sc_init.observer is None or sc_init.target is None: with pytest.raises(ValueError): # both must be specified if you're going to mess with observer sc_init.with_radial_velocity_shift(observer_shift=.1) if sc_init.observer is not None and sc_init.target is not None: # redshifting the observer should *blushift* the LOS velocity since # its the observer-to-target vector that matters new_sc4 = sc_init.with_radial_velocity_shift(observer_shift=.1) assert_quantity_allclose(new_sc4, wl / 1.1) # an equal shift in both should produce no offset at all new_sc5 = sc_init.with_radial_velocity_shift(target_shift=.1, observer_shift=.1) assert_quantity_allclose(new_sc5, wl)
def test_regression_futuretimes_4302(): """ Checks that an error is not raised for future times not covered by IERS tables (at least in a simple transform like CIRS->ITRS that simply requires the UTC<->UT1 conversion). Relevant comment: https://github.com/astropy/astropy/pull/4302#discussion_r44836531 """ from astropy.utils.compat.context import nullcontext from astropy.utils.exceptions import AstropyWarning # this is an ugly hack to get the warning to show up even if it has already # appeared from astropy.coordinates.builtin_frames import utils if hasattr(utils, '__warningregistry__'): utils.__warningregistry__.clear() # check that out-of-range warning appears among any other warnings. If # tests are run with --remote-data then the IERS table will be an instance # of IERS_Auto which is assured of being "fresh". In this case getting # times outside the range of the table does not raise an exception. Only # if using IERS_B (which happens without --remote-data, i.e. for all CI # testing) do we expect another warning. if isinstance(iers.earth_orientation_table.get(), iers.IERS_B): ctx = pytest.warns( AstropyWarning, match=r'\(some\) times are outside of range covered by IERS table.*') else: ctx = nullcontext() with ctx: future_time = Time('2511-5-1') c = CIRS(1*u.deg, 2*u.deg, obstime=future_time) c.transform_to(ITRS(obstime=future_time))
def test_create_spectral_coord_observer_target(observer, target): with nullcontext() if target is None else pytest.warns( AstropyUserWarning, match='No velocity defined on frame'): coord = SpectralCoord([100, 200, 300] * u.nm, observer=observer, target=target) if observer is None: assert coord.observer is None else: assert_frame_allclose(observer, coord.observer) if target is None: assert coord.target is None else: assert_frame_allclose(target, coord.target) assert coord.doppler_rest is None assert coord.doppler_convention is None if observer is None or target is None: assert quantity_allclose(coord.redshift, 0) assert quantity_allclose(coord.radial_velocity, 0 * u.km / u.s) elif (any(observer is lsrd for lsrd in LSRD_EQUIV) and any(target is lsrd for lsrd in LSRD_DIR_STATIONARY_EQUIV)): assert_quantity_allclose(coord.radial_velocity, -274**0.5 * u.km / u.s, atol=1e-4 * u.km / u.s) assert_quantity_allclose(coord.redshift, -5.5213158163147646e-05, atol=1e-9) else: raise NotImplementedError()
def test_no_numpy_warnings(ignore_matplotlibrc, tmpdir, grid_type): ax = plt.subplot(1, 1, 1, projection=WCS(TARGET_HEADER)) ax.imshow(np.zeros((100, 200))) ax.coords.grid(color='white', grid_type=grid_type) if MATPLOTLIB_GT_3_4_2 and grid_type == 'contours': ctx = pytest.raises(AttributeError, match='dpi') else: ctx = nullcontext() with pytest.warns(None) as warning_lines, ctx: plt.savefig(tmpdir.join('test.png').strpath) # There should be no warnings raised if some pixels are outside WCS # (since this is normal). # BUT catch_warning was ignoring some warnings before, so now we # have to catch it. Otherwise, the pytest filterwarnings=error # setting in setup.cfg will fail this test. # There are actually multiple warnings but they are all similar. for w in warning_lines: w_msg = str(w.message) assert ('converting a masked element to nan' in w_msg or 'No contour levels were found within the data range' in w_msg or 'np.asscalar(a) is deprecated since NumPy v1.16' in w_msg or 'PY_SSIZE_T_CLEAN will be required' in w_msg)
def test_read_table_subclass_with_columns_attributes(self, tmpdir): """Regression test for https://github.com/astropy/astropy/issues/7181 """ class MTable(Table): pass mt = MTable([[1, 2.5]], names=['a']) mt['a'].unit = u.m mt['a'].format = '.4f' mt['a'].description = 'hello' if HAS_YAML: ctx = nullcontext() else: ctx = pytest.warns( AstropyUserWarning, match="These will be dropped unless you install PyYAML") testfile = str(tmpdir.join('junk.fits')) with ctx: mt.write(testfile, overwrite=True) t = MTable.read(testfile) assert np.all(mt == t) assert mt.colnames == t.colnames assert type(t) is MTable assert t['a'].unit == u.m assert t['a'].format == '{:13.4f}' if HAS_YAML: assert t['a'].description == 'hello' else: assert t['a'].description is None
def test_roundtrip(self, unit): if str(unit) in ('d', '0.001 Crab'): # Special-case day, which gets auto-converted to hours, and mCrab, # which the default check does not recognize as a deprecated unit. with pytest.warns(UnitsWarning): s = unit.to_string(self.format_) a = core.Unit(s, format=self.format_) assert_allclose(a.decompose().scale, unit.decompose().scale, rtol=1e-9) else: self.check_roundtrip(unit) if str(unit) in ('mag', 'byte', 'Crab'): # Skip mag and byte, which decompose into dex and bit, resp., # both of which are unknown to OGIP, as well as Crab, which does # not decompose, and thus gives a depecated unit warning. return power_of_ten = np.log10(unit.decompose().scale) if abs(power_of_ten - round(power_of_ten)) > 1e-3: ctx = pytest.warns(UnitsWarning, match='power of 10') elif str(unit) == '0.001 Crab': ctx = pytest.warns(UnitsWarning, match='deprecated') else: ctx = nullcontext() with ctx: self.check_roundtrip_decompose(unit)
def expected_boundary_warning(boundary=None): # Helper that returns the appropriate context manager for the boundary=None # warning depending on the value of boundary. if boundary is None: ctx = pytest.warns(AstropyUserWarning, match='The convolve_fft version of boundary=None ' 'is equivalent to the convolve boundary=\'fill\'') else: ctx = nullcontext() return ctx
def test_spectralcoord_accuracy(specsys): # PyYAML is needed to read in the ecsv table pytest.importorskip('yaml') # This is a test to check the numerical results of transformations between # different velocity frames in SpectralCoord. This compares the velocity # shifts determined with SpectralCoord to those determined from the rv # package in Starlink. velocity_frame = EXPECTED_VELOCITY_FRAMES[specsys] reference_filename = get_pkg_data_filename('accuracy/data/rv.ecsv') reference_table = Table.read(reference_filename, format='ascii.ecsv') rest = 550 * u.nm with iers.conf.set_temp('auto_download', False): for row in reference_table: observer = EarthLocation.from_geodetic( -row['obslon'], row['obslat']).get_itrs(obstime=row['obstime']) with pytest.warns(AstropyUserWarning, match='No velocity defined on frame'): sc_topo = SpectralCoord(545 * u.nm, observer=observer, target=row['target']) # FIXME: A warning is emitted for dates after MJD=57754.0 even # though the leap second table should be valid until the end of # 2020. with nullcontext() if row['obstime'].mjd < 57754 else pytest.warns( AstropyWarning, match='Tried to get polar motions'): sc_final = sc_topo.with_observer_stationary_relative_to( velocity_frame) delta_vel = (sc_topo.to(u.km / u.s, doppler_convention='relativistic', doppler_rest=rest) - sc_final.to(u.km / u.s, doppler_convention='relativistic', doppler_rest=rest)) if specsys == 'galactoc': assert_allclose(delta_vel.to_value(u.km / u.s), row[specsys.lower()], atol=30) else: assert_allclose(delta_vel.to_value(u.km / u.s), row[specsys.lower()], atol=0.02, rtol=0.002)
def test_formats(format, expected): # Check that the locators/formatters work fine for all time formats with time_support(format=format, simplify=False): fig = plt.figure() ax = fig.add_subplot(1, 1, 1) # Getting unix time and plot_date requires going through a scale for # which ERFA emits a warning about the date being dubious with pytest.warns(ErfaWarning) if format in ['unix', 'plot_date' ] else nullcontext(): ax.set_xlim(Time('2014-03-22T12:30:30.9', scale=DEFAULT_SCALE), Time('2077-03-22T12:30:32.1', scale=DEFAULT_SCALE)) assert get_ticklabels(ax.xaxis) == expected ax.get_xlabel() == f'Time ({format})'
def test_mad_std_warns(): if NUMPY_LT_1_17: ctx = pytest.warns(RuntimeWarning, match='Invalid value encountered in median') else: ctx = nullcontext() with NumpyRNGContext(12345): data = np.random.normal(5, 2, size=(10, 10)) data[5, 5] = np.nan with ctx: rslt = funcs.mad_std(data, ignore_nan=False) assert np.isnan(rslt)
def test_sign(self): q = [1., np.inf, -np.inf, np.nan, -1., 0.] * u.m # Ignore "invalid value encountered in sign" warning on Windows. if sys.platform.startswith('win'): ctx = np.errstate(invalid='ignore') else: ctx = nullcontext() with ctx: out = np.sign(q) assert not isinstance(out, u.Quantity) assert out.dtype == q.dtype assert np.all((out == np.sign(q.value)) | (np.isnan(out) & np.isnan(q.value)))
def test_columns_names_with_formats(formats, issues_warning): """Test the fix for #4508.""" t = table.Table([[1, 2, 3], [4.1, 5.2, 6.3]]) out = StringIO() if issues_warning: ctx = pytest.warns(AstropyWarning) else: ctx = nullcontext() with ctx as warn: ascii.write(t, out, formats=formats) if issues_warning: assert len(warn) == 1
def test_footprint_contains(): """ Test WCS.footprint_contains(skycoord) """ header = """ WCSAXES = 2 / Number of coordinate axes CRPIX1 = 1045.0 / Pixel coordinate of reference point CRPIX2 = 1001.0 / Pixel coordinate of reference point PC1_1 = -0.00556448550786 / Coordinate transformation matrix element PC1_2 = -0.001042120133257 / Coordinate transformation matrix element PC2_1 = 0.001181477028705 / Coordinate transformation matrix element PC2_2 = -0.005590809742987 / Coordinate transformation matrix element CDELT1 = 1.0 / [deg] Coordinate increment at reference point CDELT2 = 1.0 / [deg] Coordinate increment at reference point CUNIT1 = 'deg' / Units of coordinate increment and value CUNIT2 = 'deg' / Units of coordinate increment and value CTYPE1 = 'RA---TAN' / TAN (gnomonic) projection + SIP distortions CTYPE2 = 'DEC--TAN' / TAN (gnomonic) projection + SIP distortions CRVAL1 = 250.34971683647 / [deg] Coordinate value at reference point CRVAL2 = 2.2808772582495 / [deg] Coordinate value at reference point LONPOLE = 180.0 / [deg] Native longitude of celestial pole LATPOLE = 2.2808772582495 / [deg] Native latitude of celestial pole RADESYS = 'ICRS' / Equatorial coordinate system MJD-OBS = 58612.339199259 / [d] MJD of observation matching DATE-OBS DATE-OBS= '2019-05-09T08:08:26.816Z' / ISO-8601 observation date matching MJD-OB NAXIS = 2 / NAXIS NAXIS1 = 2136 / length of first array dimension NAXIS2 = 2078 / length of second array dimension """ # noqa header = fits.Header.fromstring(header.strip(), '\n') test_wcs = wcs.WCS(header) hasCoord = test_wcs.footprint_contains(SkyCoord(254, 2, unit='deg')) assert hasCoord hasCoord = test_wcs.footprint_contains(SkyCoord(240, 2, unit='deg')) assert not hasCoord # Ignore "invalid value encountered in less" warning on Windows. if sys.platform.startswith('win'): ctx = np.errstate(invalid='ignore') else: ctx = nullcontext() with ctx: hasCoord = test_wcs.footprint_contains(SkyCoord(24, 2, unit='deg')) assert not hasCoord
def test_create_from_spectral_coord(observer, target): """ Checks that parameters are correctly copied to the new SpectralCoord object """ with nullcontext() if target is None else pytest.warns( AstropyUserWarning, match='No velocity defined on frame'): spec_coord1 = SpectralCoord([100, 200, 300] * u.nm, observer=observer, target=target, doppler_convention='optical', doppler_rest=6000 * u.AA) spec_coord2 = SpectralCoord(spec_coord1) assert spec_coord1.observer == spec_coord2.observer assert spec_coord1.target == spec_coord2.target assert spec_coord1.radial_velocity == spec_coord2.radial_velocity assert spec_coord1.doppler_convention == spec_coord2.doppler_convention assert spec_coord1.doppler_rest == spec_coord2.doppler_rest
def test_sign_inplace(self): q = [1., np.inf, -np.inf, np.nan, -1., 0.] * u.m check = np.empty(q.shape, q.dtype) # Ignore "invalid value encountered in sign" warning on Windows. if sys.platform.startswith('win'): ctx = np.errstate(invalid='ignore') else: ctx = nullcontext() with ctx: np.sign(q.value, out=check) result = np.empty(q.shape, q.dtype) out = np.sign(q, out=result) assert out is result assert type(out) is np.ndarray assert out.dtype == q.dtype assert np.all((out == np.sign(q.value)) | (np.isnan(out) & np.isnan(q.value)))
def test_unity_3_withnan(self, boundary, nan_treatment, normalize_kernel, preserve_nan): ''' Test that a unit kernel with three elements returns the same array (except when boundary is None). This version includes a NaN value in the original array. ''' x = np.array([1., np.nan, 3.], dtype='>f8') y = np.array([0., 1., 0.], dtype='>f8') # Since the kernel is actually only one pixel wide (because of the # zeros) the NaN value doesn't get interpolated over so a warning is # expected. if nan_treatment == 'interpolate' and not preserve_nan: ctx = pytest.warns(AstropyUserWarning, match="nan_treatment='interpolate', however, " "NaN values detected") else: ctx = nullcontext() with ctx: z = convolve(x, y, boundary=boundary, nan_treatment=nan_treatment, normalize_kernel=normalize_kernel, preserve_nan=preserve_nan) if preserve_nan: assert np.isnan(z[1]) x = np.nan_to_num(z) z = np.nan_to_num(z) if boundary is None: assert np.all(z == np.array([0., 0., 0.], dtype='>f8')) else: assert np.all(z == x)
def test_mad_std_scalar_return(): with NumpyRNGContext(12345): data = np.random.normal(5, 2, size=(10, 10)) # make a masked array with no masked points data = np.ma.masked_where(np.isnan(data), data) rslt = funcs.mad_std(data) # want a scalar result, NOT a masked array assert np.isscalar(rslt) if NUMPY_LT_1_17: ctx = pytest.warns(RuntimeWarning, match='Invalid value encountered in median') else: ctx = nullcontext() data[5, 5] = np.nan with ctx: rslt = funcs.mad_std(data, ignore_nan=True) assert np.isscalar(rslt) rslt = funcs.mad_std(data) assert np.isscalar(rslt) assert np.isnan(rslt)
def test_round_trip_user_defined_unit(table_cls, tmpdir): """Ensure that we can read-back enabled user-defined units.""" from astropy.utils.compat.context import nullcontext # Test adapted from #8897, where it was noted that this works # but was not tested. filename = str(tmpdir.join('test.ecsv')) unit = u.def_unit('bandpass_sol_lum') t = table_cls() t['l'] = np.arange(5) * unit t.write(filename) # without the unit enabled, get UnrecognizedUnit if table_cls is QTable: ctx = pytest.warns(u.UnitsWarning, match=r"'bandpass_sol_lum' did not parse .*") else: ctx = nullcontext() # Note: The read might also generate ResourceWarning, in addition to UnitsWarning with ctx: t2 = table_cls.read(filename) assert isinstance(t2['l'].unit, u.UnrecognizedUnit) assert str(t2['l'].unit) == 'bandpass_sol_lum' if table_cls is QTable: assert np.all(t2['l'].value == t['l'].value) else: assert np.all(t2['l'] == t['l']) # But with it enabled, it works. with u.add_enabled_units(unit): t3 = table_cls.read(filename) assert t3['l'].unit is unit assert np.all(t3['l'] == t['l']) # Just to be sure, aloso try writing with unit enabled. filename2 = str(tmpdir.join('test2.ecsv')) t3.write(filename2) t4 = table_cls.read(filename) assert t4['l'].unit is unit assert np.all(t4['l'] == t['l'])
def trp_iterate_solution(self, n_iter=20, method='Powell', options=None, seed=None): """Perform multiple iterations starting from random initial conditions. Attributes are updated in-place with the best solution in a chi-squared sense among the iterations. Parameters ---------- n_iter : int Number of iterations to run. method : str See :func:`scipy.optimize.minimize`. options : dict or `None` See :func:`scipy.optimize.minimize`. If not given, some pre-defined defaults are used. seed : int or `None` Seed for Numpy random generator. Usually used in testing for reproducibility. """ import scipy.optimize as opt from astropy.utils.compat.context import nullcontext from astropy.utils.misc import NumpyRNGContext if options is None: options = { 'xtol': 1e-5, 'ftol': 1e-5, 'maxiter': 2000, 'maxfev': 2000 } if seed is None: rand_ctx = nullcontext() else: rand_ctx = NumpyRNGContext(seed) best_chi2s = np.zeros(n_iter) best_pars = np.zeros((self.physvals.size, n_iter)) gd_fits = np.zeros(n_iter, dtype=bool) depth_half = self.origests.depth * 0.5 / 1.0e6 depth_half_abs = np.abs(depth_half) with rand_ctx: for i in range(n_iter): self.physvals = (self.physval_mins + np.random.rand(self.physvals.size) * (self.physval_maxs - self.physval_mins)) # Force depth parameter to start at minimum half the depth if self.physvals[1] < depth_half_abs: self.physvals[1] = depth_half # Replace random starts with parameters values that are fixed self.physvals = np.where(self.fixed == 1, self.physvalsavs, self.physvals) self.set_boundedvals() freeidx = np.where(self.fixed == 0)[0] start_pars = self.boundedvals[freeidx] all_output = opt.minimize(self.trp_likehood, start_pars, method=method, options=options) self.boundedvals[freeidx] = all_output['x'] self.boundedvals = np.where(self.fixed == 1, self.boundedvalsavs, self.boundedvals) self.set_physvals() chi2min = all_output['fun'] self.logger.debug(f'It: {i} Chi2: {chi2min}\n{self.physvals}') if np.isfinite(self.physvals).all(): gd_fits[i] = True best_chi2s[i] = chi2min best_pars[:, i] = self.physvals # Done with iterations find the best one by chi2min best_masked_idx = np.argmin(best_chi2s[gd_fits]) self.chi2min = best_chi2s[gd_fits][best_masked_idx] self.bestphysvals = best_pars[:, gd_fits][:, best_masked_idx] self.physvals = self.bestphysvals self.set_boundedvals() self.bestboundedvals = self.boundedvals self.logger.debug( f'Overall Best Chi2 Min: {self.chi2min}\n{self.physvals}') self.minimized = True