Skip to content

Commit

Permalink
fix various things based upon changes in astropy (#37)
Browse files Browse the repository at this point in the history
* fix naxis access

* removed _naxis and fixed np.where with units problem

* small approx in assert unit test

* shouldn't call fixtures

e.g. pytest-dev/pytest#3950 (comment)

* maybe fix to array_sequence_equal

* fix fixture names test_psf

* removed duplicated test functions

* use more recent packages travis

* Revert "use more recent packages travis"

This reverts commit 6c55f18.
  • Loading branch information
lspitler authored Aug 28, 2020
1 parent 671c37d commit 7f683b6
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 84 deletions.
29 changes: 13 additions & 16 deletions gunagala/imager.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def __init__(self, optic, camera, filters, psf, sky, num_imagers=1, num_per_comp

# Construct a simple template WCS to store the focal plane configuration parameters
self.wcs = WCS(naxis=2)
self.wcs._naxis2, self.wcs._naxis1 = self.camera.resolution.value.astype(int)
self.wcs.pixel_shape = self.camera.resolution.value.astype(int)
self.wcs.wcs.crpix = [(self.camera.resolution[1].value - 1) / 2,
(self.camera.resolution[0].value - 1) / 2]
self.wcs.wcs.cdelt = [self.pixel_scale.to(u.degree / u.pixel).value,
Expand Down Expand Up @@ -422,9 +422,8 @@ def extended_source_signal_noise(self, surface_brightness, filter_name, total_ex
# Sky counts already included in _is_saturated, need to avoid counting them twice
saturated = self._is_saturated(
0 * u.electron / (u.pixel * u.second), sub_exp_time, filter_name)
# np.where strips units, need to manually put them back.
signal = np.where(saturated, 0, signal) * u.electron / u.pixel
noise = np.where(saturated, 0, noise) * u.electron / u.pixel
signal = np.where(saturated, 0 * u.electron / u.pixel, signal)
noise = np.where(saturated, 0 * u.electron / u.pixel, noise)

# Totals per (binned) pixel for all imagers.
signal = signal * self.num_imagers * binning
Expand Down Expand Up @@ -483,8 +482,7 @@ def extended_source_snr(self, surface_brightness, filter_name, total_exp_time, s
signal, noise = self.extended_source_signal_noise(surface_brightness, filter_name, total_exp_time,
sub_exp_time, calc_type, saturation_check, binning)

# np.where() strips units, need to manually put them back
snr = np.where(noise != 0.0, signal / noise, 0.0) * u.dimensionless_unscaled
snr = np.where(noise != 0.0, signal / noise, 0.0 * u.dimensionless_unscaled)

return snr

Expand Down Expand Up @@ -1003,9 +1001,8 @@ def point_source_signal_noise(self, brightness, filter_name, total_exp_time, sub
# in a single sub exposure, and check against saturation_level.
if saturation_check:
saturated = self._is_saturated(rate * self.psf.peak, sub_exp_time, filter_name)
# np.where strips units, need to manually put them back.
signal = np.where(saturated, 0.0, signal) * u.electron
noise = np.where(saturated, 0.0, noise) * u.electron
signal = np.where(saturated, 0.0 * u.electron, signal)
noise = np.where(saturated, 0.0 * u.electron , noise)

return signal, noise

Expand Down Expand Up @@ -1046,8 +1043,7 @@ def point_source_snr(self, brightness, filter_name, total_exp_time, sub_exp_time
signal, noise = self.point_source_signal_noise(brightness, filter_name,
total_exp_time, sub_exp_time, saturation_check)

# np.where() strips units, need to manually put them back.
snr = np.where(noise != 0.0, signal / noise, 0.0) * u.dimensionless_unscaled
snr = np.where(noise != 0.0, signal / noise, 0.0 * u.dimensionless_unscaled)

return snr

Expand Down Expand Up @@ -1096,8 +1092,7 @@ def point_source_etc(self, brightness, filter_name, snr_target, sub_exp_time, sa
# in a single sub exposure, and check against saturation_level.
if saturation_check:
saturated = self._is_saturated(rate * self.psf.peak, sub_exp_time, filter_name)
# np.where() strips units, need to manually put them back
total_exp_time = np.where(saturated, 0.0, total_exp_time) * u.second
total_exp_time = np.where(saturated, 0.0 * u.second, total_exp_time)

return total_exp_time

Expand Down Expand Up @@ -1507,6 +1502,7 @@ def snr_vs_ABmag(self, exp_times, filter_name, magnitude_interval=0.02 * u.ABmag
filter_name=filter_name,
total_exp_time=exp_time,
sub_exp_time=exp_time)
# print(total_signals, signals, "LALA")
total_signals += signals
total_noises_squared += noises**2

Expand Down Expand Up @@ -1557,7 +1553,8 @@ def get_pixel_coords(self):
of the centre of all the pixels in the image.
"""
# Arrays of pixel coordinates
XY = np.meshgrid(np.arange(self.wcs._naxis1), np.arange(self.wcs._naxis2))
naxis1, naxis2 = self.wcs.pixel_shape
XY = np.meshgrid(np.arange(naxis1), np.arange(naxis2))

# Convert to arrays of RA, dec (ICRS, decimal degrees)
try:
Expand Down Expand Up @@ -1607,8 +1604,8 @@ def make_noiseless_image(self,
if isinstance(self.psf, FittablePSF):
raise NotImplementedError("Analytical PSFs currently don't work.\n They will take all system memory. See: https://github.com/AstroHuntsman/gunagala/pull/16#issuecomment-426844974 ")

electrons = np.zeros((self.wcs._naxis2,
self.wcs._naxis1)) * u.electron / (u.second * u.pixel)
naxis1, naxis2 = self.wcs.pixel_shape
electrons = np.zeros((naxis2, naxis1)) * u.electron / (u.second * u.pixel)
self.set_WCS_centre(centre, **centre_kwargs)

# Calculate observed sky background
Expand Down
9 changes: 5 additions & 4 deletions gunagala/tests/test_imager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Tests for the signal-to-noise module
import pytest
from pytest import approx
import numpy as np
import astropy.units as u
import astropy.constants as c
Expand Down Expand Up @@ -336,11 +337,11 @@ def test_extended_rates(imager, filter_name):
saturation_check=True)

# Calculating surface brightness given exposure time and SNR should match original surface brightness
assert imager.rate_to_SB(rate, filter_name) == imager.extended_source_limit(total_exp_time=t_exp,
assert approx(imager.rate_to_SB(rate, filter_name).value) == imager.extended_source_limit(total_exp_time=t_exp,
filter_name=filter_name,
snr_target=snr,
sub_exp_time=t_sub,
calc_type='per arcsecond squared')
calc_type='per arcsecond squared').value

# Can't use pixel binning with per arcsecond squared signal, noise values
with pytest.raises(ValueError):
Expand Down Expand Up @@ -754,8 +755,8 @@ def test_get_pixel_coords_with_WCS_call_first(imager_function_scope):
# now set WCS centre first, then try and get_pixel_coords
imager_function_scope.set_WCS_centre(test_coord_string, unit='deg')
centre_field_pixels = imager_function_scope.get_pixel_coords()
assert imager_function_scope.wcs._naxis1 == centre_field_pixels.shape[1]
assert imager_function_scope.wcs._naxis2 == centre_field_pixels.shape[0]
assert imager_function_scope.wcs.pixel_shape[0] == centre_field_pixels.shape[1]
assert imager_function_scope.wcs.pixel_shape[1] == centre_field_pixels.shape[0]


def test_create_imagers():
Expand Down
110 changes: 48 additions & 62 deletions gunagala/tests/test_psf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@

@pytest.fixture(scope='module')
def psf_moffat():
return make_moffat()


def make_moffat():
psf = MoffatPSF(FWHM=1 / 30 * u.arcminute, shape=4.7)
return psf


@pytest.fixture(scope='module')
def psf_pixellated():
return make_pixellated()


def make_pixellated():
psf_data = np.array([[0.0, 0.0, 0.1, 0.0, 0.0],
[0.0, 0.3, 0.7, 0.4, 0.0],
[0.1, 0.8, 1.0, 0.6, 0.1],
Expand All @@ -29,72 +37,59 @@ def psf_pixellated():
def test_base():
with pytest.raises(TypeError):
# Try to instantiate abstract base class, should fail
psf_base = PSF(FWHM=1 / 30 * u.arcminute)
_ = PSF(FWHM=1 / 30 * u.arcminute)


@pytest.mark.parametrize("psf, type", [
(psf_moffat(), MoffatPSF),
(psf_pixellated(), PixellatedPSF)],
(make_moffat(), MoffatPSF),
(make_pixellated(), PixellatedPSF)],
ids=["moffat", "pixellated"]
)
def test_instance(psf, type):
assert isinstance(psf, type)
assert isinstance(psf, PSF)


def test_pix(pix_psf):
assert isinstance(pix_psf, PixellatedPSF)
assert isinstance(pix_psf, PSF)
def test_pix(psf_pixellated):
assert isinstance(psf_pixellated, PixellatedPSF)
assert isinstance(psf_pixellated, PSF)


def test_FWHM(psf):
assert psf.FWHM == 2 * u.arcsecond
psf.FWHM = 4 * u.arcsecond
assert psf.FWHM == 1 / 15 * u.arcminute
def test_FWHM(psf_moffat):
assert psf_moffat.FWHM == 2 * u.arcsecond
psf_moffat.FWHM = 4 * u.arcsecond
assert psf_moffat.FWHM == 1 / 15 * u.arcminute
with pytest.raises(ValueError):
psf.FWHM = -1 * u.degree
psf.FWHM = 2 * u.arcsecond


def test_pixel_scale(psf):
psf.pixel_scale = 2.85 * u.arcsecond / u.pixel
assert psf.pixel_scale == 2.85 * u.arcsecond / u.pixel


def test_pixel_scale_pix(pix_psf):
pix_psf.pixel_scale = (1 / 3) * u.arcsecond / u.pixel
assert pix_psf.pixel_scale == (1 / 3) * u.arcsecond / u.pixel
pix_psf.pixel_scale = (2 / 3) * u.arcsecond / u.pixel


def test_n_pix(psf):
assert psf.n_pix == 4.25754067000986 * u.pixel
psf_moffat.FWHM = -1 * u.degree
psf_moffat.FWHM = 2 * u.arcsecond


def test_n_pix_pix(pix_psf):
assert pix_psf.n_pix.to(u.pixel).value == pytest.approx(21.01351017)
def test_pixel_scale_pix(psf_pixellated):
psf_pixellated.pixel_scale = (1 / 3) * u.arcsecond / u.pixel
assert psf_pixellated.pixel_scale == (1 / 3) * u.arcsecond / u.pixel
psf_pixellated.pixel_scale = (2 / 3) * u.arcsecond / u.pixel


def test_peak(psf):
assert psf.peak == 0.7134084656751443 / u.pixel
def test_n_pix_pix(psf_pixellated):
assert psf_pixellated.n_pix.to(u.pixel).value == pytest.approx(21.0699454)


def test_peak_pix(pix_psf):
assert pix_psf.peak.to(1 / u.pixel).value == pytest.approx(0.08073066)
def test_peak_pix(psf_pixellated):
assert psf_pixellated.peak.to(1 / u.pixel).value == pytest.approx(0.08073066)


def test_shape(psf):
assert psf.shape == 4.7
psf.shape = 2.5
assert psf.shape == 2.5
def test_shape(psf_moffat):
assert psf_moffat.shape == 4.7
psf_moffat.shape = 2.5
assert psf_moffat.shape == 2.5
with pytest.raises(ValueError):
psf_moffat.FWHM = -1 * u.degree
psf_moffat.FWHM = 2 * u.arcsecond


@pytest.mark.parametrize("psf, t_pixel_scale, pixel_scale", [
(psf_moffat(), 2.85, 2.85),
(psf_pixellated(), (1 / 3), (2 / 3))],
(make_moffat(), 2.85, 2.85),
(make_pixellated(), (1 / 3), (2 / 3))],
ids=["moffat", "pixellated"]
)
def test_pixel_scale(psf, t_pixel_scale, pixel_scale):
Expand All @@ -104,8 +99,8 @@ def test_pixel_scale(psf, t_pixel_scale, pixel_scale):


@pytest.mark.parametrize("psf, expected_n_pix, pixel_scale", [
(psf_moffat(), 4.25754067000986, 2.85),
(psf_pixellated(), 21.06994544, (2 / 3))],
(make_moffat(), 4.25754067000986, 2.85),
(make_pixellated(), 21.06994544, (2 / 3))],
ids=["moffat", "pixellated"]
)
def test_n_pix(psf, expected_n_pix, pixel_scale):
Expand All @@ -114,29 +109,20 @@ def test_n_pix(psf, expected_n_pix, pixel_scale):


@pytest.mark.parametrize("psf, expected_peak, pixel_scale", [
(psf_moffat(), 0.7134084656751443, 2.85),
(psf_pixellated(), 0.08073066, (2 / 3))],
(make_moffat(), 0.7134084656751443, 2.85),
(make_pixellated(), 0.08073066, (2 / 3))],
ids=["moffat", "pixellated"]
)
def test_peak(psf, expected_peak, pixel_scale):
psf.pixel_scale = pixel_scale * u.arcsecond / u.pixel
assert psf.peak.to(1 / (u.pixel)).value == pytest.approx(expected_peak)


def test_shape(psf_moffat):
assert psf_moffat.shape == 4.7
psf_moffat.shape = 2.5
assert psf_moffat.shape == 2.5
with pytest.raises(ValueError):
psf_moffat.shape = 0.5
psf_moffat.shape = 4.7


@pytest.mark.parametrize("psf, image_size", [
(psf_moffat(), (21, 21)),
(psf_pixellated(), (21, 21)),
(psf_moffat(), (7, 9)),
(psf_pixellated(), (7, 9))],
(make_moffat(), (21, 21)),
(make_pixellated(), (21, 21)),
(make_moffat(), (7, 9)),
(make_pixellated(), (7, 9))],
ids=["moffat_square",
"pixellated_square",
"moffat_rectangle",
Expand All @@ -155,10 +141,10 @@ def test_pixellated_dimension(psf, image_size):


@pytest.mark.parametrize("psf, offset", [
(psf_moffat(), (0.0, 0.0)),
(psf_pixellated(), (0.0, 0.0)),
(psf_moffat(), (0.3, -0.7)),
(psf_pixellated(), (0.3, -0.7))],
(make_moffat(), (0.0, 0.0)),
(make_pixellated(), (0.0, 0.0)),
(make_moffat(), (0.3, -0.7)),
(make_pixellated(), (0.3, -0.7))],
ids=["moffat_centre_offsets",
"pixellated_centre_offsets",
"moffat_noncentre_offsets",
Expand All @@ -172,8 +158,8 @@ def test_offsets(psf, offset):


@pytest.mark.parametrize("psf, test_size", [
(psf_moffat(), (1.3, -1.3)),
(psf_pixellated(), (-1.3, 1.3))],
(make_moffat(), (1.3, -1.3)),
(make_pixellated(), (-1.3, 1.3))],
ids=["moffat", "pixellated"]
)
def test_pixellated_invalid_size(psf, test_size):
Expand Down
4 changes: 2 additions & 2 deletions gunagala/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ def array_sequence_equal(array_sequence, reference=None):
for array in array_sequence:
try:
assert (array == reference).all()
except (AttributeError, AssertionError):
except (AttributeError, ValueError, AssertionError):
# Attribute error if array & reference different lengths, Assertion Error if same
# length but one or more elements differ in value.
# length but one or more elements differ in value. ValueError if different lengths.
return False
return True

Expand Down

0 comments on commit 7f683b6

Please sign in to comment.