Skip to content

Commit

Permalink
Add SAMI loaders for testing updated DC loaders
Browse files Browse the repository at this point in the history
This adds an initial version of the future SAMI loaders, in order to
test the changes to the lower level DC loaders.
  • Loading branch information
aragilar committed Mar 14, 2024
1 parent dbe14cf commit 9418b23
Show file tree
Hide file tree
Showing 2 changed files with 225 additions and 0 deletions.
185 changes: 185 additions & 0 deletions specutils/io/default_loaders/sami.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
from astropy.nddata import VarianceUncertainty
from astropy.table import QTable
from specutils import SpectrumList
from specutils.io.default_loaders.dc_common import (
FITS_FILE_EXTS, add_single_spectra_to_map,
)
from specutils.io.parsing_utils import read_fileobj_or_hdulist
from specutils.io.registers import data_loader

# There appears to be nothing which says "this is a SAMI 1D spectra", so guess
# it based on the headers that should be there
SAMI_1D_SPECTRA_HEADER_KEYWORDS = [
"BUNIT", "CATADEC", "CATARA", "CDELT1", "CRPIX1", "CRVAL1", "CTYPE1",
"CUNIT1", "DROPFACT", "ELLIP", "GRATID", "IFUPROBE", "KPC_SIZE", "NAME",
"N_SPAX", "POS_ANG", "PSFALPHA", "PSFBETA", "PSFFWHM", "RADESYS", "RADIUS",
"RO_GAIN", "RO_NOISE", "STDNAME", "WCSAXES", "Z_TONRY",
]


def identify_sami_cube(origin, *args, **kwargs):
"""
Identify if the current file is a SAMI cube file
"""
# TODO check this
with read_fileobj_or_hdulist(*args, **kwargs) as hdulist:
header = hdulist[0].header
data = hdulist[0].data
if "SAMI" in header.get("INSTRUME", "") and len(data.shape) == 3:
return True

Check warning on line 29 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L29

Added line #L29 was not covered by tests
return False


def identify_sami_1d_spec(origin, *args, **kwargs):
"""
Identify if the current file is a SAMI 1d spectra file of some kind
"""
# TODO check this
with read_fileobj_or_hdulist(*args, **kwargs) as hdulist:
header = hdulist[0].header
for key in SAMI_1D_SPECTRA_HEADER_KEYWORDS:
if key not in header:
return False
return True

Check warning on line 43 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L43

Added line #L43 was not covered by tests


@data_loader(
label="SAMI-cube", extensions=FITS_FILE_EXTS, dtype=SpectrumList,
identifier=identify_sami_cube, priority=10,
)
def sami_cube_loader(filename):
spectra_map = {

Check warning on line 51 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L51

Added line #L51 was not covered by tests
"sky": [],
"combined": [],
"unreduced": [],
"reduced": [],
}
primary_header = None

Check warning on line 57 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L57

Added line #L57 was not covered by tests

with read_fileobj_or_hdulist(filename) as hdulist:
for i, hdu in enumerate(hdulist):
if i == 0:

Check warning on line 61 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L59-L61

Added lines #L59 - L61 were not covered by tests
# This is the primary extension, and the one with the
# science data. The header is fairly complete.
primary_header = hdu.header
spec = add_single_spectra_to_map(

Check warning on line 65 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L64-L65

Added lines #L64 - L65 were not covered by tests
spectra_map,
header=primary_header,
data=hdu.data,
index=None,
all_standard_units=True,
all_keywords=True,
valid_wcs=True,
)

elif "VARIANCE" == hdu.header.get("EXTNAME"):

Check warning on line 75 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L75

Added line #L75 was not covered by tests
# This is the variance extension, and is missing wcs and
# units.
uncertainty = VarianceUncertainty(

Check warning on line 78 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L78

Added line #L78 was not covered by tests
hdu.data, unit=spec.flux.unit ** 2
)
spec.uncertainty = uncertainty

Check warning on line 81 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L81

