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

DM-45401: Write SAL Script to test ComCam guider mode. #135

Merged
merged 2 commits into from
Jul 25, 2024
Merged
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
1 change: 1 addition & 0 deletions doc/news/DM-45401.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add new TakeComCamGuiderImage script, designed to test ComCam guider mode.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python
# This file is part of ts_externalscripts
#
# Developed for the LSST Telescope and Site Systems.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# 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 3 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

import asyncio

from lsst.ts.externalscripts.maintel import TakeComCamGuiderImage

asyncio.run(TakeComCamGuiderImage.amain())
1 change: 1 addition & 0 deletions python/lsst/ts/externalscripts/maintel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from .make_comcam_calibrations import *
from .take_comcam_guider_image import *
from .track_target_sched import *
from .warmup_hexapod import *
170 changes: 170 additions & 0 deletions python/lsst/ts/externalscripts/maintel/take_comcam_guider_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# This file is part of ts_externalscripts
#
# Developed for the LSST Telescope and Site Systems.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# 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 3 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, see <https://www.gnu.org/licenses/>.

__all__ = ["TakeComCamGuiderImage"]

import yaml
from lsst.ts.observatory.control.maintel.comcam import ComCam
from lsst.ts.observatory.control.utils.roi_spec import ROISpec
from lsst.ts.standardscripts.base_block_script import BaseBlockScript


class TakeComCamGuiderImage(BaseBlockScript):
"""Script to test taking data with ComCam with guider mode on.

Parameters
----------
index : `int`
Index od Script SAL component.
"""

def __init__(self, index):
super().__init__(
index=index, descr="Take data with comcam and handle guider mode."
)

self.comcam = None
self.roi_spec = None
self.exposure_time = 0.0
self.note = None

def set_metadata(self, metadata):
metadata.duration = self.exposure_time

async def configure(self, config):
if self.comcam is None:
self.comcam = ComCam(self.domain, log=self.log)
await self.comcam.start_task

self.roi_spec = ROISpec.parse_obj(config.roi_spec)
self.exposure_time = config.exposure_time
self.note = getattr(config, "note", None)

await super().configure(config=config)

@classmethod
def get_schema(cls):
schema_yaml = """
$schema: http://json-schema.org/draft-07/schema#
$id: https://github.com/lsst-ts/ts_externalscripts/maintel/take_comcam_guider_image.py
title: TakeComCamGuiderImage v1
description: Configuration for TakeComCamGuiderImage.
type: object
properties:
filter:
description: Filter name or ID; if omitted the filter is not changed.
anyOf:
- type: string
- type: integer
minimum: 1
- type: "null"
default: null
exposure_time:
type: number
minimum: 1
description: Exposure time in seconds.
note:
description: A descriptive note about the image being taken.
type: string
roi_spec:
description: Definition of the ROI Specification.
type: object
additionalProperties: false
required:
- common
- roi
properties:
common:
description: Common properties to all ROIs.
type: object
additionalProperties: false
required:
- rows
- cols
- integration_time_millis
properties:
rows:
description: Number of rows for each ROI.
type: number
minimum: 10
maximum: 400
cols:
description: Number of columns for each ROI.
type: number
minimum: 10
maximum: 400
integration_time_millis:
description: Guider exposure integration time in milliseconds.
type: number
minimum: 5
maximum: 200
roi:
description: Definition of the ROIs regions.
minProperties: 1
additionalProperties: false
patternProperties:
"^[a-zA-Z0-9]+$":
type: object
additionalProperties: false
required:
- segment
- start_row
- start_col
properties:
segment:
type: number
description: Segment of the CCD where the center of the ROI is located.
start_row:
type: number
description: The bottom-left row origin of the ROI.
start_col:
type: number
description: The bottom-left column origin of the ROI.
additionalProperties: false
required:
- roi_spec
- exposure_time
"""
schema_dict = yaml.safe_load(schema_yaml)

base_schema_dict = super(TakeComCamGuiderImage, cls).get_schema()

