From 4a9d49dba912803593cb56d2209015b0b4bc2f34 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Date: Wed, 22 Sep 2021 10:55:48 -0400 Subject: [PATCH] Make changes for grating move duration (again) This reverts commit c2cc9f60e687aba0ff061c49660c9c995166fa3d. --- kadi/commands/states.py | 87 +++++++++++++++++++++++++++--- kadi/commands/tests/test_states.py | 34 ++++++++++-- 2 files changed, 110 insertions(+), 11 deletions(-) diff --git a/kadi/commands/states.py b/kadi/commands/states.py index a75a549a..a9ff0791 100644 --- a/kadi/commands/states.py +++ b/kadi/commands/states.py @@ -2,8 +2,7 @@ This module provides the functions for dynamically determining Chandra commanded states based entirely on known history of commands. """ -from __future__ import division, print_function, absolute_import - +import contextlib import re import collections import itertools @@ -12,8 +11,10 @@ import numpy as np from astropy.table import Table, Column +import astropy.units as u from Chandra.Time import DateTime, date2secs, secs2date +from cxotime import CxoTime import Chandra.Maneuver from Quaternion import Quat import Ska.Sun @@ -51,6 +52,17 @@ 'vid_board') +@contextlib.contextmanager +def disable_grating_move_duration(): + """ + Temporarily disable the grating move duration + """ + apply_move_duration = MechMove.apply_move_duration + MechMove.apply_move_duration = False + yield + MechMove.apply_move_duration = apply_move_duration + + class NoTransitionsError(ValueError): """No transitions found within commands""" pass @@ -378,36 +390,99 @@ class SubFormatSSR_Transition(FixedTransition): # Mech transitions ################################################################### -class HETG_INSR_Transition(FixedTransition): +class MechMove(FixedTransition): + """ + Transitions for mech moves that have non-zero duration. + + This adds two transitions per matched command: + - First one at cmd time with the transition value with ``_MOVE`` appended + - Second one at cmd time + move_duration with the straight transition value + + This inherits from FixedTransition for the case of an attribute that gets + set to a fixed value when the command occurs, e.g. pcad_mode='NMAN' for + AONMMODE. + + Class attributes: + + :param transition_key: single transition key or list of transition keys + :param transition_val: single transition value or list of values + :param move_duration: duration of the move (astropy time Quantity) + :param apply_move_duration: if True, apply the move duration to states + """ + apply_move_duration = True + + @classmethod + def set_transitions(cls, transitions_dict, cmds, start, stop): + """ + Set transitions for a Table of commands ``cmds``. + + :param transitions_dict: global dict of transitions (updated in-place) + :param cmds: commands (CmdList) + :param start: start time for states + :param stop: stop time for states + + :returns: None + """ + state_cmds = cls.get_state_changing_commands(cmds) + vals = cls.transition_val + attrs = cls.transition_key + move_duration = cls.move_duration + + if not isinstance(vals, list): + vals = [vals] + if not isinstance(attrs, list): + attrs = [attrs] + + for cmd in state_cmds: + date_start = CxoTime(cmd['date']) + date_stop = date_start + move_duration + for val, attr in zip(vals, attrs): + if attr == 'grating': + transitions_dict[date_start.date][attr] = val + else: + # 'letg' or 'hetg' insert/retract status, include the move + # interval here + if cls.apply_move_duration: + transitions_dict[date_start.date][attr] = val + '_MOVE' + transitions_dict[date_stop.date][attr] = val + else: + transitions_dict[date_start.date][attr] = val + + +class HETG_INSR_Transition(MechMove): """HETG insertion""" command_attributes = {'tlmsid': '4OHETGIN'} state_keys = ['letg', 'hetg', 'grating'] transition_key = ['hetg', 'grating'] transition_val = ['INSR', 'HETG'] + move_duration = 157 * u.s -class HETG_RETR_Transition(FixedTransition): +class HETG_RETR_Transition(MechMove): """HETG retraction""" command_attributes = {'tlmsid': '4OHETGRE'} state_keys = ['letg', 'hetg', 'grating'] transition_key = ['hetg', 'grating'] transition_val = ['RETR', 'NONE'] + move_duration = 153 * u.s -class LETG_INSR_Transition(FixedTransition): +class LETG_INSR_Transition(MechMove): """LETG insertion""" command_attributes = {'tlmsid': '4OLETGIN'} state_keys = ['letg', 'hetg', 'grating'] transition_key = ['letg', 'grating'] transition_val = ['INSR', 'LETG'] + move_duration = 203 * u.s -class LETG_RETR_Transition(FixedTransition): +class LETG_RETR_Transition(MechMove): """LETG retraction""" command_attributes = {'tlmsid': '4OLETGRE'} state_keys = ['letg', 'hetg', 'grating'] transition_key = ['letg', 'grating'] transition_val = ['RETR', 'NONE'] + move_duration = 203 * u.s class SimTscTransition(ParamTransition): diff --git a/kadi/commands/tests/test_states.py b/kadi/commands/tests/test_states.py index 5b29f05a..b886837e 100644 --- a/kadi/commands/tests/test_states.py +++ b/kadi/commands/tests/test_states.py @@ -78,8 +78,9 @@ def get_states_test(start, stop, state_keys, continuity=None): lenr = len(rcstates) cmds = commands.get_cmds(start - 7, stop) - kstates = states.get_states(state_keys=state_keys, cmds=cmds, - continuity=continuity, reduce=False) + with states.disable_grating_move_duration(): + kstates = states.get_states(state_keys=state_keys, cmds=cmds, + continuity=continuity, reduce=False) rkstates = states.reduce_states(kstates, state_keys, merge_identical=True)[-lenr:] return rcstates, rkstates @@ -155,7 +156,9 @@ def test_quick(): # Now test using start/stop pair with start/stop and no supplied cmds or continuity. # This also tests the API kwarg order: datestart, datestop, state_keys, ..) - sts = states.get_states('2018:235:12:00:00', '2018:245:12:00:00', state_keys, reduce=False) + with states.disable_grating_move_duration(): + sts = states.get_states('2018:235:12:00:00', '2018:245:12:00:00', + state_keys, reduce=False) assert np.all(DateTime(sts['tstart']).date == sts['datestart']) assert np.all(DateTime(sts['tstop']).date == sts['datestop']) @@ -383,7 +386,8 @@ def test_get_continuity_regress(): 'targ_q4': '2018:001:11:52:10.175', 'vid_board': '2018:001:11:58:21.735'} - continuity = states.get_continuity('2018:001:12:00:00') + with states.disable_grating_move_duration(): + continuity = states.get_continuity('2018:001:12:00:00') for key, val in expected.items(): if isinstance(val, (int, str)): @@ -552,7 +556,8 @@ def test_reduce_states_cmd_states(): # Default setting is reduce states with merge_identical=False, which is the same # as cmd_states. - ksr = states.get_states('2018:235:12:00:00', '2018:245:12:00:00', state_keys) + with states.disable_grating_move_duration(): + ksr = states.get_states('2018:235:12:00:00', '2018:245:12:00:00', state_keys) assert len(ksr) == len(cs) @@ -1453,3 +1458,22 @@ def test_acisfp_setpoint_state(): '2018:294:22:29:00.000 2020:048:20:59:22.304 -121.0 acisfp_setpoint', '2020:048:20:59:22.304 2020:049:13:05:52.537 -126.0 acisfp_setpoint', '2020:049:13:05:52.537 2020:061:12:00:00.000 -121.0 acisfp_setpoint'] + + +def test_grating_motion_states(): + sts = states.get_states('2021:227:12:00:00', '2021:230:12:00:00', + state_keys=['letg', 'hetg', 'grating']) + del sts['tstart'] + del sts['tstop'] + exp = [' datestart datestop letg hetg grating trans_keys ', + '--------------------- --------------------- --------- --------- ------- ------------', + '2021:227:12:00:00.000 2021:227:23:06:03.276 RETR RETR NONE ', + '2021:227:23:06:03.276 2021:227:23:08:40.276 RETR INSR_MOVE HETG grating,hetg', + '2021:227:23:08:40.276 2021:228:08:15:00.722 RETR INSR HETG hetg', + '2021:228:08:15:00.722 2021:228:08:17:33.722 RETR RETR_MOVE NONE grating,hetg', + '2021:228:08:17:33.722 2021:229:17:41:45.525 RETR RETR NONE hetg', + '2021:229:17:41:45.525 2021:229:17:45:08.525 INSR_MOVE RETR LETG grating,letg', + '2021:229:17:45:08.525 2021:230:00:37:56.002 INSR RETR LETG letg', + '2021:230:00:37:56.002 2021:230:00:41:19.002 RETR_MOVE RETR NONE grating,letg', + '2021:230:00:41:19.002 2021:230:12:00:00.000 RETR RETR NONE letg'] + assert sts.pformat_all() == exp