Added line #L81 was not covered by tests

elif "WEIGHT" == hdu.header.get("EXTNAME"):

Check warning on line 83 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L83

Added line #L83 was not covered by tests
# This is the weight extension, and is missing wcs. The
# units are effectively "normalised" (from 0-1 it seems).
spec.meta["sami_cube_weight_map"] = hdu.data

Check warning on line 86 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L86

Added line #L86 was not covered by tests

elif "COVAR" == hdu.header.get("EXTNAME"):

Check warning on line 88 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L88

Added line #L88 was not covered by tests
# This is the spatial covariance extension. It's not clear
# as to how best to expose this, so skipping for now.
pass

Check warning on line 91 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L91

Added line #L91 was not covered by tests

elif "QC" == hdu.header.get("EXTNAME"):

Check warning on line 93 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L93

Added line #L93 was not covered by tests
# This is the QC extension, and is a binary table. This we
# add to the metadata.
spec.meta["sami_QC_table"] = QTable.read(hdu)

Check warning on line 96 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L96

Added line #L96 was not covered by tests

elif "DUST" == hdu.header.get("EXTNAME"):

Check warning on line 98 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L98

Added line #L98 was not covered by tests
# This is the dust extension, and is missing wcs and
# units. This should likely be represented as an array plus
# the metadata in the header.
spec.meta["sami_dust_vector_weights"] = hdu.data

Check warning on line 102 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L102

Added line #L102 was not covered by tests

elif "BIN_MASK" == hdu.header.get("EXTNAME"):

Check warning on line 104 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L104

Added line #L104 was not covered by tests
# This is the bin mask extension, where the value of each
# pixel indicates the bin to which it belongs. The bin mask
# is used to construct the binned fluxes and variances in
# the above two extensions from the default cubes.
# This is not the same as the aperture spectra mask with the
# same HDU name.
spec.meta["sami_bin_mask"] = hdu.data

Check warning on line 111 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L111

Added line #L111 was not covered by tests

else:
raise NotImplementedError(

Check warning on line 114 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L114

Added line #L114 was not covered by tests
"Extension is not handled: index {}; name {}".format(
i, hdu.header.get("EXTNAME")
)
)

spectra = SpectrumList(

Check warning on line 120 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L120

Added line #L120 was not covered by tests
spectra_map["combined"] +
spectra_map["reduced"] +
spectra_map["unreduced"] +
spectra_map["sky"]
)
return spectra

Check warning on line 126 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L126

Added line #L126 was not covered by tests


@data_loader(
label="SAMI-1d-spec", extensions=FITS_FILE_EXTS, dtype=SpectrumList,
identifier=identify_sami_1d_spec, priority=10,
)
def sami_1d_spec_loader(filename):
spectra_map = {

Check warning on line 134 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L134

Added line #L134 was not covered by tests
"sky": [],
"combined": [],
"unreduced": [],
"reduced": [],
}
primary_header = None

Check warning on line 140 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L140

Added line #L140 was not covered by tests

with read_fileobj_or_hdulist(filename) as hdulist:
for i, hdu in enumerate(hdulist):
if i == 0:

Check warning on line 144 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L142-L144

Added lines #L142 - L144 were not covered by tests
# This is the primary extension, and the one with the
# science data. The header is fairly complete.
primary_header = hdu.header
spec = add_single_spectra_to_map(

Check warning on line 148 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L147-L148

Added lines #L147 - L148 were not covered by tests
spectra_map,
header=primary_header,
data=hdu.data,
index=None,
all_standard_units=True,
all_keywords=True,
valid_wcs=True,
)

elif "VARIANCE" == hdu.header.get("EXTNAME"):

Check warning on line 158 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L158

Added line #L158 was not covered by tests
# This is the variance extension, and is missing wcs and
# units.
uncertainty = VarianceUncertainty(

Check warning on line 161 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L161

Added line #L161 was not covered by tests
hdu.data, unit=spec.flux.unit ** 2
)
spec.uncertainty = uncertainty

