diff --git a/metisp/pymetis/pyproject.toml b/metisp/pymetis/pyproject.toml index 35c2204e..f7bf4fe2 100644 --- a/metisp/pymetis/pyproject.toml +++ b/metisp/pymetis/pyproject.toml @@ -1,13 +1,50 @@ +[project] +name = "eso-pymetis" +version = "0.1.0" +description = "METIS pipeline" +authors = [ + {name = "martin.balaz@univie.ac.at"} +] +import-names = ["pymetis"] +license = {text = "GPLv3"} +readme = "README.md" +requires-python = ">=3.11, <3.14" +dependencies = [ + "pycpl==1.0.3.post4", # prefer ivh's re-packaged pycpl + "edps", + "pyesorex", + "adari_core", +] + +[dependency-groups] +dev = [ + "pytest (>=9.0.1,<10.0.0)" +] + [build-system] -requires = [ - "setuptools >= 45", +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +packages = [ + { include = "pymetis", from = "src" }, ] -build-backend = "setuptools.build_meta" -[project] -name = "pymetis" -version = "0.0.1" -dynamic = ["description","requires-python","license","authors","classifiers","urls","dependencies","optional-dependencies"] +[tool.poetry.dependencies] +pycpl = { version = "1.0.3.post4", source = "ivh" } +pyesorex = { source = "eso" } +edps = { source = "eso" } +adari_core = { source = "eso" } + +[[tool.poetry.source]] +name = "eso" +url = "https://ftp.eso.org/pub/dfs/pipelines/repositories/stable/src" +priority = "explicit" + +[[tool.poetry.source]] +name = "ivh" +url = "https://ivh.github.io/pycpl/simple/" +priority = "explicit" [tool.pytest.ini_options] addopts = "--strict-markers" @@ -22,4 +59,4 @@ markers = [ "pyesorex: marks tests that depend on `pyesorex`", "slow: marks tasts with full-size data", "metadata: marks tests that verify recipe metadata", -] \ No newline at end of file +] diff --git a/metisp/pymetis/src/pymetis/classes/dataitems/dataitem.py b/metisp/pymetis/src/pymetis/classes/dataitems/dataitem.py index 1ba617a1..ef1ec2a2 100644 --- a/metisp/pymetis/src/pymetis/classes/dataitems/dataitem.py +++ b/metisp/pymetis/src/pymetis/classes/dataitems/dataitem.py @@ -37,7 +37,7 @@ PIPELINE = rf'METIS/1' -class DataItem(Parametrizable, ABC): +class DataItem(Parametrizable): """ The `DataItem` class encapsulates a single data item: the smallest standalone unit of detector data or a product of a recipe. @@ -48,13 +48,13 @@ class DataItem(Parametrizable, ABC): Multiple files with the same tag should correspond to multiple instances of the same DataItem class. """ # Class registry: all derived classes are automatically registered here (unless declared abstract) - __registry: dict[str, type['DataItem']] = {} + _registry: dict[str, type['DataItem']] = {} # Printable title of the data item. Not used internally, only for human-oriented output _title_template: str = None # No universal title makes sense # Actual ID of the data item. Used internally for identification. Should mirror DRLD `name`. - _name_template: str = None # No universal name makes sense - # Description for man page + _name_template: str = "DataItem" # No universal name makes sense + # A long description that will be used in the man page _description_template: Optional[str] = None # A verbose string; should correspond to the DRLD description # CPL frame group and level @@ -85,34 +85,28 @@ def __init_subclass__(cls, abstract: bool = False, **kwargs): """ - Register every subclass of DataItem in a global registry. - Classes marked as abstract are not registered and should never be instantiated. - # FixMe: Hugo says it might be useful for database views and such. But for now it is so. + Register every subclass of DataItem in a global registry based on their tags. """ + + super().__init_subclass__(**kwargs) + cls.__abstract = abstract - if cls.__abstract: - # If the class is not fully specialized, skip it + if cls.name() in DataItem._registry: + # If the class is already registered, warn about it and do nothing. Msg.debug(cls.__qualname__, - f"Class is abstract, skipping registration") + f"A class with tag {cls.name()} is already registered, " + f"skipping: {DataItem._registry[cls.name()].__qualname__}") else: - # Otherwise, add it to the global registry - assert cls.__regex_pattern.match(cls.name()) is not None, \ - (f"Tried to register {cls.__name__} ({cls.name()}) which is not fully specialized " - f"(did you mean to set `abstract=True` in the class declaration?)") - - if cls.name().format() in DataItem.__registry: - # If the class is already registered, warn about it and do nothing - Msg.warning(cls.__qualname__, - f"A class with tag {cls.name()} is already registered, " - f"skipping: {DataItem.__registry[cls.name()]}") - else: - # Otherwise add it to the registry - Msg.debug(cls.__qualname__, - f"Registered a new class {cls.name()}: {cls}") - DataItem.__registry[cls.name()] = cls + # Otherwise add the class to the global registry + Msg.debug(cls.__qualname__, + f"Registered a new class {cls.name()}: {cls}") + DataItem._registry[cls.name()] = cls - super().__init_subclass__(**kwargs) + @classmethod + @final + def schema(cls) -> dict[str, Union[None, type[Image], type[Table]]]: + return cls._schema @classmethod @final @@ -122,17 +116,16 @@ def find(cls, key: str) -> Optional[type['DataItem']]: If not found, return ``None`` instead (and leave it to the caller to raise an exception if this is not desired). """ - if key in DataItem.__registry: - return DataItem.__registry[key] + if key in DataItem._registry: + return DataItem._registry[key] else: return None @classmethod - def name_template(cls) -> str: - return cls._name_template - - @classmethod - def specialize(cls, **parameters) -> str: + def specialize(cls, **parameters: str) -> str: + """ + Specialize the data item's name template with given parameters + """ cls._name_template = partial_format(cls._name_template, **parameters) return cls._name_template @@ -155,7 +148,7 @@ def title(cls) -> str: """ assert cls._title_template is not None, \ f"{cls.__name__} title template is None" - return cls._title_template.format(**cls.__replace_empty_tags(**cls.tag_parameters())) + return partial_format(cls._title_template, **cls.__replace_empty_tags(**cls.tag_parameters())) @classmethod def name(cls) -> str: @@ -164,7 +157,7 @@ def name(cls) -> str: """ assert cls._name_template is not None, \ f"{cls.__name__} name template is None" - return cls._name_template.format(**cls.__replace_empty_tags(**cls.tag_parameters())) + return partial_format(cls._name_template, **cls.__replace_empty_tags(**cls.tag_parameters())) @classmethod def description(cls) -> str: @@ -175,7 +168,8 @@ def description(cls) -> str: """ assert cls._description_template is not None, \ f"{cls.__name__} description template is None" - return cls._description_template.format(**cls.__replace_empty_tags(**cls.tag_parameters())) + description = partial_format(cls._description_template, **cls.__replace_empty_tags(**cls.tag_parameters())) + return description @classmethod @final @@ -224,8 +218,9 @@ def __init__(self, primary_header: CplPropertyList = CplPropertyList(), *hdus: Hdu, filename: Optional[Path] = None): - if self.__abstract: - raise TypeError(f"Tried to instantiate an abstract data item {self.__class__.__qualname__}") + if self.__abstract or not self.__regex_pattern.match(self.name()): + raise TypeError(f"Tried to instantiate an abstract data item " + f"{self.__class__.__qualname__} for {self.name()}") # Check if the title is defined if self.title() is None: @@ -234,7 +229,7 @@ def __init__(self, if self.name() is None: raise NotImplementedError(f"DataItem {self.__class__.__qualname__} has no name defined!") - # Check if frame_group is defined (if not, this gives rise to strange errors deep within CPL + # Check if frame_group is defined (if not, it gives rise to strange errors deep within CPL # that you really do not want to deal with) if self.frame_group() is None: raise NotImplementedError(f"DataItem {self.__class__.__qualname__} has no group defined!") @@ -245,15 +240,16 @@ def __init__(self, # Internal usage marker (for used_frames) self._used: bool = False - self.primary_header = primary_header - self.filename = filename + self.primary_header = primary_header + # Currently all items are expected to have an empty primary HDU self._hdus: dict[str, Hdu] = {} for index, hdu in enumerate(hdus, start=1): - assert hdu.name in self._schema, \ - (f"Schema for {self.__class__.__qualname__} does not specify HDU '{hdu.name}'. " - f"Accepted extension names are {list(self._schema.keys())}.") + if hdu.name not in self._schema: + Msg.error(self.__class__.__qualname__, + f"Found a HDU '{hdu.name}', which is not defined by the schema for {self.__class__.__qualname__}. " + f"Accepted extension names are {list(self._schema.keys())}.") assert hdu.klass == self._schema[hdu.name], \ (f"Schema for {self.__class__.__qualname__} specifies that HDU '{hdu.name}' " @@ -307,6 +303,7 @@ def load(cls, extname = header['EXTNAME'].value except KeyError: try: + # FixMe: this is not reliable but XTENSION is sometimes found in the simulated data extname = header['XTENSION'].value except KeyError: extname = 'PRIMARY' @@ -350,9 +347,9 @@ def load(cls, def load_data(self, extension: int | str) -> Image | Table | None: """ - Actually load the associated data (image or a table). + Load the associated data (image or a table). - This might be expensive and therefore the call is better deferred until actually needed. + This might be an expensive operation and therefore the call is better deferred until actually needed. Parameters ---------- @@ -367,12 +364,9 @@ def load_data(self, Raises ------ KeyError - If requested extension is not available + If the requested extension is not available """ - if self[extension].klass is None: - self[extension].klass = Image - try: if self[extension].klass == Image: return self[extension].klass.load(self.filename, cpl.core.Type.FLOAT, self._hdus[extension].extno) @@ -380,7 +374,7 @@ def load_data(self, return self[extension].klass.load(self.filename, self._hdus[extension].extno) except cpl.core.DataNotFoundError as exc: Msg.error(self.__class__.__qualname__, - f"Failed to load data from extension '{extension}' in file {self.filename}") + f"Failed to load data from extension '{extension}' from file {self.filename}") raise exc @property @@ -408,11 +402,10 @@ def _get_file_name(self, override: Optional[str] = None): def add_properties(self) -> None: """ Hook for adding custom properties. - Currently only adds ESO PRO CATG to every product, + + Currently only adds/replaces ESO PRO CATG to/in every product, but derived classes are more than welcome to add their own stuff. Do not forget to call super().add_properties() then. - - #ToDo: this should not be called for raws, those do not have a PRO CATG. """ # Some data products actually have FrameGroup RAW because they are # input to other recipes (to prevent the cryptic empty set-of-frames @@ -518,39 +511,6 @@ def as_dict(self) -> dict[str, str]: 'group': self.frame_group().name, } - def _verify_same_detector_from_header(self) -> None: - """ - Verification for headers, currently disabled - """ - detectors = [] - for frame in self.frameset: - header = cpl.core.PropertyList.load(frame.file, 0) - try: - det = header['ESO DPR TECH'].value - try: - detectors.append({ - 'IMAGE,LM': '2RG', - 'IMAGE,N': 'GEO', - 'IFU': 'IFU', - }[det]) - except KeyError as e: - raise KeyError(f"Invalid detector name! In {frame.file}, ESO DPR TECH is '{det}'") from e - except KeyError: - Msg.warning(self.__class__.__qualname__, "No detector (ESO DPR TECH) set!") - - # Check if all the raws have the same detector, if not, we have a problem - if (detector_count := len(unique := list(set(detectors)))) == 1: - self._detector = unique[0] - Msg.debug(self.__class__.__qualname__, - f"Detector determined: {self._detector}") - elif detector_count == 0: - Msg.warning(self.__class__.__qualname__, - "No detectors specified (this is probably fine in skeleton stage)") - else: - # raise ValueError(f"Frames from more than one detector found: {set(detectors)}!") - Msg.warning(self.__class__.__qualname__, - f"Frames from more than one detector found: {unique}!") - @classmethod def input_for_recipes(cls) -> Generator['PipelineRecipe', None, None]: """ @@ -588,7 +548,7 @@ def _extended_description_line(cls, name: str = None) -> str: Includes leading space. """ - return f" {cls.name():39s}{cls.description() or ''}" + return f" {cls.name():49s}{cls.description() or ''}" def __str__(self): return f"{self.name()}" @@ -630,4 +590,4 @@ def __getitem__(self, item: int | str) -> Hdu: def get_name(self, index: int) -> str: for name, hdu in self._hdus.items(): if self._hdus[name].extno == index: - return name \ No newline at end of file + return name diff --git a/metisp/pymetis/src/pymetis/classes/inputs/__init__.py b/metisp/pymetis/src/pymetis/classes/inputs/__init__.py index b335f35a..c5da71c1 100644 --- a/metisp/pymetis/src/pymetis/classes/inputs/__init__.py +++ b/metisp/pymetis/src/pymetis/classes/inputs/__init__.py @@ -22,7 +22,6 @@ from .input import PipelineInput from .single import SinglePipelineInput from .multiple import MultiplePipelineInput -from .mixins import PersistenceInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin, BadPixMapInputSetMixin from .common import (RawInput, MasterDarkInput, @@ -51,5 +50,4 @@ 'PinholeTableInput', 'DistortionTableInput', 'LsfKernelInput', 'AtmProfileInput', 'MasterRsrfInput', 'WavecalInput', 'OptionalInputMixin', 'LsfKernelInput', 'AtmLineCatInput', 'LaserTableInput', 'SynthTransInput', - 'PersistenceInputSetMixin', 'GainMapInputSetMixin', 'LinearityInputSetMixin', 'BadPixMapInputSetMixin', ] diff --git a/metisp/pymetis/src/pymetis/classes/inputs/input.py b/metisp/pymetis/src/pymetis/classes/inputs/input.py index 3b67da0f..e4263d99 100644 --- a/metisp/pymetis/src/pymetis/classes/inputs/input.py +++ b/metisp/pymetis/src/pymetis/classes/inputs/input.py @@ -72,7 +72,7 @@ def load_frameset(self, frameset: cpl.ui.FrameSet) -> None: @abstractmethod def _load_frameset_specific(self, frameset: cpl.ui.FrameSet) -> None: """ - Actually load the associated frames. Implementation differs between derived classes. + Load the associated frames. Implementation differs between derived classes. """ pass @@ -118,24 +118,33 @@ def __init__(self, frameset: cpl.ui.FrameSet): f"Data item {self.Item.__qualname__} has no defined frame group" # Match all frames that can be processed by this PipelineInput. + Msg.debug(self.__class__.__qualname__, + f"Initializing an input {self.Item.name()}") + for tag, frames in self.preprocess_frameset(frameset).items(): cls = DataItem.find(tag) - if cls is None: Msg.warning(self.__class__.__qualname__, f"Found a frame with tag '{tag}', which is not a registered data item. Ignoring.") continue else: + Msg.debug(self.__class__.__qualname__, + f"Found {cls.__name__} with tag {tag}, " + f"but we are {self.Item.__qualname__} ({self.Item.name()})") if cls == self.Item: Msg.debug(self.__class__.__qualname__, f"Found a fully specialized class {cls.__qualname__} for {tag}, instantiating directly") self.load_frameset(frames) - elif cls in self.Item.__subclasses__(): + elif issubclass(cls, self.Item): + # If there is a more specialized class, use it instead Msg.debug(self.__class__.__qualname__, f"Found a specialized class {cls.__qualname__} for {tag}, " f"subclassing this {self.Item.__qualname__} and instantiating") self.Item = cls self.load_frameset(frames) + else: + Msg.debug(self.__class__.__qualname__, + f"Could not specialize class {self.Item.__qualname__} for {tag}") @abstractmethod def validate(self) -> None: @@ -147,13 +156,13 @@ def validate(self) -> None: @abstractmethod def load_structure(self) -> None: """ - Load the input structure and store as items without data yet. + Load the input structure and store as data items, but without data yet. """ @abstractmethod def load_data(self, extension: int | str = None) -> Union[cpl.core.ImageList, cpl.core.Image, cpl.core.Table]: """ - Load the actual data and return it. + Load the actual data content and return it. """ def print_debug(self, *, offset: int = 0) -> None: @@ -185,7 +194,7 @@ def _extended_description_line(cls, name: str = None) -> str: assert cls.Item.name() is not None, f"{cls.Item.__qualname__} has no name" assert cls.Item.description() is not None, f"{cls.Item.__qualname__} has no description defined" - return (f" {cls.Item.name():<24}[{cls._multiplicity}]{' (optional)' if not cls._required else ' '}" + return (f" {cls.Item.name():<34}[{cls._multiplicity}]{' (optional)' if not cls._required else ' '}" f" {cls.Item.description()}") # f"{f'\n{' ' * 84}'.join([x.__qualname__ for x in set(cls.input_for_recipes())])}") diff --git a/metisp/pymetis/src/pymetis/classes/inputs/inputset.py b/metisp/pymetis/src/pymetis/classes/inputs/inputset.py index 6b680352..8e502c75 100644 --- a/metisp/pymetis/src/pymetis/classes/inputs/inputset.py +++ b/metisp/pymetis/src/pymetis/classes/inputs/inputset.py @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ - +import copy import inspect import re @@ -26,11 +26,11 @@ import cpl from cpl.core import Msg +from pymetis.classes.dataitems import DataItem from pymetis.classes.inputs.input import PipelineInput -from pymetis.classes.mixins.base import Parametrizable, KeywordMixin -class PipelineInputSet(Parametrizable, ABC): +class PipelineInputSet(ABC): """ The `PipelineInputSet` class is a utility class for a recipe dealing with the input data. It reads and filters the input FrameSet, categorizes the frames by their metadata, @@ -75,15 +75,43 @@ def __init__(self, frameset: cpl.ui.FrameSet): self.tag_matches: dict[str, str] = {} # Now iterate over all defined Inputs, instantiate them and feed them the frameset to filter. - for (name, input_class) in self.get_inputs(): + Msg.debug(self.__class__.__qualname__, "Instantiating inputs") + for (name, input_class) in self.list_input_classes(): inp = input_class(frameset) # FixMe: very hacky for now: determine the name of the instance from the name of the class self.__setattr__(self.__make_snake.sub('_', self.__cut_input.sub('', name)).lower(), inp) # Add to the set of inputs (for easy iteration over all inputs) self.inputs |= {inp} + for inp in self.inputs: + Msg.debug(self.__class__.__qualname__, + f" - {inp.Item.name()}") + + @classmethod + def specialize(cls, **parameters) -> None: + """ + Specialize all input classes within this input set, based on tunable parameters. + """ + Msg.debug(cls.__qualname__, f"Now specializing {cls.__qualname__} for {parameters}") + + for name, inp in cls.list_input_classes(): + old_class = inp.Item + # Copy the entire type so that we do not mess up the original one + new_class = type(inp.Item.__name__, inp.Item.__bases__, dict(inp.Item.__dict__)) + new_class.specialize(**parameters) + + if (klass := DataItem.find(new_class._name_template)) is None: + inp.Item = new_class + Msg.debug(cls.__qualname__, f" ! Cannot specialize {old_class.__qualname__} ({old_class.name()}) " + f"for {parameters}, {inp.Item.__qualname__} is now {new_class.__qualname__} ({new_class.name()})") + else: + inp.Item = klass + Msg.debug(cls.__qualname__, + f" - {inp.__qualname__} data item specialized to " + f"{klass.__qualname__} ({klass.name()})") + @classmethod - def get_inputs(cls) -> list[tuple[str, type[PipelineInput]]]: + def list_input_classes(cls) -> list[tuple[str, type[PipelineInput]]]: """ List all input classes within this input set. @@ -106,48 +134,11 @@ def validate(self) -> None: if len(self.inputs) == 0: raise NotImplementedError("PipelineInputSet must define at least one input.") - for inp in self.inputs: inp.validate() + Msg.debug(self.__class__.__qualname__, f"Tag parameters for {inp} are {inp.Item.tag_parameters()}") + self.tag_matches |= inp.Item.tag_parameters() - # Validate that tag parameters match the keyword mixin from which the data items are derived - for attr, klass in KeywordMixin.registry().items(): - self._validate_attr(lambda x: x.Item.tag_parameters()[attr] if issubclass(x.Item, klass) else None, attr) - - def _validate_attr(self, _func: Callable, attr: str) -> Optional[str]: - """ - Helper method: validate the input attribute (detector, band, source or target). - - Return - None, if the attribute cannot be identified (this usually is not an error if it is not defined). - The attribute value, if the attribute only has the same value everywhere. - Raise - ValueError if the attribute has multiple different values. - """ - Msg.debug(self.__class__.__qualname__, f"--- Validating the {attr} parameters ---") - self.tag_matches[attr] = self.tag_parameters()[attr] if attr in self.tag_parameters() else None - total = list(set([_func(inp) for inp in self.inputs]) - {None}) - - for inp in self.inputs: - value = _func(inp) - det = "---" if value is None else value - Msg.debug(self.__class__.__qualname__, - f"{attr:<15s} in {inp.__class__.__qualname__:<54} {det}") - - if (count := len(total)) == 0: - # If there are no identifiable tag parameters, just emit a debug message - # (not a warning -- this is OK for items that are not attribute-specific). - Msg.debug(self.__class__.__qualname__, - f"No {attr} could be identified from the SOF") - elif count == 1: - # If there is exactly one unique value, the input is consistent, so set it as an InputSet tag parameter - result = total[0] - Msg.debug(self.__class__.__qualname__, - f"Correctly identified {attr} from the SOF: {result}") - self.tag_matches[attr] = result - else: - # If there is more than one unique value, the input is inconsistent, raise an exception - raise ValueError(f"Data from more than one {attr} found in inputset: {total}!") def print_debug(self, *, offset: int = 0) -> None: Msg.debug(self.__class__.__qualname__, f"{' ' * offset}--- Detailed class info ---") diff --git a/metisp/pymetis/src/pymetis/classes/inputs/mixins.py b/metisp/pymetis/src/pymetis/classes/inputs/mixins.py deleted file mode 100644 index 9f6faf83..00000000 --- a/metisp/pymetis/src/pymetis/classes/inputs/mixins.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -This file is part of the METIS Pipeline. -Copyright (C) 2024 European Southern Observatory - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -""" - -from .inputset import PipelineInputSet -from .common import (GainMapInput, LinearityInput, BadPixMapInput, - AtmLineCatInput, AtmProfileInput, LsfKernelInput, WcuOffInput, OptionalPersistenceMapInput) - - -class PersistenceInputSetMixin(PipelineInputSet): - PersistenceMapInput = OptionalPersistenceMapInput - - -class GainMapInputSetMixin(PipelineInputSet): - GainMapInput = GainMapInput - - -class LinearityInputSetMixin(PipelineInputSet): - LinearityInput = LinearityInput - - -class BadPixMapInputSetMixin(PipelineInputSet): - BadPixMapInput = BadPixMapInput - - -class AtmLineCatInputSetMixin(PipelineInputSet): - AtmLineCatInput = AtmLineCatInput - - -class AtmProfileInputSetMixin(PipelineInputSet): - AtmProfileInput = AtmProfileInput - - -class LsfKernelInputSetMixin(PipelineInputSet): - LsfKernelInput = LsfKernelInput - - -class WcuOffInputSetMixin(PipelineInputSet): - WcuOffInput = WcuOffInput diff --git a/metisp/pymetis/src/pymetis/classes/inputs/multiple.py b/metisp/pymetis/src/pymetis/classes/inputs/multiple.py index cc43465e..06734000 100644 --- a/metisp/pymetis/src/pymetis/classes/inputs/multiple.py +++ b/metisp/pymetis/src/pymetis/classes/inputs/multiple.py @@ -21,7 +21,7 @@ import cpl -from cpl.core import Msg, Image, ImageList, PropertyList +from cpl.core import Msg, Image, ImageList from pymetis.classes.dataitems import DataItem from pymetis.classes.inputs.input import PipelineInput @@ -57,6 +57,8 @@ def load_structure(self) -> None: ------- None """ + Msg.info(self.__class__.__name__, + f"Loading {self.Item.__qualname__} items") if len(self.items) != 0: Msg.debug(self.__class__.__qualname__, f"Input already loaded, skipping") @@ -65,11 +67,11 @@ def load_structure(self) -> None: for idx, frame in enumerate(self.frameset): Msg.info(self.__class__.__qualname__, - f"Loading input frame #{idx}: {frame.file!r}") + f" - loading input frame #{idx}: {frame.file!r}") self.items.append(self.Item.load(frame)) Msg.info(self.__class__.__qualname__, - f"Items are now {self.items}") + f"Input Items loaded: {self.items}") self.use() # FixMe: for now anything that is actually loaded is marked as used @@ -95,7 +97,7 @@ def load_data(self, extension: int | str = None) -> ImageList: self.load_structure() Msg.info(self.__class__.__qualname__, - f"Loading multiple input frames for extension: {extension}") + f"Loading extension '{extension}' from multiple frames {self.frameset}") images = [item.load_data(extension) for item in self.items] return ImageList(images) diff --git a/metisp/pymetis/src/pymetis/classes/inputs/single.py b/metisp/pymetis/src/pymetis/classes/inputs/single.py index 8a161dc0..9c0deb17 100644 --- a/metisp/pymetis/src/pymetis/classes/inputs/single.py +++ b/metisp/pymetis/src/pymetis/classes/inputs/single.py @@ -41,8 +41,10 @@ def __init__(self, def _load_frameset_specific(self, frameset: cpl.ui.FrameSet): """ - Load the associated frames. - A SinglePipelineInput verifies there is exactly one matched frame. + Assign the associated frame. + + SinglePipelineInput also verifies there is exactly one matched frame, + if not, a warning is issued and the first found frame is used. """ Msg.debug(self.__class__.__qualname__, f"Loading {frameset}") if (count := len(frameset)) == 0: @@ -72,7 +74,7 @@ def load_data(self, extension: str = None) -> Image | Table: self.load_structure() Msg.info(self.__class__.__qualname__, - f"Item is now {self.item}") + f"Loading extension '{extension}' from a single frame {self.frame.file}") return self.item.load_data(extension) diff --git a/metisp/pymetis/src/pymetis/classes/mixins/__init__.py b/metisp/pymetis/src/pymetis/classes/mixins/__init__.py index 43630fa3..3a24f139 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/__init__.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/__init__.py @@ -17,22 +17,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from .detector import (DetectorSpecificMixin, - Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin) -from .band import (BandSpecificMixin, - BandLmMixin, BandNMixin, BandIfuMixin) -from .target import (TargetSpecificMixin, - TargetStdMixin, TargetSciMixin, TargetSkyMixin) -from .source import (SourceSpecificMixin, - SourceLampMixin, SourceTwilightMixin) -from .cgrph import (CgrphSpecificMixin, - CgrphRavcMixin, CgrphCvcMixin, CgrphAppMixin) +from .detector import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin +from .band import BandLmMixin, BandNMixin, BandIfuMixin +from .target import TargetStdMixin, TargetSciMixin, TargetSkyMixin +from .source import SourceLampMixin, SourceTwilightMixin +from .cgrph import CgrphRavcMixin, CgrphCvcMixin, CgrphAppMixin __all__ = [ - 'DetectorSpecificMixin', 'Detector2rgMixin', 'DetectorGeoMixin', 'DetectorIfuMixin', - 'BandSpecificMixin', 'BandLmMixin', 'BandNMixin', 'BandIfuMixin', - 'TargetSpecificMixin', 'TargetStdMixin', 'TargetSciMixin', 'TargetSkyMixin', - 'SourceSpecificMixin', 'SourceTwilightMixin', 'SourceLampMixin', - 'CgrphSpecificMixin', 'CgrphRavcMixin', 'CgrphCvcMixin', 'CgrphAppMixin', + 'Detector2rgMixin', 'DetectorGeoMixin', 'DetectorIfuMixin', + 'BandLmMixin', 'BandNMixin', 'BandIfuMixin', + 'TargetStdMixin', 'TargetSciMixin', 'TargetSkyMixin', + 'SourceTwilightMixin', 'SourceLampMixin', + 'CgrphRavcMixin', 'CgrphCvcMixin', 'CgrphAppMixin', ] diff --git a/metisp/pymetis/src/pymetis/classes/mixins/band.py b/metisp/pymetis/src/pymetis/classes/mixins/band.py index 0b728a41..c3edbff2 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/band.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/band.py @@ -17,33 +17,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from pymetis.classes.mixins.base import KeywordMixin +from pymetis.classes.mixins.base import Parametrizable -class BandSpecificMixin(KeywordMixin, keyword='band'): - _band: str = None - - @classmethod - def band(cls) -> str: - return cls._band - - def __init_subclass__(cls, *, band=None, **kwargs): - if band is not None: - cls._band = band - super().__init_subclass__(**kwargs) - - @classmethod - def tag_parameters(cls): - return super().tag_parameters() | {'band': cls._band} - - -class BandLmMixin(BandSpecificMixin, band='LM'): +class BandLmMixin(Parametrizable, band='LM'): pass -class BandNMixin(BandSpecificMixin, band='N'): +class BandNMixin(Parametrizable, band='N'): pass -class BandIfuMixin(BandSpecificMixin, band='IFU'): +class BandIfuMixin(Parametrizable, band='IFU'): pass diff --git a/metisp/pymetis/src/pymetis/classes/mixins/base.py b/metisp/pymetis/src/pymetis/classes/mixins/base.py index d21d0891..43bdc863 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/base.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/base.py @@ -17,9 +17,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from abc import ABC -from typing import Self - class Parametrizable: """ @@ -34,33 +31,23 @@ class Parametrizable: Currently applies to DataItems, PipelineInputSets and their Mixins. """ + _tag_parameters: dict[str, str] = {} + @classmethod def tag_parameters(cls) -> dict[str, str]: """ Return the tag parameters for this class. By default, there are none, but mixins may add their own. """ - return {} - - -class KeywordMixin(Parametrizable, ABC): - """ - Base class for keyword-parametrizable mixins. - - Contains a global registry of such classes, with placeholders as keys - """ + return cls._tag_parameters - # Global registry of parametrizable tags in the form {keyword: class}, - # e.g. {'detector': DetectorSpecificMixin, ...} - # Filled automatically with __init_subclass__. - _registry: dict[str, type[Self]] = {} + def __init_subclass__(cls, **kwargs): + merged = {} + for base in reversed(cls.__mro__): + params = base.__dict__.get('_tag_parameters') + if isinstance(params, dict): + merged.update(params) - def __init_subclass__(cls, *, keyword: str = None, **kwargs): - if keyword is not None: - cls._registry[keyword] = cls - super().__init_subclass__(**kwargs) + merged.update(kwargs) - @classmethod - def registry(cls) -> dict[str, type[Self]]: - """ Class property to access the global registry """ - return cls._registry + cls._tag_parameters = merged diff --git a/metisp/pymetis/src/pymetis/classes/mixins/cgrph.py b/metisp/pymetis/src/pymetis/classes/mixins/cgrph.py index 68b346c7..7155b4ab 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/cgrph.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/cgrph.py @@ -17,34 +17,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from pymetis.classes.mixins.base import KeywordMixin +from pymetis.classes.mixins.base import Parametrizable -class CgrphSpecificMixin(KeywordMixin, keyword='cgrph'): - _cgrph: str = None - - @classmethod - def cgrph(cls) -> str: - return cls._cgrph - - def __init_subclass__(cls, *, cgrph=None, **kwargs): - if cgrph is not None: - cls._cgrph = cgrph - super().__init_subclass__(**kwargs) - - @classmethod - def tag_parameters(cls): - return super().tag_parameters() | {'cgrph': cls._cgrph} - - -class CgrphRavcMixin(CgrphSpecificMixin, cgrph='RAVC'): +class CgrphRavcMixin(Parametrizable, cgrph='RAVC'): pass -class CgrphCvcMixin(CgrphSpecificMixin, cgrph='CVC'): +class CgrphCvcMixin(Parametrizable, cgrph='CVC'): pass -class CgrphAppMixin(CgrphSpecificMixin, cgrph='APP'): +class CgrphAppMixin(Parametrizable, cgrph='APP'): pass diff --git a/metisp/pymetis/src/pymetis/classes/mixins/detector.py b/metisp/pymetis/src/pymetis/classes/mixins/detector.py index 27872988..05a10248 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/detector.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/detector.py @@ -17,35 +17,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from typing import Optional - from cpl.core import Image -from pymetis.classes.mixins.base import KeywordMixin - - -class DetectorSpecificMixin(KeywordMixin, keyword='detector'): - _detector = None - - def __init_subclass__(cls, *, detector: Optional[str] = None, **kwargs): - if detector is not None: - cls._detector = detector - super().__init_subclass__(**kwargs) - - @classmethod - def tag_parameters(cls): - return super().tag_parameters() | {'detector': cls._detector} +from pymetis.classes.mixins.base import Parametrizable -class Detector2rgMixin(DetectorSpecificMixin, detector='2RG'): +class Detector2rgMixin(Parametrizable, detector='2RG'): pass -class DetectorGeoMixin(DetectorSpecificMixin, detector='GEO'): +class DetectorGeoMixin(Parametrizable, detector='GEO'): pass -class DetectorIfuMixin(DetectorSpecificMixin, detector='IFU'): +class DetectorIfuMixin(Parametrizable, detector='IFU'): _schema = { r'PRIMARY': None, } | { diff --git a/metisp/pymetis/src/pymetis/classes/mixins/source.py b/metisp/pymetis/src/pymetis/classes/mixins/source.py index f1f28f7f..ca12d335 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/source.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/source.py @@ -17,44 +17,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from pymetis.classes.mixins.base import KeywordMixin +from pymetis.classes.mixins.base import Parametrizable -class SourceSpecificMixin(KeywordMixin, keyword='source'): - """ - Mixin class for data items that need to define the `target` attribute. - - Hopefully it does not cause any issues with the MRO. - """ - _source: str = None - - def __init_subclass__(cls, *, source=None, **kwargs): - if source is not None: - cls._source = source - super().__init_subclass__(**kwargs) - - @classmethod - def source(cls) -> str: - return cls._source - - @classmethod - def get_source_string(cls) -> str: - """ - Return a pretty formatted target string for human-oriented output. - """ - return { - 'LAMP': 'lamp', - 'TWILIGHT': 'twilight', - }.get(cls.source(), cls.source()) - - @classmethod - def tag_parameters(cls): - return super().tag_parameters() | {'source': cls._source} - - -class SourceLampMixin(SourceSpecificMixin, source='LAMP'): +class SourceLampMixin(Parametrizable, source='LAMP'): pass -class SourceTwilightMixin(SourceSpecificMixin, source='TWILIGHT'): +class SourceTwilightMixin(Parametrizable, source='TWILIGHT'): pass diff --git a/metisp/pymetis/src/pymetis/classes/mixins/target.py b/metisp/pymetis/src/pymetis/classes/mixins/target.py index 5d242df1..339c1552 100644 --- a/metisp/pymetis/src/pymetis/classes/mixins/target.py +++ b/metisp/pymetis/src/pymetis/classes/mixins/target.py @@ -17,49 +17,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -from pymetis.classes.mixins.base import KeywordMixin +from pymetis.classes.mixins.base import Parametrizable -class TargetSpecificMixin(KeywordMixin, keyword='target'): - """ - Mixin class for data items that need to define the `target` attribute. - - Hopefully it does not cause any issues with the MRO. - """ - _target: str = None - - def __init_subclass__(cls, *, target=None, **kwargs): - if target is not None: - cls._target = target - super().__init_subclass__(**kwargs) - - @classmethod - def target(cls) -> str: - return cls._target - - @classmethod - def get_target_string(cls) -> str: - """ - Return a pretty formatted target string for human-oriented output. - """ - return { - 'SCI': 'science object', - 'STD': 'standard star', - 'SKY': 'sky', - }.get(cls.target(), cls.target()) - - @classmethod - def tag_parameters(cls): - return super().tag_parameters() | {'target': cls._target} - - -class TargetStdMixin(TargetSpecificMixin, target='STD'): +class TargetStdMixin(Parametrizable, target='STD'): pass -class TargetSciMixin(TargetSpecificMixin, target='SCI'): +class TargetSciMixin(Parametrizable, target='SCI'): pass -class TargetSkyMixin(TargetSpecificMixin, target='SKY'): +class TargetSkyMixin(Parametrizable, target='SKY'): pass diff --git a/metisp/pymetis/src/pymetis/classes/prefab/darkimage.py b/metisp/pymetis/src/pymetis/classes/prefab/darkimage.py index cf4f1c3a..44bc422e 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/darkimage.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/darkimage.py @@ -43,7 +43,8 @@ class InputSet(RawImageProcessor.InputSet, abstract=True): A DarkImageProcessor's Input is just a raw image processor input with a master dark frame. The exact class is not specified at this point -- it must be set by the subclass. """ - MasterDarkInput: type[PipelineInput] = MasterDarkInput + class MasterDarkInput(MasterDarkInput): + pass def subtract_dark(self, images: cpl.core.ImageList) -> cpl.core.ImageList: diff --git a/metisp/pymetis/src/pymetis/classes/prefab/img/calibrate.py b/metisp/pymetis/src/pymetis/classes/prefab/img/calibrate.py index 8d841e51..cab52955 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/img/calibrate.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/img/calibrate.py @@ -20,7 +20,7 @@ from abc import ABC from pymetis.classes.dataitems import DataItem, Hdu -from pymetis.dataitems.background.subtracted import SciBackgroundSubtracted +from pymetis.dataitems.background.subtracted import BackgroundSubtracted from pymetis.dataitems.distortion.table import DistortionTable from pymetis.dataitems.img.basicreduced import Calibrated from pymetis.classes.inputs import FluxCalTableInput @@ -30,11 +30,12 @@ class MetisImgCalibrateImpl(MetisRecipeImpl, ABC): - class InputSet(PipelineInputSet, abstract=True): + class InputSet(PipelineInputSet): class BackgroundInput(SinglePipelineInput): - Item = SciBackgroundSubtracted + Item = BackgroundSubtracted - FluxcalTableInput = FluxCalTableInput + class FluxcalTableInput(FluxCalTableInput): + pass # ToDo let's make TAB / TABLE consistent one day class DistortionTableInput(SinglePipelineInput): diff --git a/metisp/pymetis/src/pymetis/classes/prefab/img/distortion.py b/metisp/pymetis/src/pymetis/classes/prefab/img/distortion.py index 0f81b8f4..2ddaa803 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/img/distortion.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/img/distortion.py @@ -26,20 +26,30 @@ from pymetis.dataitems.distortion.table import DistortionTable from pymetis.dataitems.raw.wcuoff import WcuOffRaw from pymetis.classes.prefab.rawimage import RawImageProcessor -from pymetis.classes.inputs import (RawInput, SinglePipelineInput, PinholeTableInput, PersistenceInputSetMixin, - LinearityInputSetMixin, GainMapInputSetMixin) +from pymetis.classes.inputs import RawInput, SinglePipelineInput, PinholeTableInput, GainMapInput, LinearityInput, \ + OptionalInputMixin, PersistenceMapInput from pymetis.utils.dummy import create_dummy_table, create_dummy_image, create_dummy_header class MetisBaseImgDistortionImpl(RawImageProcessor, ABC): - class InputSet(PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin, RawImageProcessor.InputSet): + class InputSet(RawImageProcessor.InputSet): class RawInput(RawInput): Item = WcuOffRaw + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + class DistortionInput(SinglePipelineInput): Item = DistortionRaw - PinholeTableInput = PinholeTableInput + class PinholeTableInput(PinholeTableInput): + pass ProductDistortionTable = DistortionTable ProductDistortionMap = DistortionMap diff --git a/metisp/pymetis/src/pymetis/classes/prefab/img/flat.py b/metisp/pymetis/src/pymetis/classes/prefab/img/flat.py index 6680e663..513f878f 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/img/flat.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/img/flat.py @@ -25,19 +25,29 @@ from pymetis.classes.dataitems import DataItem, Hdu from pymetis.dataitems.masterflat import MasterImgFlat from pymetis.dataitems.masterflat.raw import FlatRaw -from pymetis.classes.inputs import RawInput, MasterDarkInput +from pymetis.classes.inputs import RawInput, MasterDarkInput, OptionalInputMixin, PersistenceMapInput, GainMapInput, \ + LinearityInput from pymetis.classes.prefab.darkimage import DarkImageProcessor -from pymetis.classes.inputs import PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin from pymetis.utils.dummy import create_dummy_header class MetisBaseImgFlatImpl(DarkImageProcessor, ABC): - class InputSet(PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin, DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): """ Base class for Inputs which create flats. Requires a set of raw frames and a master dark. """ - MasterDarkInput = MasterDarkInput + class MasterDarkInput(MasterDarkInput): + pass + + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass class RawInput(RawInput): Item = FlatRaw diff --git a/metisp/pymetis/src/pymetis/classes/prefab/img/std_process.py b/metisp/pymetis/src/pymetis/classes/prefab/img/std_process.py index 553aef5b..a9ee6701 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/img/std_process.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/img/std_process.py @@ -19,24 +19,26 @@ import copy from pymetis.classes.dataitems import DataItem, Hdu -from pymetis.dataitems.background.subtracted import StdBackgroundSubtracted +from pymetis.classes.mixins import TargetStdMixin +from pymetis.dataitems.background.subtracted import BackgroundSubtracted from pymetis.dataitems.combined import Combined -from pymetis.dataitems.common import FluxCalTable from pymetis.classes.inputs import RawInput from pymetis.classes.inputs import FluxstdCatalogInput from pymetis.classes.prefab.rawimage import RawImageProcessor +from pymetis.dataitems.common import FluxCalTable from pymetis.utils.dummy import create_dummy_table, create_dummy_header -class MetisImgStdProcessImpl(RawImageProcessor): +class MetisImgStdProcessImpl(TargetStdMixin, RawImageProcessor): class InputSet(RawImageProcessor.InputSet): class RawInput(RawInput): - Item = StdBackgroundSubtracted + Item = BackgroundSubtracted - FluxstdCatalogInput = FluxstdCatalogInput + class FluxstdCatalogInput(FluxstdCatalogInput): + pass - ProductImgFluxCalTable = FluxCalTable ProductImgStdCombined = Combined + ProductImgFluxCalTable = FluxCalTable def process(self) -> set[DataItem]: raw_images = self.inputset.raw.load_data('DET1.DATA') diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/adc.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/adc.py index 163736a9..ceb6d016 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/adc.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/adc.py @@ -16,22 +16,35 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ + from pymetis.classes.dataitems import DataItem, Hdu +from pymetis.classes.inputs.common import WcuOffInput, BadPixMapInput from pymetis.dataitems.adc.adc import AdcSlitloss, AdcSlitlossRaw -from pymetis.classes.inputs import PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin, \ - BadPixMapInputSetMixin, RawInput -from pymetis.classes.inputs.mixins import WcuOffInputSetMixin +from pymetis.classes.inputs import RawInput, OptionalInputMixin, PersistenceMapInput, GainMapInput, LinearityInput from pymetis.classes.prefab import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header, create_dummy_table class MetisAdcSlitlossImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin, BadPixMapInputSetMixin, - WcuOffInputSetMixin, - DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = AdcSlitlossRaw + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class BadPixMapInput(BadPixMapInput): + pass + + class WcuOffInput(WcuOffInput): + pass + ProductAdcSlitloss = AdcSlitloss # ========================================================================================= diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_calctrans.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_calctrans.py index bf8d916a..b6e23ab4 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_calctrans.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_calctrans.py @@ -20,17 +20,26 @@ from pymetis.classes.dataitems import DataItem, Hdu from pymetis.dataitems.molecfit.model import MfBestFitTable from pymetis.dataitems.synth import LssSynthTrans -from pymetis.classes.inputs import PipelineInputSet, SinglePipelineInput -from pymetis.classes.inputs.mixins import LsfKernelInputSetMixin, AtmLineCatInputSetMixin, AtmProfileInputSetMixin +from pymetis.classes.inputs import PipelineInputSet, SinglePipelineInput, AtmLineCatInput, AtmProfileInput, \ + LsfKernelInput from pymetis.classes.recipes import MetisRecipeImpl from pymetis.utils.dummy import create_dummy_table, create_dummy_header class MetisLssMfCalctransImpl(MetisRecipeImpl): - class InputSet(AtmLineCatInputSetMixin, AtmProfileInputSetMixin, LsfKernelInputSetMixin, PipelineInputSet): + class InputSet(PipelineInputSet): class MfBestFitTableInput(SinglePipelineInput): Item = MfBestFitTable + class AtmLineCatInput(AtmLineCatInput): + pass + + class AtmProfileInput(AtmProfileInput): + pass + + class LsfKernelInput(LsfKernelInput): + pass + # TODO: Check whether calctrans creates the transmission file directly, so it should not be defined here ProductTransmission = LssSynthTrans diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_model.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_model.py index 34dcd07c..4d6cf2c9 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_model.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/mf_model.py @@ -20,17 +20,23 @@ from pymetis.classes.dataitems import DataItem, Hdu from pymetis.dataitems.lss.science import LssSciFlux1d, LssSci1d from pymetis.dataitems.molecfit.model import MfBestFitTable -from pymetis.classes.inputs import PipelineInputSet, SinglePipelineInput -from pymetis.classes.inputs.mixins import AtmProfileInputSetMixin, AtmLineCatInputSetMixin, LsfKernelInputSetMixin +from pymetis.classes.inputs import (PipelineInputSet, SinglePipelineInput, + AtmLineCatInput, AtmProfileInput, LsfKernelInput) from pymetis.classes.recipes import MetisRecipeImpl from pymetis.utils.dummy import create_dummy_header, create_dummy_table class MetisLssMfModelImpl(MetisRecipeImpl): - class InputSet(AtmProfileInputSetMixin, - AtmLineCatInputSetMixin, - LsfKernelInputSetMixin, - PipelineInputSet): + class InputSet(PipelineInputSet): + class AtmLineCatInput(AtmLineCatInput): + pass + + class AtmProfileInput(AtmProfileInput): + pass + + class LsfKernelInput(LsfKernelInput): + pass + # ++++++++++++ Main input ++++++++++++ # Default (Path #2 in DRLD Section CritAlg) class LssSciFlux1dInput(SinglePipelineInput): diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/rsrf.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/rsrf.py index e0a44f7e..b7fae2b2 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/rsrf.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/rsrf.py @@ -23,18 +23,29 @@ from pymetis.classes.dataitems import DataItem, Hdu from pymetis.dataitems.lss.rsrf import LssRsrfRaw, MedianLssRsrf, MeanLssRsrf, MasterLssRsrf from pymetis.dataitems.raw.wcuoff import WcuOffRaw -from pymetis.classes.inputs import RawInput, PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, \ - LinearityInputSetMixin +from pymetis.classes.inputs import RawInput, OptionalInputMixin, PersistenceMapInput, GainMapInput, LinearityInput, \ + BadPixMapInput from pymetis.classes.prefab import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header class MetisLssRsrfImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin, - DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = LssRsrfRaw + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class BadPixMapInput(BadPixMapInput): + pass + class LmRsrfWcuOffInput(RawInput): Item = WcuOffRaw diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/sci.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/sci.py index 5e0dac05..9fef19f2 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/sci.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/sci.py @@ -23,25 +23,35 @@ from pymetis.classes.dataitems import DataItem, Hdu from pymetis.dataitems.adc.adc import AdcSlitloss from pymetis.dataitems.lss.curve import LssDistSol, LssWaveGuess -from pymetis.dataitems.lss.raw import LssSciRaw +from pymetis.dataitems.lss.raw import LssRaw from pymetis.dataitems.lss.response import MasterResponse, StdTransmission from pymetis.dataitems.lss.rsrf import MasterLssRsrf from pymetis.dataitems.lss.science import LssObjMap, LssSkyMap, LssSci1d, LssSci2d, LssSciFlux1d, \ LssSciFlux2d, LssSciFluxTellCorr1d from pymetis.dataitems.lss.std import AoPsfModel -from pymetis.classes.inputs import RawInput, PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, \ - LinearityInputSetMixin, SinglePipelineInput -from pymetis.classes.inputs.mixins import AtmLineCatInputSetMixin +from pymetis.classes.inputs import RawInput, \ + SinglePipelineInput, AtmLineCatInput, OptionalInputMixin, PersistenceMapInput, GainMapInput, \ + LinearityInput, BadPixMapInput from pymetis.classes.prefab import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header, create_dummy_image, create_dummy_table class MetisLssSciImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin, - AtmLineCatInputSetMixin, - DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): - Item = LssSciRaw + Item = LssRaw + + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class BadPixMapInput(BadPixMapInput): + pass class MasterRsrfInput(SinglePipelineInput): Item = MasterLssRsrf @@ -79,11 +89,21 @@ class MasterAoPsfModel(SinglePipelineInput): # CHECK THE AO PSF MODEL - why not included? forgotten???? # -------------------------------------------------------------------- - ProductLssSciObjMap = LssObjMap - ProductLssSciSkyMap = LssSkyMap - ProductLssSci1d = LssSci1d - ProductLssSci2d = LssSci2d - ProductLssSciFlux1d = LssSciFlux1d + class ProductLssSciObjMap(LssObjMap, abstract=True): + pass + + class ProductLssSciSkyMap(LssSkyMap, abstract=True): + pass + + class ProductLssSci1d(LssSci1d, abstract=True): + pass + + class ProductLssSci2d(LssSci2d, abstract=True): + pass + + class ProductLssSciFlux1d(LssSciFlux1d, abstract=True): + pass + ProductLssSciFlux2d = LssSciFlux2d ProductLssSciFluxTellCorr1d = LssSciFluxTellCorr1d diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/std.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/std.py index a532d85d..5b06c88e 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/std.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/std.py @@ -23,28 +23,44 @@ from pymetis.classes.dataitems import DataItem, Hdu from pymetis.dataitems.adc.adc import AdcSlitloss from pymetis.dataitems.lss.curve import LssDistSol, LssWaveGuess -from pymetis.dataitems.lss.raw import LssStdRaw +from pymetis.dataitems.lss.raw import LssRaw from pymetis.dataitems.lss.response import MasterResponse, StdTransmission -from pymetis.dataitems.lss.rsrf import MasterLssRsrf from pymetis.dataitems.lss.science import LssSkyMap, LssObjMap from pymetis.dataitems.lss.std import RefStdCat, AoPsfModel, LssStd1d from pymetis.dataitems.lss.trace import LssTrace from pymetis.dataitems.synth import SynthTrans -from pymetis.classes.inputs import RawInput, PersistenceInputSetMixin, MasterDarkInput, BadPixMapInputSetMixin, \ - GainMapInputSetMixin, SinglePipelineInput, FluxstdCatalogInput, MasterRsrfInput, LinearityInputSetMixin -from pymetis.classes.inputs.mixins import AtmLineCatInputSetMixin +from pymetis.classes.inputs import RawInput, MasterDarkInput, \ + SinglePipelineInput, FluxstdCatalogInput, MasterRsrfInput, PersistenceMapInput, BadPixMapInput, GainMapInput, \ + LinearityInput, AtmLineCatInput from pymetis.classes.prefab import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header, create_dummy_image, create_dummy_table class MetisLssStdImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin, - AtmLineCatInputSetMixin, DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): - Item = LssStdRaw + Item = LssRaw - MasterDarkInput = MasterDarkInput - MasterRsrfInput = MasterRsrfInput + class MasterDarkInput(MasterDarkInput): + pass + + class MasterRsrfInput(MasterRsrfInput): + pass + + class PersistenceInput(PersistenceMapInput): + pass + + class BadPixMapInput(BadPixMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class AtmLineCatInput(AtmLineCatInput): + pass class MasterLssTrace(SinglePipelineInput): Item = LssTrace diff --git a/metisp/pymetis/src/pymetis/classes/prefab/lss/trace.py b/metisp/pymetis/src/pymetis/classes/prefab/lss/trace.py index df34536f..4d7c8002 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/lss/trace.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/lss/trace.py @@ -22,19 +22,30 @@ from pymetis.dataitems.lss.rsrf import LssRsrfPinholeRaw, MasterLssRsrf from pymetis.dataitems.lss.trace import LssTrace from pymetis.dataitems.raw.wcuoff import WcuOffRaw -from pymetis.classes.inputs import (SinglePipelineInput, RawInput, PersistenceInputSetMixin, - BadPixMapInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin) +from pymetis.classes.inputs import SinglePipelineInput, RawInput, PersistenceMapInput, OptionalInputMixin, GainMapInput, \ + LinearityInput, BadPixMapInput from pymetis.classes.prefab import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header, create_dummy_table class MetisLssTraceImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin, - DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = LssRsrfPinholeRaw + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class BadPixMapInput(BadPixMapInput): + pass + class LmRsrfWcuOffInput(RawInput): Item = WcuOffRaw diff --git a/metisp/pymetis/src/pymetis/classes/prefab/persistence.py b/metisp/pymetis/src/pymetis/classes/prefab/persistence.py new file mode 100644 index 00000000..b4f36210 --- /dev/null +++ b/metisp/pymetis/src/pymetis/classes/prefab/persistence.py @@ -0,0 +1,18 @@ +from cpl.core import ImageList, Msg + + +class PersistenceCorrectionMixin: + """ + A mixin that performs persistence correction. + """ + def correct_persistence(self, raw_images: ImageList) -> ImageList: + """ + Correct the raw image list for persistence. + + # FixMe Currently only a mockup, does not actually do anything. + """ + persistence = self.inputset.persistence_map.load_data(extension=rf'PERSISTENCE_MAP') + raw_images.subtract_image(persistence) + + Msg.info(self.__class__.__qualname__, f"Pretending to do persistence correction") + return raw_images diff --git a/metisp/pymetis/src/pymetis/classes/prefab/rawimage.py b/metisp/pymetis/src/pymetis/classes/prefab/rawimage.py index 0129bbd9..32989fdc 100644 --- a/metisp/pymetis/src/pymetis/classes/prefab/rawimage.py +++ b/metisp/pymetis/src/pymetis/classes/prefab/rawimage.py @@ -125,7 +125,7 @@ def combine_images_with_error(cls, return combined_image, error - def correct_gain(self, raw_images: ImageList) -> ImageList: + def correct_gain(self, raw_images: ImageList, gain: Image) -> ImageList: """ Correct the raw image list for gain. @@ -142,28 +142,18 @@ def correct_gain(self, raw_images: ImageList) -> ImageList: List of gain-corrected images """ Msg.info(self.__class__.__qualname__, - f"Correcting raw images for gain") + f"Pretending to correct raw images for gain") - gain = cpl.core.Image.zeros_like(raw_images[0]) - gain.add_scalar(1) raw_images.divide_image(gain) return raw_images - def correct_persistence(self, raw_images: ImageList) -> ImageList: - """ - Correct the raw image list for persistence. - - # FixMe Currently only a mockup, does not do anything. - """ - Msg.info(self.__class__.__qualname__, f"Pretending to do persistence correction") - return raw_images def correct_nonlinearity(self, raw_images: ImageList, linearity_map: Image) -> ImageList: """ Correct the raw image list for non-linearity. - # FixMe Currently only a mockup, does not do anything. + # FixMe Currently only a mockup, does not actually do anything. Parameters ---------- @@ -184,8 +174,8 @@ def calculate_outliers(self, kappa_low: int, kappa_high: int) -> tuple[cpl.core.Mask, cpl.core.Mask]: """ - Calculate masks for outlier pixels, with kappa-sigma clipping - whose values are outside [median - kappa_low * sigma, median + kappa_high * sigma]. + Calculate masks for outlier pixels, with kappa-sigma clipping: + mask those values are outside [median - kappa_low * sigma, median + kappa_high * sigma]. """ Msg.info(self.__class__.__qualname__, f"Identifying outlier pixels ({kappa_low=}, {kappa_high=})") @@ -199,7 +189,7 @@ def calculate_outliers(self, # ToDo: why is this not the other way around? Set everything above threshold to 0... mask_hot = cpl.core.Mask.threshold_image(image, 0, image_median + kappa_high * image_rms, 1) - # ToDo ...and then here everything below threshold to 0 too. Would be more consistent. + # ToDo ...and then here everything below threshold to 0 too. Would be more consistent maybe? mask_cold = cpl.core.Mask.threshold_image(image, 0, image_median - kappa_low * image_rms, 0) return mask_hot, mask_cold @@ -212,7 +202,7 @@ def metis_bpm_3d_compute(self, """ Calculate mask for outlier pixels based on high/low thresholds based on the frame to frame variation of a pixel. - ToDo description + ToDo detailed description Parameters ---------- diff --git a/metisp/pymetis/src/pymetis/classes/recipes/impl.py b/metisp/pymetis/src/pymetis/classes/recipes/impl.py index 81cfe13f..411be7c3 100644 --- a/metisp/pymetis/src/pymetis/classes/recipes/impl.py +++ b/metisp/pymetis/src/pymetis/classes/recipes/impl.py @@ -28,9 +28,10 @@ from pymetis.classes.dataitems import DataItem from pymetis.classes.inputs.inputset import PipelineInputSet +from pymetis.classes.mixins.base import Parametrizable -class MetisRecipeImpl(ABC): +class MetisRecipeImpl(Parametrizable, ABC): """ An abstract base class for all METIS recipe implementations. Contains central data flow control and also provides abstract methods to be overridden @@ -61,22 +62,49 @@ def __init__(self, self.frameset: cpl.ui.FrameSet = frameset self.inputset: PipelineInputSet = self.InputSet(frameset) # Create an appropriate InputSet object self.inputset.validate() # Verify that they are valid (maybe with `schema` too?) - self.promote(**self.inputset.tag_matches) + + # Promote the implementation to the correct subclass, based on + # - tag parameters (from defined mixins, class-based) + # - tag matches (from the loaded frameset, instance-based) + # ToDo: Decide what to do in case of a conflict between those two + self.promote(**(self.tag_parameters() | self.inputset.tag_matches)) self.import_settings(settings) # Import and process the provided settings dict self.inputset.print_debug() Msg.debug(self.__class__.__qualname__, f"{'-' * 40} Recipe initialization complete {'-' * 40}") @classmethod - def specialize(cls, **parameters) -> None: - Msg.info(cls.__qualname__, - f"Specializing {cls.__qualname__} with parameters: {parameters}") + def specialize(cls) -> None: + """ + Specialize the recipe implementation to the current class parameters. + """ + Msg.debug(cls.__qualname__, f"Specializing {cls.__qualname__} with {cls.tag_parameters()}") + cls.InputSet.specialize(**cls.tag_parameters()) + + for name, item_class in cls.list_product_classes(): + old_class = item_class + # Copy the entire type so that we do not mess up the original one + new_class: DataItem = type(item_class.__name__, item_class.__bases__, dict(item_class.__dict__)) + new_class.specialize(**cls.tag_parameters()) + + if (klass := DataItem.find(new_class._name_template)) is None: + setattr(cls, name, new_class) + Msg.debug(cls.__qualname__, f"Cannot specialize {old_class.__qualname__} ({old_class.name()}) with {cls.tag_parameters()}, had to create a new class {new_class.__qualname__}") + else: + setattr(cls, name, klass) + Msg.debug(cls.__qualname__, + f" - {old_class.__qualname__} specialized to " + f"{klass.__qualname__} ({klass.name()})") @classmethod def promote(cls, **parameters) -> None: """ Promote the products of this class to appropriate subclasses, as determined from the input data. This may be only called after the recipe is initialized. + + May also contain template variables that are notmixed in during class creation. + For instance, `recipe_{band}_{target}` can specify band=LM, but no target, + resulting in a partial specialiation. The target has to be supplied from the actual data.) """ Msg.info(cls.__qualname__, @@ -84,12 +112,14 @@ def promote(cls, **parameters) -> None: for name, item in cls.list_product_classes(): # Try to find a promoted class in the registry + old_class = item.__qualname__ + old_class_name = item.name() if (new_class := DataItem.find(tag := item.specialize(**parameters))) is None: raise TypeError(f"Could not promote class {item}: {tag} is not a registered tag") else: - Msg.debug(cls.__class__.__qualname__, - f"Promoting {item.__qualname__} ({item.name()}) " - f"to {new_class.__qualname__} ({new_class.name()})") + Msg.debug(cls.__qualname__, + f" - {old_class} ({old_class_name}) => " + f"{new_class.__qualname__} ({new_class.name()})") # Replace the product attribute with the new class cls.__class__.__setattr__(cls, name, new_class) @@ -105,7 +135,7 @@ def run(self) -> cpl.ui.FrameSet: """ try: - self.products = self.process() # Do all the actual processing + self.products: set[DataItem] = self.process() # Do all the actual processing self._save_products() # Save the output products return self.build_product_frameset() # Return the output as a pycpl FrameSet @@ -132,26 +162,29 @@ def process(self) -> set[DataItem]: """ The core method of the recipe implementation. It should contain all the processing logic. At its entry point, the `InputSet` class must be already loaded and validated. + This should not be a concern of the author of a recipe, as long as everything is declared correctly. - All pixel manipulation should happen inside this function (or something it calls from within). + All pixel manipulation should happen inside this function (or private subroutines it calls from within). Put explicitly, this means - no pixel manipulation *before* entering `process`, - and no pixel manipulation *after* exiting `process`. The basic workflow inside this function should be as follows: - 1. Load the CPL structures associated with `Input` frames. + 1. Load the CPL structures associated with `PipelineInput` frames. + To conserve resources, most importantly memory, defer the `load_data` call + until the data are actually needed. 2. Do the preprocessing (dark, bias, flat, persistence...) as needed. When implementing this function, please always use the topmost applicable method: - - Use the functions provided in the pipeline if possible (derive or override). - Much of the functionality is common to many recipes, and we should not repeat ourselves. + - Use the functions provided by the pipeline package if possible (derive or override). + Much of the functionality is trivially common to many recipes, and we should not repeat ourselves. Some classes / functions are provided in ``prefab``. - Use HDRL functions, if available. - Use CPL functions, if available. - - Implement what you need yourself. + - Implement what you need yourself as a subroutine. 3. Build the output images as specified in the DRLD. Each product should be a ``DataItem`` and there should be exactly one for every file produced. - 4. Return a set of ``DataItem``. + 4. Return a set of ``DataItem`` instance. The resulting products set is then passed to `save_products()` (see `run`). """ diff --git a/metisp/pymetis/src/pymetis/classes/recipes/recipe.py b/metisp/pymetis/src/pymetis/classes/recipes/recipe.py index 90ad0438..9c2e2b33 100644 --- a/metisp/pymetis/src/pymetis/classes/recipes/recipe.py +++ b/metisp/pymetis/src/pymetis/classes/recipes/recipe.py @@ -49,7 +49,8 @@ class MetisRecipe(cpl.ui.PyRecipe): _copyright: str = "GPL-3.0-or-later" # I guess we are using the same copyright everywhere _synopsis: str = "Abstract-like base class for METIS recipes" _description: str = ("This class serves as the base class for all METIS recipes. " - "Bonus points if it is not visible from pyesorex.") + "Bonus points if it is not visible from pyesorex " + "(if it is, override the _description attribute in the final class).") # More internal attributes follow. These are **not** required by pyesorex and are specific to METIS / A*. _matched_keywords: set[str] = set() @@ -109,6 +110,8 @@ def _build_description(self) -> str: else: matched_keywords = '\n '.join(self._matched_keywords) + self.Impl.specialize() + inputs = '\n'.join(sorted([input_type._extended_description_line(name) for (name, input_type) in self._list_inputs()])) products = '\n'.join(sorted([product_type._extended_description_line(name) @@ -116,9 +119,7 @@ def _build_description(self) -> str: description = self._format_spacing(self._description, 'description', 2) algorithm = self._format_spacing(self._algorithm, 'algorithm', 4) - return \ - f"""{self.synopsis}\n\n{description} - + return f"""{self.synopsis}\n\n{description}\n Matched keywords {matched_keywords} Inputs\n{inputs} diff --git a/metisp/pymetis/src/pymetis/dataitems/adc/adc.py b/metisp/pymetis/src/pymetis/dataitems/adc/adc.py index 05f610e8..35d92ef4 100644 --- a/metisp/pymetis/src/pymetis/dataitems/adc/adc.py +++ b/metisp/pymetis/src/pymetis/dataitems/adc/adc.py @@ -22,10 +22,10 @@ from pymetis.classes.dataitems import TableDataItem from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandSpecificMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class AdcSlitloss(BandSpecificMixin, TableDataItem, abstract=True): +class AdcSlitloss(TableDataItem, abstract=True): _name_template = r'{band}_ADC_SLITLOSS' _title_template = "{band} ADC slit loss" _description_template = "Table with ADC induced {band} slitlosses" @@ -42,7 +42,7 @@ class NAdcSlitloss(BandNMixin, AdcSlitloss): pass -class AdcSlitlossRaw(BandSpecificMixin, Raw, abstract=True): +class AdcSlitlossRaw(Raw, abstract=True): _name_template = r'{band}_ADC_SLITLOSS_RAW' _title_template = r'{band} ADC slit loss raw' _description_template = "Raw files for ADC slitloss determination (TBD)." diff --git a/metisp/pymetis/src/pymetis/dataitems/background/__init__.py b/metisp/pymetis/src/pymetis/dataitems/background/__init__.py index 5a0889f6..1fef18ab 100644 --- a/metisp/pymetis/src/pymetis/dataitems/background/__init__.py +++ b/metisp/pymetis/src/pymetis/dataitems/background/__init__.py @@ -19,5 +19,5 @@ from .background import Background, LmStdBackground, LmSciBackground, NStdBackground, NSciBackground from .subtracted import (BackgroundSubtracted, - StdBackgroundSubtracted, LmStdBackgroundSubtracted, NStdBackgroundSubtracted, - SciBackgroundSubtracted, LmSciBackgroundSubtracted, NSciBackgroundSubtracted) \ No newline at end of file + LmStdBackgroundSubtracted, NStdBackgroundSubtracted, + LmSciBackgroundSubtracted, NSciBackgroundSubtracted) \ No newline at end of file diff --git a/metisp/pymetis/src/pymetis/dataitems/background/background.py b/metisp/pymetis/src/pymetis/dataitems/background/background.py index 2b976cf0..b7d66e6c 100644 --- a/metisp/pymetis/src/pymetis/dataitems/background/background.py +++ b/metisp/pymetis/src/pymetis/dataitems/background/background.py @@ -21,11 +21,11 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import (TargetSpecificMixin, TargetSciMixin, TargetStdMixin, - BandNMixin, BandLmMixin, BandSpecificMixin) +from pymetis.classes.mixins import (TargetSciMixin, TargetStdMixin, + BandLmMixin, BandNMixin) -class Background(BandSpecificMixin, TargetSpecificMixin, ImageDataItem, abstract=True): +class Background(ImageDataItem, abstract=True): _name_template = r'{band}_{target}_BKG' _title_template = r'{band}_{target} background, subtracted' _description_template = r"Thermal background subtracted images of {target} {band} exposures." diff --git a/metisp/pymetis/src/pymetis/dataitems/background/subtracted.py b/metisp/pymetis/src/pymetis/dataitems/background/subtracted.py index d760b5ed..9b8adfd6 100644 --- a/metisp/pymetis/src/pymetis/dataitems/background/subtracted.py +++ b/metisp/pymetis/src/pymetis/dataitems/background/subtracted.py @@ -21,11 +21,12 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import (TargetSpecificMixin, TargetSciMixin, TargetStdMixin, - BandSpecificMixin, BandLmMixin, BandNMixin) +from pymetis.classes.mixins import (TargetSciMixin, TargetStdMixin, + BandLmMixin, BandNMixin) +from pymetis.dataitems.img.basicreduced import Calibrated -class BackgroundSubtracted(BandSpecificMixin, TargetSpecificMixin, ImageDataItem, abstract=True): +class BackgroundSubtracted(ImageDataItem, abstract=True): _name_template = r'{band}_{target}_BKG_SUBTRACTED' _title_template = "{band} background-subtracted" _description_template = r"Thermal background subtracted images of science {band} {target} exposures." @@ -39,34 +40,27 @@ class BackgroundSubtracted(BandSpecificMixin, TargetSpecificMixin, ImageDataItem } -class StdBackgroundSubtracted(TargetStdMixin, BackgroundSubtracted, abstract=True): - _schema = { - 'PRIMARY': None, - 'DET1.DATA': Image, - } - +class LmBackgroundSubtracted(BandLmMixin, BackgroundSubtracted): + pass -class LmStdBackgroundSubtracted(BandLmMixin, StdBackgroundSubtracted): +class LmStdBackgroundSubtracted(TargetStdMixin, LmBackgroundSubtracted): pass -class NStdBackgroundSubtracted(BandNMixin, StdBackgroundSubtracted): +class LmSciBackgroundSubtracted(TargetSciMixin, LmBackgroundSubtracted): pass -class SciBackgroundSubtracted(TargetSciMixin, BackgroundSubtracted, abstract=True): - _schema = { - 'PRIMARY': None, - 'DET1.DATA': Image, - } +class NBackgroundSubtracted(BandNMixin, BackgroundSubtracted): + pass -class LmSciBackgroundSubtracted(BandLmMixin, SciBackgroundSubtracted): +class NStdBackgroundSubtracted(TargetStdMixin, NBackgroundSubtracted): pass -class NSciBackgroundSubtracted(BandNMixin, SciBackgroundSubtracted): +class NSciBackgroundSubtracted(TargetSciMixin, NBackgroundSubtracted): pass diff --git a/metisp/pymetis/src/pymetis/dataitems/badpixmap.py b/metisp/pymetis/src/pymetis/dataitems/badpixmap.py index e5e61b1b..f196055e 100644 --- a/metisp/pymetis/src/pymetis/dataitems/badpixmap.py +++ b/metisp/pymetis/src/pymetis/dataitems/badpixmap.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins.detector import DetectorSpecificMixin, Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin +from pymetis.classes.mixins.detector import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin -class BadPixMap(DetectorSpecificMixin, ImageDataItem, abstract=True): +class BadPixMap(ImageDataItem, abstract=True): _title_template = "bad pixel map" _name_template = r'BADPIX_MAP_{detector}' _description_template = "Bad pixel map. Warning: may contain detector masks." diff --git a/metisp/pymetis/src/pymetis/dataitems/coadd.py b/metisp/pymetis/src/pymetis/dataitems/coadd.py index a08489c5..cf17cd07 100644 --- a/metisp/pymetis/src/pymetis/dataitems/coadd.py +++ b/metisp/pymetis/src/pymetis/dataitems/coadd.py @@ -21,15 +21,16 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandIfuMixin, BandLmMixin +from pymetis.classes.mixins import BandIfuMixin, BandLmMixin -class SciCoadd(BandSpecificMixin, ImageDataItem, abstract=True): +class SciCoadd(ImageDataItem, abstract=True): _name_template = r'{band}_SCI_COADD' _title_template = r"{band} science co-added" _frame_group = cpl.ui.Frame.FrameGroup.PRODUCT _frame_level = cpl.ui.Frame.FrameLevel.FINAL _oca_keywords = {'PRO.CATG', 'DRS.FILTER'} + _description_template = "{band} science co-added" _schema = { 'PRIMARY': None, diff --git a/metisp/pymetis/src/pymetis/dataitems/combined.py b/metisp/pymetis/src/pymetis/dataitems/combined.py index bb9f0f36..011e3a60 100644 --- a/metisp/pymetis/src/pymetis/dataitems/combined.py +++ b/metisp/pymetis/src/pymetis/dataitems/combined.py @@ -21,13 +21,13 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import (BandSpecificMixin, BandLmMixin, BandNMixin) +from pymetis.classes.mixins import BandLmMixin, BandNMixin """ The hierarchy is somewhat atypical here by design: no N data item, and only IFU supports STD|SKY target. """ -class Combined(BandSpecificMixin, ImageDataItem, abstract=True): +class Combined(ImageDataItem, abstract=True): _name_template = r'{band}_STD_COMBINED' _title_template = r'band standard combined' _description_template = r"Stacked {band} band exposures." diff --git a/metisp/pymetis/src/pymetis/dataitems/common.py b/metisp/pymetis/src/pymetis/dataitems/common.py index 7daed9b8..de39e7a9 100644 --- a/metisp/pymetis/src/pymetis/dataitems/common.py +++ b/metisp/pymetis/src/pymetis/dataitems/common.py @@ -34,7 +34,7 @@ class PersistenceMap(ImageDataItem): _schema = { 'PRIMARY': None, - 'DET1.DATA': Image, + 'PERSISTENCE_MAP': Image, } diff --git a/metisp/pymetis/src/pymetis/dataitems/distortion/map.py b/metisp/pymetis/src/pymetis/dataitems/distortion/map.py index 71ea653e..39930de9 100644 --- a/metisp/pymetis/src/pymetis/dataitems/distortion/map.py +++ b/metisp/pymetis/src/pymetis/dataitems/distortion/map.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class DistortionMap(BandSpecificMixin, ImageDataItem, abstract=True): +class DistortionMap(ImageDataItem, abstract=True): _name_template = r'{band}_DISTORTION_MAP' _title_template = "{band} distortion map" _description_template = "Map of pixel scale across the {band} detector" diff --git a/metisp/pymetis/src/pymetis/dataitems/distortion/raw.py b/metisp/pymetis/src/pymetis/dataitems/distortion/raw.py index 30aa1807..0d85e45a 100644 --- a/metisp/pymetis/src/pymetis/dataitems/distortion/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/distortion/raw.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin, BandIfuMixin, DetectorIfuMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandIfuMixin, DetectorIfuMixin -class DistortionRaw(BandSpecificMixin, Raw, abstract=True): +class DistortionRaw(Raw, abstract=True): _name_template = r'{band}_DISTORTION_RAW' _title_template = "distortion raw" _description_template = "Raw data for distortion determination in other recipes in the {band} band." @@ -45,5 +45,5 @@ class NDistortionRaw(BandNMixin, DistortionRaw): pass -class IfuDistortionRaw(DetectorIfuMixin, BandIfuMixin, DistortionRaw): +class IfuDistortionRaw(BandIfuMixin, DetectorIfuMixin, DistortionRaw): pass \ No newline at end of file diff --git a/metisp/pymetis/src/pymetis/dataitems/distortion/reduced.py b/metisp/pymetis/src/pymetis/dataitems/distortion/reduced.py index d4077565..2c4acf72 100644 --- a/metisp/pymetis/src/pymetis/dataitems/distortion/reduced.py +++ b/metisp/pymetis/src/pymetis/dataitems/distortion/reduced.py @@ -18,13 +18,13 @@ """ import cpl.ui -from cpl.core import Image, Table +from cpl.core import Image from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin, BandIfuMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandIfuMixin -class DistortionReduced(BandSpecificMixin, TableDataItem, abstract=True): +class DistortionReduced(TableDataItem, abstract=True): _name_template = r'{band}_DIST_REDUCED' _title_template = r"{band} distortion reduced" _description_template = r"Table of polynomial coefficients for distortion correction" diff --git a/metisp/pymetis/src/pymetis/dataitems/distortion/table.py b/metisp/pymetis/src/pymetis/dataitems/distortion/table.py index 2392d980..213eba9e 100644 --- a/metisp/pymetis/src/pymetis/dataitems/distortion/table.py +++ b/metisp/pymetis/src/pymetis/dataitems/distortion/table.py @@ -20,13 +20,13 @@ import numpy as np import cpl -from cpl.core import Table, Image +from cpl.core import Table from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin, BandIfuMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandIfuMixin -class DistortionTable(BandSpecificMixin, TableDataItem, abstract=True): +class DistortionTable(TableDataItem, abstract=True): _name_template = r'{band}_DISTORTION_TABLE' _title_template = "distortion table" _description_template = r"Table of distortion coefficients for a {band} band data set" diff --git a/metisp/pymetis/src/pymetis/dataitems/gainmap.py b/metisp/pymetis/src/pymetis/dataitems/gainmap.py index edfb271a..d0aa08fc 100644 --- a/metisp/pymetis/src/pymetis/dataitems/gainmap.py +++ b/metisp/pymetis/src/pymetis/dataitems/gainmap.py @@ -21,13 +21,13 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin, DetectorSpecificMixin +from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin -class GainMap(DetectorSpecificMixin, ImageDataItem, abstract=True): +class GainMap(ImageDataItem, abstract=True): _name_template = r'GAIN_MAP_{detector}' - _title_template = "gain map" - _description_template = "Gain map" + _title_template = "gain map for {detector} detector" + _description_template = "Gain map for the {detector} detector" _frame_group = cpl.ui.Frame.FrameGroup.CALIB _frame_level = cpl.ui.Frame.FrameLevel.INTERMEDIATE _oca_keywords = {'PRO.CATG'} diff --git a/metisp/pymetis/src/pymetis/dataitems/hci/hci.py b/metisp/pymetis/src/pymetis/dataitems/hci/hci.py index a8d9b542..2cb434da 100644 --- a/metisp/pymetis/src/pymetis/dataitems/hci/hci.py +++ b/metisp/pymetis/src/pymetis/dataitems/hci/hci.py @@ -23,12 +23,9 @@ from pymetis.classes.dataitems import ImageDataItem from pymetis.classes.mixins import CgrphRavcMixin, CgrphCvcMixin, CgrphAppMixin from pymetis.classes.mixins import BandLmMixin -from pymetis.classes.mixins.band import BandSpecificMixin -from pymetis.classes.mixins.cgrph import CgrphSpecificMixin -class OffAxisPsfRaw(BandSpecificMixin, ImageDataItem, abstract=True): - +class OffAxisPsfRaw(ImageDataItem, abstract=True): _name_template = r'{band}_OFF_AXIS_PSF_RAW' _title_template = r"{band} RAVC sci calibration" _description_template = "calibration ADI image data" @@ -41,8 +38,7 @@ class OffAxisPsfRaw(BandSpecificMixin, ImageDataItem, abstract=True): 'DET1.DATA': Image, } -class AdiCalibrated(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): - +class AdiCalibrated(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_CALIBRATED' _title_template = r"{band} RAVC sci calibration" _description_template = "calibration ADI image data" @@ -55,8 +51,7 @@ class AdiCalibrated(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstra 'DET1.DATA': Image, } -class OnAxisPsfTemplate(BandSpecificMixin, ImageDataItem, abstract=True): - +class OnAxisPsfTemplate(ImageDataItem, abstract=True): _name_template = r'{band}_ON_AXIS_PSF_TEMPLATE' _title_template = r"{band} RAVC sci calibration" _description_template = "calibration ADI image data" @@ -71,7 +66,7 @@ class OnAxisPsfTemplate(BandSpecificMixin, ImageDataItem, abstract=True): -class SciCentred(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciCentred(ImageDataItem, abstract=True): _name_template = r"{band}_RAVC_SCI_CENTRED" _title_template = r"{band} RAVC sci centred" @@ -85,7 +80,7 @@ class SciCentred(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract= 'DET1.DATA': Image, } -class CentroidTab(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class CentroidTab(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_CENTROID_TAB' _title_template = r"{band} RAVC centroid tab" @@ -99,7 +94,7 @@ class CentroidTab(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract 'DET1.DATA': Table, } -class SciSpeckle(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciSpeckle(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_SPECKLE' _title_template = r"{band} RAVC sci speckle" @@ -113,7 +108,7 @@ class SciSpeckle(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract= 'DET1.DATA': Image, } -class SciHifilt(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciHifilt(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_HIFILT' _title_template = r"{band} RAVC sci hifilt" @@ -127,7 +122,7 @@ class SciHifilt(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=T 'DET1.DATA': Image, } -class SciDerotatedPsfsub(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciDerotatedPsfsub(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_DEROTATED_PSFSUB' _title_template = r"{band} RAVC sci derotated psfsub" @@ -141,8 +136,8 @@ class SciDerotatedPsfsub(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, a 'DET1.DATA': Image, } -class SciDerotated(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciDerotated(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_DEROTATED' _title_template = r"{band} RAVC sci derotated" _description_template = "" @@ -155,8 +150,8 @@ class SciDerotated(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstrac 'DET1.DATA': Image, } -class SciContrastRadprof(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciContrastRadprof(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_CONTRAST_RADPROF' _title_template = r"{band} RAVC sci contrast radprof" _description_template = "" @@ -169,8 +164,8 @@ class SciContrastRadprof(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, a 'DET1.DATA': Table, } -class SciContrastAdi(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciContrastAdi(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_CONTRAST_ADI' _title_template = r"{band} RAVC sci contrast adi" _description_template = "" @@ -183,8 +178,8 @@ class SciContrastAdi(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstr 'DET1.DATA': Table, } -class SciThroughput(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciThroughput(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_THROUGHPUT' _title_template = r"{band} RAVC sci throughput" _description_template = "" @@ -197,8 +192,8 @@ class SciThroughput(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstra 'DET1.DATA': Table, } -class SciCoverage(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciCoverage(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_COVERAGE' _title_template = r"{band} RAVC sci coverage" _description_template = "" @@ -211,8 +206,8 @@ class SciCoverage(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract 'DET1.DATA': Image, } -class SciSnr(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): +class SciSnr(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_SNR' _title_template = r"{band} RAVC sci snr" _description_template = "" @@ -224,8 +219,9 @@ class SciSnr(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True 'PRIMARY': None, 'DET1.DATA': Image, } -class PsfMedian(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=True): + +class PsfMedian(ImageDataItem, abstract=True): _name_template = r'{band}_RAVC_SCI_PSF_MEDIAN' _title_template = r"{band} RAVC sci psf median" _description_template = "" @@ -242,9 +238,11 @@ class PsfMedian(BandSpecificMixin, CgrphSpecificMixin, ImageDataItem, abstract=T class LmRavcCalibrated(BandLmMixin, CgrphRavcMixin, AdiCalibrated): pass + class LmCvcCalibrated(BandLmMixin, CgrphCvcMixin, AdiCalibrated): pass + class LmAppCalibrated(BandLmMixin, CgrphAppMixin, AdiCalibrated): pass diff --git a/metisp/pymetis/src/pymetis/dataitems/ifu/ifu.py b/metisp/pymetis/src/pymetis/dataitems/ifu/ifu.py index 50d2b94f..2d9ae8f2 100644 --- a/metisp/pymetis/src/pymetis/dataitems/ifu/ifu.py +++ b/metisp/pymetis/src/pymetis/dataitems/ifu/ifu.py @@ -23,10 +23,9 @@ from pymetis.classes.dataitems import ImageDataItem from pymetis.classes.mixins import TargetStdMixin, TargetSciMixin from pymetis.classes.mixins.band import BandIfuMixin -from pymetis.classes.mixins.target import TargetSpecificMixin -class IfuBase(TargetSpecificMixin, BandIfuMixin, ImageDataItem, abstract=True): +class IfuBase(BandIfuMixin, ImageDataItem, abstract=True): _oca_keywords = {'PRO.CATG', 'DRS.IFU'} _schema = { diff --git a/metisp/pymetis/src/pymetis/dataitems/ifu/raw.py b/metisp/pymetis/src/pymetis/dataitems/ifu/raw.py index ffa3a0ef..ffd33fc2 100644 --- a/metisp/pymetis/src/pymetis/dataitems/ifu/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/ifu/raw.py @@ -20,12 +20,13 @@ from cpl.core import Image from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import BandIfuMixin, TargetSpecificMixin, TargetStdMixin, TargetSciMixin +from pymetis.classes.mixins import BandIfuMixin, TargetStdMixin, TargetSciMixin -class IfuRaw(BandIfuMixin, TargetSpecificMixin, Raw, abstract=True): +class IfuRaw(BandIfuMixin, Raw, abstract=True): _name_template = r'{band}_{target}_RAW' _title_template = r"{band} {target} raw" + _description_template = r"{band} {target} raw image" _frame_level = cpl.ui.Frame.FrameLevel.INTERMEDIATE _frame_group = cpl.ui.Frame.FrameGroup.RAW _oca_keywords = {"DPR.CATG", "DPR.TECH", "DPR.TYPE", "INS.OPTI3.NAME", @@ -38,7 +39,6 @@ class IfuRaw(BandIfuMixin, TargetSpecificMixin, Raw, abstract=True): } - class IfuStdRaw(TargetStdMixin, IfuRaw): _description_template = "Raw spectra of flux standard star." diff --git a/metisp/pymetis/src/pymetis/dataitems/img/basicreduced.py b/metisp/pymetis/src/pymetis/dataitems/img/basicreduced.py index 7ef8ec60..09ed0ccc 100644 --- a/metisp/pymetis/src/pymetis/dataitems/img/basicreduced.py +++ b/metisp/pymetis/src/pymetis/dataitems/img/basicreduced.py @@ -21,14 +21,13 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import TargetSpecificMixin, TargetSciMixin, TargetStdMixin, \ - BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins import TargetSciMixin, TargetStdMixin, BandLmMixin, BandNMixin -class BasicReduced(BandLmMixin, TargetSpecificMixin, ImageDataItem, abstract=True): +class BasicReduced(ImageDataItem, abstract=True): _name_template = r'{band}_{target}_BASIC_REDUCED' _title_template = "{band} {target} basic reduced" - _description_template = "Detrended exposure of the {band} image mode." + _description_template = "Detrended {target} exposure of the {band} image mode." _frame_group = cpl.ui.Frame.FrameGroup.CALIB _frame_level = cpl.ui.Frame.FrameLevel.FINAL _oca_keywords = {'PRO.CATG', 'INS.OPTI3.NAME', 'INS.OPTI9.NAME', 'INS.OPTI10.NAME', 'DRS.FILTER'} @@ -39,11 +38,15 @@ class BasicReduced(BandLmMixin, TargetSpecificMixin, ImageDataItem, abstract=Tru } -class LmStdBasicReduced(TargetStdMixin, BasicReduced): +class LmBasicReduced(BandLmMixin, BasicReduced): pass -class LmSciBasicReduced(TargetSciMixin, BasicReduced): +class LmStdBasicReduced(TargetStdMixin, LmBasicReduced): + pass + + +class LmSciBasicReduced(TargetSciMixin, LmBasicReduced): pass @@ -61,7 +64,7 @@ class LmSkyBasicReduced(ImageDataItem): } -class Calibrated(BandSpecificMixin, TargetSpecificMixin, ImageDataItem, abstract=True): +class Calibrated(ImageDataItem, abstract=True): _name_template = r'{band}_{target}_CALIBRATED' _title_template = '{band} {target} calibrated' _description_template = 'Calibrated {band} {target}' diff --git a/metisp/pymetis/src/pymetis/dataitems/img/raw.py b/metisp/pymetis/src/pymetis/dataitems/img/raw.py index 71ecfe12..64e5c9db 100644 --- a/metisp/pymetis/src/pymetis/dataitems/img/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/img/raw.py @@ -19,11 +19,11 @@ import cpl.ui from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import (BandSpecificMixin, BandLmMixin, BandNMixin, - TargetSpecificMixin, TargetStdMixin, TargetSciMixin, TargetSkyMixin) +from pymetis.classes.mixins import (BandLmMixin, BandNMixin, + TargetStdMixin, TargetSciMixin, TargetSkyMixin) -class ImageRaw(BandSpecificMixin, TargetSpecificMixin, Raw, abstract=True): +class ImageRaw(Raw, abstract=True): """ Abstract intermediate class for image raws. """ @@ -35,21 +35,29 @@ class ImageRaw(BandSpecificMixin, TargetSpecificMixin, Raw, abstract=True): "INS.OPTI9.NAME", "INS.OPTI10.NAME", "DRS.FILTER"} -class LmImageStdRaw(BandLmMixin, TargetStdMixin, ImageRaw): +class LmImageRaw(BandLmMixin, ImageRaw): pass -class LmImageSciRaw(BandLmMixin, TargetSciMixin, ImageRaw): +class LmImageStdRaw(TargetStdMixin, LmImageRaw): pass -class LmImageSkyRaw(BandLmMixin, TargetSkyMixin, ImageRaw): +class LmImageSciRaw(TargetSciMixin, LmImageRaw): pass -class NImageStdRaw(BandNMixin, TargetStdMixin, ImageRaw): +class LmImageSkyRaw(TargetSkyMixin, LmImageRaw): pass -class NImageSciRaw(BandNMixin, TargetSciMixin, ImageRaw): +class NImageRaw(BandNMixin, ImageRaw): + pass + + +class NImageStdRaw(TargetStdMixin, NImageRaw): + pass + + +class NImageSciRaw(TargetSciMixin, NImageRaw): pass diff --git a/metisp/pymetis/src/pymetis/dataitems/linearity/linearity.py b/metisp/pymetis/src/pymetis/dataitems/linearity/linearity.py index 76f1f8ec..dcb0b02e 100644 --- a/metisp/pymetis/src/pymetis/dataitems/linearity/linearity.py +++ b/metisp/pymetis/src/pymetis/dataitems/linearity/linearity.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import DetectorSpecificMixin, Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin +from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin -class LinearityMap(DetectorSpecificMixin, ImageDataItem, abstract=True): +class LinearityMap(ImageDataItem, abstract=True): _name_template = r'LINEARITY_{detector}' _title_template = r'{detector} linearity' _description_template = "Coefficients for the pixel {detector} non-linearity correction" diff --git a/metisp/pymetis/src/pymetis/dataitems/linearity/raw.py b/metisp/pymetis/src/pymetis/dataitems/linearity/raw.py index d58068d4..e5c10716 100644 --- a/metisp/pymetis/src/pymetis/dataitems/linearity/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/linearity/raw.py @@ -20,10 +20,10 @@ import cpl from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import DetectorSpecificMixin, Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin +from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin -class LinearityRaw(DetectorSpecificMixin, Raw, abstract=True): +class LinearityRaw(Raw, abstract=True): _name_template = r'DETLIN_{detector}_RAW' _title_template = r'{detector} linearity raw' _description_template = r"Raw data for non-linearity determination for {detector} observations" diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/curve.py b/metisp/pymetis/src/pymetis/dataitems/lss/curve.py index 6afbe839..3d9d2d73 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/curve.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/curve.py @@ -19,11 +19,11 @@ import cpl -from pymetis.classes.dataitems import ImageDataItem, TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.dataitems import TableDataItem +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class LssCurve(BandSpecificMixin, TableDataItem, abstract=True): +class LssCurve(TableDataItem, abstract=True): """ Trace curvature """ @@ -43,7 +43,7 @@ class NLssCurve(BandNMixin, LssCurve): pass -class LssDistSol(BandSpecificMixin, TableDataItem, abstract=True): +class LssDistSol(TableDataItem, abstract=True): """ Distortion solution """ @@ -63,7 +63,7 @@ class NLssDistSol(BandNMixin, LssDistSol): pass -class LssWaveGuess(BandSpecificMixin, TableDataItem, abstract=True): +class LssWaveGuess(TableDataItem, abstract=True): """ First guess of the wavelength solution """ diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/raw.py b/metisp/pymetis/src/pymetis/dataitems/lss/raw.py index 520363db..f780c1ad 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/raw.py @@ -20,10 +20,10 @@ import cpl from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import BandLmMixin, TargetStdMixin, BandNMixin, TargetSciMixin, BandSpecificMixin +from pymetis.classes.mixins import BandLmMixin, TargetStdMixin, BandNMixin, TargetSciMixin -class LssRaw(BandSpecificMixin, Raw, abstract=True): +class LssRaw(Raw, abstract=True): _name_template = r'{band}_LSS_{target}_RAW' _title_template = "{band} LSS {target} raw" _description_template = "{band}-band long-slit spectroscopy raw exposure of a {target}" @@ -33,25 +33,26 @@ class LssRaw(BandSpecificMixin, Raw, abstract=True): 'DRS.SLIT'} -class LssStdRaw(TargetStdMixin, LssRaw, abstract=True): +class LmLssRaw(BandLmMixin, LssRaw): pass -class LmLssStdRaw(BandLmMixin, LssStdRaw): +class LmLssStdRaw(TargetStdMixin, LmLssRaw): pass -class NLssStdRaw(BandNMixin, LssStdRaw): +class LmLssSciRaw(TargetSciMixin, LmLssRaw): pass -class LssSciRaw(TargetSciMixin, LssRaw, abstract=True): +class NLssRaw(BandNMixin, LssRaw): pass -class LmLssSciRaw(BandLmMixin, LssSciRaw): +class NLssStdRaw(TargetStdMixin, NLssRaw): pass -class NLssSciRaw(BandNMixin, LssSciRaw): - pass \ No newline at end of file +class NLssSciRaw(TargetSciMixin, NLssRaw): + pass + diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/response.py b/metisp/pymetis/src/pymetis/dataitems/lss/response.py index ada93575..23639508 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/response.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/response.py @@ -20,10 +20,10 @@ import cpl from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class MasterResponse(BandSpecificMixin, TableDataItem, abstract=True): +class MasterResponse(TableDataItem, abstract=True): _name_template = r'MASTER_{band}_RESPONSE' _title_template = r'master {band}-band response' _description_template = "Master {band}-band response function for absolute flux calibration" diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/rsrf.py b/metisp/pymetis/src/pymetis/dataitems/lss/rsrf.py index 86cc5cce..a1bc3a4e 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/rsrf.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/rsrf.py @@ -22,10 +22,10 @@ from pymetis.classes.dataitems import ImageDataItem from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandSpecificMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class LssRsrfRaw(BandSpecificMixin, Raw, abstract=True): +class LssRsrfRaw(Raw, abstract=True): _name_template = r'{band}_LSS_RSRF_RAW' _title_template = "{band} LSS RSRF raw" _description_template = "Raw exposure of the WCU flat field lamp through the LSS to achieve the RSRF." @@ -48,7 +48,7 @@ class NLssStdRaw(BandNMixin, LssRsrfRaw): pass -class MedianLssRsrf(BandSpecificMixin, ImageDataItem, abstract=True): +class MedianLssRsrf(ImageDataItem, abstract=True): _name_template = r'MEDIAN_{band}_LSS_RSRF' _title_template = "median {band} LSS RSRF image" _description_template = "Median {band} RSRF pixel map" @@ -70,7 +70,7 @@ class MedianNLssRsrf(BandNMixin, MedianLssRsrf): pass -class MeanLssRsrf(BandSpecificMixin, ImageDataItem, abstract=True): +class MeanLssRsrf(ImageDataItem, abstract=True): _name_template = r'MEAN_{band}_LSS_RSRF' _title_template = "mean {band} LSS RSRF image" _description_template = "Mean {band} RSRF pixel map" @@ -92,7 +92,7 @@ class MeanNLssRsrf(BandNMixin, MeanLssRsrf): pass -class MasterLssRsrf(BandSpecificMixin, ImageDataItem, abstract=True): +class MasterLssRsrf(ImageDataItem, abstract=True): _name_template = r'MASTER_{band}_LSS_RSRF' _title_template = "master {band} LSS RSRF" _description_template = "Master {band} RSRF pixel map" @@ -114,7 +114,7 @@ class MasterNLssRsrfImg(BandNMixin, MasterLssRsrf): pass -class LssRsrfPinholeRaw(BandSpecificMixin, ImageDataItem, abstract=True): +class LssRsrfPinholeRaw(ImageDataItem, abstract=True): _name_template = r'{band}_LSS_RSRF_PINH_RAW' _title_template = "{band} LSS RSRF pinhole raw" _description_template = "Raw flats taken with black-body calibration lamp through the pinhole mask." diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/science.py b/metisp/pymetis/src/pymetis/dataitems/lss/science.py index 6df19d90..ae00c358 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/science.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/science.py @@ -21,11 +21,10 @@ from cpl.core import Table, Image from pymetis.classes.dataitems import ImageDataItem, TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, TargetSpecificMixin, BandLmMixin, BandNMixin, TargetSciMixin, \ - TargetStdMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin, TargetSciMixin, TargetStdMixin -class LssObjMap(BandSpecificMixin, TargetSpecificMixin, ImageDataItem, abstract=True): +class LssObjMap(ImageDataItem, abstract=True): _name_template = r'{band}_LSS_{target}_OBJ_MAP' _title_template = "{band} LSS {target} object map" _description_template = "Pixel map of object pixels (QC)" @@ -55,7 +54,7 @@ class NLssSciObjMap(BandNMixin, TargetSciMixin, LssObjMap): pass -class LssSkyMap(BandSpecificMixin, TargetSpecificMixin, ImageDataItem, abstract=True): +class LssSkyMap(ImageDataItem, abstract=True): _name_template = r'{band}_LSS_{target}_SKY_MAP' _title_template = "{band} LSS {target} sky map" _description_template = "Image with detected plain sky pixels of the {target} observation." @@ -85,7 +84,7 @@ class NLssSciSkyMap(BandNMixin, TargetSciMixin, LssSkyMap): pass -class LssSci1d(BandSpecificMixin, TableDataItem, abstract=True): +class LssSci1d(TableDataItem, abstract=True): _name_template = r'{band}_LSS_SCI_1D' _title_template = "{band} LSS 1D science spectrum" _description_template = "Extracted {band} 1D science spectrum." @@ -102,7 +101,7 @@ class NLssSci1d(BandNMixin, LssSci1d): pass -class LssSci2d(BandSpecificMixin, ImageDataItem, abstract=True): +class LssSci2d(ImageDataItem, abstract=True): _name_template = r'{band}_LSS_SCI_2D' _title_template = "{band} LSS 2D science spectrum" _description_template = "Rectified 2D {band} spectrum of science object." @@ -124,7 +123,7 @@ class NLssSci2d(BandNMixin, LssSci2d): pass -class LssSciFlux1d(BandSpecificMixin, TableDataItem, abstract=True): +class LssSciFlux1d(TableDataItem, abstract=True): """ Final flux calibrated 1D spectrum of standard star """ @@ -149,7 +148,7 @@ class NLssSciFlux1d(BandNMixin, LssSciFlux1d): pass -class LssSciFlux2d(BandSpecificMixin, ImageDataItem, abstract=True): +class LssSciFlux2d(ImageDataItem, abstract=True): """ Final flux calibrated 1D spectrum of standard star """ @@ -174,7 +173,7 @@ class NLssSciFlux2d(BandNMixin, LssSciFlux2d): pass -class LssSciFluxTellCorr1d(BandSpecificMixin, TableDataItem, abstract=True): +class LssSciFluxTellCorr1d(TableDataItem, abstract=True): """ Final flux calibrated, telluric corrected 1D spectrum of standard star """ diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/std.py b/metisp/pymetis/src/pymetis/dataitems/lss/std.py index 003d4eb8..83bddd0a 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/std.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/std.py @@ -20,10 +20,10 @@ import cpl from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class LssStd1d(BandSpecificMixin, TableDataItem, abstract=True): +class LssStd1d(TableDataItem, abstract=True): _name_template = r'{band}_LSS_STD_1D' _title_template = "{band} LSS 1D standard star spectrum" _description_template = "Extracted {band} 1D standard star spectrum." diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/trace.py b/metisp/pymetis/src/pymetis/dataitems/lss/trace.py index e9d9f74f..ff17d1cc 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/trace.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/trace.py @@ -20,10 +20,10 @@ import cpl from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandSpecificMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class LssTrace(BandSpecificMixin, TableDataItem, abstract=True): +class LssTrace(TableDataItem, abstract=True): """ Final trace table """ diff --git a/metisp/pymetis/src/pymetis/dataitems/lss/wave.py b/metisp/pymetis/src/pymetis/dataitems/lss/wave.py index a65bd1e2..aabfdcf0 100644 --- a/metisp/pymetis/src/pymetis/dataitems/lss/wave.py +++ b/metisp/pymetis/src/pymetis/dataitems/lss/wave.py @@ -20,10 +20,10 @@ import cpl from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class LssWaveRaw(BandSpecificMixin, Raw, abstract=True): +class LssWaveRaw(Raw, abstract=True): _name_template = r'{band}_LSS_WAVE_RAW' _title_template = "{band} LSS wave raw" _description_template = "Raw LSS spectra of the WCU lasers in {band} band" diff --git a/metisp/pymetis/src/pymetis/dataitems/masterdark/masterdark.py b/metisp/pymetis/src/pymetis/dataitems/masterdark/masterdark.py index c5e3eb33..8b07890f 100644 --- a/metisp/pymetis/src/pymetis/dataitems/masterdark/masterdark.py +++ b/metisp/pymetis/src/pymetis/dataitems/masterdark/masterdark.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import DetectorSpecificMixin, Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin +from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin -class MasterDark(DetectorSpecificMixin, ImageDataItem, abstract=True): +class MasterDark(ImageDataItem, abstract=True): _name_template = r'MASTER_DARK_{detector}' _title_template = r"{detector} master dark" _description_template = "Master dark frame for {detector} data" diff --git a/metisp/pymetis/src/pymetis/dataitems/masterdark/raw.py b/metisp/pymetis/src/pymetis/dataitems/masterdark/raw.py index 271a402d..3d6e4c31 100644 --- a/metisp/pymetis/src/pymetis/dataitems/masterdark/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/masterdark/raw.py @@ -20,10 +20,10 @@ import cpl from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins.detector import DetectorSpecificMixin, Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin +from pymetis.classes.mixins.detector import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin -class DarkRaw(DetectorSpecificMixin, Raw, abstract=True): +class DarkRaw(Raw, abstract=True): _name_template = r'DARK_{detector}_RAW' _title_template = r'{detector} dark raw' _description_template = r"Raw data for creating a {detector} master dark." diff --git a/metisp/pymetis/src/pymetis/dataitems/masterflat/masterflat.py b/metisp/pymetis/src/pymetis/dataitems/masterflat/masterflat.py index 8471e23f..15fa5c70 100644 --- a/metisp/pymetis/src/pymetis/dataitems/masterflat/masterflat.py +++ b/metisp/pymetis/src/pymetis/dataitems/masterflat/masterflat.py @@ -21,11 +21,11 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin, BandSpecificMixin, \ - BandLmMixin, SourceLampMixin, BandNMixin, SourceSpecificMixin, DetectorSpecificMixin, SourceTwilightMixin +from pymetis.classes.mixins import Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin, \ + BandLmMixin, SourceLampMixin, BandNMixin, SourceTwilightMixin -class MasterFlat(DetectorSpecificMixin, ImageDataItem, abstract=True): +class MasterFlat(ImageDataItem, abstract=True): _name_template = r'MASTER_FLAT_{detector}' _title_template = r'{detector} master flat' _description_template = "Abstract base class for master flats. Please subclass." @@ -54,7 +54,7 @@ class MasterFlatIfu(DetectorIfuMixin, MasterFlat): } -class MasterImgFlat(BandSpecificMixin, SourceSpecificMixin, ImageDataItem, abstract=True): +class MasterImgFlat(ImageDataItem, abstract=True): _name_template = r'MASTER_IMG_FLAT_{source}_{band}' _title_template = r'{band} {source} master flat' _description_template = "Master flat frame for {band} data" @@ -67,17 +67,25 @@ class MasterImgFlat(BandSpecificMixin, SourceSpecificMixin, ImageDataItem, abstr } -class MasterImgFlatLampLm(BandLmMixin, SourceLampMixin, MasterImgFlat): +class MasterImgFlatLm(BandLmMixin, MasterImgFlat): pass -class MasterImgFlatTwilightLm(BandLmMixin, SourceTwilightMixin, MasterImgFlat): +class MasterImgFlatLampLm(SourceLampMixin, MasterImgFlatLm): pass -class MasterImgFlatLampN(BandNMixin, SourceLampMixin, MasterImgFlat): +class MasterImgFlatTwilightLm(SourceTwilightMixin, MasterImgFlatLm): pass -class MasterImgFlatTwilightN(BandNMixin, SourceTwilightMixin, MasterImgFlat): +class MasterImgFlatN(BandNMixin, MasterImgFlat): + pass + + +class MasterImgFlatLampN(SourceLampMixin, MasterImgFlatN): + pass + + +class MasterImgFlatTwilightN(SourceTwilightMixin, MasterImgFlatN): pass \ No newline at end of file diff --git a/metisp/pymetis/src/pymetis/dataitems/masterflat/raw.py b/metisp/pymetis/src/pymetis/dataitems/masterflat/raw.py index 2a236a54..6f954cf6 100644 --- a/metisp/pymetis/src/pymetis/dataitems/masterflat/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/masterflat/raw.py @@ -21,11 +21,11 @@ from cpl.core import Image from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins.band import BandNMixin, BandLmMixin, BandSpecificMixin -from pymetis.classes.mixins.source import SourceSpecificMixin, SourceLampMixin, SourceTwilightMixin +from pymetis.classes.mixins.band import BandNMixin, BandLmMixin +from pymetis.classes.mixins.source import SourceLampMixin, SourceTwilightMixin -class FlatRaw(BandSpecificMixin, SourceSpecificMixin, Raw, abstract=True): +class FlatRaw(Raw, abstract=True): _name_template = r'{band}_FLAT_{source}_RAW' _title_template = r'{band} flat {source} raw' _description_template = r'Flat raw' @@ -38,25 +38,26 @@ class FlatRaw(BandSpecificMixin, SourceSpecificMixin, Raw, abstract=True): 'DET1.DATA': Image, } +class LmFlatRaw(BandLmMixin, FlatRaw): + pass + -class LmFlatLampRaw(BandLmMixin, SourceLampMixin, FlatRaw): +class LmFlatLampRaw(SourceLampMixin, LmFlatRaw): pass -class LmFlatTwilightRaw(BandLmMixin, SourceTwilightMixin, FlatRaw): +class LmFlatTwilightRaw(SourceTwilightMixin, LmFlatRaw): pass -class NFlatLampRaw(BandNMixin, SourceLampMixin, FlatRaw): - _schema = { - 'PRIMARY': None, - 'DET1.DATA': Image, - } +class NFlatRaw(BandNMixin, FlatRaw): + pass -class NFlatTwilightRaw(BandNMixin, SourceTwilightMixin, FlatRaw): - _schema = { - 'PRIMARY': None, - 'DET1.DATA': Image, - } +class NFlatLampRaw(SourceLampMixin, NFlatRaw): + pass + + +class NFlatTwilightRaw(SourceTwilightMixin, NFlatRaw): + pass diff --git a/metisp/pymetis/src/pymetis/dataitems/objectcatalog.py b/metisp/pymetis/src/pymetis/dataitems/objectcatalog.py index c11205f3..3ae4125a 100644 --- a/metisp/pymetis/src/pymetis/dataitems/objectcatalog.py +++ b/metisp/pymetis/src/pymetis/dataitems/objectcatalog.py @@ -20,11 +20,11 @@ import cpl from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import (BandSpecificMixin, BandNMixin, BandLmMixin, - TargetSpecificMixin, TargetStdMixin, TargetSciMixin) +from pymetis.classes.mixins import (BandLmMixin, BandNMixin, + TargetStdMixin, TargetSciMixin) -class ObjectCatalog(BandSpecificMixin, TargetSpecificMixin, TableDataItem, abstract=True): +class ObjectCatalog(TableDataItem, abstract=True): _name_template = r'{band}_{target}_OBJECT_CAT' _title_template = "{band} {target} object catalog" _description_template = "Catalog of masked objects in {target} {band} exposures" diff --git a/metisp/pymetis/src/pymetis/dataitems/pupil/pupil.py b/metisp/pymetis/src/pymetis/dataitems/pupil/pupil.py index b11f6ce0..5679b63c 100644 --- a/metisp/pymetis/src/pymetis/dataitems/pupil/pupil.py +++ b/metisp/pymetis/src/pymetis/dataitems/pupil/pupil.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins.band import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins.band import BandLmMixin, BandNMixin -class PupilImagingReduced(BandSpecificMixin, ImageDataItem, abstract=True): +class PupilImagingReduced(ImageDataItem, abstract=True): _name_template = r'{band}_PUPIL_REDUCED' _title_template = r"{band} pupil reduced" _description_template = "Reduced pupil image in {band} mode." diff --git a/metisp/pymetis/src/pymetis/dataitems/pupil/raw.py b/metisp/pymetis/src/pymetis/dataitems/pupil/raw.py index abb1eecf..f2de4825 100644 --- a/metisp/pymetis/src/pymetis/dataitems/pupil/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/pupil/raw.py @@ -19,17 +19,16 @@ import cpl -from pymetis.classes.dataitems import DataItem -from pymetis.classes.mixins.band import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.dataitems import ImageDataItem +from pymetis.classes.mixins.band import BandLmMixin, BandNMixin -class PupilRaw(BandSpecificMixin, DataItem, abstract=True): +class PupilRaw(ImageDataItem, abstract=True): _name_template = r'{band}_PUPIL_RAW' _title_template = "{band} pupil raw" _description_template = "Raw exposure of the pupil in {band} image mode." _frame_group = cpl.ui.Frame.FrameGroup.RAW _frame_level = cpl.ui.Frame.FrameLevel.FINAL - _frame_type = cpl.ui.Frame.FrameType.IMAGE class LmPupilRaw(BandLmMixin, PupilRaw): diff --git a/metisp/pymetis/src/pymetis/dataitems/raw/wcuoff.py b/metisp/pymetis/src/pymetis/dataitems/raw/wcuoff.py index 563ed707..3947d64d 100644 --- a/metisp/pymetis/src/pymetis/dataitems/raw/wcuoff.py +++ b/metisp/pymetis/src/pymetis/dataitems/raw/wcuoff.py @@ -21,10 +21,10 @@ from cpl.core import Image from pymetis.classes.dataitems import ImageDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin, BandIfuMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin, BandIfuMixin -class WcuOffRaw(BandSpecificMixin, ImageDataItem, abstract=True): +class WcuOffRaw(ImageDataItem, abstract=True): """ WCU_OFF input illuminated by the WCU up-to and including the integrating sphere, but no source. diff --git a/metisp/pymetis/src/pymetis/dataitems/rsrf/raw.py b/metisp/pymetis/src/pymetis/dataitems/rsrf/raw.py index 92c998ac..18726bd2 100644 --- a/metisp/pymetis/src/pymetis/dataitems/rsrf/raw.py +++ b/metisp/pymetis/src/pymetis/dataitems/rsrf/raw.py @@ -20,11 +20,10 @@ import cpl from pymetis.dataitems.raw import Raw -from pymetis.classes.mixins import DetectorSpecificMixin, Detector2rgMixin, DetectorGeoMixin, DetectorIfuMixin, \ - BandSpecificMixin, BandLmMixin, BandNMixin, BandIfuMixin +from pymetis.classes.mixins import DetectorIfuMixin, BandIfuMixin -class RsrfRaw(DetectorSpecificMixin, BandSpecificMixin, Raw, abstract=True): +class RsrfRaw(Raw, abstract=True): _name_template = r'{band}_LSS_RSRF_RAW' _frame_level = cpl.ui.Frame.FrameLevel.INTERMEDIATE _frame_group = cpl.ui.Frame.FrameGroup.RAW diff --git a/metisp/pymetis/src/pymetis/dataitems/synth.py b/metisp/pymetis/src/pymetis/dataitems/synth.py index cc6cb4a5..929a4e1d 100644 --- a/metisp/pymetis/src/pymetis/dataitems/synth.py +++ b/metisp/pymetis/src/pymetis/dataitems/synth.py @@ -20,10 +20,10 @@ import cpl from pymetis.classes.dataitems import TableDataItem -from pymetis.classes.mixins import BandSpecificMixin, BandLmMixin, BandNMixin +from pymetis.classes.mixins import BandLmMixin, BandNMixin -class SynthTrans(BandSpecificMixin, TableDataItem, abstract=True): +class SynthTrans(TableDataItem, abstract=True): _name_template = r'{band}_SYNTH_TRANS' _title_template = "{band} synthetic transmission" _description_template = "Synthetic {band} transmission used for default telluric correction of STD stars" @@ -39,7 +39,7 @@ class NSynthTrans(BandNMixin, SynthTrans): pass -class LssSynthTrans(BandSpecificMixin, TableDataItem, abstract=True): +class LssSynthTrans(TableDataItem, abstract=True): """ Transmission spectrum """ diff --git a/metisp/pymetis/src/pymetis/recipes/cal/metis_cal_chophome.py b/metisp/pymetis/src/pymetis/recipes/cal/metis_cal_chophome.py index 288bea1c..e8676ce4 100644 --- a/metisp/pymetis/src/pymetis/recipes/cal/metis_cal_chophome.py +++ b/metisp/pymetis/src/pymetis/recipes/cal/metis_cal_chophome.py @@ -19,14 +19,12 @@ import cpl from cpl.core import Msg -from cpl.core import ImageList from pyesorex.parameter import ParameterList, ParameterEnum, ParameterRange from pymetis.classes.dataitems import DataItem from pymetis.classes.dataitems.hdu import Hdu +from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin from pymetis.dataitems.chophome import LmChophomeRaw, LmChophomeCombined, LmChophomeBackground -from pymetis.dataitems.gainmap import GainMap2rg -from pymetis.dataitems.linearity.linearity import LinearityMap2rg from pymetis.dataitems.raw.wcuoff import LmWcuOffRaw from pymetis.classes.recipes import MetisRecipe from pymetis.classes.inputs import (RawInput, GainMapInput, PersistenceMapInput, BadPixMapInput, @@ -35,7 +33,7 @@ from pymetis.utils.dummy import create_dummy_header -class MetisCalChophomeImpl(RawImageProcessor): # TODO replace parent class? +class MetisCalChophomeImpl(BandLmMixin, Detector2rgMixin, RawImageProcessor): # TODO replace parent class? """Implementation class for metis_cal_chophome""" class InputSet(RawImageProcessor.InputSet): """Inputs for metis_cal_chophome""" @@ -46,12 +44,13 @@ class WcuOffInput(RawInput): Item = LmWcuOffRaw class GainMapInput(OptionalInputMixin, GainMapInput): - Item = GainMap2rg + pass class LinearityInput(OptionalInputMixin, LinearityInput): - Item = LinearityMap2rg + pass - PersistenceMapInput = PersistenceMapInput + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass class BadPixMapInput(OptionalInputMixin, BadPixMapInput): pass @@ -79,7 +78,7 @@ def process(self) -> set[DataItem]: raw_images = self.inputset.raw.load_data(extension='DET1.DATA') self.inputset.raw.use() - # I think there's a bit of confusion abotu different sources of persistence maps that's + # I think there's a bit of confusion about different sources of persistence maps that's # causing the workflow to crash. For now, I'll comment out the two lines, to be # uncommented after the workflow demonstration in Koln # persistence_map = self.inputset.persistence_map.load_data(extension='DET1.DATA') diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_calibrate.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_calibrate.py index 5854be91..f660f417 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_calibrate.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_calibrate.py @@ -20,6 +20,7 @@ from pymetis.classes.dataitems import DataItem from pymetis.classes.dataitems.hdu import Hdu +from pymetis.classes.mixins import BandIfuMixin, DetectorIfuMixin from pymetis.dataitems.common import IfuTelluric from pymetis.dataitems.ifu.ifu import IfuScienceCubeCalibrated, IfuSciReduced from pymetis.classes.recipes import MetisRecipe, MetisRecipeImpl @@ -28,7 +29,7 @@ from pymetis.utils.dummy import create_dummy_image, create_dummy_header -class MetisIfuCalibrateImpl(MetisRecipeImpl): +class MetisIfuCalibrateImpl(BandIfuMixin, DetectorIfuMixin, MetisRecipeImpl): class InputSet(PipelineInputSet): class ReducedInput(SinglePipelineInput): Item = IfuSciReduced diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_distortion.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_distortion.py index 5cdef477..87c5239c 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_distortion.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_distortion.py @@ -26,12 +26,12 @@ from pymetis.classes.dataitems.dataitem import DataItem from pymetis.classes.dataitems.hdu import Hdu -from pymetis.classes.inputs.common import OptionalPersistenceMapInput +from pymetis.classes.inputs.common import GainMapInput, LinearityInput +from pymetis.classes.mixins import DetectorIfuMixin from pymetis.dataitems.distortion import IfuDistortionRaw, IfuDistortionTable, IfuDistortionReduced from pymetis.classes.recipes import MetisRecipe from pymetis.classes.inputs import RawInput, MasterDarkInput, OptionalInputMixin, PersistenceMapInput from pymetis.classes.inputs import PinholeTableInput -from pymetis.classes.inputs import PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin from pymetis.classes.prefab.darkimage import DarkImageProcessor from pymetis.utils.dummy import create_dummy_table, create_dummy_header @@ -140,11 +140,23 @@ def create_distortion_table(ext: Literal[1, 2, 3, 4]) -> cpl.core.Table: return table -class MetisIfuDistortionImpl(DarkImageProcessor): - class InputSet(LinearityInputSetMixin, GainMapInputSetMixin, DarkImageProcessor.InputSet): - MasterDarkInput = MasterDarkInput - PinholeTableInput = PinholeTableInput - PersistenceMap = OptionalPersistenceMapInput +class MetisIfuDistortionImpl(DetectorIfuMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): + class MasterDarkInput(MasterDarkInput): + pass + + class PinholeTableInput(PinholeTableInput): + pass + + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + class RawInput(RawInput): Item = IfuDistortionRaw diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_postprocess.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_postprocess.py index 6e9f00d5..4d1761ba 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_postprocess.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_postprocess.py @@ -17,12 +17,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -import cpl -from cpl.core import ImageList as CplImageList from pyesorex.parameter import ParameterList, ParameterEnum, ParameterValue from pymetis.classes.dataitems import DataItem from pymetis.classes.dataitems.hdu import Hdu +from pymetis.classes.mixins import BandIfuMixin, DetectorIfuMixin from pymetis.dataitems.coadd import IfuSciCoadd from pymetis.dataitems.ifu.ifu import IfuScienceCubeCalibrated from pymetis.classes.recipes import MetisRecipe, MetisRecipeImpl @@ -30,7 +29,7 @@ from pymetis.utils.dummy import create_dummy_header -class MetisIfuPostprocessImpl(MetisRecipeImpl): +class MetisIfuPostprocessImpl(BandIfuMixin, DetectorIfuMixin, MetisRecipeImpl): class InputSet(PipelineInputSet): class SciCubeCalibratedInput(MultiplePipelineInput): Item = IfuScienceCubeCalibrated diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_reduce.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_reduce.py index 4d933018..b7c30156 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_reduce.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_reduce.py @@ -23,6 +23,7 @@ from pyesorex.parameter import ParameterList, ParameterEnum, ParameterValue from pymetis.classes.dataitems import DataItem, Hdu +from pymetis.classes.mixins import BandIfuMixin, DetectorIfuMixin from pymetis.dataitems.distortion.table import IfuDistortionTable from pymetis.dataitems.ifu.raw import IfuSkyRaw, IfuRaw from pymetis.dataitems.ifu.ifu import IfuCombined, IfuReduced, IfuReducedCube @@ -31,20 +32,30 @@ from pymetis.classes.recipes import MetisRecipe from pymetis.classes.prefab.darkimage import DarkImageProcessor from pymetis.classes.inputs import (SinglePipelineInput, RawInput, WavecalInput, - PersistenceInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin) + OptionalInputMixin, PersistenceMapInput, GainMapInput, LinearityInput) from pymetis.utils.dummy import create_dummy_header -class MetisIfuReduceImpl(DarkImageProcessor): - class InputSet(GainMapInputSetMixin, PersistenceInputSetMixin, LinearityInputSetMixin, DarkImageProcessor.InputSet): +class MetisIfuReduceImpl(BandIfuMixin, DetectorIfuMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = IfuRaw class RawSkyInput(RawInput): Item = IfuSkyRaw - WavecalInput = WavecalInput + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class WavecalInput(WavecalInput): + pass # We need to create a new class here, not reuse the old one! class DistortionTableInput(SinglePipelineInput): Item = IfuDistortionTable diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_rsrf.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_rsrf.py index 450e91c5..9c8ce1bf 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_rsrf.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_rsrf.py @@ -29,6 +29,7 @@ from pymetis.classes.dataitems import DataItem from pymetis.classes.dataitems.hdu import Hdu +from pymetis.classes.mixins import DetectorIfuMixin, BandIfuMixin from pymetis.dataitems.badpixmap import BadPixMapIfu from pymetis.dataitems.gainmap import GainMapIfu from pymetis.dataitems.linearity.linearity import LinearityMapIfu @@ -42,15 +43,14 @@ from pymetis.classes.inputs import (BadPixMapInput, MasterDarkInput, RawInput, GainMapInput, WavecalInput, DistortionTableInput, LinearityInput, OptionalInputMixin, SinglePipelineInput, PersistenceMapInput) -from pymetis.classes.inputs import LinearityInputSetMixin from pymetis.utils.dummy import create_dummy_table, create_dummy_header ma = np.ma EXT = 4 # TODO: update to read multi-extension files and index by EXTNAME instead of integer -class MetisIfuRsrfImpl(DarkImageProcessor): - class InputSet(LinearityInputSetMixin, DarkImageProcessor.InputSet): +class MetisIfuRsrfImpl(DetectorIfuMixin, BandIfuMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = IfuRsrfRaw diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_telluric.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_telluric.py index 3d9db8f3..d83f80a5 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_telluric.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_telluric.py @@ -20,6 +20,7 @@ from pymetis.classes.dataitems import DataItem from pymetis.classes.dataitems.hdu import Hdu +from pymetis.classes.mixins import BandIfuMixin, DetectorIfuMixin from pymetis.dataitems.common import FluxCalTable, IfuTelluric from pymetis.dataitems.ifu.ifu import IfuReduced1d, IfuCombined from pymetis.dataitems.ifu.raw import IfuRaw @@ -37,7 +38,7 @@ # Note that there will be most probably a redesign / split into more recipes to follow the approach # implemented already in other ESO pipelines -class MetisIfuTelluricImpl(MetisRecipeImpl): +class MetisIfuTelluricImpl(DetectorIfuMixin, BandIfuMixin, MetisRecipeImpl): """Implementation class for metis_ifu_telluric""" # ++++++++++++++ Defining input +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_wavecal.py b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_wavecal.py index 006df617..79e34250 100644 --- a/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_wavecal.py +++ b/metisp/pymetis/src/pymetis/recipes/ifu/metis_ifu_wavecal.py @@ -27,23 +27,31 @@ from pymetis.dataitems.wavecal import IfuWavecalRaw, IfuWavecal from pymetis.classes.mixins import BandIfuMixin, DetectorIfuMixin from pymetis.classes.recipes import MetisRecipe -from pymetis.classes.inputs import MasterDarkInput, RawInput, DistortionTableInput -from pymetis.classes.inputs import PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin +from pymetis.classes.inputs import MasterDarkInput, RawInput, DistortionTableInput, OptionalInputMixin, \ + PersistenceMapInput, GainMapInput, LinearityInput from pymetis.classes.prefab.darkimage import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header -class MetisIfuWavecalImpl(DarkImageProcessor): - class InputSet(BandIfuMixin, DetectorIfuMixin, - PersistenceInputSetMixin, - LinearityInputSetMixin, - GainMapInputSetMixin, - DarkImageProcessor.InputSet): +class MetisIfuWavecalImpl(BandIfuMixin, DetectorIfuMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = IfuWavecalRaw - MasterDarkInput = MasterDarkInput - DistortionTableInput = DistortionTableInput + class MasterDarkInput(MasterDarkInput): + pass + + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class DistortionTableInput(DistortionTableInput): + pass ProductIfuWavecal = IfuWavecal diff --git a/metisp/pymetis/src/pymetis/recipes/instrument/metis_pupil_imaging.py b/metisp/pymetis/src/pymetis/recipes/instrument/metis_pupil_imaging.py index 65991109..c3951586 100644 --- a/metisp/pymetis/src/pymetis/recipes/instrument/metis_pupil_imaging.py +++ b/metisp/pymetis/src/pymetis/recipes/instrument/metis_pupil_imaging.py @@ -35,14 +35,13 @@ from pymetis.dataitems.pupil import PupilRaw from pymetis.dataitems.pupil.pupil import PupilImagingReduced from pymetis.classes.recipes import MetisRecipe -from pymetis.classes.inputs import (RawInput, MasterDarkInput, MasterFlatInput, - LinearityInputSetMixin, GainMapInputSetMixin) +from pymetis.classes.inputs import RawInput, MasterDarkInput, MasterFlatInput, GainMapInput, LinearityInput from pymetis.classes.prefab.darkimage import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header class MetisPupilImagingImpl(DarkImageProcessor): - class InputSet(LinearityInputSetMixin, GainMapInputSetMixin, DarkImageProcessor.InputSet): + class InputSet(DarkImageProcessor.InputSet): """ Define the input sets and tags. Here, we define dark, flat, linearity, persistence and gain map @@ -54,7 +53,14 @@ class InputSet(LinearityInputSetMixin, GainMapInputSetMixin, DarkImageProcessor. class RawInput(RawInput): Item = PupilRaw - MasterDarkInput = MasterDarkInput + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class MasterDarkInput(MasterDarkInput): + pass # Also, one master flat is required. We use a prefabricated class class MasterFlatInput(MasterFlatInput): diff --git a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_background.py b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_background.py index 0daf7b2d..7d1b1579 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_background.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_background.py @@ -28,11 +28,11 @@ from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin from pymetis.classes.recipes import MetisRecipe, MetisRecipeImpl from pymetis.classes.inputs import PipelineInputSet, SinglePipelineInput -from pymetis.utils.dummy import create_dummy_image, create_dummy_table, create_dummy_header +from pymetis.utils.dummy import create_dummy_table, create_dummy_header -class MetisLmImgBackgroundImpl(MetisRecipeImpl): - class InputSet(BandLmMixin, Detector2rgMixin, PipelineInputSet): +class MetisLmImgBackgroundImpl(BandLmMixin, Detector2rgMixin, MetisRecipeImpl): + class InputSet(PipelineInputSet): class BasicReducedInput(SinglePipelineInput): Item = BasicReduced @@ -73,7 +73,8 @@ class MetisLmImgBackground(MetisRecipe): _author = "Chi-Hung Yan, A*" _email = "chyan@asiaa.sinica.edu.tw" _copyright = "GPL-3.0-or-later" - _synopsis = "Basic reduction of raw exposures from the LM-band imager" + _synopsis = "Basic reduction of raw exposures from the {band} imager" + _description = "Something" parameters = ParameterList([ ParameterEnum( diff --git a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_basic_reduce.py b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_basic_reduce.py index 87f8329e..6d553a3e 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_basic_reduce.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_basic_reduce.py @@ -24,18 +24,19 @@ from pyesorex.parameter import ParameterList, ParameterEnum from pymetis.classes.dataitems import DataItem, Hdu +from pymetis.classes.mixins import BandLmMixin from pymetis.dataitems.img.basicreduced import BasicReduced from pymetis.dataitems.img.raw import ImageRaw from pymetis.dataitems.masterflat import MasterImgFlat from pymetis.classes.inputs import (RawInput, MasterDarkInput, MasterFlatInput, - PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin) + OptionalInputMixin, PersistenceMapInput, GainMapInput, LinearityInput) from pymetis.classes.prefab.darkimage import DarkImageProcessor from pymetis.classes.recipes import MetisRecipe from pymetis.utils.dummy import create_dummy_header -class MetisLmImgBasicReduceImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin, DarkImageProcessor.InputSet): +class MetisLmImgBasicReduceImpl(BandLmMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): """ The first step of writing a recipe is to define an InputSet: the one-to-one class that wraps all the recipe inputs. It encapsulates the entire input and @@ -68,7 +69,17 @@ class RawInput(RawInput): # Now we need a master dark frame. Since nothing is changed and the tag is always the same, # we just point to the provided MasterDarkInput. Note that we do not have to instantiate # it explicitly anywhere, `MasterDarkInput` takes care of that for us. - MasterDarkInput = MasterDarkInput + class MasterDarkInput(MasterDarkInput): + pass + + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass # Also, one master flat is required. Again, we use a prefabricated class but reset the tags class MasterFlatInput(MasterFlatInput): diff --git a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_calibrate.py b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_calibrate.py index dd8752d8..42d069ac 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_calibrate.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_calibrate.py @@ -25,8 +25,8 @@ from pymetis.classes.prefab import MetisImgCalibrateImpl -class MetisLmImgCalibrateImpl(MetisImgCalibrateImpl): - class InputSet(BandLmMixin, Detector2rgMixin, MetisImgCalibrateImpl.InputSet): +class MetisLmImgCalibrateImpl(BandLmMixin, Detector2rgMixin, MetisImgCalibrateImpl): + class InputSet(MetisImgCalibrateImpl.InputSet): pass diff --git a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_distortion.py b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_distortion.py index bb623c7a..8eaee379 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_distortion.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_distortion.py @@ -23,11 +23,12 @@ from pyesorex.parameter import ParameterList, ParameterEnum from pymetis.classes.dataitems import DataItem +from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin from pymetis.classes.recipes import MetisRecipe from pymetis.classes.prefab import MetisBaseImgDistortionImpl -class MetisLmImgDistortionImpl(MetisBaseImgDistortionImpl): +class MetisLmImgDistortionImpl(BandLmMixin, Detector2rgMixin, MetisBaseImgDistortionImpl): class InputSet(MetisBaseImgDistortionImpl.InputSet): class RawInput(MetisBaseImgDistortionImpl.InputSet.RawInput): pass diff --git a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_flat.py b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_flat.py index 6ba1186e..8314df5e 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_flat.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_flat.py @@ -21,13 +21,13 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins.band import BandLmMixin +from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin, SourceLampMixin from pymetis.classes.recipes import MetisRecipe from pymetis.classes.prefab import MetisBaseImgFlatImpl -class MetisLmImgFlatImpl(MetisBaseImgFlatImpl, ABC): - class InputSet(BandLmMixin, MetisBaseImgFlatImpl.InputSet): +class MetisLmImgFlatImpl(BandLmMixin, Detector2rgMixin, MetisBaseImgFlatImpl): + class InputSet(MetisBaseImgFlatImpl.InputSet): pass diff --git a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_std_process.py b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_std_process.py index 962106bc..ff0190f8 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_std_process.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_img/metis_lm_img_std_process.py @@ -26,16 +26,15 @@ from pymetis.dataitems.background.subtracted import LmStdBackgroundSubtracted -class MetisLmImgStdProcessImpl(MetisImgStdProcessImpl): +class MetisLmImgStdProcessImpl(BandLmMixin, MetisImgStdProcessImpl): class InputSet(MetisImgStdProcessImpl.InputSet): - class RawInput(BandLmMixin, MetisImgStdProcessImpl.InputSet.RawInput): + class RawInput(MetisImgStdProcessImpl.InputSet.RawInput): Item = LmStdBackgroundSubtracted ProductImgStdCombined = LmStdCombined class MetisLmImgStdProcess(MetisRecipe): - # FixMe This can be probably also largely deduplicated _name: str = "metis_lm_img_std_process" _version: str = "0.1" _author: str = "Chi-Hung Yan, A*" diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_adc_slitloss.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_adc_slitloss.py index cb8529b0..1ea78e48 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_adc_slitloss.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_adc_slitloss.py @@ -25,8 +25,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisLmAdcSlitlossImpl(MetisAdcSlitlossImpl): - class InputSet(BandLmMixin, MetisAdcSlitlossImpl.InputSet): +class MetisLmAdcSlitlossImpl(BandLmMixin, MetisAdcSlitlossImpl): + class InputSet(MetisAdcSlitlossImpl.InputSet): pass @@ -39,7 +39,7 @@ class MetisLmAdcSlitloss(MetisRecipe): _synopsis: str = "Determines ADC slitlosses" # TODO: Check whether WCU_OFF frames are necessary as input (cf. ifu rsrf recipe) - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Incredible fancy description of algorithm follows... ***TBD***""" # TODO: Write description # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_calctrans.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_calctrans.py index 78944b84..0a65d9cd 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_calctrans.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_calctrans.py @@ -24,8 +24,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisLmLssMfCalctransImpl(MetisLssMfCalctransImpl): - class InputSet(BandLmMixin, MetisLssMfCalctransImpl.InputSet): +class MetisLmLssMfCalctransImpl(BandLmMixin, MetisLssMfCalctransImpl): + class InputSet(MetisLssMfCalctransImpl.InputSet): pass @@ -42,23 +42,8 @@ class MetisLmLssMfCalctrans(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Calculation of transmission function" - _description: str = """\ - Calculation of transmission function - Inputs - MF_BEST_FIT_TAB: Table with best-fit parameters - LSF_KERNEL: LSF Kernel file - ATM_LINE_CAT: Catalogue of atmospheric lines - ATM_PROFILE: Atmospheric input profile - - Matched Keywords - DRS.SLIT - - Outputs - LM_LSS_SYNTH_TRANS: Synthetic transmission of the Earth's atmosphere - """ - - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_correct.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_correct.py index ed8c91a7..5990c7a5 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_correct.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_correct.py @@ -25,8 +25,8 @@ # TODO: Check 2D input spectra -- correct all row with same trans? -class MetisLmLssMfCorrectImpl(MetisLssMfCorrectImpl): - class InputSet(BandLmMixin, MetisLssMfCorrectImpl.InputSet): +class MetisLmLssMfCorrectImpl(BandLmMixin, MetisLssMfCorrectImpl): + class InputSet(MetisLssMfCorrectImpl.InputSet): pass @@ -38,7 +38,7 @@ class MetisLmLssMfCorrect(MetisRecipe): _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Application of the telluric correction" - _matched_keywords: {str} = {'DRS.SLIT'} + _matched_keywords: set[str] = {'DRS.SLIT'} _algorithm = """Apply telluric correction, i.e. divide the input science spectrum by the synthetic transmission.""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ @@ -46,7 +46,7 @@ class MetisLmLssMfCorrect(MetisRecipe): # TODO: Implement real parameters parameters = ParameterList([ ParameterEnum( - name=f"{_name}parameter1", + name=f"{_name}.parameter1", context=_name, description="Description of parameter 1", default="value1", diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_model.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_model.py index 7cc6e3e8..05b38006 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_model.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_mf_model.py @@ -24,8 +24,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisLmLssMfModelImpl(MetisLssMfModelImpl): - class InputSet(BandLmMixin, MetisLssMfModelImpl.InputSet): +class MetisLmLssMfModelImpl(BandLmMixin, MetisLssMfModelImpl): + class InputSet(MetisLssMfModelImpl.InputSet): pass @@ -34,10 +34,9 @@ class MetisLmLssMfModel(MetisRecipe): _version: str = "0.1" _author: str = "Wolfgang Kausch, A*" _email: str = "wolfgang.kausch@uibk.ac.at" - _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Calculation of molecfit model" - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fit of telluric features visible in the science input spectrum Determination of best-fit parameter set""" diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_rsrf.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_rsrf.py index 751c3f3b..e2b677cd 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_rsrf.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_rsrf.py @@ -24,8 +24,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisLmLssRsrfImpl(MetisLssRsrfImpl): - class InputSet(BandLmMixin, Detector2rgMixin, MetisLssRsrfImpl.InputSet): +class MetisLmLssRsrfImpl(BandLmMixin, Detector2rgMixin, MetisLssRsrfImpl): + class InputSet(MetisLssRsrfImpl.InputSet): pass @@ -44,7 +44,7 @@ class MetisLmLssRsrf(MetisRecipe): _synopsis: str = "Create spectroscopic relative spectral response function (RSRF) for the 2RG detector" # TODO: Check whether WCU_OFF frames are necessary as input (cf. ifu rsrf recipe) - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # TODO: Write description # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_sci.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_sci.py index 3042c48e..81af7403 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_sci.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_sci.py @@ -19,13 +19,13 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin +from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin, TargetSciMixin from pymetis.classes.prefab.lss.sci import MetisLssSciImpl from pymetis.classes.recipes import MetisRecipe -class MetisLmLssSciImpl(MetisLssSciImpl): - class InputSet(BandLmMixin, Detector2rgMixin, MetisLssSciImpl.InputSet): +class MetisLmLssSciImpl(BandLmMixin, Detector2rgMixin, TargetSciMixin, MetisLssSciImpl): + class InputSet(MetisLssSciImpl.InputSet): pass @@ -43,7 +43,7 @@ class MetisLmLssSci(MetisRecipe): _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Reduction of the LSS science star frames" - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_std.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_std.py index 8ea49bbd..fb7f33fa 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_std.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_std.py @@ -19,12 +19,12 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin +from pymetis.classes.mixins import BandLmMixin, Detector2rgMixin, TargetStdMixin from pymetis.classes.prefab.lss.std import MetisLssStdImpl from pymetis.classes.recipes import MetisRecipe -class MetisLmLssStdImpl(MetisLssStdImpl): +class MetisLmLssStdImpl(BandLmMixin, Detector2rgMixin, TargetStdMixin, MetisLssStdImpl): class InputSet(BandLmMixin, Detector2rgMixin, MetisLssStdImpl.InputSet): pass @@ -43,7 +43,7 @@ class MetisLmLssStd(MetisRecipe): _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Reduction of the standard star frames for determining the response function (flux calibration) and/or the transmission (telluric correction)" - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_trace.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_trace.py index c769ded0..fce9ea05 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_trace.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_trace.py @@ -25,7 +25,7 @@ class MetisLmLssTraceImpl(MetisLssTraceImpl): - class InputSet(BandLmMixin, MetisLssTraceImpl.InputSet): + class InputSet(MetisLssTraceImpl.InputSet): pass diff --git a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_wave.py b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_wave.py index 5137f8f6..c113d3d9 100644 --- a/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_wave.py +++ b/metisp/pymetis/src/pymetis/recipes/lm_lss/metis_lm_lss_wave.py @@ -25,32 +25,43 @@ from pymetis.dataitems.lss.rsrf import MasterLssRsrf from pymetis.dataitems.lss.trace import LssTrace from pymetis.dataitems.lss.wave import LssWaveRaw -from pymetis.classes.inputs import (SinglePipelineInput, RawInput, - LaserTableInput, - PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, - LinearityInputSetMixin) -from pymetis.classes.inputs.common import WcuOffInput +from pymetis.classes.inputs import SinglePipelineInput, RawInput, LaserTableInput +from pymetis.classes.inputs.common import WcuOffInput, OptionalInputMixin, PersistenceMapInput, GainMapInput, \ + LinearityInput, BadPixMapInput from pymetis.classes.mixins import BandLmMixin from pymetis.classes.prefab import DarkImageProcessor from pymetis.classes.recipes import MetisRecipe from pymetis.utils.dummy import create_dummy_table, create_dummy_header -class MetisLmLssWaveImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, BadPixMapInputSetMixin, GainMapInputSetMixin, LinearityInputSetMixin, - BandLmMixin, - DarkImageProcessor.InputSet): +class MetisLmLssWaveImpl(BandLmMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): class RawInput(RawInput): Item = LssWaveRaw + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + class BadPixMapInput(BadPixMapInput): + pass + class MasterRsrfInput(SinglePipelineInput): Item = MasterLssRsrf class LssTraceInput(SinglePipelineInput): Item = LssTrace - WcuOffInput = WcuOffInput - LaserTableInput = LaserTableInput + class WcuOffInput(WcuOffInput): + pass + + class LaserTableInput(LaserTableInput): + pass # ++++++++++++ Intermediate / QC products ++++++++++++ ProductLssCurve = LssCurve @@ -133,7 +144,7 @@ class MetisLmLssWave(MetisRecipe): LM_LSS_WAVE_GUESS: First guess of the wavelength solution """ - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/metis_det_dark.py b/metisp/pymetis/src/pymetis/recipes/metis_det_dark.py index 802524de..ad3248ac 100644 --- a/metisp/pymetis/src/pymetis/recipes/metis_det_dark.py +++ b/metisp/pymetis/src/pymetis/recipes/metis_det_dark.py @@ -29,6 +29,7 @@ from pymetis.classes.dataitems import DataItem from pymetis.classes.dataitems.hdu import Hdu +from pymetis.classes.prefab.persistence import PersistenceCorrectionMixin from pymetis.dataitems.masterdark.masterdark import MasterDark from pymetis.dataitems.masterdark.raw import DarkRaw from pymetis.classes.inputs import (RawInput, BadPixMapInput, PersistenceMapInput, @@ -42,9 +43,9 @@ from pymetis.utils.dummy import create_dummy_header, python_to_cpl_type -class MetisDetDarkImpl(RawImageProcessor, ABC): +class MetisDetDarkImpl(PersistenceCorrectionMixin, RawImageProcessor, ABC): """ - Implementation class for `metis_det_dark`. + Implementation class for the `metis_det_dark` recipe. """ # We start by deriving the implementation class from `MetisRecipeImpl`, or in this case, one of its subclasses, @@ -148,8 +149,10 @@ def _process_single_detector(self, detector: Literal[1, 2, 3, 4]) -> list[Hdu]: badpix_mask = zeros_like(raw_images[0], cpl.core.Type.FLOAT) # fake the gain at the moment by setting to 1 + gain = cpl.core.Image.zeros_like(raw_images[0]) + gain.add_scalar(1) - raw_images = self.correct_gain(raw_images) + raw_images = self.correct_gain(raw_images, gain) raw_images = self.correct_persistence(raw_images) linearity_map = self.inputset.linearity.load_data(extension=rf'DET{detector:1d}.SCI') @@ -289,7 +292,7 @@ class MetisDetDark(MetisRecipe): _email = "hugo@buddelmeijer.nl" _synopsis = "Create master dark" _description = ( - "Prototype to create a METIS masterdark." + "Prototype to create a METIS masterdark for {detector} in {2RG, GEO, IFU}" ) # And also fill in information from DRLD. These are specific to METIS and are used to build the description @@ -310,7 +313,7 @@ class MetisDetDark(MetisRecipe): default="average", alternatives=("add", "average", "median", "sigclip"), ), - # ToDo: Maybe these should be user-configurable as well? + # ToDo: Maybe these should be user-configurable as well? Added them commented out. #ParameterValue( # name=f"{_name}.outliers.kappa_low", # context=_name, diff --git a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_calibrate.py b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_calibrate.py index 811ab006..5773b2fd 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_calibrate.py +++ b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_calibrate.py @@ -25,8 +25,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisNImgCalibrateImpl(MetisImgCalibrateImpl): - class InputSet(BandNMixin, DetectorGeoMixin, MetisImgCalibrateImpl.InputSet): +class MetisNImgCalibrateImpl(BandNMixin, DetectorGeoMixin, MetisImgCalibrateImpl): + class InputSet(MetisImgCalibrateImpl.InputSet): pass diff --git a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_chopnod.py b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_chopnod.py index c6efd5a9..61557298 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_chopnod.py +++ b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_chopnod.py @@ -24,19 +24,20 @@ from pyesorex.parameter import ParameterList, ParameterEnum from pymetis.classes.dataitems import DataItem, Hdu +from pymetis.classes.mixins import DetectorGeoMixin, BandNMixin from pymetis.dataitems.background.background import NStdBackground from pymetis.dataitems.background.subtracted import NStdBackgroundSubtracted from pymetis.dataitems.masterflat import MasterImgFlat from pymetis.dataitems.img.raw import ImageRaw from pymetis.classes.recipes import MetisRecipe from pymetis.classes.inputs import (RawInput, MasterDarkInput, MasterFlatInput, - PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin) + OptionalInputMixin, PersistenceMapInput, GainMapInput, LinearityInput) from pymetis.classes.prefab.darkimage import DarkImageProcessor from pymetis.utils.dummy import create_dummy_header -class MetisNImgChopnodImpl(DarkImageProcessor): - class InputSet(PersistenceInputSetMixin, LinearityInputSetMixin, GainMapInputSetMixin, DarkImageProcessor.InputSet): +class MetisNImgChopnodImpl(BandNMixin, DetectorGeoMixin, DarkImageProcessor): + class InputSet(DarkImageProcessor.InputSet): """ The first step of writing a recipe is to define an InputSet: the one-to-one class that wraps all the recipe inputs. @@ -68,12 +69,23 @@ class RawInput(RawInput): # Now we need a master dark frame. # Since nothing is changed and the tag is always the same, # we just point to the provided MasterDarkInput. # Note that we do not have to instantiate it explicitly anywhere, `MasterDarkInput` takes care of that for us. - MasterDarkInput = MasterDarkInput + class MasterDarkInput(MasterDarkInput): + pass # Also one master flat is required. Again, we use a prefabricated class but reset the tags class MasterFlatInput(MasterFlatInput): Item = MasterImgFlat + class PersistenceMapInput(OptionalInputMixin, PersistenceMapInput): + pass + + class GainMapInput(GainMapInput): + pass + + class LinearityInput(LinearityInput): + pass + + ProductReduced = NStdBackgroundSubtracted ProductBackground = NStdBackground diff --git a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_flat.py b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_flat.py index a43300b2..34432941 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_flat.py +++ b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_flat.py @@ -19,13 +19,13 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins.band import BandNMixin, BandLmMixin +from pymetis.classes.mixins import BandNMixin, DetectorGeoMixin from pymetis.classes.recipes import MetisRecipe from pymetis.classes.prefab import MetisBaseImgFlatImpl -class MetisNImgFlatImpl(MetisBaseImgFlatImpl): - class InputSet(BandNMixin, MetisBaseImgFlatImpl.InputSet): +class MetisNImgFlatImpl(BandNMixin, DetectorGeoMixin, MetisBaseImgFlatImpl): + class InputSet(MetisBaseImgFlatImpl.InputSet): pass diff --git a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_std_process.py b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_std_process.py index 81067396..9f740870 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_std_process.py +++ b/metisp/pymetis/src/pymetis/recipes/n_img/metis_n_img_std_process.py @@ -25,9 +25,9 @@ from pymetis.classes.prefab.img.std_process import MetisImgStdProcessImpl -class MetisNImgStdProcessImpl(MetisImgStdProcessImpl): +class MetisNImgStdProcessImpl(BandNMixin, MetisImgStdProcessImpl): class InputSet(MetisImgStdProcessImpl.InputSet): - class RawInput(BandNMixin, MetisImgStdProcessImpl.InputSet.RawInput): + class RawInput(MetisImgStdProcessImpl.InputSet.RawInput): pass ProductFluxcalTab = FluxCalTable diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_adc_slitloss.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_adc_slitloss.py index 4a47b72e..faced5eb 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_adc_slitloss.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_adc_slitloss.py @@ -37,31 +37,10 @@ class MetisNAdcSlitloss(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Determines ADC slitlosses" - _description: str = """\ - Determines ADC slitlosses - Remark: Recipe not welldefined as actual algorithm not well defined (cf. DRLD, Calib plan) + # TODO: Check whether WCU_OFF frames are necessary as input (cf. ifu rsrf recipe) - Inputs - N_ADC_SLITLOSS_RAW: Raw SLITLOSS images [1-n] ***TBD*** - N_WCU_OFF_RAW: Raw WCU OFF background frames [1-n] - MASTER_DARK_GEO: Master dark frame [optional?] ***TBChecked*** - BADPIX_MAP_GEO: Bad-pixel map for GEO detector [optional] ***TBChecked*** - PERSISTENCE_MAP: Persistence map [optional] ***TBChecked*** - GAIN_MAP_GEO: Gain map for GEO detector ***TBChecked*** - LINEARITY_GEO: Linearity map for GEO detector ***TBChecked*** - - Matched Keywords - DET.DIT - DET.NDIT - DRS.SLIT - - Outputs - N_ADC_SLITLOSS: Table with slit losses ***TBD*** - """ -# TODO: Check whether WCU_OFF frames are necessary as input (cf. ifu rsrf recipe) - - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Incredible fancy description of algorithm follows... ***TBD***""" # TODO: Write description # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_calctrans.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_calctrans.py index c48564eb..596f900e 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_calctrans.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_calctrans.py @@ -24,8 +24,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisNLssMfCalctransImpl(MetisLssMfCalctransImpl): - class InputSet(BandNMixin, MetisLssMfCalctransImpl.InputSet): +class MetisNLssMfCalctransImpl(BandNMixin, MetisLssMfCalctransImpl): + class InputSet(MetisLssMfCalctransImpl.InputSet): pass @@ -42,23 +42,8 @@ class MetisNLssMfCalctrans(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Calculation of transmission function" - _description: str = """\ - Calculation of transmission function - Inputs - MF_BEST_FIT_TAB: Table with best-fit parameters - LSF_KERNEL: LSF Kernel file - ATM_LINE_CAT: Catalogue of atmospheric lines - ATM_PROFILE: Atmospheric input profile - - Matched Keywords - DRS.SLIT - - Outputs - N_LSS_SYNTH_TRANS: Synthetic transmission of the Earth's atmosphere - """ - - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_correct.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_correct.py index 0ddb9bab..6cc08382 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_correct.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_correct.py @@ -25,7 +25,7 @@ # TODO: Check 2D input spectra - correct all row with same trans? -class MetisNLssMfCorrectImpl(MetisLssMfCorrectImpl): +class MetisNLssMfCorrectImpl(BandNMixin, MetisLssMfCorrectImpl): class InputSet(BandNMixin, MetisLssMfCorrectImpl.InputSet): pass @@ -43,19 +43,7 @@ class MetisNLssMfCorrect(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Application of the telluric correction" - _description: str = """\ - Application of the telluric correction - Inputs - N_LSS_SCI_FLUX_1D: Coadded, wavelength + flux calibrated, collapsed 1D spectrum of the science - N_LSS_SYNTH_TRANS: Synthetic transmission of the Earth's atmosphere' - - Matched Keywords - DRS.SLIT - - Outputs - N_LSS_SCI_FLUX_TELL_1D: Coadded, wavelength + flux calibrated, telluric corrected 1D spectrum of the science object - """ _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_model.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_model.py index bca0f983..c14931fc 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_model.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_mf_model.py @@ -24,8 +24,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisNLssMfModelImpl(MetisLssMfModelImpl): - class InputSet(BandNMixin, MetisLssMfModelImpl.InputSet): +class MetisNLssMfModelImpl(BandNMixin, MetisLssMfModelImpl): + class InputSet(MetisLssMfModelImpl.InputSet): pass @@ -36,24 +36,8 @@ class MetisNLssMfModel(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Calculation of molecfit model" - _description: str = """\ - Calculation of molecfit model - Inputs - N_LSS_SCI_FLUX_1D: Coadded, wavelength + flux calibrated, collapsed 1D spectrum of the science object - N_LSS_STD_1D: Coadded, wavelength calibrated, collapsed 1D spectrum of the standard star - LSF_KERNEL: LSF Kernel file - ATM_LINE_CAT: Catalogue of atmospheric lines - ATMP_PROFILE: Atmospheric input profile - - Matched Keywords - DRS.SLIT ***TBChecked*** - - Outputs - MF_BEST_FIT_TAB: Table with best-fit parameters - """ - - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ @@ -61,7 +45,7 @@ class MetisNLssMfModel(MetisRecipe): # TODO: Implement real parameters parameters = ParameterList([ ParameterEnum( - name=f"{_name}parameter1", + name=f"{_name}.parameter1", context=_name, description="Description of parameter 1", default="value1", diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_rsrf.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_rsrf.py index 986bd49f..08e1fcf8 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_rsrf.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_rsrf.py @@ -24,8 +24,8 @@ from pymetis.classes.recipes import MetisRecipe -class MetisNLssRsrfImpl(MetisLssRsrfImpl): - class InputSet(BandNMixin, DetectorGeoMixin, MetisLssRsrfImpl.InputSet): +class MetisNLssRsrfImpl(BandNMixin, DetectorGeoMixin, MetisLssRsrfImpl): + class InputSet(MetisLssRsrfImpl.InputSet): pass @@ -50,31 +50,10 @@ class MetisNLssRsrf(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Create spectroscopic relative spectral response function (RSRF) for the GEO detector" - _description: str = """\ - Create relative spectral response function for the GEO LSS detector - - Inputs - N_LSS_RSRF_RAW: Raw RSRF images [1-n] - N_WCU_OFF_RAW: raw WCU OFF background frames [1-n] - MASTER_DARK_GEO: Master dark frame [optional?] - BADPIX_MAP_GEO: Bad-pixel map for GEO detector [optional] - PERSISTENCE_MAP: Persistence map [optional] - GAIN_MAP_GEO: Gain map for GEO detector - LINEARITY_GEO: Linearity map for GEO detector - - Matched Keywords - DET.DIT - DET.NDIT - DRS.SLIT - - Outputs - MASTER_N_LSS_RSRF: Master flat (RSRF) frame - MEDIAN_N_LSS_RSRF_IMG: Median map (QC) - MEAN_N_LSS_RSRF_IMG: Mean map (QC) - """ + # TODO: Check whether WCU_OFF frames are necessary as input (cf. ifu rsrf recipe) - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # TODO: Write description # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_sci.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_sci.py index 8608faa6..90d37587 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_sci.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_sci.py @@ -19,13 +19,13 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins import BandNMixin, DetectorGeoMixin +from pymetis.classes.mixins import BandNMixin, DetectorGeoMixin, TargetSciMixin from pymetis.classes.prefab.lss.sci import MetisLssSciImpl from pymetis.classes.recipes import MetisRecipe -class MetisNLssSciImpl(MetisLssSciImpl): - class InputSet(BandNMixin, DetectorGeoMixin, MetisLssSciImpl.InputSet): +class MetisNLssSciImpl(BandNMixin, DetectorGeoMixin, TargetSciMixin, MetisLssSciImpl): + class InputSet(MetisLssSciImpl.InputSet): pass @@ -42,38 +42,6 @@ class MetisNLssSci(MetisRecipe): _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Reduction of the LSS science star frames" - _description: str = """\ - Reduction of the LSS science star frames - - Inputs - N_LSS_SCI_RAW: Raw science images [1-n] - PERSISTENCE_MAP: Persistence map [optional] - LINEARITY_GEO: Linearity map for GEO detector - GAIN_MAP_GEO: Gain map for GEO detector - BADPIX_MAP_GEO: Bad-pixel map for GEO detector [optional] - MASTER_DARK_GEO: Master dark frame [optional?] - MASTER_N_LSS_RSRF: Master flat (RSRF) frame - N_LSS_DIST_SOL: Distortion solution - N_LSS_WAVE_GUESS: First guess of the wavelength solution - ATM_LINE_CAT: Catalogue of atmospheric lines - N_ADC_SLITLOSS: Slitloss information - STD_TRANSMISSION: Transmission of the Earth's atmosphere derived from the STD for telluric correction [optional] - MASTER_N_RESPONSE: Response function for flux calibration - - Matched Keywords - DET.DIT - DET.NDIT - DRS.SLIT - - Outputs - N_LSS_SCI_OBJ_MAP: Pixel map of the object pixels (QC) - N_LSS_SCI_SKY_MAP: Pixel map of the sky pixels (QC) - N_LSS_SCI_2D: Coadded, wavelength calibrated, 2D spectrum of the science object - N_LSS_SCI_1D: Coadded, wavelength calibrated, collapsed 1D spectrum of the science object - N_LSS_SCI_FLUX_2D: Coadded, wavelength + flux calibrated, 2D spectrum of the science object - N_LSS_SCI_FLUX_1D: Coadded, wavelength + flux calibrated, collapsed 1D spectrum of the science object - N_LSS_SCI_FLUX_TELL_1D: Coadded, wavelength + flux calibrated, collapsed 1D spectrum of the science object (optional) - """ _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" @@ -83,7 +51,7 @@ class MetisNLssSci(MetisRecipe): # TODO: Implement real parameters parameters = ParameterList([ ParameterEnum( - name=f"{_name}parameter1", + name=f"{_name}.parameter1", context=_name, description="Description of parameter 1", default="value1", diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_std.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_std.py index 6fa4ea26..4a2aeef0 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_std.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_std.py @@ -19,13 +19,13 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins import BandNMixin, DetectorGeoMixin +from pymetis.classes.mixins import BandNMixin, DetectorGeoMixin, TargetStdMixin from pymetis.classes.prefab.lss.std import MetisLssStdImpl from pymetis.classes.recipes import MetisRecipe -class MetisNLssStdImpl(MetisLssStdImpl): - class InputSet(BandNMixin, DetectorGeoMixin, MetisLssStdImpl.InputSet): +class MetisNLssStdImpl(BandNMixin, DetectorGeoMixin, TargetStdMixin, MetisLssStdImpl): + class InputSet(MetisLssStdImpl.InputSet): pass @@ -41,41 +41,10 @@ class MetisNLssStd(MetisRecipe): _author: str = "Wolfgang Kausch, A*" _email: str = "wolfgang.kausch@uibk.ac.at" _copyright: str = "GPL-3.0-or-later" - _synopsis: str = "Reduction of the standard star frames for determining the response function (flux calibration) and/or the transmission (telluric correction)" - _description: str = """\ - Reduction of the standard star frames for determining the response function (flux calibration) and/or the transmission (telluric correction) + _synopsis: str = ("Reduction of the standard star frames for determining the response " + "function (flux calibration) and/or the transmission (telluric correction)") - Inputs - N_LSS_STD_RAW: Raw standard star images [1-n] - PERSISTENCE_MAP: Persistence map [optional] - LINEARITY_GEO: Linearity map for GEO detector - GAIN_MAP_GEO: Gain map for GEO detector - BADPIX_MAP_GEO: Bad-pixel map for GEO detector [optional] - MASTER_DARK_GEO: Master dark frame [optional?] - MASTER_N_LSS_RSRF: Master flat (RSRF) frame - N_LSS_DIST_SOL: Distortion solution - N_LSS_WAVE_GUESS: First guess of the wavelength solution - AO_PSF_MODEL: Model of the AO PSF - ATM_LINE_CAT: Catalogue of atmospheric lines - N_ADC_SLITLOSS: Slitloss information - N_SYNTH_TRANS: Synthetic model of the Earth's atmopshere transmission - REF_STD_CAT: Catalogue of standard stars - - Matched Keywords - DET.DIT - DET.NDIT - DRS.SLIT - - Outputs - N_LSS_STD_OBJ_MAP: Pixel map of the object pixels (QC) - N_LSS_STD_SKY_MAP: Pixel map of the sky pixels (QC) - N_LSS_STD_1D: Coadded, wavelength calibrated, collapsed 1D spectrum of the standard star - N_LSS_STD_WAVE: Wavelength solution based on std star - STD_TRANSMISSION: Transmission of the Earth's atmosphere derived from the STD for telluric correction [optional] - MASTER_N_RESPONSE: Response function for flux calibration - """ - - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD***""" # ++++++++++++++++++ Define parameters ++++++++++++++++++ @@ -83,7 +52,7 @@ class MetisNLssStd(MetisRecipe): # TODO: Implement real parameters parameters = ParameterList([ ParameterEnum( - name=f"{_name}parameter1", + name=f"{_name}.parameter1", context=_name, description="Description of parameter 1", default="value1", diff --git a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_trace.py b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_trace.py index 2f9a5f00..3bc25506 100644 --- a/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_trace.py +++ b/metisp/pymetis/src/pymetis/recipes/n_lss/metis_n_lss_trace.py @@ -19,13 +19,13 @@ from pyesorex.parameter import ParameterList, ParameterEnum -from pymetis.classes.mixins import BandNMixin +from pymetis.classes.mixins import BandNMixin, DetectorGeoMixin from pymetis.classes.prefab.lss.trace import MetisLssTraceImpl from pymetis.classes.recipes import MetisRecipe -class MetisNLssTraceImpl(MetisLssTraceImpl): - class InputSet(BandNMixin, MetisLssTraceImpl.InputSet): +class MetisNLssTraceImpl(BandNMixin, DetectorGeoMixin, MetisLssTraceImpl): + class InputSet(MetisLssTraceImpl.InputSet): pass @@ -43,7 +43,7 @@ class MetisNLssTrace(MetisRecipe): _copyright: str = "GPL-3.0-or-later" _synopsis: str = "Detection of N order location on the GEO detector" - _matched_keywords: {str} = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} + _matched_keywords: set[str] = {'DET.DIT', 'DET.NDIT', 'DRS.SLIT'} _algorithm = """Fancy algorithm description follows ***TBD*** """ # ++++++++++++++++++ Define parameters ++++++++++++++++++ diff --git a/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_reduce.py b/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_reduce.py index 519dc144..24410a41 100644 --- a/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_reduce.py +++ b/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_reduce.py @@ -19,7 +19,6 @@ import pytest -from pymetis.classes.recipes import MetisRecipe, MetisRecipeImpl from pymetis.recipes.ifu.metis_ifu_reduce import (MetisIfuReduce as Recipe, MetisIfuReduceImpl as Impl, MetisIfuReduceImpl) from pymetis.tests.classes import BaseInputSetTest, TargetParamRecipeTest, BaseProductTest @@ -38,7 +37,6 @@ def sof(name: str) -> str: return f'{name}.std.sof' -@pytest.mark.xfail(reason="Current testing data are of mismatched size") class TestRecipe(TargetParamRecipeTest): Recipe = Recipe diff --git a/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_rsrf.py b/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_rsrf.py index dea4792f..4f7a1c62 100644 --- a/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_rsrf.py +++ b/metisp/pymetis/src/pymetis/tests/recipes/ifu/test_metis_ifu_rsrf.py @@ -42,7 +42,6 @@ def sof(name: str) -> str: @pytest.mark.slow -@pytest.mark.xfail(reason="Testing data mismatch") class TestRecipe(BaseRecipeTest): """A bunch of extremely simple and stupid test cases... just to see if it does something.""" Recipe = Recipe diff --git a/runner.py b/runner.py new file mode 100755 index 00000000..f26116b4 --- /dev/null +++ b/runner.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +import cpl +import argparse +import inspect + +from cpl.core import Msg + +from metisp.pyrecipes import metis_recipes +from pymetis.classes.recipes import MetisRecipe + + +def main(): + parser = argparse.ArgumentParser(description='Pyesorexless recipe runner') + parser.add_argument('recipe', metavar='recipe', type=str) + parser.add_argument('sof', type=argparse.FileType('r')) + parser.add_argument('--debug', action='store_true') + args = parser.parse_args() + + recipes = { + recipe._name: recipe + for name, recipe in inspect.getmembers(metis_recipes) + if inspect.isclass(recipe) and issubclass(recipe, MetisRecipe) + } + + if args.debug: + Msg.set_config(level=Msg.SeverityLevel.DEBUG) + + frameset = cpl.ui.FrameSet(args.sof.name) + recipe = recipes[args.recipe]() + recipe.run(frameset, {}) + + +main() \ No newline at end of file