Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix various things based upon changes in astropy #37

Merged
merged 9 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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