diff --git a/scopesim/effects/metis_lms_trace_list.py b/scopesim/effects/metis_lms_trace_list.py index cde712a0..8b616b94 100644 --- a/scopesim/effects/metis_lms_trace_list.py +++ b/scopesim/effects/metis_lms_trace_list.py @@ -1,5 +1,5 @@ """SpectralTraceList and SpectralTrace for the METIS LM spectrograph.""" -import copy + import warnings import numpy as np @@ -13,9 +13,9 @@ from ..utils import from_currsys, find_file, quantify, get_logger from .spectral_trace_list import SpectralTraceList -from .spectral_trace_list_utils import SpectralTrace -from .spectral_trace_list_utils import Transform2D -from .spectral_trace_list_utils import make_image_interpolations +from .spectral_trace_list_utils import (SpectralTrace, Transform2D, + make_image_interpolations, + SpecTraceError) from .apertures import ApertureMask from .ter_curves import TERCurve from ..base_classes import FieldOfViewBase, FOVSetupBase @@ -138,7 +138,11 @@ def apply_to(self, obj, **kwargs): slicefov.cube = fits.ImageHDU(header=slicewcs.to_header(), data=slicecube) # slicefov.cube.writeto(f"slicefov_{sptid}.fits", overwrite=True) - slicefov.hdu = spt.map_spectra_to_focal_plane(slicefov) + try: + slicefov.hdu = spt.map_spectra_to_focal_plane(slicefov) + except SpecTraceError as err: + logger.warning(err) + continue sxmin = slicefov.hdu.header["XMIN"] sxmax = slicefov.hdu.header["XMAX"] @@ -159,11 +163,12 @@ def make_spectral_traces(self): self.meta["angle"] = tempres["Angle"] spec_traces = {} - for sli in np.arange(self.meta["nslice"]): - slicename = "Slice " + str(sli + 1) + for sli in range(self.meta["nslice"]): + slicename = f"Slice {sli + 1}" spec_traces[slicename] = MetisLMSSpectralTrace( self._file, - spslice=sli, params=self.meta) + spslice=sli, + params=self.meta) self.spectral_traces = spec_traces @@ -223,10 +228,13 @@ 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, - wave_min=wave_min, wave_max=wave_max, - xi_min=xi_min, xi_max=xi_max, - bin_width=dwave) + try: + result = spt.rectify(hdulist, interps=interps, + wave_min=wave_min, wave_max=wave_max, + xi_min=xi_min, xi_max=xi_max, + bin_width=dwave) + except SpecTraceError as err: + logger.warning(err) cube[:, i, :] = result.data.T # FIXME: use wcs object here @@ -280,7 +288,7 @@ def __init__(self, hdulist, spslice, params, **kwargs): super().__init__(polyhdu, **params) self._file = hdulist - self.meta["description"] = "Slice " + str(spslice + 1) + self.meta["description"] = f"Slice {spslice + 1}" self.meta["trace_id"] = f"Slice {spslice + 1}" self.meta.update(params) # Provisional: @@ -307,8 +315,7 @@ def fov_grid(self): y_min = aperture["bottom"] y_max = aperture["top"] - filename_det_layout = from_currsys("!DET.layout.file_name", cmds=self.cmds) - layout = ioascii.read(find_file(filename_det_layout)) + layout = ioascii.read(find_file(self.cmds["!DET.layout.filename"])) det_lims = {} xhw = layout["pixel_size"] * layout["x_size"] / 2 yhw = layout["pixel_size"] * layout["y_size"] / 2 @@ -562,13 +569,10 @@ class MetisLMSEfficiency(TERCurve): } def __init__(self, **kwargs): - # TODO: Refactor these _class_params? - self.meta = copy.copy(self._class_params) - assert "grat_spacing" in self.meta, "grat_spacing is missing from self.meta 1" - super().__init__(**kwargs) - assert "grat_spacing" in self.meta, "grat_spacing is missing from self.meta 2" + self.meta = self._class_params + self.meta.update(kwargs) - filename = find_file(self.meta["filename"]) + filename = find_file(from_currsys(self.meta["filename"], kwargs.get("cmds"))) wcal = fits.getdata(filename, extname="WCAL") if "wavelen" in kwargs: wavelen = from_currsys(kwargs["wavelen"], kwargs.get("cmds")) @@ -580,6 +584,13 @@ def __init__(self, **kwargs): lam, efficiency = self.make_ter_curve(wcal, wavelen) + # HACK: Somehow we end up with duplicate keywords here. This hack + # should not be necessary at all! Investigate what's really + # going on... + self.meta.pop("wavelength", None) + self.meta.pop("transmission", None) + self.meta.pop("emissivity", None) + super().__init__(wavelength=lam, transmission=efficiency, emissivity=np.zeros_like(lam), diff --git a/scopesim/effects/spectral_trace_list_utils.py b/scopesim/effects/spectral_trace_list_utils.py index 849887b1..f93f8081 100644 --- a/scopesim/effects/spectral_trace_list_utils.py +++ b/scopesim/effects/spectral_trace_list_utils.py @@ -30,6 +30,26 @@ logger = get_logger(__name__) +class SpecTraceError(Exception): + """Base class for exceptions in this module.""" + + +class NoXlimError(SpecTraceError): + """Dunno.""" + + +class TraceOutsideFovError(SpecTraceError): + """The spectral trace falls outside the given FOV.""" + + +class OutsideFilterRangeError(SpecTraceError): + """Trace wavelength is not within filter waverange.""" + + +class KwNotFoundError(SpecTraceError): + """Required keyword for rectification was not found.""" + + class SpectralTrace: """Definition of one spectral trace. @@ -168,8 +188,7 @@ def map_spectra_to_focal_plane(self, fov): xi_min=xi_min, xi_max=xi_max) if xlim_mm is None: - logger.warning("xlim_mm is None") - return None + raise NoXlimError("xlim_mm is None") fov_header = fov.header det_header = fov.detector_header @@ -190,9 +209,8 @@ def map_spectra_to_focal_plane(self, fov): # Check if spectral trace footprint is outside FoV if xmax < 0 or xmin > naxis1d or ymax < 0 or ymin > naxis2d: - logger.info( - "Spectral trace %d: footprint is outside FoV", fov.trace_id) - return None + raise TraceOutsideFovError( + f"Spectral trace {fov.trace_id}: footprint is outside FoV") # Only work on parts within the FoV xmin = max(xmin, 0) @@ -222,7 +240,7 @@ def map_spectra_to_focal_plane(self, fov): xilam = XiLamImage(fov, self.dlam_per_pix) self._xilamimg = xilam # ..todo: remove or make available with a debug flag? except ValueError: - logger.warning(" ---> %d gave ValueError", self.trace_id) + logger.warning(" ---> %s gave ValueError", self.trace_id) npix_xi, npix_lam = xilam.npix_xi, xilam.npix_lam xilam_wcs = xilam.wcs @@ -323,8 +341,8 @@ def rectify(self, hdulist, interps=None, wcs=None, **kwargs): wave_max = kwargs.get("wave_max", self.wave_max) if wave_max < self.wave_min or wave_min > self.wave_max: - logger.info(" Outside filter range") - return None + raise OutsideFilterRangeError(" Outside filter range") + wave_min = max(wave_min, self.wave_min) wave_max = min(wave_max, self.wave_max) logger.info(" %.02f .. %.02f um", wave_min, wave_max) @@ -345,15 +363,14 @@ def rectify(self, hdulist, interps=None, wcs=None, **kwargs): try: xi_min = hdulist[0].header["HIERARCH INS SLIT XIMIN"] except KeyError: - logger.error("xi_min not found") - return None + raise KwNotFoundError("xi_min not found") + xi_max = kwargs.get("xi_max", None) if xi_max is None: try: xi_max = hdulist[0].header["HIERARCH INS SLIT XIMAX"] except KeyError: - logger.error("xi_max not found") - return None + raise KwNotFoundError("xi_max not found") if wcs is None: wcs = WCS(naxis=2) diff --git a/scopesim/optics/fov.py b/scopesim/optics/fov.py index 2d50aa8d..30efcc96 100644 --- a/scopesim/optics/fov.py +++ b/scopesim/optics/fov.py @@ -144,8 +144,9 @@ def extract_from(self, src): spec_refs.add(ref) waves = volume["waves"] * u.Unit(volume["wave_unit"]) - spectra = {ref: fu.extract_range_from_spectrum(src.spectra[ref], waves) - for ref in spec_refs} + spectra = {ref: fu.extract_range_from_spectrum( + src.spectra[int(ref)], waves) + for ref in spec_refs} self.fields = fields_in_fov self.spectra = spectra