From 7aedac148cdf99ecb69280ce2e17d310204e651a Mon Sep 17 00:00:00 2001 From: x01dc Date: Tue, 1 Sep 2026 19:16:35 +0200 Subject: [PATCH] feat(omny): seed realistic values in SimOMNYDewar and SimOMNYTemperatures - SimOMNYDewar: patched_device()'s all-zero default read as an alarm state (LN2 flow 0.0 l/s trips OMNYDewar.is_flow_low()'s 3.8 l/s threshold). Seeded to a healthy/nominal state instead. These values are illustrative -- no real dewar-controller reference was available. - SimOMNYTemperatures: seeded names/units/readings/setpoints for the 29 real "TEMP" channels, sourced from the real OMNY_tempcontroller/ tempcontrol.py channel config (name, EGU, ChanHeat, ALARMLIM) and cross-referenced against the existing _set_TEMP_default_setpoints() (already in this repo, confirmed to cover the same 29 channels). Heated channels read at their real setpoint; monitor-only channels get a plausible reading below their real alarm limit -- no channel now shows a false alarm. Channels not in use are now named "-" (matching tempcontrol.py's real default), so show_all() cleanly hides them instead of listing 19 fake all-zero rows. temperature_update_time and cryo_temperature_update_time are set to now() to avoid a false "controller communication is not running" warning. - The 4 "CRYO" channels are NOT seeded yet -- pending the cryocon controller reference (still needed from Mirko). --- csaxs_bec/devices/sim/sim_omny.py | 89 ++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/csaxs_bec/devices/sim/sim_omny.py b/csaxs_bec/devices/sim/sim_omny.py index 5aebf832..929310fc 100644 --- a/csaxs_bec/devices/sim/sim_omny.py +++ b/csaxs_bec/devices/sim/sim_omny.py @@ -21,6 +21,7 @@ uses the patched-device pattern with in-memory mock PVs. from __future__ import annotations import random +import time from bec_lib.logger import bec_logger from ophyd_devices.tests.utils import patched_device @@ -266,16 +267,100 @@ class SimOMNYSampleStorage(OMNYSampleStorage): class SimOMNYDewar(OMNYDewar): - """OMNYDewar with all EPICS PVs replaced by in-memory mock PVs.""" + """OMNYDewar with all EPICS PVs replaced by in-memory mock PVs, seeded to a + healthy/nominal state instead of the all-zero patched_device() default (which + reads as an alarm state: OMNYDewar.is_flow_low() trips below 3.8 l/s). These + values are illustrative -- no real dewar-controller reference was available + when writing this (unlike SimOMNYTemperatures below); adjust if real nominal + values are known. + """ def __new__(cls, *args, **kwargs): with patched_device(OMNYDewar, *args, **kwargs) as dewar: + dewar.dewar_press_0.put(1200) + dewar.dewar_refilling.put(0) + dewar.dewar_press_1.put(1500) + dewar.dewar_press_2.put(950) + dewar.dewar_flow_0.put(4.5) # above the 3.8 l/s is_flow_low() threshold + dewar.dewar_valvepos.put(0.35) + dewar.dewar_supply_voltage.put(24.0) + dewar.dewar_uptime_h.put(12) + dewar.dewar_uptime_m.put(30) + dewar.dewar_uptime_s.put(0) + dewar.dewar_valve_movements_h.put(0) + dewar.dewar_valve_movements_m.put(5) + dewar.dewar_valve_movements_s.put(0) return dewar +# OMNY temperature-controller channels ("TEMP" bank, channels 1-48), sourced from the +# real OMNY_tempcontroller/tempcontrol.py channel config (name, EGU, ChanHeat, ALARMLIM) +# cross-referenced against OMNYTemperatures._set_TEMP_default_setpoints()'s existing +# per-channel setpoints (already in this repo, confirmed to cover exactly the same 29 +# channels -- the setpoint value below is copied from that method, not re-derived). +# Sentinel setpoints ("no active control": -199.9 degC / 73.2 K, matching +# tempcontrol.py's configure_device()'s unused-channel convention) mark monitor-only +# channels (ChanHeat=0); those get a plausible physical reading instead of the sentinel. +# channel: (name, EGU, alarm limit, simulated current reading, real setpoint) +_TEMP_CHANNELS = { + 8: ("XEye Chamber", "degC", 50, 24.0, -199.9), + 9: ("Kuehlsystem RT ZufOSA", "degC", 50, 23.0, 23.0), + 10: ("OSA_HaltZul_517", "K", 140, 100.0, 73.2), + 16: ("XEye Air", "degC", 50, 24.0, -199.9), + 17: ("SampleShield_RT_440", "degC", 50, 23.0, 23.0), + 18: ("DeltaA_RT", "degC", 50, 26.0, 26.0), + 19: ("DeltaB_RT", "degC", 50, 26.0, 26.0), + 20: ("DeltaC_RT", "degC", 50, 26.0, 26.0), + 21: ("Haube_ST_RT", "degC", 50, 23.0, 23.0), + 22: ("Delta_Basisplatte", "degC", 50, 24.0, -199.9), + 23: ("InterfBridge", "degC", 30, 24.0, -199.9), + 24: ("XEye Cam", "degC", 50, 24.0, -199.9), + 25: ("OSA_HSupp_RT_403", "degC", 50, 25.0, 25.0), + 27: ("OSA_Supp_RT_404", "degC", 50, 25.0, 25.0), + 28: ("ST_Shield_1", "K", 140, 100.0, 73.2), + 29: ("ST_Shield_2", "K", 140, 100.0, 73.2), + 30: ("OSA_CoolConn_407", "K", 125, 95.0, 73.2), + 31: ("OSA_Holder_406", "K", 115, 90.0, 73.2), + 35: ("Gripper_Halter_460", "degC", 5, 25.0, 25.0), + 36: ("Gripper_Flex_A", "degC", 5, 25.0, 25.0), + 37: ("Gripper_Flex_B", "degC", 5, 25.0, 25.0), + 38: ("Gripper_A", "K", 140, 100.0, 73.2), + 39: ("Gripper_B", "K", 140, 100.0, 73.2), + 41: ("FZP", "degC", 1, 30.0, 30.0), + 42: ("Park_RT_A", "degC", 5, 25.0, 25.0), + 44: ("Park_RT_B", "degC", 5, 25.0, 25.0), + 45: ("BaseBlock", "degC", 50, 24.0, -199.9), + 46: ("Park_Cryo_R", "K", 140, 100.0, 73.2), + 47: ("Park_Cryo_L", "K", 140, 100.0, 73.2), +} + + class SimOMNYTemperatures(OMNYTemperatures): - """OMNYTemperatures with all EPICS PVs replaced by in-memory mock PVs.""" + """OMNYTemperatures with all EPICS PVs replaced by in-memory mock PVs, seeded + with realistic per-channel names/units/readings/setpoints for the 29 real "TEMP" + channels (see _TEMP_CHANNELS above). The 4 "CRYO" channels are not seeded yet -- + pending the cryocon controller reference. + """ def __new__(cls, *args, **kwargs): with patched_device(OMNYTemperatures, *args, **kwargs) as temperatures: + now = time.time() + for channel in range(1, 49): + if channel not in _TEMP_CHANNELS: + # matches tempcontrol.py's real ChanName default ('-') for + # channels not in use; show_all() hides these accordingly + getattr(temperatures.temperature_names, f"temperature_name{channel}").put("-") + continue + name, egu, _alarmlim, reading, setpoint = _TEMP_CHANNELS[channel] + getattr(temperatures.temperature_names, f"temperature_name{channel}").put(name) + getattr(temperatures.temperature_unit, f"temperature_unit{channel}").put(egu) + getattr(temperatures.temperature, f"temperature{channel}").put(reading) + getattr(temperatures.temperature_setpoint, f"temperature_setpoint{channel}").put( + setpoint + ) + getattr( + temperatures.temperature_alarmstate, f"temperature_alarmstate{channel}" + ).put(0) + temperatures.temperature_update_time.put(now) + temperatures.cryo_temperature_update_time.put(now) return temperatures