From 425a6c8775ed511d3c98ba6bca008543c87f09a6 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 11 Feb 2025 22:42:07 +0000 Subject: [PATCH 1/6] #480 added auxiliary coolant redstone output --- scada-common/rsio.lua | 5 +++-- scada-common/util.lua | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scada-common/rsio.lua b/scada-common/rsio.lua index b88180a..850706b 100644 --- a/scada-common/rsio.lua +++ b/scada-common/rsio.lua @@ -78,6 +78,7 @@ local IO_PORT = { -- unit outputs U_ALARM = 25, -- active high, unit alarm U_EMER_COOL = 26, -- active low, emergency coolant control + U_AUX_COOL = 30, -- active low, auxiliary coolant control -- analog outputs -- @@ -90,8 +91,8 @@ rsio.IO_DIR = IO_DIR rsio.IO_MODE = IO_MODE rsio.IO = IO_PORT -rsio.NUM_PORTS = 29 -rsio.NUM_DIG_PORTS = 28 +rsio.NUM_PORTS = 30 +rsio.NUM_DIG_PORTS = 29 rsio.NUM_ANA_PORTS = 1 -- self checks diff --git a/scada-common/util.lua b/scada-common/util.lua index 40a9fe3..56e659c 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.4.10" +util.version = "1.4.11" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 From 7b297020007925ee99b3d02449ea93b9acd5b221 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 11 Feb 2025 22:42:52 +0000 Subject: [PATCH 2/6] #480 auxiliary coolant control logic --- supervisor/startup.lua | 2 +- supervisor/unit.lua | 13 ++++++++----- supervisor/unitlogic.lua | 33 +++++++++++++++++++++++++-------- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/supervisor/startup.lua b/supervisor/startup.lua index f54144b..61a6c78 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.6.3" +local SUPERVISOR_VERSION = "v1.6.4" local println = util.println local println_ts = util.println_ts diff --git a/supervisor/unit.lua b/supervisor/unit.lua index 01d0d3e..3a02204 100644 --- a/supervisor/unit.lua +++ b/supervisor/unit.lua @@ -92,7 +92,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) io_ctl = nil, ---@type rs_controller ---@diagnostic disable-next-line: missing-fields valves = {}, ---@type unit_valves - emcool_opened = false, + em_cool_opened = false, + aux_cool_opened = false, -- auto control auto_engaged = false, auto_idle = false, @@ -373,6 +374,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) local waste_po = _make_valve_iface(IO.WASTE_POPL) local waste_sps = _make_valve_iface(IO.WASTE_AM) local emer_cool = _make_valve_iface(IO.U_EMER_COOL) + local aux_cool = _make_valve_iface(IO.U_AUX_COOL) ---@class unit_valves self.valves = { @@ -380,7 +382,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) waste_sna = waste_sna, waste_po = waste_po, waste_sps = waste_sps, - emer_cool = emer_cool + emer_cool = emer_cool, + aux_cool = aux_cool } -- route reactor waste for a given waste product @@ -606,7 +609,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) if #self.redstone > 0 then logic.handle_redstone(self) elseif not self.plc_cache.rps_trip then - self.emcool_opened = false + self.em_cool_opened = false end end @@ -724,7 +727,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- queue a command to clear timeout/auto-scram if set function public.auto_cond_rps_reset() - if self.plc_s ~= nil and self.plc_i ~= nil and (not self.auto_was_alarmed) and (not self.emcool_opened) then + if self.plc_s ~= nil and self.plc_i ~= nil and (not self.auto_was_alarmed) and (not self.em_cool_opened) then local rps = self.plc_i.get_rps() if rps.timeout or rps.automatic then self.plc_i.auto_lock(true) -- if it timed out/restarted, auto lock was lost, so re-lock it @@ -865,7 +868,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- check if emergency coolant activation has been tripped ---@nodiscard - function public.is_emer_cool_tripped() return self.emcool_opened end + function public.is_emer_cool_tripped() return self.em_cool_opened end -- get build properties of machines -- diff --git a/supervisor/unitlogic.lua b/supervisor/unitlogic.lua index 8364d20..b5c8b8c 100644 --- a/supervisor/unitlogic.lua +++ b/supervisor/unitlogic.lua @@ -728,7 +728,7 @@ function logic.update_status_text(self) self.status_text = { "RCS TRANSIENT", "check coolant system" } -- elseif is_active(self.alarms.RPSTransient) then -- RPS status handled when checking reactor status - elseif self.emcool_opened then + elseif self.em_cool_opened then self.status_text = { "EMERGENCY COOLANT OPENED", "reset RPS to close valve" } -- connection dependent states elseif self.plc_i ~= nil then @@ -886,7 +886,7 @@ function logic.handle_redstone(self) (annunc.CoolantLevelLow or (boiler_water_low and rps.ex_hcool)) and is_active(self.alarms.ReactorOverTemp)) - if enable_emer_cool and not self.emcool_opened then + if enable_emer_cool and not self.em_cool_opened then log.debug(util.c(">> Emergency Coolant Enable Detail Report (Unit ", self.r_id, ") <<")) log.debug(util.c("| CoolantLevelLow[", annunc.CoolantLevelLow, "] CoolantLevelLowLow[", rps.low_cool, "] ExcessHeatedCoolant[", rps.ex_hcool, "]")) log.debug(util.c("| ReactorOverTemp[", AISTATE_NAMES[self.alarms.ReactorOverTemp.state], "]")) @@ -910,13 +910,13 @@ function logic.handle_redstone(self) end end - if annunc.EmergencyCoolant > 1 and self.emcool_opened then + if annunc.EmergencyCoolant > 1 and self.em_cool_opened then log.info(util.c("UNIT ", self.r_id, " emergency coolant valve closed")) log.info(util.c("UNIT ", self.r_id, " turbines set to not dump steam")) end - self.emcool_opened = false - elseif enable_emer_cool or self.emcool_opened then + self.em_cool_opened = false + elseif enable_emer_cool or self.em_cool_opened then -- set turbines to dump excess steam for i = 1, #self.turbines do local session = self.turbines[i] @@ -937,16 +937,33 @@ function logic.handle_redstone(self) end end - if annunc.EmergencyCoolant > 1 and not self.emcool_opened then + if annunc.EmergencyCoolant > 1 and not self.em_cool_opened then log.info(util.c("UNIT ", self.r_id, " emergency coolant valve opened")) log.info(util.c("UNIT ", self.r_id, " turbines set to dump excess steam")) end - self.emcool_opened = true + self.em_cool_opened = true end -- set valve state always - if self.emcool_opened then self.valves.emer_cool.open() else self.valves.emer_cool.close() end + if self.em_cool_opened then self.valves.emer_cool.open() else self.valves.emer_cool.close() end + + ----------------------- + -- Auxiliary Coolant -- + ----------------------- + + local enable_aux_cool = boiler_water_low or (annunc.CoolantLevelLow and self.num_boilers == 0) + + if enable_aux_cool and not self.aux_cool_opened then + log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve opened")) + self.aux_cool_opened = true + elseif self.aux_cool_opened and self.turbine_flow_stable and not enable_aux_cool then + log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve closed")) + self.aux_cool_opened = false + end + + -- set valve state always + if self.aux_cool_opened then self.valves.aux_cool.open() else self.valves.aux_cool.close() end end return logic From de41ee56aab2c9b9006ff80eac0026cd4cbb1483 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 25 Feb 2025 14:33:25 -0500 Subject: [PATCH 3/6] #480 auxiliary water coolant --- coordinator/iocontrol.lua | 5 +- coordinator/startup.lua | 2 +- coordinator/ui/components/unit_flow.lua | 18 +++++-- coordinator/ui/layout/flow_view.lua | 29 ++++++++++- rtu/config/redstone.lua | 5 +- rtu/startup.lua | 2 +- scada-common/rsio.lua | 6 ++- scada-common/util.lua | 2 +- supervisor/config/facility.lua | 67 +++++++++++++++++++------ supervisor/config/system.lua | 16 +++++- supervisor/configure.lua | 5 +- supervisor/facility.lua | 5 +- supervisor/startup.lua | 2 +- supervisor/supervisor.lua | 2 + supervisor/unit.lua | 7 ++- supervisor/unitlogic.lua | 28 ++++++----- 16 files changed, 153 insertions(+), 48 deletions(-) diff --git a/coordinator/iocontrol.lua b/coordinator/iocontrol.lua index 95a3e6f..58aed0e 100644 --- a/coordinator/iocontrol.lua +++ b/coordinator/iocontrol.lua @@ -164,6 +164,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) num_turbines = 0, num_snas = 0, has_tank = conf.cooling.r_cool[i].TankConnection, + aux_cool = conf.cooling.aux_coolant[i], status_lines = { "", "" }, @@ -1214,7 +1215,7 @@ function iocontrol.update_unit_statuses(statuses) local valve_states = status[6] if type(valve_states) == "table" then - if #valve_states == 5 then + if #valve_states == 6 then unit.unit_ps.publish("V_pu_conn", valve_states[1] > 0) unit.unit_ps.publish("V_pu_state", valve_states[1] == 2) unit.unit_ps.publish("V_po_conn", valve_states[2] > 0) @@ -1225,6 +1226,8 @@ function iocontrol.update_unit_statuses(statuses) unit.unit_ps.publish("V_am_state", valve_states[4] == 2) unit.unit_ps.publish("V_emc_conn", valve_states[5] > 0) unit.unit_ps.publish("V_emc_state", valve_states[5] == 2) + unit.unit_ps.publish("V_aux_conn", valve_states[6] > 0) + unit.unit_ps.publish("V_aux_state", valve_states[6] == 2) else log.debug(log_header .. "valve states length mismatch") valid = false diff --git a/coordinator/startup.lua b/coordinator/startup.lua index e91228a..7343145 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer") local sounder = require("coordinator.sounder") local threads = require("coordinator.threads") -local COORDINATOR_VERSION = "v1.6.6" +local COORDINATOR_VERSION = "v1.6.7" local CHUNK_LOAD_DELAY_S = 30.0 diff --git a/coordinator/ui/components/unit_flow.lua b/coordinator/ui/components/unit_flow.lua index 192c89f..3a6f47b 100644 --- a/coordinator/ui/components/unit_flow.lua +++ b/coordinator/ui/components/unit_flow.lua @@ -59,7 +59,7 @@ local function make(parent, x, y, wide, unit_id) local tank_conns = facility.tank_conns local tank_types = facility.tank_fluid_types - local v_start = 1 + ((unit.unit_id - 1) * 5) + local v_start = 1 + ((unit.unit_id - 1) * 6) local prv_start = 1 + ((unit.unit_id - 1) * 3) local v_fields = { "pu", "po", "pl", "am" } local v_names = { @@ -94,11 +94,19 @@ local function make(parent, x, y, wide, unit_id) if unit.num_boilers > 0 then table.insert(rc_pipes, pipe(0, 1, _wide(28, 19), 1, colors.lightBlue, true)) table.insert(rc_pipes, pipe(0, 3, _wide(28, 19), 3, colors.orange, true)) - table.insert(rc_pipes, pipe(_wide(46 ,39), 1, _wide(72,58), 1, colors.blue, true)) - table.insert(rc_pipes, pipe(_wide(46,39), 3, _wide(72,58), 3, colors.white, true)) + table.insert(rc_pipes, pipe(_wide(46, 39), 1, _wide(72, 58), 1, colors.blue, true)) + table.insert(rc_pipes, pipe(_wide(46, 39), 3, _wide(72, 58), 3, colors.white, true)) + + if unit.aux_cool then + table.insert(rc_pipes, pipe(_wide(51, 41), 0, _wide(51, 41), 1, colors.blue, true)) + end else - table.insert(rc_pipes, pipe(0, 1, _wide(72,58), 1, colors.blue, true)) - table.insert(rc_pipes, pipe(0, 3, _wide(72,58), 3, colors.white, true)) + table.insert(rc_pipes, pipe(0, 1, _wide(72, 58), 1, colors.blue, true)) + table.insert(rc_pipes, pipe(0, 3, _wide(72, 58), 3, colors.white, true)) + + if unit.aux_cool then + table.insert(rc_pipes, pipe(8, 0, 8, 1, colors.blue, true)) + end end if unit.has_tank then diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index 7b89212..5616406 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -286,7 +286,7 @@ local function init(main) TextBox{parent=main,x=12,y=vy,text="\x10\x11",fg_bg=text_col,width=2} - local conn = IndicatorLight{parent=main,x=9,y=vy+1,label=util.sprintf("PV%02d-EMC", i * 5),colors=style.ind_grn} + local conn = IndicatorLight{parent=main,x=9,y=vy+1,label=util.sprintf("PV%02d-EMC", (i * 6) - 1),colors=style.ind_grn} local open = IndicatorLight{parent=main,x=9,y=vy+2,label="OPEN",colors=style.ind_wht} conn.register(units[i].unit_ps, "V_emc_conn", conn.update) @@ -294,6 +294,33 @@ local function init(main) end end + ------------------------------ + -- auxiliary coolant valves -- + ------------------------------ + + for i = 1, facility.num_units do + if units[i].aux_cool then + local vx + local vy = 3 + y_ofs(i) + + if #emcool_pipes == 0 then + vx = util.trinary(units[i].num_boilers == 0, 36, 79) + else + vx = util.trinary(units[i].num_boilers == 0, 58, 91) + end + + PipeNetwork{parent=main,x=vx-6,y=vy,pipes={pipe(0,1,9,0,colors.blue,true)},bg=style.theme.bg} + + TextBox{parent=main,x=vx,y=vy,text="\x10\x11",fg_bg=text_col,width=2} + + local conn = IndicatorLight{parent=main,x=vx-3,y=vy+1,label=util.sprintf("PV%02d-AUX", i * 6),colors=style.ind_grn} + local open = IndicatorLight{parent=main,x=vx-3,y=vy+2,label="OPEN",colors=style.ind_wht} + + conn.register(units[i].unit_ps, "V_aux_conn", conn.update) + open.register(units[i].unit_ps, "V_aux_state", open.update) + end + end + ------------------- -- dynamic tanks -- ------------------- diff --git a/rtu/config/redstone.lua b/rtu/config/redstone.lua index c38f2ff..2d9e9f5 100644 --- a/rtu/config/redstone.lua +++ b/rtu/config/redstone.lua @@ -74,11 +74,12 @@ local PORT_DESC_MAP = { { IO.R_PLC_FAULT, "RPS PLC Fault" }, { IO.R_PLC_TIMEOUT, "RPS Supervisor Timeout" }, { IO.U_ALARM, "Unit Alarm" }, - { IO.U_EMER_COOL, "Unit Emergency Cool. Valve" } + { IO.U_EMER_COOL, "Unit Emergency Cool. Valve" }, + { IO.U_AUX_COOL, "Unit Auxiliary Cool. Valve" } } -- designation (0 = facility, 1 = unit) -local PORT_DSGN = { [-1] = 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 } +local PORT_DSGN = { [-1] = 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 } assert(#PORT_DESC_MAP == rsio.NUM_PORTS) assert(#PORT_DSGN == rsio.NUM_PORTS) diff --git a/rtu/startup.lua b/rtu/startup.lua index d40eefd..3df4694 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "v1.11.1" +local RTU_VERSION = "v1.11.2" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_HW_STATE = databus.RTU_HW_STATE diff --git a/scada-common/rsio.lua b/scada-common/rsio.lua index 850706b..9c4d569 100644 --- a/scada-common/rsio.lua +++ b/scada-common/rsio.lua @@ -150,6 +150,7 @@ local MODES = { [IO.R_PLC_TIMEOUT] = IO_MODE.DIGITAL_OUT, [IO.U_ALARM] = IO_MODE.DIGITAL_OUT, [IO.U_EMER_COOL] = IO_MODE.DIGITAL_OUT, + [IO.U_AUX_COOL] = IO_MODE.DIGITAL_OUT, [IO.F_MATRIX_CHG] = IO_MODE.ANALOG_OUT } @@ -209,10 +210,11 @@ local RS_DIO_MAP = { [IO.R_PLC_TIMEOUT] = { _in = _I_ACTIVE_HIGH, _out = _O_ACTIVE_HIGH, mode = IO_DIR.OUT }, [IO.U_ALARM] = { _in = _I_ACTIVE_HIGH, _out = _O_ACTIVE_HIGH, mode = IO_DIR.OUT }, - [IO.U_EMER_COOL] = { _in = _I_ACTIVE_LOW, _out = _O_ACTIVE_LOW, mode = IO_DIR.OUT } + [IO.U_EMER_COOL] = { _in = _I_ACTIVE_LOW, _out = _O_ACTIVE_LOW, mode = IO_DIR.OUT }, + [IO.U_AUX_COOL] = { _in = _I_ACTIVE_LOW, _out = _O_ACTIVE_LOW, mode = IO_DIR.OUT } } -assert(rsio.NUM_DIG_PORTS == #RS_DIO_MAP, "RS_DIO_MAP length incorrect") +assert(rsio.NUM_DIG_PORTS == util.table_len(RS_DIO_MAP), "RS_DIO_MAP length incorrect") -- get the I/O direction of a port ---@nodiscard diff --git a/scada-common/util.lua b/scada-common/util.lua index 56e659c..a4c7d4e 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.4.11" +util.version = "1.4.12" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index 13e238c..ba90b72 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -185,8 +185,9 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) local fac_c_6 = Div{parent=fac_cfg,x=2,y=4,width=49} local fac_c_7 = Div{parent=fac_cfg,x=2,y=4,width=49} local fac_c_8 = Div{parent=fac_cfg,x=2,y=4,width=49} + local fac_c_9 = Div{parent=fac_cfg,x=2,y=4,width=49} - local fac_pane = MultiPane{parent=fac_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3,fac_c_4,fac_c_5,fac_c_6,fac_c_7, fac_c_8}} + local fac_pane = MultiPane{parent=fac_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3,fac_c_4,fac_c_5,fac_c_6,fac_c_7,fac_c_8,fac_c_9}} TextBox{parent=fac_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)} @@ -205,10 +206,18 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) nu_error.hide(true) tmp_cfg.UnitCount = count - local confs = tool_ctl.cooling_elems - if count >= 2 then confs[2].line.show() else confs[2].line.hide(true) end - if count >= 3 then confs[3].line.show() else confs[3].line.hide(true) end - if count == 4 then confs[4].line.show() else confs[4].line.hide(true) end + local c_confs = tool_ctl.cooling_elems + local a_confs = tool_ctl.aux_cool_elems + + for i = 2, 4 do + if count >= i then + c_confs[i].line.show() + a_confs[i].line.show() + else + c_confs[i].line.hide(true) + a_confs[i].line.hide(true) + end + end fac_pane.set_value(2) else nu_error.show() end @@ -285,6 +294,13 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) else elem.div.hide(true) end end + if not any_has_tank then + tmp_cfg.FacilityTankMode = 0 + tmp_cfg.FacilityTankDefs = {} + tmp_cfg.FacilityTankList = {} + tmp_cfg.FacilityTankConns = {} + end + if any_has_tank then fac_pane.set_value(3) else main_pane.set_value(3) end end end @@ -672,25 +688,48 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) PushButton{parent=fac_c_7,x=1,y=14,text="\x1b Back",callback=back_from_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_7,x=44,y=14,text="Next \x1a",callback=submit_tank_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + --#endregion + --#region Auxiliary Coolant + + TextBox{parent=fac_c_8,height=5,text="Auxiliary water coolant can be enabled for units to provide extra water during turbine ramp-up. For water cooled reactors, this goes to the reactor. For sodium cooled reactors, water goes to the boiler."} + + for i = 1, 4 do + local line = Div{parent=fac_c_8,x=1,y=7+i,height=1} + + TextBox{parent=line,text="Unit "..i.." -",width=8} + local aux_cool = Checkbox{parent=line,x=10,y=1,label="Has Auxiliary Coolant",default=ini_cfg.AuxiliaryCoolant[i],box_fg_bg=cpair(colors.yellow,colors.black)} + + tool_ctl.aux_cool_elems[i] = { line = line, enable = aux_cool } + end + + local function submit_aux_cool() + tmp_cfg.AuxiliaryCoolant = {} + + for i = 1, tmp_cfg.UnitCount do + tmp_cfg.AuxiliaryCoolant[i] = tool_ctl.aux_cool_elems[i].enable.get_value() + end + + fac_pane.set_value(9) + end + + PushButton{parent=fac_c_8,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=fac_c_8,x=44,y=14,text="Next \x1a",callback=submit_aux_cool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + --#endregion --#region Extended Idling - TextBox{parent=fac_c_8,height=6,text="Charge control provides automatic control to maintain an induction matrix charge level. In order to have smoother control, reactors that were activated will be held on at 0.01 mB/t for a short period before allowing them to turn off. This minimizes overshooting the charge target."} - TextBox{parent=fac_c_8,y=8,height=3,text="You can extend this to a full minute to minimize reactors flickering on/off, but there may be more overshoot of the target."} + TextBox{parent=fac_c_9,height=6,text="Charge control provides automatic control to maintain an induction matrix charge level. In order to have smoother control, reactors that were activated will be held on at 0.01 mB/t for a short period before allowing them to turn off. This minimizes overshooting the charge target."} + TextBox{parent=fac_c_9,y=8,height=3,text="You can extend this to a full minute to minimize reactors flickering on/off, but there may be more overshoot of the target."} - local ext_idling = Checkbox{parent=fac_c_8,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)} - - local function back_from_idling() - fac_pane.set_value(tri(tmp_cfg.FacilityTankMode == 0, 3, 7)) - end + local ext_idling = Checkbox{parent=fac_c_9,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)} local function submit_idling() tmp_cfg.ExtChargeIdling = ext_idling.get_value() main_pane.set_value(3) end - PushButton{parent=fac_c_8,x=1,y=14,text="\x1b Back",callback=back_from_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - PushButton{parent=fac_c_8,x=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=fac_c_9,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(8)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=fac_c_9,x=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} --#endregion diff --git a/supervisor/config/system.lua b/supervisor/config/system.lua index 71483f9..600c35d 100644 --- a/supervisor/config/system.lua +++ b/supervisor/config/system.lua @@ -402,6 +402,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit try_set(tool_ctl.tank_elems[i].tank_opt, ini_cfg.FacilityTankDefs[i]) end + for i = 1, #ini_cfg.AuxiliaryCoolant do + try_set(tool_ctl.aux_cool_elems[i].enable, ini_cfg.AuxiliaryCoolant[i]) + end + tool_ctl.en_fac_tanks.set_value(ini_cfg.FacilityTankMode > 0) tool_ctl.view_cfg.enable() @@ -588,7 +592,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit end if val == "" then val = "no facility tanks" end - elseif f[1] == "FacilityTankMode" and raw == 0 then val = "0 (n/a, unit mode)" + elseif f[1] == "FacilityTankMode" and raw == 0 then val = "no facility tanks" elseif f[1] == "FacilityTankDefs" and type(cfg.FacilityTankDefs) == "table" then local tank_name_list = { table.unpack(cfg.FacilityTankList) } ---@type (string|integer)[] local next_f = 1 @@ -647,6 +651,16 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit end if val == "" then val = "no emergency coolant tanks" end + elseif f[1] == "AuxiliaryCoolant" then + val = "" + + for idx = 1, #cfg.AuxiliaryCoolant do + if cfg.AuxiliaryCoolant[idx] then + val = val .. tri(val == "", "", "\n") .. util.sprintf(" \x07 auxiliary coolant for unit %d", idx) + end + end + + if val == "" then val = "no auxiliary coolant" end end if not skip then diff --git a/supervisor/configure.lua b/supervisor/configure.lua index 6e760bd..b25f891 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -72,7 +72,8 @@ local tool_ctl = { load_legacy = nil, ---@type function cooling_elems = {}, ---@type { line: Div, turbines: NumberField, boilers: NumberField, tank: Checkbox }[] - tank_elems = {} ---@type { div: Div, tank_opt: Radio2D, no_tank: TextBox }[] + tank_elems = {}, ---@type { div: Div, tank_opt: Radio2D, no_tank: TextBox }[] + aux_cool_elems = {} ---@type { line: Div, enable: Checkbox }[] } ---@class svr_config @@ -84,6 +85,7 @@ local tmp_cfg = { FacilityTankList = {}, ---@type integer[] list of tanks by slot (0 = none or covered by an above tank, 1 = unit tank, 2 = facility tank) FacilityTankConns = {}, ---@type integer[] map of unit tank connections (indicies are units, values are tank indicies in the tank list) TankFluidTypes = {}, ---@type integer[] which type of fluid each tank in the tank list should be containing + AuxiliaryCoolant = {}, ---@type boolean[] if a unit has auxiliary coolant ExtChargeIdling = false, SVR_Channel = nil, ---@type integer PLC_Channel = nil, ---@type integer @@ -117,6 +119,7 @@ local fields = { { "FacilityTankList", "Facility Tank List", {} }, -- hidden { "FacilityTankConns", "Facility Tank Connections", {} }, -- hidden { "TankFluidTypes", "Tank Fluid Types", {} }, + { "AuxiliaryCoolant", "Auxiliary Water Coolant", {} }, { "ExtChargeIdling", "Extended Charge Idling", false }, { "SVR_Channel", "SVR Channel", 16240 }, { "PLC_Channel", "PLC Channel", 16241 }, diff --git a/supervisor/facility.lua b/supervisor/facility.lua index 08ece5f..f3cf18b 100644 --- a/supervisor/facility.lua +++ b/supervisor/facility.lua @@ -64,7 +64,8 @@ function facility.new(config) fac_tank_defs = config.FacilityTankDefs, fac_tank_list = config.FacilityTankList, fac_tank_conns = config.FacilityTankConns, - tank_fluid_types = config.TankFluidTypes + tank_fluid_types = config.TankFluidTypes, + aux_coolant = config.AuxiliaryCoolant }, -- rtus rtu_gw_conn_count = 0, @@ -147,7 +148,7 @@ function facility.new(config) -- create units for i = 1, config.UnitCount do - table.insert(self.units, unit.new(i, self.cooling_conf.r_cool[i].BoilerCount, self.cooling_conf.r_cool[i].TurbineCount, config.ExtChargeIdling)) + table.insert(self.units, unit.new(i, self.cooling_conf.r_cool[i].BoilerCount, self.cooling_conf.r_cool[i].TurbineCount, config.ExtChargeIdling, self.cooling_conf.aux_coolant[i])) table.insert(self.group_map, AUTO_GROUP.MANUAL) table.insert(self.last_unit_states, false) end diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 61a6c78..c235e09 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.6.4" +local SUPERVISOR_VERSION = "v1.6.5" local println = util.println local println_ts = util.println_ts diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua index 47ee6d2..42b8ff0 100644 --- a/supervisor/supervisor.lua +++ b/supervisor/supervisor.lua @@ -44,6 +44,7 @@ function supervisor.load_config() config.FacilityTankList = settings.get("FacilityTankList") config.FacilityTankConns = settings.get("FacilityTankConns") config.TankFluidTypes = settings.get("TankFluidTypes") + config.AuxiliaryCoolant = settings.get("AuxiliaryCoolant") config.ExtChargeIdling = settings.get("ExtChargeIdling") config.SVR_Channel = settings.get("SVR_Channel") @@ -78,6 +79,7 @@ function supervisor.load_config() cfv.assert_type_table(config.FacilityTankList) cfv.assert_type_table(config.FacilityTankConns) cfv.assert_type_table(config.TankFluidTypes) + cfv.assert_type_table(config.AuxiliaryCoolant) cfv.assert_range(config.FacilityTankMode, 0, 8) cfv.assert_type_bool(config.ExtChargeIdling) diff --git a/supervisor/unit.lua b/supervisor/unit.lua index 3a02204..67992aa 100644 --- a/supervisor/unit.lua +++ b/supervisor/unit.lua @@ -66,7 +66,8 @@ local unit = {} ---@param num_boilers integer number of boilers expected ---@param num_turbines integer number of turbines expected ---@param ext_idle boolean extended idling mode -function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) +---@param aux_coolant boolean if this unit has auxiliary coolant +function unit.new(reactor_id, num_boilers, num_turbines, ext_idle, aux_coolant) -- time (ms) to idle for auto idling local IDLE_TIME = util.trinary(ext_idle, 60000, 10000) @@ -79,6 +80,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) plc_i = nil, ---@type plc_session num_boilers = num_boilers, num_turbines = num_turbines, + aux_coolant = aux_coolant, types = { DT_KEYS = DT_KEYS, AISTATE = AISTATE }, -- rtus rtu_list = {}, ---@type unit_session[][] @@ -1062,7 +1064,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) v.waste_sna.check(), v.waste_po.check(), v.waste_sps.check(), - v.emer_cool.check() + v.emer_cool.check(), + v.aux_cool.check() } end diff --git a/supervisor/unitlogic.lua b/supervisor/unitlogic.lua index b5c8b8c..25e4f24 100644 --- a/supervisor/unitlogic.lua +++ b/supervisor/unitlogic.lua @@ -341,11 +341,11 @@ function logic.update_annunciator(self) end if rotation_stable then - log.debug(util.c("UNIT ", self.r_id, ": turbine ", idx, " reached rotational stability (", rotation, ")")) + log.debug(util.c("UNIT ", self.r_id, " turbine ", idx, " reached rotational stability (", rotation, ")")) end if flow_stable then - log.debug(util.c("UNIT ", self.r_id, ": turbine ", idx, " reached flow stability (", turbine.state.flow_rate, " mB/t)")) + log.debug(util.c("UNIT ", self.r_id, " turbine ", idx, " reached flow stability (", turbine.state.flow_rate, " mB/t)")) end turbines_stable = turbines_stable and (rotation_stable or flow_stable) @@ -357,7 +357,7 @@ function logic.update_annunciator(self) turbines_stable = false - log.debug(util.c("UNIT ", self.r_id, ": turbine ", idx, " reset stability (new rate ", turbine.state.steam_input_rate, " != ", last.input_rate," mB/t)")) + log.debug(util.c("UNIT ", self.r_id, " turbine ", idx, " reset stability (new rate ", turbine.state.steam_input_rate, " != ", last.input_rate," mB/t)")) end last.input_rate = turbine.state.steam_input_rate @@ -952,18 +952,20 @@ function logic.handle_redstone(self) -- Auxiliary Coolant -- ----------------------- - local enable_aux_cool = boiler_water_low or (annunc.CoolantLevelLow and self.num_boilers == 0) + if self.aux_coolant then + local enable_aux_cool = boiler_water_low or (annunc.CoolantLevelLow and self.num_boilers == 0) - if enable_aux_cool and not self.aux_cool_opened then - log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve opened")) - self.aux_cool_opened = true - elseif self.aux_cool_opened and self.turbine_flow_stable and not enable_aux_cool then - log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve closed")) - self.aux_cool_opened = false + if enable_aux_cool and not self.aux_cool_opened then + log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve opened")) + self.aux_cool_opened = true + elseif self.aux_cool_opened and self.turbine_flow_stable and not enable_aux_cool then + log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve closed")) + self.aux_cool_opened = false + end + + -- set valve state always + if self.aux_cool_opened then self.valves.aux_cool.open() else self.valves.aux_cool.close() end end - - -- set valve state always - if self.aux_cool_opened then self.valves.aux_cool.open() else self.valves.aux_cool.close() end end return logic From 7ab5ea710f334844526c77d434f88ca407697922 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 25 Feb 2025 14:52:05 -0500 Subject: [PATCH 4/6] additional supervisor config validations --- supervisor/config/facility.lua | 1 + supervisor/startup.lua | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index ba90b72..b67e8f4 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -299,6 +299,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) tmp_cfg.FacilityTankDefs = {} tmp_cfg.FacilityTankList = {} tmp_cfg.FacilityTankConns = {} + tmp_cfg.TankFluidTypes = {} end if any_has_tank then fac_pane.set_value(3) else main_pane.set_value(3) end diff --git a/supervisor/startup.lua b/supervisor/startup.lua index c235e09..3e63616 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -10,6 +10,7 @@ local log = require("scada-common.log") local network = require("scada-common.network") local ppm = require("scada-common.ppm") local tcd = require("scada-common.tcd") +local types = require("scada-common.types") local util = require("scada-common.util") local core = require("graphics.core") @@ -72,6 +73,21 @@ if config.FacilityTankMode > 0 then cfv.assert_type_int(def) cfv.assert_range(def, 0, 2) assert(cfv.valid(), "startup> invalid facility tank definition for reactor unit " .. i) + + local entry = config.FacilityTankList[i] + cfv.assert_type_int(entry) + cfv.assert_range(entry, 0, 2) + assert(cfv.valid(), "startup> invalid facility tank list entry for tank " .. i) + + local conn = config.FacilityTankConns[i] + cfv.assert_type_int(conn) + cfv.assert_range(conn, 0, #config.FacilityTankDefs) + assert(cfv.valid(), "startup> invalid facility tank connection for reactor unit " .. i) + + local type = config.TankFluidTypes[i] + cfv.assert_type_int(type) + cfv.assert_range(type, 0, types.COOLANT_TYPE.SODIUM) + assert(cfv.valid(), "startup> invalid tank fluid type for tank " .. i) end end From d45f19c8a61200517c1925f42c9497a1344c634c Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 25 Feb 2025 15:32:07 -0500 Subject: [PATCH 5/6] refactor --- coordinator/iocontrol.lua | 2 +- coordinator/ui/components/unit_flow.lua | 4 ++-- coordinator/ui/layout/flow_view.lua | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coordinator/iocontrol.lua b/coordinator/iocontrol.lua index 58aed0e..f44becb 100644 --- a/coordinator/iocontrol.lua +++ b/coordinator/iocontrol.lua @@ -164,7 +164,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) num_turbines = 0, num_snas = 0, has_tank = conf.cooling.r_cool[i].TankConnection, - aux_cool = conf.cooling.aux_coolant[i], + aux_coolant = conf.cooling.aux_coolant[i], status_lines = { "", "" }, diff --git a/coordinator/ui/components/unit_flow.lua b/coordinator/ui/components/unit_flow.lua index 3a6f47b..f9e0fc8 100644 --- a/coordinator/ui/components/unit_flow.lua +++ b/coordinator/ui/components/unit_flow.lua @@ -97,14 +97,14 @@ local function make(parent, x, y, wide, unit_id) table.insert(rc_pipes, pipe(_wide(46, 39), 1, _wide(72, 58), 1, colors.blue, true)) table.insert(rc_pipes, pipe(_wide(46, 39), 3, _wide(72, 58), 3, colors.white, true)) - if unit.aux_cool then + if unit.aux_coolant then table.insert(rc_pipes, pipe(_wide(51, 41), 0, _wide(51, 41), 1, colors.blue, true)) end else table.insert(rc_pipes, pipe(0, 1, _wide(72, 58), 1, colors.blue, true)) table.insert(rc_pipes, pipe(0, 3, _wide(72, 58), 3, colors.white, true)) - if unit.aux_cool then + if unit.aux_coolant then table.insert(rc_pipes, pipe(8, 0, 8, 1, colors.blue, true)) end end diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index 5616406..4d1c18f 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -299,7 +299,7 @@ local function init(main) ------------------------------ for i = 1, facility.num_units do - if units[i].aux_cool then + if units[i].aux_coolant then local vx local vy = 3 + y_ofs(i) From 2b73196130ca20dbb6d0f837301fb20d4ac69ca0 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 25 Feb 2025 16:43:03 -0500 Subject: [PATCH 6/6] #480 updated aux coolant logic --- scada-common/constants.lua | 2 ++ supervisor/unit.lua | 1 + supervisor/unitlogic.lua | 23 +++++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/scada-common/constants.lua b/scada-common/constants.lua index 0472a6c..11a8929 100644 --- a/scada-common/constants.lua +++ b/scada-common/constants.lua @@ -72,6 +72,8 @@ local rs = {} rs.IMATRIX_CHARGE_LOW = 0.05 -- activation threshold (less than) for F_MATRIX_LOW rs.IMATRIX_CHARGE_HIGH = 0.95 -- activation threshold (greater than) for F_MATRIX_HIGH +rs.AUX_COOL_ENABLE = 0.60 -- actiation threshold (less than or equal) for U_AUX_COOL +rs.AUX_COOL_DISABLE = 1.00 -- deactivation threshold (greater than or equal) for U_AUX_COOL constants.RS_THRESHOLDS = rs diff --git a/supervisor/unit.lua b/supervisor/unit.lua index 67992aa..b448a95 100644 --- a/supervisor/unit.lua +++ b/supervisor/unit.lua @@ -114,6 +114,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle, aux_coolant) damage_est_last = 0, waste_product = WASTE.PLUTONIUM, ---@type WASTE_PRODUCT status_text = { "UNKNOWN", "awaiting connection..." }, + enable_aux_cool = false, -- logic for alarms had_reactor = false, turbine_flow_stable = false, diff --git a/supervisor/unitlogic.lua b/supervisor/unitlogic.lua index 25e4f24..6bd7470 100644 --- a/supervisor/unitlogic.lua +++ b/supervisor/unitlogic.lua @@ -35,6 +35,7 @@ local FLOW_STABILITY_DELAY_MS = const.FLOW_STABILITY_DELAY_MS local ANNUNC_LIMS = const.ANNUNCIATOR_LIMITS local ALARM_LIMS = const.ALARM_LIMITS +local RS_THRESH = const.RS_THRESHOLDS ---@class unit_logic_extension local logic = {} @@ -54,6 +55,10 @@ function logic.update_annunciator(self) -- variables for boiler, or reactor if no boilers used local total_boil_rate = 0.0 + -- auxiliary coolant control + local need_aux_cool = false + local dis_aux_cool = true + --#region Reactor annunc.AutoControl = self.auto_engaged @@ -148,6 +153,9 @@ function logic.update_annunciator(self) -- if no boilers, use reactor heating rate to check for boil rate mismatch if num_boilers == 0 then total_boil_rate = plc_db.mek_status.heating_rate + + need_aux_cool = plc_db.mek_status.ccool_fill <= RS_THRESH.AUX_COOL_ENABLE + dis_aux_cool = plc_db.mek_status.ccool_fill >= RS_THRESH.AUX_COOL_DISABLE end else self.plc_cache.ok = false @@ -215,6 +223,9 @@ function logic.update_annunciator(self) annunc.BoilerOnline[idx] = true annunc.WaterLevelLow[idx] = boiler.tanks.water_fill < ANNUNC_LIMS.WaterLevelLow + + need_aux_cool = need_aux_cool or (boiler.tanks.water_fill <= RS_THRESH.AUX_COOL_ENABLE) + dis_aux_cool = dis_aux_cool and (boiler.tanks.water_fill >= RS_THRESH.AUX_COOL_DISABLE) end -- check heating rate low @@ -406,6 +417,12 @@ function logic.update_annunciator(self) -- update auto control ready state for this unit self.db.control.ready = plc_ready and boilers_ready and turbines_ready + + -- update auxiliary coolant command + if plc_ready then + self.enable_aux_cool = self.plc_i.get_db().mek_status.status and + (self.enable_aux_cool or need_aux_cool) and not (dis_aux_cool and self.turbine_flow_stable) + else self.enable_aux_cool = false end end -- update an alarm state given conditions @@ -953,12 +970,10 @@ function logic.handle_redstone(self) ----------------------- if self.aux_coolant then - local enable_aux_cool = boiler_water_low or (annunc.CoolantLevelLow and self.num_boilers == 0) - - if enable_aux_cool and not self.aux_cool_opened then + if self.enable_aux_cool and (not self.aux_cool_opened) then log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve opened")) self.aux_cool_opened = true - elseif self.aux_cool_opened and self.turbine_flow_stable and not enable_aux_cool then + elseif (not self.enable_aux_cool) and self.aux_cool_opened then log.info(util.c("UNIT ", self.r_id, " auxiliary coolant valve closed")) self.aux_cool_opened = false end