From 340add55f067687e408c4c502d594875b36dc6ae Mon Sep 17 00:00:00 2001 From: Kieran Leschinski Date: Tue, 13 Feb 2024 14:08:16 +0100 Subject: [PATCH 1/7] reduce SurfaceList dependence on radiometry_utils. Delete unused RadiometryTable --- scopesim/effects/data_container.py | 3 + scopesim/effects/effects_utils.py | 24 -- scopesim/effects/surface_list.py | 19 +- scopesim/optics/__init__.py | 1 - scopesim/optics/radiometry.py | 93 ----- scopesim/optics/surface.py | 28 +- scopesim/tests/test_utils_functions.py | 12 +- .../tests_optics/test_RadiometryTable.py | 333 ------------------ 8 files changed, 37 insertions(+), 476 deletions(-) delete mode 100644 scopesim/optics/radiometry.py delete mode 100644 scopesim/tests/tests_optics/test_RadiometryTable.py diff --git a/scopesim/effects/data_container.py b/scopesim/effects/data_container.py index c584b52e..73a697f1 100644 --- a/scopesim/effects/data_container.py +++ b/scopesim/effects/data_container.py @@ -128,6 +128,9 @@ def _load_ascii(self): self.meta.update(hdr_dict) # self.table.meta.update(hdr_dict) self.table.meta.update(self.meta) + if self.table.meta.get("cmds"): + self.table.meta.pop("cmds") + self.meta["history"] += ["ASCII table read from " f"{self.meta['filename']}"] diff --git a/scopesim/effects/effects_utils.py b/scopesim/effects/effects_utils.py index 40d2a9ef..7ae0623b 100644 --- a/scopesim/effects/effects_utils.py +++ b/scopesim/effects/effects_utils.py @@ -13,30 +13,6 @@ logger = get_logger(__name__) -def combine_surface_effects_OLD(surface_effects): - surflist_list = [eff for eff in surface_effects - if isinstance(eff, efs.SurfaceList)] - surf_list = [eff for eff in surface_effects - if isinstance(eff, efs.TERCurve)] - - if len(surflist_list) == 0: - surf = empty_surface_list() - surf.meta["name"] = "Radiometry Table" - surflist_list += [surf] - - new_surflist = deepcopy(surflist_list[0]) - for surflist in surflist_list[1:]: - new_surflist.add_surface_list(surflist) - - for surf in surf_list: - position = surf.meta["position"] if "position" in surf.meta else -1 - new_surflist.add_surface(surf, surf.meta["name"], position=position) - - new_surflist.table = new_surflist.radiometry_table.table - - return new_surflist - - def combine_surface_effects(surface_effects): surflist_list = [eff for eff in surface_effects if isinstance(eff, efs.SurfaceList)] diff --git a/scopesim/effects/surface_list.py b/scopesim/effects/surface_list.py index 7b02661c..9ba3594c 100644 --- a/scopesim/effects/surface_list.py +++ b/scopesim/effects/surface_list.py @@ -1,4 +1,6 @@ """TBA.""" +from collections import OrderedDict +from copy import deepcopy import warnings import numpy as np @@ -6,7 +8,7 @@ from .ter_curves import TERCurve, FilterWheelBase from ..optics import radiometry_utils as rad_utils -from ..optics.surface import PoorMansSurface +from ..optics.surface import PoorMansSurface, SpectralSurface from ..utils import quantify, from_currsys, figure_factory @@ -21,11 +23,18 @@ def __init__(self, **kwargs): self.meta.update(params) self.meta.update(kwargs) - tbl = from_currsys(self.table, self.cmds) - self.surfaces = rad_utils.make_surface_dict_from_table(tbl) self._surface = None self._throughput = None self._emission = None + self.surfaces = OrderedDict({}) + + if self.table is not None: + for row in self.table: + surf_kwargs = deepcopy(self.table.meta) + surf_kwargs.update(dict(row)) + surf_kwargs["cmds"] = self.cmds + surf_kwargs["filename"] = from_currsys(surf_kwargs["filename"], self.cmds) + self.surfaces[surf_kwargs["name"]] = SpectralSurface(**surf_kwargs) def fov_grid(self, which="waveset", **kwargs): warnings.warn("The fov_grid method is deprecated and will be removed " @@ -137,8 +146,8 @@ def add_surface(self, surface, name=None, position=-1, add_to_table=True): def add_surface_list(self, surface_list, prepend=False): if isinstance(surface_list, SurfaceList): self.surfaces.update(surface_list.surfaces) - new_tbl = from_currsys(surface_list.table, self.cmds), - self.table = rad_utils.combine_tables(new_tbl, self.table, prepend) + # new_tbl = from_currsys(surface_list.table, self.cmds), + self.table = rad_utils.combine_tables(surface_list.table, self.table, prepend) def plot(self, which="x", wavelength=None, *, axes=None, **kwargs): """Plot TER curves. diff --git a/scopesim/optics/__init__.py b/scopesim/optics/__init__.py index ab5c5fe5..ad0276a9 100644 --- a/scopesim/optics/__init__.py +++ b/scopesim/optics/__init__.py @@ -9,7 +9,6 @@ from .surface import SpectralSurface from . import surface_utils -from .radiometry import RadiometryTable from . import radiometry_utils from .fov import FieldOfView diff --git a/scopesim/optics/radiometry.py b/scopesim/optics/radiometry.py deleted file mode 100644 index 189112a7..00000000 --- a/scopesim/optics/radiometry.py +++ /dev/null @@ -1,93 +0,0 @@ -from collections import OrderedDict - -import numpy as np - -from ..utils import real_colname, quantify -from .radiometry_utils import combine_emissions, combine_throughputs, \ - combine_tables, add_surface_to_table, add_surface_to_dict, \ - make_surface_from_row - - -class RadiometryTable: - def __init__(self, tables=(), **kwargs): - self.meta = {"area": None} - self.meta.update(kwargs) - - self.table = None - self.surfaces = OrderedDict({}) - - if len(tables) > 0: - self.add_surface_list(tables) - - def add_surface_list(self, surface_list, prepend=False): - self.table = combine_tables(surface_list, self.table, prepend=prepend) - - r_name = real_colname("name", self.table.colnames) - for row in self.table: - if row[r_name] not in self.surfaces: - surf = make_surface_from_row(row) - self.add_surface(surf, row[r_name], position=-1, - add_to_table=False) - - def add_surface(self, surface, name, position=-1, add_to_table=True): - if self.table is None: - raise ValueError("Cannot add surface without .table template." - "Please add an empty table to define column names") - - if position < 0: - position += len(self.table) + 1 - self.surfaces = add_surface_to_dict(self.surfaces, surface, - name, position) - if add_to_table: - self.table = add_surface_to_table(self.table, surface, - name, position) - - def get_throughput(self, start=0, end=None, rows=None): - - if self.table is None: - return None - - if end is None: - end = len(self.table) - elif end < 0: - end += len(self.table) - if rows is None: - rows = np.arange(start, end) - - return combine_throughputs(self.table, self.surfaces, rows) - - def get_emission(self, etendue, start=0, end=None, rows=None, - use_area=False): - if self.table is None: - return None - - if end is None: - end = len(self.table) - elif end < 0: - end += len(self.table) - if rows is None: - rows = np.arange(start, end) - - return combine_emissions(self.table, self.surfaces, rows, etendue, - use_area) - - @property - def emission(self): - if "etendue" not in self.meta: - raise ValueError("self.meta[\"etendue\"] must be set") - etendue = quantify(self.meta["etendue"], "m2 arcsec2") - - return self.get_emission(etendue) - - @property - def throughput(self): - return self.get_throughput() - - def plot(self, what="all", rows=None): - raise NotImplementedError() - - def __getitem__(self, item): - return self.surfaces[item] - - def __repr__(self): - return f"{self.__class__.__name__}({self.table!r}, **{self.meta})" diff --git a/scopesim/optics/surface.py b/scopesim/optics/surface.py index 401ce582..97854748 100644 --- a/scopesim/optics/surface.py +++ b/scopesim/optics/surface.py @@ -12,13 +12,12 @@ from synphot.models import Empirical1D from ..effects import ter_curves_utils as ter_utils -from .surface_utils import make_emission_from_emissivity,\ +from .surface_utils import make_emission_from_emissivity, \ make_emission_from_array from ..utils import (get_meta_quantity, quantify, extract_type_from_unit, from_currsys, convert_table_comments_to_dict, find_file, get_logger) - logger = get_logger(__name__) @@ -43,13 +42,14 @@ class SpectralSurface: """ - def __init__(self, filename=None, **kwargs): + def __init__(self, filename=None, cmds=None, **kwargs): filename = find_file(filename) self.meta = {"filename": filename, "temperature": -270 * u.deg_C, # deg C "emission_unit": "", "wavelength_unit": u.um} + self.cmds = cmds self.table = Table() if filename is not None and Path(filename).exists(): self.table = ioascii.read(filename) @@ -62,10 +62,10 @@ def __init__(self, filename=None, **kwargs): @property def area(self): if "area" in self.meta: - the_area = self.from_meta("area", u.m**2) + the_area = self.from_meta("area", u.m ** 2) elif "outer" in self.meta: outer_diameter = self.from_meta("outer", u.m) - the_area = np.pi * (0.5 * outer_diameter)**2 + the_area = np.pi * (0.5 * outer_diameter) ** 2 if "inner" in self.meta: inner_diameter = self.from_meta("inner", u.m) the_area -= np.pi * (0.5 * inner_diameter) ** 2 @@ -106,7 +106,7 @@ def reflection(self): def emission(self): """ Look for an emission array in self.meta. - + If it doesn't find this, it defaults to creating a blackbody and multiplies this by the emissivity. Assumption is that ``self.meta["temperature"]`` is in ``deg_C``, unless it is a @@ -118,8 +118,8 @@ def emission(self): wave = self._get_array("wavelength") flux = make_emission_from_array(flux, wave, meta=self.meta) elif "temperature" in self.meta: - emiss = self.emissivity # SpectralElement [0..1] - temp = from_currsys(self.meta["temperature"]) + emiss = self.emissivity # SpectralElement [0..1] + temp = from_currsys(self.meta["temperature"], self.cmds) if not isinstance(temp, u.Quantity): temp = quantify(temp, u.deg_C) temp = temp.to(u.Kelvin, equivalencies=u.temperature()) @@ -133,11 +133,11 @@ def emission(self): if flux is not None and has_solid_angle: conversion_factor = flux.meta["solid_angle"].to(u.arcsec ** -2) flux = flux * conversion_factor - flux.meta["solid_angle"] = u.arcsec**-2 + flux.meta["solid_angle"] = u.arcsec ** -2 flux.meta["history"].append(f"Converted to arcsec-2: {conversion_factor}") if flux is not None and "rescale_emission" in self.meta: - dic = from_currsys(self.meta["rescale_emission"]) + dic = from_currsys(self.meta["rescale_emission"], self.cmds) amplitude = dic["value"] * u.Unit(dic["unit"]) filter_name = dic["filter_name"] if "filename_format" in dic: @@ -226,11 +226,11 @@ def _compliment_array(self, colname_a, colname_b): compliment_b = self._get_array(colname_b) if compliment_a is not None and compliment_b is not None: - actual = 1*compliment_a.unit - (compliment_a + compliment_b) + actual = 1 * compliment_a.unit - (compliment_a + compliment_b) elif compliment_a is not None and compliment_b is None: - actual = 1*compliment_a.unit - compliment_a + actual = 1 * compliment_a.unit - compliment_a elif compliment_b is not None and compliment_a is None: - actual = 1*compliment_b.unit - compliment_b + actual = 1 * compliment_b.unit - compliment_b elif compliment_b is None and compliment_a is None: actual = None @@ -261,7 +261,7 @@ def _get_array(self, colname): colname, self.meta.get("name", self.meta["filename"])) return None - col_units = colname+"_unit" + col_units = colname + "_unit" if isinstance(val, u.Quantity): units = val.unit elif col_units in self.meta: diff --git a/scopesim/tests/test_utils_functions.py b/scopesim/tests/test_utils_functions.py index 26a08b7c..1c6b12ee 100644 --- a/scopesim/tests/test_utils_functions.py +++ b/scopesim/tests/test_utils_functions.py @@ -226,9 +226,9 @@ def test_loads_ifu_optical_train_object(self): assert isinstance(opt, OpticalTrain) assert from_currsys(opt["ifu_spectral_traces"].include) - @pytest.mark.xfail - def test_loads_mos_optical_train_object(self): - opt = load_example_optical_train(set_modes=["mos"]) - - assert isinstance(opt, OpticalTrain) - assert from_currsys(opt["slit_wheel"].include) + # @pytest.mark.xfail + # def test_loads_mos_optical_train_object(self): + # opt = load_example_optical_train(set_modes=["mos"]) + # + # assert isinstance(opt, OpticalTrain) + # assert from_currsys(opt["slit_wheel"].include) diff --git a/scopesim/tests/tests_optics/test_RadiometryTable.py b/scopesim/tests/tests_optics/test_RadiometryTable.py deleted file mode 100644 index 13a829ee..00000000 --- a/scopesim/tests/tests_optics/test_RadiometryTable.py +++ /dev/null @@ -1,333 +0,0 @@ -""" -1. read in the tables -2. read in curves from the set of unique files -3. create a dictionary of curves -""" - -import pytest -from unittest.mock import patch - -import numpy as np -from astropy.table import Table -from astropy.io import ascii as ioascii -from astropy import units as u - -from synphot import SpectralElement, SourceSpectrum - -import scopesim.optics.radiometry_utils as rad_utils -from scopesim import utils -from scopesim.optics import radiometry as opt_rad -from scopesim.optics import surface as opt_surf - - -@pytest.fixture(scope="module") -def input_tables(mock_path_micado): - filenames = ["ELT", "SCAO_relay", "MICADO_Wide"] - return [str(mock_path_micado / f"LIST_mirrors_{fname}.tbl") - for fname in filenames] - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestRadiometryTableInit: - def test_initialises_with_no_input(self): - rt = opt_rad.RadiometryTable() - assert isinstance(rt, opt_rad.RadiometryTable) - assert rt.table is None - - def test_initialises_with_single_table(self, input_tables): - rt = opt_rad.RadiometryTable([input_tables[0]]) - assert isinstance(rt, opt_rad.RadiometryTable) - assert len(rt.table) == 5 - - def test_initialises_with_list_of_tables(self, input_tables): - rt = opt_rad.RadiometryTable(input_tables) - assert isinstance(rt, opt_rad.RadiometryTable) - assert len(rt.table) == 19 - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestRadiometryTableAddSurfaceList: - def test_append_single_table_from_filename(self, input_tables): - rad_table = opt_rad.RadiometryTable() - rad_table.add_surface_list(input_tables[0]) - assert len(rad_table.table) == 5 - - def test_combine_two_tables_from_filename(self, input_tables): - rad_table = opt_rad.RadiometryTable() - rad_table.add_surface_list([input_tables[0], input_tables[1]]) - assert len(rad_table.table) == 6 - - def test_combine_list_of_filename(self, input_tables): - rad_table = opt_rad.RadiometryTable() - rad_table.add_surface_list(input_tables) - assert len(rad_table.table) == 19 - - def test_all_surfaces_where_added_to_dict_surface(self, input_tables): - rad_table = opt_rad.RadiometryTable() - rad_table.add_surface_list(input_tables) - names = rad_table.table["name"] - assert np.all(name in rad_table.surface for name in names) - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestRadiometryTableAddSurface: - @pytest.mark.parametrize("position", (0, 2, 5)) - def test_add_empty_surface_to_full_table(self, input_tables, position): - rt = opt_rad.RadiometryTable(tables=(input_tables[0])) - surf = opt_surf.SpectralSurface() - rt.add_surface(surf, "new_surf", position) - colname = utils.real_colname("name", rt.table.colnames) - assert rt.table[colname][position] == "new_surf" - assert "new_surf" in rt.surfaces - assert isinstance(rt.surfaces["new_surf"], opt_surf.SpectralSurface) - - def test_add_empty_surface_to_empty_table(self): - rt = opt_rad.RadiometryTable() - surf = opt_surf.SpectralSurface() - with pytest.raises(ValueError): - rt.add_surface(surf, "new_surf", 0) - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestRadiometryTableGetThroughput: - def test_return_spectral_element_from_get_throughput(self, input_tables): - rt = opt_rad.RadiometryTable(input_tables) - thru = rt.get_throughput() - assert isinstance(thru, SpectralElement) - - def test_return_spectral_element_for_only_2_rows(self, input_tables): - rt = opt_rad.RadiometryTable(input_tables) - thru = rt.get_throughput(start=1, end=3) - assert isinstance(thru, SpectralElement) - assert thru.model.n_submodels == 2 - - def test_return_none_for_empty_radiometry_table(self): - rt = opt_rad.RadiometryTable() - thru = rt.get_throughput() - assert thru is None - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestRadiometryTableGetEmission: - def test_return_spectral_element_from_get_throughput(self, input_tables): - rt = opt_rad.RadiometryTable(input_tables) - etendue = (996*u.m**2) * (0.004*u.arcsec)**2 - emiss = rt.get_emission(etendue=etendue) - assert isinstance(emiss, SourceSpectrum) - - def test_return_spectral_element_for_only_2_rows(self, input_tables): - rt = opt_rad.RadiometryTable(input_tables) - etendue = (996*u.m ** 2) * (0.004 * u.arcsec) ** 2 - emiss = rt.get_emission(etendue=etendue, start=1, end=3) - assert isinstance(emiss, SourceSpectrum) - assert emiss.model.n_submodels == 7 - - def test_return_none_for_empty_radiometry_table(self): - rt = opt_rad.RadiometryTable() - emiss = rt.get_throughput() - assert emiss is None - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestCombineEmissions: - def test_super_simple_case(self): - n = 11 - surf = opt_surf.SpectralSurface(wavelength=np.linspace(1, 2, n) * u.um, - transmission=0.5*np.ones(n), - area=2*u.m**2, - angle=0*u.deg) - dic = {"surf" + str(i + 1): surf for i in range(3)} - tbl = ioascii.read(""" name action - surf1 reflection - surf2 transmission - surf3 transmission """) - etendue = 1 * u.m**2 * u.arcsec**2 - combi = rad_utils.combine_emissions(tbl, dic, [0, 1, 2], etendue) - assert isinstance(combi, SourceSpectrum) - - def test_returns_source_spectrum_for_full_path(self, input_tables): - rt = opt_rad.RadiometryTable(tables=input_tables) - row_list = np.arange(len(rt.table)) - etendue = (996*u.m**2) * (0.004*u.arcsec)**2 - comb_emission = rad_utils.combine_emissions(rt.table, rt.surfaces, - row_indexes=row_list, - etendue=etendue) - assert isinstance(comb_emission, SourceSpectrum) - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestCombineThroughputs: - def test_returns_spectral_element_containing_everything(self, input_tables): - rt = opt_rad.RadiometryTable(tables=(input_tables)) - row_list = np.arange(len(rt.table)) - comb_throughput = rad_utils.combine_throughputs(rt.table, rt.surfaces, - rows_indexes=row_list) - assert isinstance(comb_throughput, SpectralElement) - - def test_super_simple_combine_3_surfaces(self): - n = 10 - surf = opt_surf.SpectralSurface(wavelength=np.linspace(1, 2, n)*u.um, - transmission=np.ones(n)) - dic = {"surf"+str(i+1): surf for i in range(3)} - tbl = ioascii.read(""" name action - surf1 reflection - surf2 transmission - surf3 transmission """) - combi = rad_utils.combine_throughputs(tbl, dic, [0, 1, 2]) - assert isinstance(combi, SpectralElement) - - def test_return_none_if_table_is_empty(self): - n = 10 - surf = opt_surf.SpectralSurface(wavelength=np.linspace(1, 2, n) * u.um, - transmission=np.ones(n)) - dic = {"surf" + str(i + 1): surf for i in range(3)} - tbl = Table() - combi = rad_utils.combine_throughputs(tbl, dic, [0, 1, 2]) - assert combi is None - - -class TestCombineTables: - def test_adds_two_tables(self): - tblA = Table(names=["colA", "colB"], data=[[0, 1], [0, 1]]) - tblB = Table(names=["colA", "colB"], data=[[2, 3], [2, 3]]) - tblC = rad_utils.combine_tables(tblB, tblA) - assert np.all(tblC["colB"] == np.array([0, 1, 2, 3])) - - def test_adds_single_table(self): - tblA = Table(names=["colA", "colB"], data=[[0, 1], [0, 1]]) - tblC = rad_utils.combine_tables(tblA) - assert np.all(tblC["colA"] == np.array([0, 1])) - - def test_adds_three_tables_to_old_table(self): - tblA = Table(names=["colA", "colB"], data=[[0, 1], [0, 1]]) - tblB = Table(names=["colA", "colB"], data=[[2, 3], [2, 3]]) - tblC = Table(names=["colA", "colB"], data=[[4, 5], [4, 5]]) - tblD = Table(names=["colA", "colB"], data=[[6, 7], [6, 7]]) - tblE = rad_utils.combine_tables([tblB, tblC, tblD], tblA) - assert np.all(tblE["colA"] == np.arange(8)) - - def test_adds_table_from_filename_to_nothing(self, input_tables): - tblA = ioascii.read(input_tables[0]) - tblC = rad_utils.combine_tables(tblA) - assert len(tblC) == 5 - - def test_adds_table_from_filename_to_table_object(self, input_tables): - tblA = ioascii.read(input_tables[0]) - tblB = input_tables[1] - tblC = rad_utils.combine_tables(tblB, tblA) - assert len(tblC) == 6 - - def test_adds_table_from_filename_to_table_from_file(self, input_tables): - tblA = input_tables[0] - tblB = input_tables[1] - tblC = rad_utils.combine_tables(tblB, tblA) - assert len(tblC) == 6 - - def test_adds_3_tables_from_filename_to_nothing(self, input_tables): - tblC = rad_utils.combine_tables(input_tables) - assert len(tblC) == 19 - - def test_prepend_table(self): - tblA = Table(names=["colA", "colB"], data=[[0, 1], [0, 1]]) - tblB = Table(names=["colA", "colB"], data=[[2, 3], [2, 3]]) - tblC = rad_utils.combine_tables(tblB, tblA, prepend=True) - assert np.all(tblC["colB"] == np.array([2, 3, 0, 1])) - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestMakeSurfaceFromRow: - def test_return_none_from_empty_row(self, input_tables): - tblA = ioascii.read(input_tables[0]) - surf = rad_utils.make_surface_from_row(tblA[0]) - assert isinstance(surf, opt_surf.SpectralSurface) - - def test_surface_has_processed_ter_filename_in_row(self, input_tables): - tblA = ioascii.read(input_tables[0]) - surf = rad_utils.make_surface_from_row(tblA[0]) - assert isinstance(surf.transmission, SpectralElement) - assert isinstance(surf.reflection, SpectralElement) - assert isinstance(surf.emissivity, SpectralElement) - assert isinstance(surf.emission, SourceSpectrum) - - -class TestRealColname: - @pytest.mark.parametrize("name, colnames", [ - ("yahoo", ["Yahoo", "Bogus"]), - ("yahoo", ["yahoo", "Bogus"]), - ("yahoo", ["YAHOO", "Bogus"])]) - def test_returns_real_name(self, name, colnames): - assert utils.real_colname(name, colnames) == colnames[0] - - def test_returns_none_if_name_not_in_colname(self): - assert utils.real_colname("yahoo", ["Bogus"]) is None - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestMakeSurfaceDictFromTable: - def test_return_dict_from_table(self, input_tables): - tbl = ioascii.read(input_tables[0]) - surf_dict = rad_utils.make_surface_dict_from_table(tbl) - assert isinstance(surf_dict, dict) - assert "M1" in surf_dict - - -class TestInsertIntoOrderedDict: - @pytest.mark.parametrize("dic, new_entry, pos", - [({}, ["a", 1], 0), - ({"x": 42, "y": 3.14}, {"a": 1}, 0), - ({"x": 42, "y": 3.14}, ("a", 1), 2), - ({"x": 42, "y": 3.14}, [("b", 2), ("a", 1)], -1)]) - def test_works_as_prescribed(self, dic, new_entry, pos): - new_dic = utils.insert_into_ordereddict(dic, new_entry, pos) - print(new_dic, pos) - assert list(new_dic.keys())[pos] == "a" - assert list(new_dic.values())[pos] == 1 - assert new_dic["a"] == 1 - if "x" in new_dic: - assert new_dic["x"] == 42 - if "b" in new_dic: - assert new_dic["b"] == 2 - - -class TestEmptyType: - @pytest.mark.parametrize("x, expected", - [(int, 0), (float, 0.), (bool, False), (str, " ")]) - def test_works_for_all_common_types(self, x, expected): - assert utils.empty_type(x) == expected - - -@pytest.mark.usefixtures("patch_mock_path_micado") -class TestAddSurfaceToTable: - @pytest.mark.parametrize("position", [0, 2, 5]) - def test_(self, input_tables, position): - tbl = ioascii.read(input_tables[0]) - surf = opt_surf.SpectralSurface(tbl[0]["filename"]) - tbl = rad_utils.add_surface_to_table(tbl, surf, "new_row", position) - assert tbl[position]["filename"] == surf.meta["filename"] - assert tbl[position]["name"] == "new_row" - - -class TestRadiometryTableFromELT: - def local_basic_test_comparing_single_and_5_component_elt_reflections(self): - import scopesim - - fname = "LIST_mirrors_ELT.tbl" - comb = scopesim.effects.SurfaceList(filename=fname) - - fname = "TER_ELT_System_20190611.dat" - eso = scopesim.effects.TERCurve(filename=fname) - eso.surface.meta["temperature"] = 0 - - from matplotlib import pyplot as plt - wave = np.arange(0.3, 3, 0.001) * 1e4 - plt.plot(wave * 1E-4, eso.surface.reflection(wave), label="ESO 2019") - plt.plot(wave * 1E-4, comb.throughput(wave), label="5 component") - - plt.xlabel("Wavelength [um]") - plt.ylabel("Throughput ") - plt.legend(loc=5) - plt.xlim(0.3, 3) - - plt.show() - - print(comb.throughput(3E4), eso.surface.reflection(3E4)) From c9139064d6893f1f81e84b418e326aae62b32cd4 Mon Sep 17 00:00:00 2001 From: Kieran Leschinski Date: Tue, 13 Feb 2024 14:55:07 +0100 Subject: [PATCH 2/7] removed some unused code --- scopesim/optics/radiometry_utils.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/scopesim/optics/radiometry_utils.py b/scopesim/optics/radiometry_utils.py index f9bd7ffb..8b721ddc 100644 --- a/scopesim/optics/radiometry_utils.py +++ b/scopesim/optics/radiometry_utils.py @@ -144,28 +144,3 @@ def add_surface_to_table(tbl, surf, name, position, silent=True): new_tbl = change_table_entry(new_tbl, colname, name, position=position) return new_tbl - - -def add_surface_to_dict(dic, surf, name, position=0): - new_entry = OrderedDict({name : surf}) - dic = insert_into_ordereddict(dic, new_entry, position) - - return dic - - -def make_surface_dict_from_table(tbl): - surf_dict = OrderedDict({}) - if tbl is not None and len(tbl) > 0: - names = tbl[real_colname("name", tbl.colnames)] - for ii, row in enumerate(tbl): - surf_dict[names[ii]] = make_surface_from_row(row, **tbl.meta) - - return surf_dict - - -def make_surface_from_row(row, **kwargs): - row_dict = {colname.lower(): row[colname] for colname in row.colnames} - kwargs.update(row_dict) - surface = SpectralSurface(**kwargs) - - return surface From 1058d21153cdaab16e021639cf4087ce8c74572a Mon Sep 17 00:00:00 2001 From: Kieran Leschinski Date: Tue, 13 Feb 2024 15:01:39 +0100 Subject: [PATCH 3/7] patch double entries of cmds dict to SPectralTraceList --- scopesim/effects/spectral_trace_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scopesim/effects/spectral_trace_list.py b/scopesim/effects/spectral_trace_list.py index d8799e4d..401ef792 100644 --- a/scopesim/effects/spectral_trace_list.py +++ b/scopesim/effects/spectral_trace_list.py @@ -489,9 +489,9 @@ def __init__(self, **kwargs): self.trace_lists = {} for name in from_currsys(self.meta["trace_list_names"], self.cmds): kwargs["name"] = name + kwargs["cmds"] = self.cmds fname = str(path).format(name) self.trace_lists[name] = SpectralTraceList(filename=fname, - cmds=self.cmds, **kwargs) def apply_to(self, obj, **kwargs): From 4b5216eab1b0b02c03876fb11d4005dcba786b9b Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Wed, 14 Feb 2024 20:44:33 +0100 Subject: [PATCH 4/7] Fix bug with cmds and ignore_effects --- scopesim/optics/optics_manager.py | 2 +- scopesim/tests/tests_optics/test_OpticalTrain.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/scopesim/optics/optics_manager.py b/scopesim/optics/optics_manager.py index 293d4cc9..0a88555f 100644 --- a/scopesim/optics/optics_manager.py +++ b/scopesim/optics/optics_manager.py @@ -94,7 +94,7 @@ def load_effects(self, yaml_dicts, **kwargs): """ if not isinstance(yaml_dicts, Sequence): yaml_dicts = [yaml_dicts] - self.optical_elements.extend(OpticalElement(dic, **kwargs) + self.optical_elements.extend(OpticalElement(dic, cmds=self.cmds, **kwargs) for dic in yaml_dicts if "effects" in dic) def add_effect(self, effect, ext=0): diff --git a/scopesim/tests/tests_optics/test_OpticalTrain.py b/scopesim/tests/tests_optics/test_OpticalTrain.py index 962e32d4..9c4583c8 100644 --- a/scopesim/tests/tests_optics/test_OpticalTrain.py +++ b/scopesim/tests/tests_optics/test_OpticalTrain.py @@ -40,6 +40,13 @@ def cmds(mock_path, mock_path_yamls): with patch("scopesim.rc.__search_path__", [mock_path, mock_path_yamls]): return UserCommands(yamls=[find_file("CMD_mvs_cmds.yaml")]) +@pytest.fixture(scope="class") +def cmds_with_ignore(mock_path, mock_path_yamls): + with patch("scopesim.rc.__search_path__", [mock_path, mock_path_yamls]): + cmds = UserCommands(yamls=[find_file("CMD_mvs_cmds.yaml")]) + cmds.ignore_effects += ["detector QE curve"] + return cmds + # TODO: check if class scope breaks anything (used to be function scope) @pytest.fixture(scope="class") @@ -99,6 +106,10 @@ def test_has_yaml_dict_object_after_initialising(self, cmds): opt = OpticalTrain(cmds=cmds) assert isinstance(opt.yaml_dicts, list) and len(opt.yaml_dicts) > 0 + def test_ignore_effects_works(self, cmds_with_ignore): + opt = OpticalTrain(cmds=cmds_with_ignore) + assert opt["detector QE curve"].include is False + @pytest.mark.usefixtures("patch_mock_path") class TestObserve: From 8dab9449b2c32a23104c8a20b04fd9645226e4f5 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Wed, 14 Feb 2024 21:43:02 +0100 Subject: [PATCH 5/7] Pass cmd on to fits header keywords --- scopesim/effects/fits_headers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scopesim/effects/fits_headers.py b/scopesim/effects/fits_headers.py index c129e626..ced8b1ce 100644 --- a/scopesim/effects/fits_headers.py +++ b/scopesim/effects/fits_headers.py @@ -218,7 +218,7 @@ class ExtraFitsKeywords(Effect): """ - def __init__(self, **kwargs): + def __init__(self, cmds=None, **kwargs): # don't pass kwargs, as DataContainer can't handle yaml files super().__init__() params = {"name": "extra_fits_keywords", @@ -419,7 +419,7 @@ class EffectsMetaKeywords(ExtraFitsKeywords): """ - def __init__(self, **kwargs): + def __init__(self, cmds=None, **kwargs): super(ExtraFitsKeywords, self).__init__() params = {"name": "effects_fits_keywords", "description": "Effect Meta FITS headers", @@ -453,7 +453,7 @@ def apply_to(self, hdul, **kwargs): keys = list(eff_meta.keys()) for key in keys: value = eff_meta[key] - if key in ["history", "notes", "changes"]: + if key in ["history", "notes", "changes", "cmds"]: eff_meta.pop(key) if isinstance(value, Table): eff_meta[key] = f"Table object of length: {len(value)}" @@ -506,7 +506,7 @@ class SourceDescriptionFitsKeywords(ExtraFitsKeywords): """ - def __init__(self, **kwargs): + def __init__(self, cmds=None, **kwargs): super(ExtraFitsKeywords, self).__init__() params = {"name": "source_fits_keywords", "description": "Source description FITS headers", @@ -590,7 +590,7 @@ class SimulationConfigFitsKeywords(ExtraFitsKeywords): """ - def __init__(self, **kwargs): + def __init__(self, cmds=None, **kwargs): super(ExtraFitsKeywords, self).__init__() params = {"name": "simulation_fits_keywords", "description": "Simulation Config FITS headers", From 38fa6672d0edce804ce6db909e8eb85fd380b4b4 Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Wed, 14 Feb 2024 21:43:20 +0100 Subject: [PATCH 6/7] Add TODO --- scopesim/tests/tests_effects/test_fits_headers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scopesim/tests/tests_effects/test_fits_headers.py b/scopesim/tests/tests_effects/test_fits_headers.py index c9af95b2..d74dcd8c 100644 --- a/scopesim/tests/tests_effects/test_fits_headers.py +++ b/scopesim/tests/tests_effects/test_fits_headers.py @@ -195,6 +195,7 @@ def test_works(self): assert flat_dict["HIERARCH SIM SRC0 scaling_unit"] == "mag" def test_resolves_bang_strings(self): + # TODO: Use fixtures, because success depends on order of tests. dic = {"SIM": {"random_seed": "!SIM.random.seed"}} flat_dict = fh.flatten_dict(dic, resolve=True) assert flat_dict["SIM random_seed"] is None From 804c2ef28ed5e0d3de6e92b5c6f2844981b4e46e Mon Sep 17 00:00:00 2001 From: Hugo Buddelmeijer Date: Wed, 14 Feb 2024 21:43:26 +0100 Subject: [PATCH 7/7] Ignore some more warnings... --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 08e29db5..8c320fd1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,10 +85,12 @@ filterwarnings = [ # Should probably be fixed: "ignore::ResourceWarning", "ignore:The fit may be poorly conditioned:astropy.utils.exceptions.AstropyUserWarning", + "ignore::astropy.units.core.UnitsWarning", # Perhaps fix? "ignore:divide by zero encountered in scalar divide:RuntimeWarning", "ignore:divide by zero encountered in double_scalars:RuntimeWarning", "ignore:invalid value encountered in multiply:RuntimeWarning", + "ignore:invalid value encountered in divide:RuntimeWarning", "ignore:Cannot merge meta key.*:astropy.utils.metadata.MergeConflictWarning", "default:The fov_grid*:DeprecationWarning", # Raised when saving fits files, not so important to fix: @@ -102,7 +104,7 @@ filterwarnings = [ "ignore:datetime.datetime.utcfromtimestamp()*:DeprecationWarning", # Pytest Notebook stuff "ignore:The*:pytest.PytestRemovedIn8Warning", - "ignore:Proactor*:RuntimeWarning" + "ignore:Proactor*:RuntimeWarning", ] [tool.coverage.report]