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

Tickets/DM-47601: Add sync dof script #251

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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-47601.perf.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
In set_dof.py script add ability to synchronize dof with state of a specific dayobs and sequence number.
125 changes: 125 additions & 0 deletions python/lsst/ts/standardscripts/maintel/set_dof.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

__all__ = ["SetDOF"]

import numpy as np
import yaml
from astropy.time import Time, TimeDelta
from lsst_efd_client import EfdClient

from .apply_dof import ApplyDOF

STD_TIMEOUT = 30
Expand All @@ -42,11 +47,131 @@ class SetDOF(ApplyDOF):

"""

@classmethod
def get_schema(cls):
schema_yaml = """
$schema: http://json-schema.org/draft-07/schema#
$id: https://github.com/lsst-ts/ts_standardscripts/maintel/SetDOF.yaml
title: SetDOF v1
description: Configuration for SetDOF.
type: object
properties:
day:
description: Day obs to be used for synchronizing the state.
type: number
default: null
seq:
description: Sequence number to be used for synchronizing the state.
type: number
default: null
anyOf:
- required:
- day
- seq
- required:
- dofs
additionalProperties: false
"""
schema_dict = yaml.safe_load(schema_yaml)

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

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

return schema_dict

async def configure(self, config) -> None:
"""Configure script.

Parameters
----------
config : `types.SimpleNamespace`
Script configuration, as defined by `schema`.
"""
super(ApplyDOF, self).configure(config)

if hasattr(config, "day") and hasattr(config, "seq"):
self.day = config.day
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, self.day and self.seq are only created here and later you try to access them. consider doing:

self.day = getattr(config, "day", None)
self.seq = getattr(config, "seq", None)

self.seq = config.seq

async def get_image_time(self, day, seq):
"""Get the image time from the given day and sequence number.

Parameters
----------
day : `int`
Day obs to be used for synchronizing the state.
seq : `int`
Sequence number to be used for synchronizing the state.

Returns
-------
image_time : `datetime.datetime`
Image time.
"""

query = f"""
SELECT "imageDate", "imageNumber"
FROM "efd"."autogen"."lsst.sal.CCCamera.logevent_endReadout"
WHERE imageDate =~ /{day}/ AND imageNumber = {seq}
"""

time = await self.client.influx_client.query(query)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to make some validation here that it returns something... what if the users passed a bad image number?

return Time(time.iloc[0].name)

async def get_last_issued_state(self, time):
"""Get the state from the given day and sequence number.

Parameters
----------
time : `datetime.datetime`
Initial time to query.

Returns
-------
state : `dict`
State of the system.
"""

topics = [f"aggregatedDoF{i}" for i in range(50)]

current_end = time
lookback_interval = TimeDelta(1, format="jd")
max_lookback_days = 7

while True:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is a good idea. I would actually be a bit more aggressive here in limiting the look back and search only between the image the user asked and the previous image (something like seq and seq-1), and if there are no event in that time frame you fail the script.

current_start = current_end - lookback_interval

state = await self.client.select_time_series(
"lsst.sal.MTAOS.logevent_degreeOfFreedom",
topics,
current_start,
current_end,
)

if not state.empty:
state = state.iloc[[-1]]
return state.values.squeeze()

current_end = current_start
if (time - current_end).jd > max_lookback_days:
self.log.info(
"No data found within the specified range and maximum lookback period."
)
return np.zeros(50)
return state.values.squeeze()

async def run(self) -> None:
"""Run script."""
# Assert feasibility
await self.assert_feasibility()

if self.day is not None and self.seq is not None:
self.client = EfdClient("summit_efd")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that you are hard-coding which EFD to use here, which means we won't be able to test this script at BTS or TTS.

Consider doing something like the BaseBlockScript script does. See here and here.

image_end_time = self.get_image_time(self.day, self.seq)
self.dofs = self.get_last_issued_state(image_end_time)

await self.checkpoint("Setting DOF...")
current_dof = await self.mtcs.rem.mtaos.evt_degreeOfFreedom.aget(
timeout=STD_TIMEOUT
Expand Down
Loading