Skip to content

Commit

Permalink
Wrote tests for image parsing methods + codestyle
Browse files Browse the repository at this point in the history
  • Loading branch information
ojustino committed Nov 15, 2022
1 parent c5a99b5 commit ce717f0
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 10 deletions.
1 change: 0 additions & 1 deletion specreduce/background.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import numpy as np
from astropy.nddata import NDData
from astropy.units import UnitTypeError
from astropy import units as u
from specutils import Spectrum1D

from specreduce.core import _ImageParser
Expand Down
2 changes: 1 addition & 1 deletion specreduce/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from astropy.modeling import Model, models, fitting
from astropy.nddata import NDData, VarianceUncertainty

from specreduce.core import _ImageParser, SpecreduceOperation
from specreduce.core import SpecreduceOperation
from specreduce.tracing import Trace, FlatTrace
from specutils import Spectrum1D

Expand Down
10 changes: 6 additions & 4 deletions specreduce/tests/test_background.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy as np

import astropy.units as u
from astropy.nddata import CCDData, VarianceUncertainty
from astropy.nddata import VarianceUncertainty
from specutils import Spectrum1D

from specreduce.background import Background
Expand Down Expand Up @@ -43,11 +43,13 @@ def test_background():
bg = Background(image, trace, width=bkg_width)

# test that image subtraction works
sub1 = image - bg1
# NOTE: uncomment sub1 test once Spectrum1D and Background subtraction works
# (meaning specutils PR #988 is merged, released, and pinned here)
# sub1 = image - bg1
sub2 = bg1.sub_image(image)
sub3 = bg1.sub_image()
assert np.allclose(sub1.flux, sub2.flux)
assert np.allclose(sub1.flux, sub3.flux)
# assert np.allclose(sub1.flux, sub2.flux)
assert np.allclose(sub2.flux, sub3.flux)

bkg_spec = bg1.bkg_spectrum()
assert isinstance(bkg_spec, Spectrum1D)
Expand Down
1 change: 0 additions & 1 deletion specreduce/tests/test_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ def test_horne_variance_errors():
# single negative value raises error
err = image.uncertainty.array
err[0][0] = -1
mask = np.zeros_like(image)
with pytest.raises(ValueError, match='variance must be fully positive'):
# remember variance, mask, and unit args are only checked if image
# object doesn't have those attributes (e.g., numpy and Quantity arrays)
Expand Down
104 changes: 104 additions & 0 deletions specreduce/tests/test_image_parsing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import numpy as np

from astropy import units as u
from astropy.io import fits
from astropy.nddata import CCDData, NDData, VarianceUncertainty
from astropy.utils.data import download_file

from specreduce.extract import HorneExtract
from specreduce.tracing import FlatTrace
from specutils import Spectrum1D, SpectralAxis

# fetch test image
fn = download_file('https://stsci.box.com/shared/static/exnkul627fcuhy5akf2gswytud5tazmw.fits',
cache=True)

# duplicate image in all accepted formats
# (one Spectrum1D variant has a physical spectral axis; the other is in pixels)
img = fits.getdata(fn).T
flux = img * u.MJy / u.sr
sax = SpectralAxis(np.linspace(14.377, 3.677, flux.shape[-1]) * u.um)
unc = VarianceUncertainty(np.random.rand(*flux.shape))

all_images = {}
all_images['arr'] = img
all_images['s1d'] = Spectrum1D(flux, spectral_axis=sax, uncertainty=unc)
all_images['s1d_pix'] = Spectrum1D(flux, uncertainty=unc)
all_images['ccd'] = CCDData(img, uncertainty=unc, unit=flux.unit)
all_images['ndd'] = NDData(img, uncertainty=unc, unit=flux.unit)
all_images['qnt'] = img * flux.unit

# save default values used for spectral axis and uncertainty when they are not
# available from the image object or provided by the user
sax_def = np.arange(img.shape[1]) * u.pix
unc_def = np.ones_like(img)


# (for use inside tests)
def compare_images(key, collection, compare='s1d'):
# was input converted to Spectrum1D?
assert isinstance(collection[key], Spectrum1D), (f"image '{key}' not "
"of type Spectrum1D")

# do key's fluxes match its comparison's fluxes?
assert np.allclose(collection[key].data,
collection[compare].data), (f"images '{key}' and "
f"'{compare}' have unequal "
"flux values")

# if the image came with a spectral axis, was it kept? if not, was the
# default spectral axis in pixels applied?
sax_provided = hasattr(all_images[key], 'spectral_axis')
assert np.allclose(collection[key].spectral_axis,
(all_images[key].spectral_axis if sax_provided
else sax_def)), (f"spectral axis of image '{key}' does "
f"not match {'input' if sax_provided else 'default'}")

# if the image came with an uncertainty, was it kept? if not, was the
# default uncertainty created?
unc_provided = hasattr(all_images[key], 'uncertainty')
assert np.allclose(collection[key].uncertainty.array,
(all_images[key].uncertainty.array if unc_provided
else unc_def)), (f"uncertainty of image '{key}' does "
f"not match {'input' if unc_provided else 'default'}")

# were masks created despite none being given? (all indices should be False)
assert (getattr(collection[key], 'mask', None)
is not None), f"no mask was created for image '{key}'"
assert np.all(collection[key].mask == 0), ("mask not all False "
f"for image '{key}'")


# test consistency of general image parser results
def test_parse_general():
all_images_parsed = {k: FlatTrace._parse_image(object, im)
for k, im in all_images.items()}

for key in all_images_parsed.keys():
compare_images(key, all_images_parsed)


# use verified general image parser results to check HorneExtract's image parser
def test_parse_horne():
# HorneExtract's parser is more stringent than the general one, hence the
# separate test. Given proper inputs, both should produce the same results.
images_collection = {k: {} for k in all_images.keys()}

for key, col in images_collection.items():
img = all_images[key]
col['general'] = FlatTrace._parse_image(object, img)

if hasattr(all_images[key], 'uncertainty'):
defaults = {}
else:
# save default values of attributes used in general parser when
# they are not available from the image object. HorneExtract always
# requires a variance, so it's chosen here to be on equal footing
# with the general case
defaults = {'variance': unc_def,
'mask': np.ma.masked_invalid(img).mask,
'unit': getattr(img, 'unit', u.DN)}

col[key] = HorneExtract._parse_image(object, img, **defaults)

compare_images(key, col, compare='general')
4 changes: 1 addition & 3 deletions specreduce/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
import warnings

from astropy.modeling import fitting, models
from astropy.nddata import NDData, VarianceUncertainty
from astropy.nddata import NDData
from astropy.stats import gaussian_sigma_to_fwhm
from astropy import units as u
from scipy.interpolate import UnivariateSpline
from specutils import Spectrum1D
import numpy as np

from specreduce.core import _ImageParser
Expand Down

0 comments on commit ce717f0

Please sign in to comment.