From eb45ff899bdd3b70293e2803317ef1ef0c9fb27d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 29 Apr 2024 22:03:54 -0400 Subject: [PATCH] #455 calculate reactor temp high limit --- scada-common/constants.lua | 10 ++++++---- supervisor/session/plc.lua | 23 +++++++++++++++++++++-- supervisor/startup.lua | 2 +- supervisor/unit.lua | 3 ++- supervisor/unitlogic.lua | 19 ++++++++++++++----- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/scada-common/constants.lua b/scada-common/constants.lua index 678ea98..b2755b9 100644 --- a/scada-common/constants.lua +++ b/scada-common/constants.lua @@ -29,7 +29,7 @@ local annunc = {} annunc.RCSFlowLow_H2O = -3.2 -- flow < -3.2 mB/s annunc.RCSFlowLow_NA = -2.0 -- flow < -2.0 mB/s annunc.CoolantLevelLow = 0.4 -- fill < 40% -annunc.ReactorTempHigh = 1000 -- temp > 1000K +annunc.OpTempTolerance = 5 -- high temp if >= operational temp + X annunc.ReactorHighDeltaT = 50 -- rate > 50K/s annunc.FuelLevelLow = 0.05 -- fill <= 5% annunc.WasteLevelHigh = 0.80 -- fill >= 80% @@ -101,9 +101,11 @@ constants.EXTREME_RADIATION = 100.0 ---@class _mek_constants local mek = {} -mek.TURBINE_GAS_PER_TANK = 64000 -- mekanism: turbineGasPerTank -mek.TURBINE_DISPERSER_FLOW = 1280 -- mekanism: turbineDisperserGasFlow -mek.TURBINE_VENT_FLOW = 32000 -- mekanism: turbineVentGasFlow +mek.BASE_BOIL_TEMP = 373.15 -- mekanism: HeatUtils.BASE_BOIL_TEMP +mek.JOULES_PER_MB = 1000000 -- mekanism: energyPerFissionFuel +mek.TURBINE_GAS_PER_TANK = 64000 -- mekanism: turbineGasPerTank +mek.TURBINE_DISPERSER_FLOW = 1280 -- mekanism: turbineDisperserGasFlow +mek.TURBINE_VENT_FLOW = 32000 -- mekanism: turbineVentGasFlow constants.mek = mek diff --git a/supervisor/session/plc.lua b/supervisor/session/plc.lua index 5bb097e..e058816 100644 --- a/supervisor/session/plc.lua +++ b/supervisor/session/plc.lua @@ -1,4 +1,5 @@ local comms = require("scada-common.comms") +local const = require("scada-common.constants") local log = require("scada-common.log") local mqueue = require("scada-common.mqueue") local types = require("scada-common.types") @@ -105,6 +106,8 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f formed = false, rps_tripped = false, rps_trip_cause = "ok", ---@type rps_trip_cause + max_op_temp_H2O = 1200, + max_op_temp_Na = 1200, ---@class rps_status rps_status = { high_dmg = false, @@ -138,11 +141,11 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f waste = 0, waste_need = 0, waste_fill = 0.0, - ccool_type = "?", + ccool_type = types.FLUID.EMPTY_GAS, ---@type fluid ccool_amnt = 0, ccool_need = 0, ccool_fill = 0.0, - hcool_type = "?", + hcool_type = types.FLUID.EMPTY_GAS, ---@type fluid hcool_amnt = 0, hcool_need = 0, hcool_fill = 0.0 @@ -169,6 +172,21 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f ---@class plc_session local public = {} + -- compute maximum expected operational temperatures for high temp warnings + local function _compute_op_temps() + local JOULES_PER_MB = const.mek.JOULES_PER_MB + local BASE_BOIL_TEMP = const.mek.BASE_BOIL_TEMP + + local heat_cap = self.sDB.mek_struct.heat_cap + local max_burn = self.sDB.mek_struct.max_burn + + self.sDB.max_op_temp_H2O = max_burn * 2 * (JOULES_PER_MB * heat_cap ^ -1) + BASE_BOIL_TEMP + self.sDB.max_op_temp_Na = max_burn * (JOULES_PER_MB * heat_cap ^ -1) + BASE_BOIL_TEMP + + log.info(util.sprintf(log_header .. "computed maximum operational temperatures %.3f (H2O) and %.3f (Na)", + self.sDB.max_op_temp_H2O, self.sDB.max_op_temp_Na)) + end + -- copy in the RPS status ---@param rps_status table local function _copy_rps_status(rps_status) @@ -351,6 +369,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f local status = pcall(_copy_struct, pkt.data) if status then -- copied in structure data OK + _compute_op_temps() self.received_struct = true out_queue.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, reactor_id) else diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 2a2202c..d15ddc5 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.3.7" +local SUPERVISOR_VERSION = "v1.3.8" local println = util.println local println_ts = util.println_ts diff --git a/supervisor/unit.lua b/supervisor/unit.lua index f0dccf2..8747b61 100644 --- a/supervisor/unit.lua +++ b/supervisor/unit.lua @@ -147,7 +147,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) }, damage = 0, temp = 0, - waste = 0 + waste = 0, + high_temp_lim = 1150 }, ---@class alarm_monitors alarms = { diff --git a/supervisor/unitlogic.lua b/supervisor/unitlogic.lua index ad2b522..3fe2ebc 100644 --- a/supervisor/unitlogic.lua +++ b/supervisor/unitlogic.lua @@ -133,7 +133,15 @@ function logic.update_annunciator(self) self.last_heartbeat = plc_db.last_status_update end - local flow_low = util.trinary(plc_db.mek_status.ccool_type == types.FLUID.SODIUM, ANNUNC_LIMS.RCSFlowLow_NA, ANNUNC_LIMS.RCSFlowLow_H2O) + local flow_low = ANNUNC_LIMS.RCSFlowLow_H2O + local high_temp = plc_db.max_op_temp_H2O + + if plc_db.mek_status.ccool_type == types.FLUID.SODIUM then + flow_low = ANNUNC_LIMS.RCSFlowLow_NA + high_temp = plc_db.max_op_temp_Na + end + + self.plc_cache.high_temp_lim = math.min(high_temp + ANNUNC_LIMS.OpTempTolerance, 1200) -- update other annunciator fields annunc.ReactorSCRAM = plc_db.rps_tripped @@ -142,7 +150,7 @@ function logic.update_annunciator(self) annunc.RCPTrip = plc_db.rps_tripped and (plc_db.rps_status.ex_hcool or plc_db.rps_status.low_cool) annunc.RCSFlowLow = _get_dt(DT_KEYS.ReactorCCool) < flow_low annunc.CoolantLevelLow = plc_db.mek_status.ccool_fill < ANNUNC_LIMS.CoolantLevelLow - annunc.ReactorTempHigh = plc_db.mek_status.temp > ANNUNC_LIMS.ReactorTempHigh + annunc.ReactorTempHigh = plc_db.mek_status.temp >= self.plc_cache.high_temp_lim annunc.ReactorHighDeltaT = _get_dt(DT_KEYS.ReactorTemp) > ANNUNC_LIMS.ReactorHighDeltaT annunc.FuelInputRateLow = _get_dt(DT_KEYS.ReactorFuel) < -1.0 or plc_db.mek_status.fuel_fill <= ANNUNC_LIMS.FuelLevelLow annunc.WasteLineOcclusion = _get_dt(DT_KEYS.ReactorWaste) > 1.0 or plc_db.mek_status.waste_fill >= ANNUNC_LIMS.WasteLevelHigh @@ -542,7 +550,8 @@ function logic.update_alarms(self) end -- High Temperature - _update_alarm_state(self, plc_cache.temp >= ALARM_LIMS.HIGH_TEMP, self.alarms.ReactorHighTemp) + local high_temp = math.min(math.max(self.plc_cache.high_temp_lim, 1100), 1199.995) + _update_alarm_state(self, plc_cache.temp >= high_temp, self.alarms.ReactorHighTemp) -- Waste Leak _update_alarm_state(self, plc_cache.waste >= 1.0, self.alarms.ReactorWasteLeak) @@ -718,11 +727,11 @@ function logic.update_status_text(self) self.status_text[2] = "elevated level of radiation" end elseif is_active(self.alarms.ReactorOverTemp) then - self.status_text = { "CORE OVER TEMP", "reactor core temperature >=1200K" } + self.status_text = { "CORE OVER TEMP", "reactor core temp damaging" } elseif is_active(self.alarms.ReactorWasteLeak) then self.status_text = { "WASTE LEAK", "radioactive waste leak detected" } elseif is_active(self.alarms.ReactorHighTemp) then - self.status_text = { "CORE TEMP HIGH", "reactor core temperature >1150K" } + self.status_text = { "CORE TEMP HIGH", "reactor core temperature high" } elseif is_active(self.alarms.ReactorHighWaste) then self.status_text = { "WASTE LEVEL HIGH", "waste accumulating in reactor" } elseif is_active(self.alarms.TurbineTrip) then