From 60a191d210113f2ffc6b96b5c38d3439b60fcfa3 Mon Sep 17 00:00:00 2001 From: havok2063 Date: Wed, 29 Jul 2026 10:48:22 -0400 Subject: [PATCH 1/3] adding flag for returning model spectra for boss spec files --- specutils/io/default_loaders/sdss_v.py | 12 ++- .../io/default_loaders/tests/test_sdss_v.py | 75 ++++++++++++++----- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/specutils/io/default_loaders/sdss_v.py b/specutils/io/default_loaders/sdss_v.py index d3575f3d9..3aaec2250 100644 --- a/specutils/io/default_loaders/sdss_v.py +++ b/specutils/io/default_loaders/sdss_v.py @@ -481,7 +481,7 @@ def load_sdss_spec_list(file_obj, **kwargs): return SpectrumList(spectra) -def _load_BOSS_HDU(hdulist: HDUList, hdu: int, **kwargs): +def _load_BOSS_HDU(hdulist: HDUList, hdu: int, model: bool = False, **kwargs): """ HDU processor for BOSS spectra redux HDU's @@ -503,7 +503,14 @@ def _load_BOSS_HDU(hdulist: HDUList, hdu: int, **kwargs): flux_unit = Unit("1e-17 erg / (Angstrom cm2 s)") # NOTE: hardcoded unit spectral_axis = Quantity(10**hdulist[hdu].data["LOGLAM"], unit=Angstrom) - flux = Quantity(hdulist[hdu].data["FLUX"], unit=flux_unit) + if model and 'MODEL' not in hdulist[hdu].data.names: + raise ValueError(f"MODEL column not found in HDU{hdu}. Cannot load model spectrum.") + + if model: + # set the model spectrum as the "flux" ; until specutils supports models + flux = Quantity(hdulist[hdu].data["MODEL"], unit=flux_unit) + else: + flux = Quantity(hdulist[hdu].data["FLUX"], unit=flux_unit) # no e_flux, so we use inverse of variance ivar = InverseVariance(hdulist[hdu].data["IVAR"]) @@ -522,6 +529,7 @@ def _load_BOSS_HDU(hdulist: HDUList, hdu: int, **kwargs): meta = dict() meta["header"] = hdulist[0].header meta["name"] = hdulist[hdu].name + meta["is_model"] = model return Spectrum(spectral_axis=spectral_axis, flux=flux, diff --git a/specutils/io/default_loaders/tests/test_sdss_v.py b/specutils/io/default_loaders/tests/test_sdss_v.py index c14cf3568..4ba6b992b 100644 --- a/specutils/io/default_loaders/tests/test_sdss_v.py +++ b/specutils/io/default_loaders/tests/test_sdss_v.py @@ -420,7 +420,7 @@ def apVisit_HDUList(): return hdulist -def spec_HDUList(n_spectra): +def spec_HDUList(n_spectra, model=True): """Mock an BOSS spec HDUList of n_spectra spectra + 1 coadd.""" np.random.seed(20) @@ -437,10 +437,7 @@ def spec_HDUList(n_spectra): hdulist = fits.HDUList() hdulist.append(fits.PrimaryHDU(header=hdr)) - # Init the key HDU's (flux, error, bitmask, spectral) - names = ["COADD", "SPALL", "ZALL", "ZLINE"] - for i in range(4): - hdu = fits.BinTableHDU.from_columns([ + cols = [ fits.Column(name="FLUX", format="E", array=np.random.random(10)), fits.Column(name="LOGLAM", format="E", @@ -451,22 +448,42 @@ def spec_HDUList(n_spectra): array=np.random.random(10)), fits.Column(name="OR_MASK", format="E", array=np.random.random(10)), - ]) + ] + if model: + cols.append(fits.Column(name="MODEL", format="E", array=np.random.random(10))) + + # Init the key HDU's (flux, error, bitmask, spectral) + names = ["COADD", "SPALL", "ZALL", "ZLINE"] + for i in range(4): + # cols = [ + # fits.Column(name="FLUX", format="E", array=np.random.random(10)), + # fits.Column(name="LOGLAM", + # format="E", + # array=np.random.random(10).sort()), + # fits.Column(name="IVAR", format="E", array=np.random.random(10)), + # fits.Column(name="AND_MASK", + # format="E", + # array=np.random.random(10)), + # fits.Column(name="OR_MASK", format="E", + # array=np.random.random(10)), + # ] + hdu = fits.BinTableHDU.from_columns(cols) hdu.name = names[i] hdulist.append(hdu) for i in range(n_spectra): - hdu = fits.BinTableHDU.from_columns([ - fits.Column(name="LOGLAM", - format="E", - array=np.random.random(10).sort()), - fits.Column(name="FLUX", format="E", array=np.random.random(10)), - fits.Column(name="IVAR", format="E", array=np.random.random(10)), - fits.Column(name="AND_MASK", - format="E", - array=np.random.random(10)), - fits.Column(name="OR_MASK", format="E", - array=np.random.random(10)), - ]) + # hdu = fits.BinTableHDU.from_columns([ + # fits.Column(name="LOGLAM", + # format="E", + # array=np.random.random(10).sort()), + # fits.Column(name="FLUX", format="E", array=np.random.random(10)), + # fits.Column(name="IVAR", format="E", array=np.random.random(10)), + # fits.Column(name="AND_MASK", + # format="E", + # array=np.random.random(10)), + # fits.Column(name="OR_MASK", format="E", + # array=np.random.random(10)), + # ]) + hdu = fits.BinTableHDU.from_columns(cols) hdu.name = f"spectrum{i}" hdulist.append(hdu) @@ -937,6 +954,28 @@ def test_spec_1d_fail_hdu(file_obj, hdu): os.remove(tmpfile) +def test_spec_model(): + """Test if model spectrum can be loaded""" + tmpfile = "spec-temp.fits" + spec_HDUList(1, model=True).writeto(tmpfile, overwrite=True) + + flux = Spectrum.read(tmpfile, hdu=1, model=False) + model = Spectrum.read(tmpfile, hdu=1, model=True) + assert flux != model + assert flux.meta["is_model"] is False + assert model.meta["is_model"] is True + os.remove(tmpfile) + +def test_spec_model_fail(): + """Test if model spectrum can be loaded""" + tmpfile = "spec-temp.fits" + spec_HDUList(1, model=False).writeto(tmpfile, overwrite=True) + + with pytest.raises(ValueError, match='MODEL column not found in HDU'): + Spectrum.read(tmpfile, hdu=1, model=True) + os.remove(tmpfile) + + @pytest.mark.parametrize( "file_obj,idx", [ From dd82745c7b7bbeefcd56868aef61dea0ff7cb721 Mon Sep 17 00:00:00 2001 From: havok2063 Date: Wed, 29 Jul 2026 10:55:33 -0400 Subject: [PATCH 2/3] cleanup --- .../io/default_loaders/tests/test_sdss_v.py | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/specutils/io/default_loaders/tests/test_sdss_v.py b/specutils/io/default_loaders/tests/test_sdss_v.py index 4ba6b992b..7a1d251c2 100644 --- a/specutils/io/default_loaders/tests/test_sdss_v.py +++ b/specutils/io/default_loaders/tests/test_sdss_v.py @@ -455,34 +455,10 @@ def spec_HDUList(n_spectra, model=True): # Init the key HDU's (flux, error, bitmask, spectral) names = ["COADD", "SPALL", "ZALL", "ZLINE"] for i in range(4): - # cols = [ - # fits.Column(name="FLUX", format="E", array=np.random.random(10)), - # fits.Column(name="LOGLAM", - # format="E", - # array=np.random.random(10).sort()), - # fits.Column(name="IVAR", format="E", array=np.random.random(10)), - # fits.Column(name="AND_MASK", - # format="E", - # array=np.random.random(10)), - # fits.Column(name="OR_MASK", format="E", - # array=np.random.random(10)), - # ] hdu = fits.BinTableHDU.from_columns(cols) hdu.name = names[i] hdulist.append(hdu) for i in range(n_spectra): - # hdu = fits.BinTableHDU.from_columns([ - # fits.Column(name="LOGLAM", - # format="E", - # array=np.random.random(10).sort()), - # fits.Column(name="FLUX", format="E", array=np.random.random(10)), - # fits.Column(name="IVAR", format="E", array=np.random.random(10)), - # fits.Column(name="AND_MASK", - # format="E", - # array=np.random.random(10)), - # fits.Column(name="OR_MASK", format="E", - # array=np.random.random(10)), - # ]) hdu = fits.BinTableHDU.from_columns(cols) hdu.name = f"spectrum{i}" hdulist.append(hdu) From 6ce93dea603a45fec133cafad65bb81e325de0c2 Mon Sep 17 00:00:00 2001 From: havok2063 Date: Wed, 29 Jul 2026 10:56:54 -0400 Subject: [PATCH 3/3] cleanup --- specutils/io/default_loaders/tests/test_sdss_v.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specutils/io/default_loaders/tests/test_sdss_v.py b/specutils/io/default_loaders/tests/test_sdss_v.py index 7a1d251c2..8edf3b192 100644 --- a/specutils/io/default_loaders/tests/test_sdss_v.py +++ b/specutils/io/default_loaders/tests/test_sdss_v.py @@ -943,7 +943,7 @@ def test_spec_model(): os.remove(tmpfile) def test_spec_model_fail(): - """Test if model spectrum can be loaded""" + """Test if model spectrum is not available """ tmpfile = "spec-temp.fits" spec_HDUList(1, model=False).writeto(tmpfile, overwrite=True)