def test_sample_lm_broadcast( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: l = np.array([0.01, 0.02]) m = np.array([0.03, -0.04, 0.01]) frequency = 1500 * u.MHz actual = aperture_plane_model.sample(l[np.newaxis, :], m[:, np.newaxis], frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) expected = np.zeros((len(m), len(l), 2, 2), np.complex64) for i in range(len(m)): for j in range(len(l)): expected[i, j] = aperture_plane_model.sample( l[j], m[i], frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) # It isn't exact, presumably because the matrix multiplications sum # in a different order depending on size. np.testing.assert_allclose(actual, expected, atol=1e-7) # Also check with RADecFrame actual = aperture_plane_model.sample( -l[np.newaxis, :], m[:, np.newaxis], frequency, primary_beam.RADecFrame.from_parallactic_angle(0 * u.deg), primary_beam.OutputType.JONES_HV) np.testing.assert_allclose(actual, expected, atol=1e-7)
def test_sample_scalar_lm( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: l = 0.01 m = 0.02 frequency = 1500 * u.MHz scalar = aperture_plane_model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) vector = aperture_plane_model.sample(np.array([l]), np.array([m]), frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) assert scalar.shape == (2, 2) np.testing.assert_array_equal(scalar, vector[0])
def test_sample_radec( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane, lat: u.Quantity) -> None: model = aperture_plane_model location = EarthLocation.from_geodetic(18 * u.deg, lat=lat, height=100 * u.m) obstime = Time('2021-04-22T13:00:00Z') frequency = 1 * u.GHz altaz_frame = AltAz(obstime=obstime, location=location) target_altaz = SkyCoord(alt=70 * u.deg, az=150 * u.deg, frame=altaz_frame) l_altaz = [-0.002, 0.001, 0.0, 0.0, 0.0] m_altaz = [0.0, 0.02, 0.0, -0.03, 0.01] coords_altaz = _lm_to_coords(l_altaz, m_altaz, target_altaz) target_icrs = target_altaz.icrs coords_icrs = coords_altaz.icrs l_icrs, m_icrs = _coords_to_lm(coords_icrs, target_icrs) out_radec = model.sample( l_icrs, m_icrs, frequency, primary_beam.RADecFrame.from_sky_coord(target_icrs), primary_beam.OutputType.JONES_HV) out_altaz = model.sample(l_altaz, m_altaz, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) # Tolerance is high because RADecFrame doesn't account for aberration np.testing.assert_allclose(out_radec, out_altaz, atol=1e-4)
def test_sample_out_of_range( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane, l: float, m: float, frequency: u.Quantity) -> None: actual = aperture_plane_model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) expected = np.full((2, 2), np.nan) np.testing.assert_array_equal(actual, expected)
def test_sample_multi_dim_lm( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: rs = np.random.RandomState(1) shape = (2, 3, 4) l = rs.random(shape) * 0.05 m = rs.random(shape) * 0.05 frequency = 1500 * u.MHz multi = aperture_plane_model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) flat = aperture_plane_model.sample(l.ravel(), m.ravel(), frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) np.testing.assert_array_equal(multi, flat.reshape(multi.shape)) # Make sure that we're comparing meaningful values, not just NaNs assert not np.any(np.isnan(multi))
def test_sample_lm_np_flags( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: """Check that flags on l and m arrays are not modified.""" l = np.array([0.01, 0.02]) m = np.array([0.03, 0.04]) aperture_plane_model.sample(l, m, 1500 * u.MHz, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) assert l.flags.writeable assert m.flags.writeable
def test_sample_frequency_array( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: l = np.array([0.01]) m = np.array([0.02]) frequency = np.array([[1000, 1200], [1100, 1500]]) * u.MHz # Evaluate one frequency at a time expected = np.zeros(frequency.shape + (1, 2, 2), np.complex64) # Astropy units don't work with np.ndenumerate, hence npindex instead for idx in np.ndindex(frequency.shape): expected[idx] = aperture_plane_model.sample( l, m, frequency[idx], primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) # Evaluate them all together actual = aperture_plane_model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) np.testing.assert_array_equal(actual, expected)
def test_sample_bad_out( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane, out: np.ndarray, expectation) -> None: model = aperture_plane_model l = np.array([0.01]) m = np.array([0.02]) frequency = np.array([[1000, 1200], [1100, 1500]]) * u.MHz with expectation: model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV, out=out)
def test_sample_interp_scalar_freq( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: model = aperture_plane_model l = [0.0, 0.05, -0.02] m = [0.0, 0.03, 0.04] frequency_idx = 50 frequency = np.mean(model.frequency[frequency_idx:frequency_idx + 2]) actual = aperture_plane_model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) samples = np.mean(model.samples[frequency_idx:frequency_idx + 2], axis=0) expected = _compute_expected(model, samples, l, m, frequency) # atol is more appropriate than rtol since there is cancellation of small terms np.testing.assert_allclose(actual, expected, rtol=0, atol=1e-6) # Check that we get identity matrix at the origin np.testing.assert_allclose(actual[0], np.eye(2), rtol=0, atol=1e-6)
def test_sample_partially_out_of_range( aperture_plane_model: primary_beam.PrimaryBeamAperturePlane) -> None: model = aperture_plane_model l = [0.1, -0.19, 0.21] # 0.2 is (roughly) the limit at 1.5 GHz m = [0.0] frequency = [1000, 1500, 1630, 2000] * u.MHz actual = model.sample(l, m, frequency, primary_beam.AltAzFrame(), primary_beam.OutputType.JONES_HV) expected_nan = np.array([ [False, False, False], [False, False, True], [False, True, True], [True, True, True] # frequency is out of range ]) for i in range(2): for j in range(2): np.testing.assert_array_equal(np.isnan(actual[..., i, j]), expected_nan)
from astropy.coordinates import EarthLocation, AltAz, SkyCoord, CartesianRepresentation from astropy.time import Time import numpy as np try: from numpy.typing import ArrayLike except ImportError: ArrayLike = Any # type: ignore import h5py import pytest from katsdpmodels import models, primary_beam import katsdpmodels.fetch.requests as fetch_requests FRAME_OUTPUT_TYPE_COMBOS = [ (frame, output_type) for frame in [ primary_beam.AltAzFrame(), primary_beam.RADecFrame.from_parallactic_angle(40 * u.deg), primary_beam.RADecFrame.from_parallactic_angle([[40], [80]] * u.deg) ] for output_type in primary_beam.OutputType if (isinstance(frame, primary_beam.RADecFrame) or output_type in { primary_beam.OutputType.JONES_HV, primary_beam.OutputType.UNPOLARIZED_POWER }) ] @pytest.fixture def aperture_plane_model_file(tmp_path) -> h5py.File: """Create an aperture-plane model for testing. It writes the model directly rather than using the PrimaryBeam API