From 24fa5937e098ae091c39fd3fb6eebdda1052e7cd Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Mon, 26 Feb 2024 22:06:18 +0100 Subject: [PATCH 01/11] Changes required to not use usercommands as currsys --- scopesim/effects/fits_headers.py | 6 +++--- scopesim/optics/fov_manager.py | 9 +++++++-- scopesim/tests/tests_effects/test_fits_headers.py | 9 +++++---- scopesim/tests/tests_optics/test_OpticalTrain.py | 4 +++- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/scopesim/effects/fits_headers.py b/scopesim/effects/fits_headers.py index 7fbd37ab..984716f5 100644 --- a/scopesim/effects/fits_headers.py +++ b/scopesim/effects/fits_headers.py @@ -425,7 +425,7 @@ class EffectsMetaKeywords(ExtraFitsKeywords): """ def __init__(self, cmds=None, **kwargs): - super(ExtraFitsKeywords, self).__init__() + super(ExtraFitsKeywords, self).__init__(cmds=cmds, **kwargs) params = {"name": "effects_fits_keywords", "description": "Effect Meta FITS headers", "z_order": [998], @@ -512,7 +512,7 @@ class SourceDescriptionFitsKeywords(ExtraFitsKeywords): """ def __init__(self, cmds=None, **kwargs): - super(ExtraFitsKeywords, self).__init__() + super(ExtraFitsKeywords, self).__init__(cmds=cmds, **kwargs) params = {"name": "source_fits_keywords", "description": "Source description FITS headers", "z_order": [997], @@ -596,7 +596,7 @@ class SimulationConfigFitsKeywords(ExtraFitsKeywords): """ def __init__(self, cmds=None, **kwargs): - super(ExtraFitsKeywords, self).__init__() + super(ExtraFitsKeywords, self).__init__(cmds=cmds, **kwargs) params = {"name": "simulation_fits_keywords", "description": "Simulation Config FITS headers", "z_order": [996], diff --git a/scopesim/optics/fov_manager.py b/scopesim/optics/fov_manager.py index 04942a29..fa5c86b0 100644 --- a/scopesim/optics/fov_manager.py +++ b/scopesim/optics/fov_manager.py @@ -166,8 +166,13 @@ def generate_fovs_list(self): det_eff = eu.get_all_effects(self.effects, DetectorList)[0] dethdr = det_eff.image_plane_header - fovs.append(FieldOfView(skyhdr, waverange, detector_header=dethdr, - **vol["meta"])) + fovs.append(FieldOfView( + skyhdr, + waverange, + detector_header=dethdr, + cmds=self.cmds, + **vol["meta"], + )) return fovs diff --git a/scopesim/tests/tests_effects/test_fits_headers.py b/scopesim/tests/tests_effects/test_fits_headers.py index d74dcd8c..21c3197a 100644 --- a/scopesim/tests/tests_effects/test_fits_headers.py +++ b/scopesim/tests/tests_effects/test_fits_headers.py @@ -301,10 +301,11 @@ def test_works(self, simplecado_opt): } } } - extra_keys = fh.ExtraFitsKeywords(header_dict=hdr_dic) - opt_keys = fh.EffectsMetaKeywords() - src_keys = fh.SourceDescriptionFitsKeywords() - config_keys = fh.SimulationConfigFitsKeywords() + cmds = simplecado_opt.cmds + extra_keys = fh.ExtraFitsKeywords(header_dict=hdr_dic, cmds=cmds) + opt_keys = fh.EffectsMetaKeywords(cmds=cmds) + src_keys = fh.SourceDescriptionFitsKeywords(cmds=cmds) + config_keys = fh.SimulationConfigFitsKeywords(cmds=cmds) for eff in [src_keys, opt_keys, config_keys, extra_keys]: simplecado_opt.optics_manager.add_effect(eff) diff --git a/scopesim/tests/tests_optics/test_OpticalTrain.py b/scopesim/tests/tests_optics/test_OpticalTrain.py index 9c4583c8..612aa508 100644 --- a/scopesim/tests/tests_optics/test_OpticalTrain.py +++ b/scopesim/tests/tests_optics/test_OpticalTrain.py @@ -77,6 +77,7 @@ def simplecado_opt(mock_path_yamls): return sim.OpticalTrain(cmd) +@pytest.mark.usefixtures("patch_mock_path") class TestInit: def test_initialises_with_nothing(self): assert isinstance(OpticalTrain(), OpticalTrain) @@ -294,7 +295,8 @@ def test_files_closed_on_shutdown(self, simplecado_opt, mock_path): # Add an effect with a psf with patch("scopesim.rc.__search_path__", [mock_path]): psf = sim.effects.FieldConstantPSF(filename="test_ConstPSF.fits", - name="testpsf") + name="testpsf", + cmds=simplecado_opt.cmds) simplecado_opt.optics_manager.add_effect(psf) # This is just to make sure that we have an open file assert not simplecado_opt['testpsf']._file._file.closed From 1ea8ae1ff59414c31e06fcb0bed707df166a707d Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Mon, 26 Feb 2024 22:06:41 +0100 Subject: [PATCH 02/11] Actually commenting out setting user commands as currsys --- scopesim/optics/optical_train.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scopesim/optics/optical_train.py b/scopesim/optics/optical_train.py index b2d250e8..b8169891 100644 --- a/scopesim/optics/optical_train.py +++ b/scopesim/optics/optical_train.py @@ -139,7 +139,10 @@ def load(self, user_commands): # UserCommands via rc.__currsys__, but on the other hand some # tests (now with proper patching) fail because of this type # change. THIS IS A PROBLEM! - rc.__currsys__ = user_commands + # NOTE: All tests pass without setting rc.__currsys__ to user_commands. + # Nevertheless, I'm a bit reluctant to removing this code just + # yet. So it is commented out. + # rc.__currsys__ = user_commands self.yaml_dicts = self.cmds.yaml_dicts self.optics_manager = OpticsManager(self.yaml_dicts, self.cmds) self.update() From d6b666ea6bd9610cc78392a6f49600945e7199e6 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Mon, 26 Feb 2024 23:06:49 +0100 Subject: [PATCH 03/11] Fix from_currsys recursion --- scopesim/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scopesim/utils.py b/scopesim/utils.py index 5989b796..a4c8e578 100644 --- a/scopesim/utils.py +++ b/scopesim/utils.py @@ -877,7 +877,7 @@ def from_currsys(item, cmds=None): if item in cmds: item = cmds[item] if isinstance(item, str) and item.startswith("!"): - item = from_currsys(item) + item = from_currsys(item, cmds=cmds) else: raise ValueError(f"{item} was not found in rc.__currsys__") From edb9caedbbfbbf49fcaa11f39a35e55d6c379ddd Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Mon, 26 Feb 2024 23:17:23 +0100 Subject: [PATCH 04/11] Another one --- scopesim/effects/ter_curves.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scopesim/effects/ter_curves.py b/scopesim/effects/ter_curves.py index 340d9931..5ce2e414 100644 --- a/scopesim/effects/ter_curves.py +++ b/scopesim/effects/ter_curves.py @@ -918,6 +918,7 @@ def __init__(self, cmds=None, **kwargs): for name in from_currsys(self.meta["adc_names"], cmds=self.cmds): kwargs["name"] = name self.adcs[name] = TERCurve(filename=str(path).format(name), + cmds=cmds, **kwargs) self.table = self.get_table() From aec9895af2cff832b9e8ffa011b419c6b8394dd6 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Mon, 26 Feb 2024 23:17:39 +0100 Subject: [PATCH 05/11] Fix AutoExposure and DetectorModePropertiesSetter --- scopesim/effects/electronic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scopesim/effects/electronic.py b/scopesim/effects/electronic.py index 7405dfea..1076787d 100644 --- a/scopesim/effects/electronic.py +++ b/scopesim/effects/electronic.py @@ -105,9 +105,9 @@ def apply_to(self, obj, **kwargs): self.meta["detector_readout_mode"] = mode_name props_dict = self.mode_properties[mode_name] - rc.__currsys__["!OBS.detector_readout_mode"] = mode_name + self.cmds["!OBS.detector_readout_mode"] = mode_name for key, value in props_dict.items(): - rc.__currsys__[key] = value + self.cmds[key] = value return obj @@ -226,8 +226,8 @@ def apply_to(self, obj, **kwargs): logger.info("Exposure parameters: DIT=%.3f s NDIT=%d", dit, ndit) logger.info("Total exposure time: %.3f s", dit * ndit) - rc.__currsys__["!OBS.dit"] = dit - rc.__currsys__["!OBS.ndit"] = ndit + self.cmds["!OBS.dit"] = dit + self.cmds["!OBS.ndit"] = ndit return obj From 2fd8967a7165afa6e8e39dd7820b440e7f09e2e8 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Mon, 26 Feb 2024 23:28:27 +0100 Subject: [PATCH 06/11] Another one --- scopesim/effects/ter_curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scopesim/effects/ter_curves.py b/scopesim/effects/ter_curves.py index 5ce2e414..fd4f2c9e 100644 --- a/scopesim/effects/ter_curves.py +++ b/scopesim/effects/ter_curves.py @@ -89,7 +89,7 @@ def __init__(self, filename=None, **kwargs): self.meta.update(params) self.meta.update(kwargs) - self.surface = SpectralSurface() + self.surface = SpectralSurface(cmds=self.cmds) self.surface.meta.update(self.meta) self._background_source = None From 3bc87a55a1906ccbc177f760f735812f50b899b3 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Tue, 27 Feb 2024 01:08:14 +0100 Subject: [PATCH 07/11] Use a default for self.cmds, e.g. for AutoExposure --- scopesim/effects/data_container.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scopesim/effects/data_container.py b/scopesim/effects/data_container.py index 50c999da..1312adcf 100644 --- a/scopesim/effects/data_container.py +++ b/scopesim/effects/data_container.py @@ -64,7 +64,12 @@ class DataContainer: def __init__(self, filename=None, table=None, array_dict=None, cmds=None, **kwargs): + self.cmds = cmds + if self.cmds is None: + from scopesim import UserCommands + self.cmds = UserCommands() + if filename is None and "file_name" in kwargs: warn("The 'file_name' kwarg is deprecated and will raise an error " "in the future, please use 'filename' instead!", From c48f769f63057ea3c2bbc22790b58e23a64ae7e2 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Tue, 27 Feb 2024 01:13:14 +0100 Subject: [PATCH 08/11] Fix setting default for cmds --- scopesim/effects/data_container.py | 8 +++++--- scopesim/effects/electronic.py | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/scopesim/effects/data_container.py b/scopesim/effects/data_container.py index 1312adcf..5b000258 100644 --- a/scopesim/effects/data_container.py +++ b/scopesim/effects/data_container.py @@ -66,9 +66,11 @@ def __init__(self, filename=None, table=None, array_dict=None, cmds=None, **kwargs): self.cmds = cmds - if self.cmds is None: - from scopesim import UserCommands - self.cmds = UserCommands() + # Setting a default for cmds cannot be done here, because from_currsys + # checks whether cmds is None. TODO: make this possible. + # if self.cmds is None: + # from scopesim import UserCommands + # self.cmds = UserCommands() if filename is None and "file_name" in kwargs: warn("The 'file_name' kwarg is deprecated and will raise an error " diff --git a/scopesim/effects/electronic.py b/scopesim/effects/electronic.py index 1076787d..d87a7949 100644 --- a/scopesim/effects/electronic.py +++ b/scopesim/effects/electronic.py @@ -226,6 +226,10 @@ def apply_to(self, obj, **kwargs): logger.info("Exposure parameters: DIT=%.3f s NDIT=%d", dit, ndit) logger.info("Total exposure time: %.3f s", dit * ndit) + if self.cmds is None: + from scopesim import UserCommands + self.cmds = UserCommands() + self.cmds["!OBS.dit"] = dit self.cmds["!OBS.ndit"] = ndit From 968d31034f13dcab02cf3655a0bf52699bdc9af5 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Tue, 27 Feb 2024 01:13:45 +0100 Subject: [PATCH 09/11] Workaround for autoexposure tests --- .../tests/tests_effects/test_AutoExposure.py | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/scopesim/tests/tests_effects/test_AutoExposure.py b/scopesim/tests/tests_effects/test_AutoExposure.py index 2eeb60aa..ffa93c3f 100644 --- a/scopesim/tests/tests_effects/test_AutoExposure.py +++ b/scopesim/tests/tests_effects/test_AutoExposure.py @@ -6,7 +6,6 @@ from scopesim import UserCommands from scopesim.optics.image_plane import ImagePlane from scopesim.effects.electronic import AutoExposure -from scopesim.utils import from_currsys from scopesim.tests.mocks.py_objects.imagehdu_objects import _image_hdu_square @@ -28,7 +27,7 @@ def fixture_imageplane(): return implane -@pytest.fixture(name="autoexposure", scope="class") +@pytest.fixture(name="autoexposure", scope="function") def fixture_autoexposure(): """Instantiate an AutoExposure object""" return AutoExposure(fill_frac=0.75, @@ -45,8 +44,8 @@ def test_initialises_correctly(self): assert isinstance(autoexposure, AutoExposure) def test_returns_imageplane(self, autoexposure, imageplane): - with patch("scopesim.rc.__currsys__", _patched_cmds()): - outimpl = autoexposure.apply_to(imageplane) + autoexposure.cmds = _patched_cmds() + outimpl = autoexposure.apply_to(imageplane) assert isinstance(outimpl, ImagePlane) @@ -59,24 +58,24 @@ def test_produces_correct_values(self, autoexposure, imageplane): ref_dit = 0.75 # TODO: Change AutoExposure to read exptime like dit and ndit - with patch("scopesim.rc.__currsys__", _patched_cmds(exptime=exptime)): - autoexposure.apply_to(imageplane) + autoexposure.cmds = _patched_cmds(exptime=exptime) + autoexposure.apply_to(imageplane) - out_dit = from_currsys("!OBS.dit") - out_ndit = from_currsys("!OBS.ndit") + out_dit = autoexposure.cmds["!OBS.dit"] + out_ndit = autoexposure.cmds["!OBS.ndit"] assert out_dit == pytest.approx(ref_dit) assert out_dit * out_ndit == pytest.approx(exptime) def test_detects_saturation(self, imageplane): mindit = 0.011 - with patch("scopesim.rc.__currsys__", _patched_cmds(exptime=100.)): - autoexposure = AutoExposure(fill_frac=0.75, - full_well=10., - mindit=mindit) - autoexposure.apply_to(imageplane) + autoexposure = AutoExposure(fill_frac=0.75, + full_well=10., + mindit=mindit, + cmds=_patched_cmds(exptime=100.)) + autoexposure.apply_to(imageplane) - out_dit = from_currsys("!OBS.dit") + out_dit = autoexposure.cmds["!OBS.dit"] assert out_dit == mindit @@ -85,19 +84,19 @@ def test_fill_frac_acts_correctly(self, imageplane): fill_2 = 0.5 autoexp_1 = AutoExposure(fill_frac=fill_1, full_well=1e5, - mindit=0.011) - with patch("scopesim.rc.__currsys__", _patched_cmds()): - autoexp_1.apply_to(imageplane) - out_dit_1 = from_currsys("!OBS.dit") - out_ndit_1 = from_currsys("!OBS.ndit") + mindit=0.011, + cmds=_patched_cmds()) + autoexp_1.apply_to(imageplane) + out_dit_1 = autoexp_1.cmds["!OBS.dit"] + out_ndit_1 = autoexp_1.cmds["!OBS.ndit"] autoexp_2 = AutoExposure(fill_frac=fill_2, full_well=1e5, - mindit=0.011) - with patch("scopesim.rc.__currsys__", _patched_cmds()): - autoexp_2.apply_to(imageplane) - out_dit_2 = from_currsys("!OBS.dit") - out_ndit_2 = from_currsys("!OBS.ndit") + mindit=0.011, + cmds=_patched_cmds()) + autoexp_2.apply_to(imageplane) + out_dit_2 = autoexp_2.cmds["!OBS.dit"] + out_ndit_2 = autoexp_2.cmds["!OBS.ndit"] assert out_dit_1 == fill_1 / fill_2 * out_dit_2 assert out_ndit_1 == fill_2 / fill_1 * out_ndit_2 @@ -108,17 +107,18 @@ def test_exptime_specified_by_dit_ndit(self, autoexposure, imageplane): instead of `!OBS.exptime`. """ # 1. use exptime - with patch("scopesim.rc.__currsys__", _patched_cmds(exptime=10.)): - autoexposure.apply_to(imageplane) - dit_1 = from_currsys("!OBS.dit") - ndit_1 = from_currsys("!OBS.ndit") + autoexposure.cmds["!OBS.exptime"] = 10.0 + autoexposure.apply_to(imageplane) + dit_1 = autoexposure.cmds["!OBS.dit"] + ndit_1 = autoexposure.cmds["!OBS.ndit"] # 2. use dit and ndit - with patch("scopesim.rc.__currsys__", - _patched_cmds(exptime=None, dit=5, ndit=2)): - autoexposure.apply_to(imageplane) - dit_2 = from_currsys("!OBS.dit") - ndit_2 = from_currsys("!OBS.ndit") + autoexposure.cmds["!OBS.exptime"] = None + autoexposure.cmds["!OBS.dit"] = 5 + autoexposure.cmds["!OBS.ndit"] = 2 + autoexposure.apply_to(imageplane) + dit_2 = autoexposure.cmds["!OBS.dit"] + ndit_2 = autoexposure.cmds["!OBS.ndit"] assert dit_1 == dit_2 assert ndit_1 == ndit_2 @@ -129,10 +129,10 @@ def test_exptime_at_least_mindit(self, imageplane): autoexposure = AutoExposure(fill_frac=0.75, full_well=1e5, mindit=mindit) - with patch("scopesim.rc.__currsys__", _patched_cmds(exptime=exptime)): - autoexposure.apply_to(imageplane) - dit = from_currsys("!OBS.dit") - ndit = from_currsys("!OBS.ndit") + autoexposure.cmds["!OBS.exptime"] = exptime + autoexposure.apply_to(imageplane) + dit = autoexposure.cmds["!OBS.dit"] + ndit = autoexposure.cmds["!OBS.ndit"] assert dit == mindit assert ndit == 1 From 3a3c73c41cbc45d9cffd673c43dacd4002cdf739 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Tue, 27 Feb 2024 01:14:56 +0100 Subject: [PATCH 10/11] Yet another way to do a default --- scopesim/effects/electronic.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scopesim/effects/electronic.py b/scopesim/effects/electronic.py index d87a7949..8504ca79 100644 --- a/scopesim/effects/electronic.py +++ b/scopesim/effects/electronic.py @@ -185,6 +185,9 @@ def __init__(self, **kwargs): params = {"z_order": [902]} self.meta.update(params) self.meta.update(kwargs) + if self.cmds is None: + from scopesim import UserCommands + self.cmds = UserCommands() required_keys = ["fill_frac", "full_well", "mindit"] check_keys(self.meta, required_keys, action="error") @@ -226,10 +229,6 @@ def apply_to(self, obj, **kwargs): logger.info("Exposure parameters: DIT=%.3f s NDIT=%d", dit, ndit) logger.info("Total exposure time: %.3f s", dit * ndit) - if self.cmds is None: - from scopesim import UserCommands - self.cmds = UserCommands() - self.cmds["!OBS.dit"] = dit self.cmds["!OBS.ndit"] = ndit From 58c54412b0693710a58c8ad0c6cc4c9603aa15bf Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Wed, 28 Feb 2024 15:29:49 +0100 Subject: [PATCH 11/11] Do not use cmds in utility functions --- scopesim/effects/psf_utils.py | 4 +--- scopesim/effects/psfs.py | 9 ++++++--- scopesim/effects/ter_curves_utils.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/scopesim/effects/psf_utils.py b/scopesim/effects/psf_utils.py index 6c12a672..b91050d3 100644 --- a/scopesim/effects/psf_utils.py +++ b/scopesim/effects/psf_utils.py @@ -109,9 +109,7 @@ def make_strehl_map_from_table(tbl, pixel_scale=1*u.arcsec): return map_hdu -def rescale_kernel(image, scale_factor, spline_order=None, cmds=None): - if spline_order is None: - spline_order = utils.from_currsys("!SIM.computing.spline_order", cmds=cmds) +def rescale_kernel(image, scale_factor, spline_order): sum_image = np.sum(image) image = zoom(image, scale_factor, order=spline_order) image = np.nan_to_num(image, copy=False) # numpy version >=1.13 diff --git a/scopesim/effects/psfs.py b/scopesim/effects/psfs.py index 941b53e4..d6c2d0c7 100644 --- a/scopesim/effects/psfs.py +++ b/scopesim/effects/psfs.py @@ -495,7 +495,8 @@ def remake_kernel(self, x): def wavelength(self): wave = from_currsys(self.meta["wavelength"], self.cmds) if isinstance(wave, str) and wave in tu.FILTER_DEFAULTS: - wave = tu.get_filter_effective_wavelength(wave, cmds=self.cmds) + filter_name = from_currsys(wave, cmds=self.cmds) + wave = tu.get_filter_effective_wavelength(filter_name) wave = quantify(wave, u.um).value return wave @@ -634,7 +635,8 @@ def get_kernel(self, fov): # rescaling kept inside loop to avoid rescaling for every fov pix_ratio = kernel_pixel_scale / fov_pixel_scale if abs(pix_ratio - 1) > self.meta["flux_accuracy"]: - self.kernel = pu.rescale_kernel(self.kernel, pix_ratio) + spline_order = from_currsys("!SIM.computing.spline_order", cmds=self.cmds) + self.kernel = pu.rescale_kernel(self.kernel, pix_ratio, spline_order) if ((fov.header["NAXIS1"] < hdr["NAXIS1"]) or (fov.header["NAXIS2"] < hdr["NAXIS2"])): @@ -830,8 +832,9 @@ def get_kernel(self, fov): # rescale the pixel scale of the kernel to match the fov images pix_ratio = fov_pixel_scale / kernel_pixel_scale if abs(pix_ratio - 1) > self.meta["flux_accuracy"]: + spline_order = from_currsys("!SIM.computing.spline_order", cmds=self.cmds) for ii, kern in enumerate(self.kernel): - self.kernel[ii][0] = pu.rescale_kernel(kern[0], pix_ratio) + self.kernel[ii][0] = pu.rescale_kernel(kern[0], pix_ratio, spline_order) for i, kern in enumerate(self.kernel): self.kernel[i][0] /= np.sum(kern[0]) diff --git a/scopesim/effects/ter_curves_utils.py b/scopesim/effects/ter_curves_utils.py index 8e2ac8cd..66645538 100644 --- a/scopesim/effects/ter_curves_utils.py +++ b/scopesim/effects/ter_curves_utils.py @@ -50,9 +50,9 @@ PATH_SVO_DATA = PATH_HERE.parent / "data" / "svo" -def get_filter_effective_wavelength(filter_name, cmds=None): +def get_filter_effective_wavelength(filter_name): if isinstance(filter_name, str): - filter_name = from_currsys(filter_name, cmds=cmds) + assert FILTER_DEFAULTS.get(filter_name), f"{filter_name} not found in FILTER_DEFAULTS" wave, trans = download_svo_filter(FILTER_DEFAULTS[filter_name], return_style="quantity") eff_wave = np.sum(wave * trans) / np.sum(trans) # convert from Angstrom