Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add persistence recipe #96

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/run_edps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ jobs:
- name: Fetch test data
run: |
git clone https://github.com/AstarVienna/METIS_Pipeline_Test_Data.git
# Try to checkout a branch in METIS_Pipeline_Test_Data that has
# the same name as the branch in METIS_Pipeline that we are testing.
git -C METIS_Pipeline_Test_Data checkout "${GITHUB_HEAD_REF}" || true
- name: Run pytest tests
run: |
set +x
Expand Down
145 changes: 145 additions & 0 deletions metisp/pymetis/src/pymetis/recipes/metis_det_persistence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""
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
"""

import re
from typing import Dict

from astropy.io import fits
import cpl
from cpl.core import Msg

from pymetis.base import MetisRecipeImpl
from pymetis.base.recipe import MetisRecipe
from pymetis.base.product import PipelineProduct
from pymetis.inputs import SinglePipelineInput, PipelineInputSet, RawInput


class PersistenceMainInput(SinglePipelineInput):
_title: str = "primary raw input"
_tags: re.Pattern = re.compile(r"RAW")
_group: cpl.ui.Frame.FrameGroup = cpl.ui.Frame.FrameGroup.RAW


class MetisDetPersistenceImpl(MetisRecipeImpl):

class InputSet(PipelineInputSet):
"""Input to metis_det_persistence

For now just a single raw image.
"""

def __init__(self, frameset: cpl.ui.FrameSet):
super().__init__(frameset)
self.raw = PersistenceMainInput(frameset)
self.others = PersistenceOtherInput(frameset)
self.inputs |= {self.raw, self.others}

class Product(PipelineProduct):
"""A Persistence Map."""
group = cpl.ui.Frame.FrameGroup.PRODUCT
level = cpl.ui.Frame.FrameLevel.FINAL
frame_type = cpl.ui.Frame.FrameType.IMAGE

@property
def category(self) -> str:
return r"PERSISTENCE_MAP"

@property
def output_file_name(self) -> str:
return fr"{self.category}.fits"

@property
def tag(self) -> str:
return self.category

inputset: InputSet = None

def process_images(self) -> Dict[str, PipelineProduct]:
"""
This is where the magic happens: all business logic of the recipe should be contained within this function.
You can define extra private functions, or use functions from the parent classes:
for instance combine_images is a helper function that takes a frameset and a method and returns
a single combined frame that is used throughout the pipeline.
"""

Msg.info(self.__class__.__qualname__, f"Starting processing image attribute.")

hdus_raw = fits.open(self.inputset.raw.frame.file)
hduss_others = [
fits.open(frame.file)
for frame in self.inputset.others.frameset
]
assert set(len(hdus) for hdus in hduss_others) == {len(hdus_raw)}
header_primary_raw = hdus_raw[0].header
headers_primary_others = [
hdus[0].header for hdus in hduss_others
]
assert header_primary_raw["INSTRUME"] == "METIS"
assert all(
header["INSTRUME"] == "METIS"
for header in headers_primary_others
)
# TODO: Assert all input is from the same subinstrument.
# There currently does not seem to be an easy way to determine the
# subinstrument from the headers.

raw = cpl.core.Image.load(self.inputset.raw.frame.file, extension=1)

persistence = cpl.core.Image.zeros_like(raw)
header_primary = cpl.core.PropertyList.load(self.inputset.raw.frame.file, 0)

self.products = {
"PERSISTENCE_MAP": self.Product(self, header_primary, persistence),
}

return self.products


class MetisDetPersistence(MetisRecipe):
"""metis_det_persistence

metis_det_persistence is usually run by ESO, since it needs all previous
observations of the preceding X hours. However, it can also be run by
individuals.
"""
# Fill in recipe information
_name = "metis_det_persistence"
_version = "0.1"
_author = "A*"
_email = "[email protected]"
_copyright = "GPL-3.0-or-later"
_synopsis = "Calculates persistence for a single frame"
_description = """Calculate persistence."""

parameters = cpl.ui.ParameterList([
cpl.ui.ParameterEnum(
name="metis_det_persistence.dummy",
context="metis_det_persistence",
description="dummy parameter to prevent pyesorex problems",
default="1",
alternatives=("0", "1"),
)
])
implementation_class = MetisDetPersistenceImpl


class PersistenceOtherInput(RawInput):
_title: str = "other raw input"
_tags: re.Pattern = re.compile(r"OTHER")
_group: cpl.ui.Frame.FrameGroup = cpl.ui.Frame.FrameGroup.CALIB
45 changes: 45 additions & 0 deletions metisp/pymetis/src/pymetis/tests/test_metis_det_persistence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
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
"""

import pytest

import cpl

from pymetis.recipes.metis_det_persistence import MetisDetPersistence as Recipe, MetisDetPersistenceImpl as Impl

from generic import BaseRecipeTest, BaseProductTest, RawInputSetTest


@pytest.fixture
def name():
return 'metis_det_persistence'


@pytest.fixture
def sof():
return f"metis_det_persistence.sof"


class TestRecipe(BaseRecipeTest):
""" A bunch of simple and stupid test cases... just to see if it does something """
_recipe = Recipe


class TestProduct(BaseProductTest):
product = Impl.Product
2 changes: 2 additions & 0 deletions metisp/pyrecipes/metis_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from pymetis.recipes.metis_det_lingain import MetisDetLinGain
from pymetis.recipes.metis_det_dark import MetisDetDark
from pymetis.recipes.metis_det_persistence import MetisDetPersistence
from pymetis.recipes.img.metis_lm_img_basic_reduce import MetisLmImgBasicReduce
from pymetis.recipes.img.metis_lm_img_flat import MetisLmImgFlat
from pymetis.recipes.img.metis_lm_img_background import MetisLmImgBackground
Expand All @@ -41,6 +42,7 @@
__all__ = [
MetisDetLinGain,
MetisDetDark,
MetisDetPersistence,
MetisLmImgBasicReduce,
MetisLmImgBackground,
MetisLmImgStdProcess,
Expand Down