diff --git a/kadi/commands/states.py b/kadi/commands/states.py index c9ae9a09..816b7bdc 100644 --- a/kadi/commands/states.py +++ b/kadi/commands/states.py @@ -5,6 +5,7 @@ """ import collections import contextlib +import functools import inspect import itertools import re @@ -1580,6 +1581,108 @@ def set_transitions(cls, transitions, cmds, start, stop): transitions[date].update(acisfp_setpoint=-float(match.group(1))) +class FidsTransition(BaseTransition): + """ + Fid light transitions. + + This sets the "fids" to a Python set of FID IDs that are currently on. + + The relevant fid light commands are shown below. Basically it comes down to AFLCxxDy + (fid id xx and driver y) commands, AFLCRSET and AFLCAAOF/AFLCAAON/AFLCABOF/AFLCABON + commands. The latter four are never used (we don't turn the fid light controllers on + or off in loads). This table is from the CDB in + ``$SKA/data/Ska.tdb/cdb/p010/cdb_command.csv``. + :: + + cmd_mnemonic technical_name + ------------ --------------------------------------------- + AFLC01D1 drive flca fid light 1 (acis-1) on driver 1 + AFLC01D2 drive flca fid light 1 (acis-1) on driver 2 + AFLC01D3 drive flca fid light 1 (acis-1) on driver 3 + AFLC01D4 drive flca fid light 1 (acis-1) on driver 4 + AFLC02D1 drive flca fid light 2 (acis-2) on driver 1 + AFLC02D2 drive flca fid light 2 (acis-2) on driver 2 + AFLC02D3 drive flca fid light 2 (acis-2) on driver 3 + AFLC02D4 drive flca fid light 2 (acis-2) on driver 4 + AFLC03D1 drive flca fid light 3 (acis-3) on driver 1 + AFLC03D2 drive flca fid light 3 (acis-3) on driver 2 + AFLC03D3 drive flca fid light 3 (acis-3) on driver 3 + AFLC03D4 drive flca fid light 3 (acis-3) on driver 4 + AFLC04D1 drive flca fid light 4 (acis-4) on driver 1 + AFLC04D2 drive flca fid light 4 (acis-4) on driver 2 + AFLC04D3 drive flca fid light 4 (acis-4) on driver 3 + AFLC04D4 drive flca fid light 4 (acis-4) on driver 4 + AFLC05D1 drive flca fid light 5 (acis-5) on driver 1 + AFLC05D2 drive flca fid light 5 (acis-5) on driver 2 + AFLC05D3 drive flca fid light 5 (acis-5) on driver 3 + AFLC05D4 drive flca fid light 5 (acis-5) on driver 4 + AFLC06D1 drive flca fid light 6 (acis-6) on driver 1 + AFLC06D2 drive flca fid light 6 (acis-6) on driver 2 + AFLC06D3 drive flca fid light 6 (acis-6) on driver 3 + AFLC06D4 drive flca fid light 6 (acis-6) on driver 4 + AFLC07D1 drive flca fid light 7 (hrc-i-1) on driver 1 + AFLC08D2 drive flca fid light 8 (hrc-i-2) on driver 2 + AFLC09D3 drive flca fid light 9 (hrc-i-3) on driver 3 + AFLC10D4 drive flca fid light 10 (hrc-i-4) on driver 4 + AFLC11D1 drive flca fid light 11 (hrc-s-1) on driver 1 + AFLC12D2 drive flca fid light 12 (hrc-s-3) on driver 2 + AFLC13D3 drive flca fid light 13 (hrc-s-2) on driver 3 + AFLC14D4 drive flca fid light 14 (hrc-s-4) on driver 4 + AFLCAAOF flca - a off + AFLCAAON flca - a on + AFLCABOF flca - b off + AFLCABON flca - b on + AFLCRSET flca configuration reset + """ + + command_attributes = {"tlmsid": "AFIDP"} + state_keys = ["fids"] + + @classmethod + def set_transitions(cls, transitions_dict, cmds, start, stop): + """ + Set transitions for a Table of commands ``cmds``. + + Parameters + ---------- + transitions_dict + global dict of transitions (updated in-place) + cmds + commands (CmdList) + start + start time for states + stop + stop time for states + + Returns + ------- + None + """ + state_cmds = cls.get_state_changing_commands(cmds) + + for cmd in state_cmds: + msid = cmd["msid"] + if msid == "AFLCRSET" or re.match(r"AFLC \d\d D \d $", msid, re.VERBOSE): + transitions_dict[cmd["date"]]["fids"] = functools.partial( + FidsTransition.fids_callback, msid + ) + + @staticmethod + def fids_callback(msid, date, transitions, state, idx): + """Update ``state`` for the given fid light command ``msid``.""" + if msid == "AFLCRSET": + state["fids"] = set() + else: + # Only AFLCxxDy commands can make it here from set_transitions filtering + fid_id = int(msid[4:6]) + # state["fids"] could be None at the beginning + fids = state["fids"] + if fids is None: + fids = set() + # Add the fid light to the ON set + state["fids"] = fids | {fid_id} + + ################################################################### # State transitions processing code ################################################################### diff --git a/kadi/commands/tests/test_states.py b/kadi/commands/tests/test_states.py index c8104aa0..1eaf8b14 100644 --- a/kadi/commands/tests/test_states.py +++ b/kadi/commands/tests/test_states.py @@ -417,6 +417,30 @@ def test_dither(): ) +def test_fids_state(): + kstates = states.get_states("2023:001", "2023:002", state_keys=["fids"]) + exp = [ + " datestart datestop fids trans_keys", + "--------------------- --------------------- --------- ----------", + "2023:001:00:00:00.000 2023:001:03:23:59.954 {3, 4, 5} ", + "2023:001:03:23:59.954 2023:001:13:47:14.830 set() fids", + "2023:001:13:47:14.830 2023:001:13:47:15.830 set() fids", + "2023:001:13:47:15.830 2023:001:13:47:16.086 {2} fids", + "2023:001:13:47:16.086 2023:001:13:47:16.342 {2, 4} fids", + "2023:001:13:47:16.342 2023:001:18:09:53.020 {2, 4, 5} fids", + "2023:001:18:09:53.020 2023:001:18:09:54.020 set() fids", + "2023:001:18:09:54.020 2023:001:18:09:54.276 {1} fids", + "2023:001:18:09:54.276 2023:001:18:09:54.532 {1, 2} fids", + "2023:001:18:09:54.532 2023:001:23:10:51.222 {1, 2, 5} fids", + "2023:001:23:10:51.222 2023:001:23:10:52.222 set() fids", + "2023:001:23:10:52.222 2023:001:23:10:52.478 {2} fids", + "2023:001:23:10:52.478 2023:001:23:10:52.734 {2, 4} fids", + "2023:001:23:10:52.734 2023:002:00:00:00.000 {2, 4, 5} fids", + ] + out = kstates["datestart", "datestop", "fids", "trans_keys"].pformat_all() + assert out == exp + + def test_get_continuity_regress(fast_sun_position_method): """Regression test against values produced by get_continuity during development. Correctness not validated for all values.