Skip to content
Open
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
3 changes: 2 additions & 1 deletion scopesim/effects/metis_lms_trace_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def rectify_cube(self, hdulist, xi_min=None, xi_max=None, interps=None,
for i, spt in enumerate(self.spectral_traces.values()):
spt.wave_min = wave_min
spt.wave_max = wave_max
result = spt.rectify(hdulist, interps=interps,
result = spt.rectify(inhdul, interps=interps,
wave_min=wave_min, wave_max=wave_max,
xi_min=xi_min, xi_max=xi_max,
bin_width=dwave,
Expand Down Expand Up @@ -301,6 +301,7 @@ class MetisLMSSpectralTrace(SpectralTrace):

def __init__(self, hdulist, spslice, params, **kwargs):
polyhdu = hdulist["Polynomial coefficients"]
params = dict(params) # do not modify the caller's dictionary
params.update(kwargs)
params["aperture_id"] = spslice
params["slice"] = spslice
Expand Down
4 changes: 2 additions & 2 deletions scopesim/effects/spectral_trace_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ def rectify_traces(self, hdulist, xi_min=None, xi_max=None, interps=None,

if interps is None:
logger.debug("Computing interpolation functions")
interps = make_image_interpolations(hdulist)
interps = make_image_interpolations(inhdul)

pdu = fits.PrimaryHDU()
pdu.header["FILETYPE"] = "Rectified spectra"
Expand All @@ -358,7 +358,7 @@ def rectify_traces(self, hdulist, xi_min=None, xi_max=None, interps=None,

for i, trace_id in tqdm(enumerate(self.spectral_traces, start=1),
desc=" Traces", total=len(self.spectral_traces)):
hdu = self[trace_id].rectify(hdulist,
hdu = self[trace_id].rectify(inhdul,
interps=interps,
bin_width=bin_width,
xi_min=xi_min, xi_max=xi_max,
Expand Down
1 change: 1 addition & 0 deletions scopesim/effects/spectral_trace_list_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ def map_spectra_to_focal_plane(self, fov):
self._xilamimg = xilam # ..todo: remove or make available with a debug flag?
except ValueError:
logger.warning(" ---> %s gave ValueError", self.trace_id)
return None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was a debugging thing. The idea was to see all cases where a trace gave a ValueError. If we want to finish on the first one, we can simply remove the try...except.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be happy with simply removing the try/except, as that forces it to fail loudly... right?


npix_xi, npix_lam = xilam.npix_xi, xilam.npix_lam
xilam_wcs = xilam.wcs
Expand Down
24 changes: 23 additions & 1 deletion scopesim/tests/tests_effects/test_MetisLMSTraceList.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import pytest
from numpy.testing import assert_allclose
from astropy.io import fits
from scopesim.effects.metis_lms_trace_list import predisperser_angle
from scopesim.effects.metis_lms_trace_list import (predisperser_angle,
echelle_setting,
MetisLMSSpectralTrace)


# pylint: disable=missing-class-docstring
Expand Down Expand Up @@ -38,6 +40,26 @@ def counting_read(*args, **kwargs):
assert first is second
mlt._read_detector_layout.cache_clear()

class TestMetisLMSSpectralTraceInit:
def test_does_not_mutate_caller_params(self, mock_dir, monkeypatch):
"""The params dict is passed by reference from the trace list's
self.meta; the trace previously wrote its slice-specific values
(slice, aperture_id, ...) back into it."""
monkeypatch.setattr(MetisLMSSpectralTrace, "fov_grid",
lambda self: {})

with fits.open(mock_dir / "METIS_LMS/TRACE_LMS.fits") as hdul:
ech = echelle_setting(4.2, 18.2, hdul["WCAL"].data)
params = {"order": ech["Ord"], "echelle": ech["Echelle"],
"wavelen": 4.2}
snapshot = dict(params)

trace = MetisLMSSpectralTrace(hdul, spslice=0, params=params)

assert params == snapshot, \
"constructor modified the caller's params dict"
assert trace.meta["slice"] == 0
assert trace.meta["aperture_id"] == 0


@pytest.mark.usefixtures("patch_mock_path_metis")
Expand Down
43 changes: 43 additions & 0 deletions scopesim/tests/tests_effects/test_SpectralTraceList.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,49 @@ def fixture_spectral_trace_list():
# spectral_trace_list.rectify_traces(hdulist)


class TestRectifyTracesInput:
def test_rectify_traces_opens_filename_before_use(
self, spectral_trace_list, tmp_path, monkeypatch):
"""rectify_traces accepts a filename, but passed the raw string on
to make_image_interpolations and SpectralTrace.rectify instead of
the opened HDUList."""
import numpy as np
from astropy.table import Table
from scopesim.effects import spectral_trace_list as stl_mod

readout = tmp_path / "readout.fits"
fits.HDUList([fits.PrimaryHDU(),
fits.ImageHDU(data=np.zeros((10, 10)))]
).writeto(readout)

# Stub the filter lookup; it needs a fully configured instrument
class FakeFilterCurve:
table = Table(data=[[1.0, 2.0], [1.0, 1.0]],
names=["wavelength", "transmission"])

monkeypatch.setattr(stl_mod, "FilterCurve",
lambda **kwargs: FakeFilterCurve())
monkeypatch.setattr(stl_mod, "from_currsys",
lambda *args, **kwargs: "J")

# Record what object each trace's rectify() receives
received = []

def fake_rectify(self, hdulist, **kwargs):
received.append(hdulist)
return None

monkeypatch.setattr(SpectralTrace, "rectify", fake_rectify)

result = spectral_trace_list.rectify_traces(
str(readout), xi_min=-1, xi_max=1)

assert isinstance(result, fits.HDUList)
assert received, "rectify() was never called"
assert all(isinstance(hdul, fits.HDUList) for hdul in received), \
"traces received the filename string, not the opened HDUList"


class TestSpectralTraceListWheel:
@pytest.mark.usefixtures("no_file_error")
def test_basic_init(self):
Expand Down
26 changes: 26 additions & 0 deletions scopesim/tests/tests_effects/test_SpectralTraceListUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,32 @@ def test_grid_false_shape_is_preserved(self, tf2d):
assert res.shape == (n_y, n_x)


class TestMapSpectraErrorPath:
def test_returns_none_when_xilamimage_fails(self, monkeypatch):
"""A ValueError from XiLamImage was logged but then the unbound
variable was used anyway, raising NameError instead."""
from scopesim.effects import spectral_trace_list_utils as stlu_mod
from scopesim.tests.mocks.py_objects import header_objects as ho

class FailingXiLamImage:
def __init__(self, *args, **kwargs):
raise ValueError("simulated failure")

monkeypatch.setattr(stlu_mod, "XiLamImage", FailingXiLamImage)

spt = SpectralTrace(tlo.trace_1(), trace_id="TRACE_1",
pixel_scale=0.004, plate_scale=0.266)

class FakeFov:
header = ho._basic_fov_header()
detector_header = header
trace_id = "TRACE_1"
meta = {"wave_min": 1.2 * u.um, "wave_max": 2.4 * u.um,
"xi_min": -1.5 * u.arcsec, "xi_max": 1.5 * u.arcsec}

assert spt.map_spectra_to_focal_plane(FakeFov()) is None


class MockCubeFov:
"""Minimal stand-in for a FieldOfView carrying a spectral cube."""
def __init__(self, n_lam=20, n_eta=3, n_xi=11):
Expand Down