for prop in base_schema_dict["properties"]:
schema_dict["properties"][prop] = base_schema_dict["properties"][prop]

return schema_dict

async def run_block(self):

note = self.note
reason = self.reason
program = self.program

await self.comcam.init_guider(roi_spec=self.roi_spec)

await self.comcam.take_engtest(
n=1,
exptime=self.exposure_time,
reason=reason,
program=program,
group_id=self.group_id,
note=note,
)
164 changes: 164 additions & 0 deletions tests/maintel/test_take_comcam_guider_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# This file is part of ts_externalscripts
#
# Developed for the LSST Telescope and Site Systems.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# 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 3 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, see <https://www.gnu.org/licenses/>.

import unittest
import unittest.mock as mock

import pytest
from lsst.ts import salobj
from lsst.ts.externalscripts import get_scripts_dir
from lsst.ts.externalscripts.maintel.take_comcam_guider_image import (
TakeComCamGuiderImage,
)
from lsst.ts.standardscripts import BaseScriptTestCase


class TestTakeComCamGuiderImage(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase):
async def basic_make_script(self, index):
self.script = TakeComCamGuiderImage(index=index)

self.script.comcam = mock.AsyncMock()

return [
self.script,
]

async def test_configure(self):
config = dict(
exposure_time=30,
roi_spec=dict(
common=dict(
rows=50,
cols=50,
integration_time_millis=100,
),
roi=dict(
R00SG0=dict(
segment=3,
start_row=100,
start_col=200,
),
),
),
)
async with self.make_script():
await self.configure_script(**config)

assert self.script.exposure_time == 30
assert self.script.roi_spec is not None
assert self.script.roi_spec.common.rows == 50
assert self.script.roi_spec.common.cols == 50
assert self.script.roi_spec.common.integrationTimeMillis == 100
assert self.script.roi_spec.roi["R00SG0"].segment == 3
assert self.script.roi_spec.roi["R00SG0"].startRow == 100
assert self.script.roi_spec.roi["R00SG0"].startCol == 200

async def test_configure_fail_if_empty(self):

async with self.make_script():
with pytest.raises(
salobj.ExpectedError, match="'roi_spec' is a required property"
):
await self.configure_script()

async def test_configure_fail_empty_roi_spec(self):

config = dict(roi_spec=dict())
async with self.make_script():
with pytest.raises(salobj.ExpectedError):
await self.configure_script(**config)

async def test_configure_fail_no_common(self):

config = dict(
roi_spec=dict(
roi=dict(
R00SG0=dict(
segment=3,
start_row=100,
start_col=200,
),
),
),
)
async with self.make_script():
with pytest.raises(salobj.ExpectedError):
await self.configure_script(**config)

async def test_configure_fail_no_roi(self):
config = dict(
roi_spec=dict(
common=dict(
rows=50,
cols=50,
integration_time_millis=100,
),
),
)
async with self.make_script():
with pytest.raises(salobj.ExpectedError):
await self.configure_script(**config)

async def test_run(self):
reason = "test guider"
program = "BLOCK-T123"
note = "this is a test"
config = dict(
exposure_time=30,
reason=reason,
program=program,
note=note,
roi_spec=dict(
common=dict(
rows=50,
cols=50,
integration_time_millis=100,
),
roi=dict(
R00SG0=dict(
segment=3,
start_row=100,
start_col=200,
),
),
),
)
async with self.make_script():
await self.configure_script(**config)

await self.run_script()

self.script.comcam.init_guider.assert_awaited_with(
roi_spec=self.script.roi_spec
)
self.script.comcam.take_engtest.assert_awaited_with(
n=1,
exptime=self.script.exposure_time,
reason=reason,
program=program,
group_id=self.script.group_id,
note=note,
)

async def test_executable(self):
scripts_dir = get_scripts_dir()
script_path = scripts_dir / "maintel" / "take_comcam_guider_image.py"
await self.check_executable(script_path)
Loading