Check warning on line 164 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L164

Added line #L164 was not covered by tests

elif "BIN_MASK" == hdu.header.get("EXTNAME"):

Check warning on line 166 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L166

Added line #L166 was not covered by tests
# Contains the bin mask used to construct the aperture
# spectra. A 1 indicates a spaxel was included in the
# aperture, a 0 indicates a spaxel was not included.
spec.meta["sami_aperture_spectra_mask"] = hdu.data

Check warning on line 170 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L170

Added line #L170 was not covered by tests

else:
raise NotImplementedError(

Check warning on line 173 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L173

Added line #L173 was not covered by tests
"Extension is not handled: index {}; name {}".format(
i, hdu.header.get("EXTNAME")
)
)

spectra = SpectrumList(

Check warning on line 179 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L179

Added line #L179 was not covered by tests
spectra_map["combined"] +
spectra_map["reduced"] +
spectra_map["unreduced"] +
spectra_map["sky"]
)
return spectra

Check warning on line 185 in specutils/io/default_loaders/sami.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/sami.py#L185

Added line #L185 was not covered by tests
40 changes: 40 additions & 0 deletions specutils/tests/test_loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -1740,3 +1740,43 @@ def test_jwst_niriss_c1d_v1_2_3(remote_data_path):
[assert_multi_equals(d.shape, r) for d,r in zip(data, [(56,), (107,)])]
[assert_multi_equals(d.unit, u.Jy) for d in data]
[assert_multi_equals(d.spectral_axis.unit, u.um) for d in data]


class TestSAMI:
@remote_access([
{'id': "10802828", 'filename':"24433_A_adaptive_blue.fits.gz"},
{'id': "10802828", 'filename':"24433_A_adaptive_red.fits.gz"},
{'id': "10802828", 'filename':"24433_A_annular_blue.fits.gz"},
{'id': "10802828", 'filename':"24433_A_annular_red.fits.gz"},
{'id': "10802828", 'filename':"24433_A_cube_blue.fits.gz"},
{'id': "10802828", 'filename':"24433_A_cube_red.fits.gz"},
{'id': "10802828", 'filename':"24433_adaptive_blue.fits.gz"},
{'id': "10802828", 'filename':"24433_adaptive_red.fits.gz"},
{'id': "10802828", 'filename':"24433_spectrum_1-4-arcsec_blue.fits"},
{'id': "10802828", 'filename':"24433_spectrum_1-4-arcsec_red.fits"},
{'id': "10802828", 'filename':"24433_spectrum_2-arcsec_blue.fits"},
{'id': "10802828", 'filename':"24433_spectrum_2-arcsec_red.fits"},
{'id': "10802828", 'filename':"24433_spectrum_3-arcsec_blue.fits"},
{'id': "10802828", 'filename':"24433_spectrum_3-arcsec_red.fits"},
{'id': "10802828", 'filename':"24433_spectrum_3-kpc_blue.fits"},
{'id': "10802828", 'filename':"24433_spectrum_3-kpc_red.fits"},
{'id': "10802828", 'filename':"24433_spectrum_4-arcsec_blue.fits"},
{'id': "10802828", 'filename':"24433_spectrum_4-arcsec_red.fits"},
{'id': "10802828", 'filename':"24433_spectrum_re_blue.fits"},
{'id': "10802828", 'filename':"24433_spectrum_re_red.fits"},
])
def test_sami_guess(self, remote_data_path):
spectra = SpectrumList.read(remote_data_path)
assert len(spectra) == 1

spec = spectra[0]
assert isinstance(spec.uncertainty, VarianceUncertainty)
assert spec.flux.unit == u.Unit('10**(-16) erg/s/cm**2/angstrom/pixel')

if len(spec.flux.shape) == 3:
# This is a cube
assert spec.flux.shape == (50, 50, 2048)

else:
# This is a 1D spectrum
assert spec.flux.shape == (2048,)

0 comments on commit 9418b23

Please sign in to comment.