#25 sna/sps integration, plutonium fallback, waste rate reporting
This commit is contained in:
@@ -11,6 +11,9 @@ local rsctl = require("supervisor.session.rsctl")
|
||||
local PROCESS = types.PROCESS
|
||||
local PROCESS_NAMES = types.PROCESS_NAMES
|
||||
local PRIO = types.ALARM_PRIORITY
|
||||
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||
local WASTE = types.WASTE_PRODUCT
|
||||
local WASTE_MODE = types.WASTE_MODE
|
||||
|
||||
local IO = rsio.IO
|
||||
|
||||
@@ -61,6 +64,7 @@ function facility.new(num_reactors, cooling_conf)
|
||||
rtu_conn_count = 0,
|
||||
redstone = {},
|
||||
induction = {},
|
||||
sps = {},
|
||||
envd = {},
|
||||
-- redstone I/O control
|
||||
io_ctl = nil, ---@type rs_controller
|
||||
@@ -99,6 +103,10 @@ function facility.new(num_reactors, cooling_conf)
|
||||
last_update = 0,
|
||||
last_error = 0.0,
|
||||
last_time = 0.0,
|
||||
-- waste processing
|
||||
waste_product = WASTE.PLUTONIUM,
|
||||
current_waste_product = WASTE.PLUTONIUM,
|
||||
pu_fallback = false,
|
||||
-- statistics
|
||||
im_stat_init = false,
|
||||
avg_charge = util.mov_avg(3, 0.0),
|
||||
@@ -211,6 +219,12 @@ function facility.new(num_reactors, cooling_conf)
|
||||
table.insert(self.induction, imatrix)
|
||||
end
|
||||
|
||||
-- link an SPS RTU session
|
||||
---@param sps unit_session
|
||||
function public.add_sps(sps)
|
||||
table.insert(self.sps, sps)
|
||||
end
|
||||
|
||||
-- link an environment detector RTU session
|
||||
---@param envd unit_session
|
||||
function public.add_envd(envd)
|
||||
@@ -222,6 +236,7 @@ function facility.new(num_reactors, cooling_conf)
|
||||
function public.purge_rtu_devices(session)
|
||||
util.filter_table(self.redstone, function (s) return s.get_session_id() ~= session end)
|
||||
util.filter_table(self.induction, function (s) return s.get_session_id() ~= session end)
|
||||
util.filter_table(self.sps, function (s) return s.get_session_id() ~= session end)
|
||||
util.filter_table(self.envd, function (s) return s.get_session_id() ~= session end)
|
||||
end
|
||||
|
||||
@@ -238,6 +253,7 @@ function facility.new(num_reactors, cooling_conf)
|
||||
-- unlink RTU unit sessions if they are closed
|
||||
_unlink_disconnected_units(self.redstone)
|
||||
_unlink_disconnected_units(self.induction)
|
||||
_unlink_disconnected_units(self.sps)
|
||||
_unlink_disconnected_units(self.envd)
|
||||
|
||||
-- current state for process control
|
||||
@@ -277,6 +293,8 @@ function facility.new(num_reactors, cooling_conf)
|
||||
-- Run Process Control --
|
||||
-------------------------
|
||||
|
||||
--#region Process Control
|
||||
|
||||
local avg_charge = self.avg_charge.compute()
|
||||
local avg_inflow = self.avg_inflow.compute()
|
||||
|
||||
@@ -542,10 +560,14 @@ function facility.new(num_reactors, cooling_conf)
|
||||
next_mode = PROCESS.INACTIVE
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
------------------------------
|
||||
-- Evaluate Automatic SCRAM --
|
||||
------------------------------
|
||||
|
||||
--#region Automatic SCRAM
|
||||
|
||||
local astatus = self.ascram_status
|
||||
|
||||
if self.induction[1] ~= nil then
|
||||
@@ -659,6 +681,8 @@ function facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
-- update last mode and set next mode
|
||||
self.last_mode = self.mode
|
||||
self.mode = next_mode
|
||||
@@ -692,12 +716,33 @@ function facility.new(num_reactors, cooling_conf)
|
||||
|
||||
self.io_ctl.digital_write(IO.F_ALARM, has_alarm)
|
||||
end
|
||||
|
||||
-----------------------------
|
||||
-- Update Waste Processing --
|
||||
-----------------------------
|
||||
|
||||
local insufficent_po_rate = false
|
||||
for i = 1, #self.units do
|
||||
local u = self.units[i] ---@type reactor_unit
|
||||
if u.get_control_inf().waste_mode == WASTE_MODE.AUTO then
|
||||
if (u.get_sna_rate() * 10.0) < u.get_burn_rate() then
|
||||
insufficent_po_rate = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.waste_product == WASTE.PLUTONIUM or (self.pu_fallback and insufficent_po_rate) then
|
||||
self.current_waste_product = WASTE.PLUTONIUM
|
||||
else self.current_waste_product = self.waste_product end
|
||||
end
|
||||
|
||||
-- call the update function of all units in the facility
|
||||
-- call the update function of all units in the facility<br>
|
||||
-- additionally sets the requested auto waste mode if applicable
|
||||
function public.update_units()
|
||||
for i = 1, #self.units do
|
||||
local u = self.units[i] ---@type reactor_unit
|
||||
u.auto_set_waste(self.current_waste_product)
|
||||
u.update()
|
||||
end
|
||||
end
|
||||
@@ -721,15 +766,15 @@ function facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
|
||||
-- stop auto control
|
||||
function public.auto_stop()
|
||||
self.mode = PROCESS.INACTIVE
|
||||
end
|
||||
function public.auto_stop() self.mode = PROCESS.INACTIVE end
|
||||
|
||||
-- set automatic control configuration and start the process
|
||||
---@param config coord_auto_config configuration
|
||||
---@return table response ready state (successfully started) and current configuration (after updating)
|
||||
function public.auto_start(config)
|
||||
local ready = false
|
||||
local charge_scaler = 1000000 -- convert MFE to FE
|
||||
local gen_scaler = 1000 -- convert kFE to FE
|
||||
local ready = false
|
||||
|
||||
-- load up current limits
|
||||
local limits = {}
|
||||
@@ -749,11 +794,11 @@ function facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
|
||||
if (type(config.charge_target) == "number") and config.charge_target >= 0 then
|
||||
self.charge_setpoint = config.charge_target * 1000000 -- convert MFE to FE
|
||||
self.charge_setpoint = config.charge_target * charge_scaler
|
||||
end
|
||||
|
||||
if (type(config.gen_target) == "number") and config.gen_target >= 0 then
|
||||
self.gen_rate_setpoint = config.gen_target * 1000 -- convert kFE to FE
|
||||
self.gen_rate_setpoint = config.gen_target * gen_scaler
|
||||
end
|
||||
|
||||
if (type(config.limits) == "table") and (#config.limits == num_reactors) then
|
||||
@@ -782,7 +827,14 @@ function facility.new(num_reactors, cooling_conf)
|
||||
if ready then self.mode = self.mode_set end
|
||||
end
|
||||
|
||||
return { ready, self.mode_set, self.burn_target, self.charge_setpoint, self.gen_rate_setpoint, limits }
|
||||
return {
|
||||
ready,
|
||||
self.mode_set,
|
||||
self.burn_target,
|
||||
self.charge_setpoint / charge_scaler,
|
||||
self.gen_rate_setpoint / gen_scaler,
|
||||
limits
|
||||
}
|
||||
end
|
||||
|
||||
-- SETTINGS --
|
||||
@@ -807,15 +859,35 @@ function facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
end
|
||||
|
||||
-- set waste production
|
||||
---@param product WASTE_PRODUCT target product
|
||||
---@return WASTE_PRODUCT product newly set value, if valid
|
||||
function public.set_waste_product(product)
|
||||
if product == WASTE.PLUTONIUM or product == WASTE.POLONIUM or product == WASTE.ANTI_MATTER then
|
||||
self.waste_product = product
|
||||
end
|
||||
|
||||
return self.waste_product
|
||||
end
|
||||
|
||||
-- enable/disable plutonium fallback
|
||||
---@param enabled boolean requested state
|
||||
---@return boolean enabled newly set value
|
||||
function public.set_pu_fallback(enabled)
|
||||
self.pu_fallback = enabled == true
|
||||
return self.pu_fallback
|
||||
end
|
||||
|
||||
-- READ STATES/PROPERTIES --
|
||||
|
||||
-- get build properties of all machines
|
||||
-- get build properties of all facility devices
|
||||
---@nodiscard
|
||||
---@param inc_imatrix boolean? true/nil to include induction matrix build, false to exclude
|
||||
function public.get_build(inc_imatrix)
|
||||
---@param type RTU_UNIT_TYPE? type or nil to include only a particular unit type, or to include all if nil
|
||||
function public.get_build(type)
|
||||
local all = type == nil
|
||||
local build = {}
|
||||
|
||||
if inc_imatrix ~= false then
|
||||
if all or type == RTU_UNIT_TYPE.IMATRIX then
|
||||
build.induction = {}
|
||||
for i = 1, #self.induction do
|
||||
local matrix = self.induction[i] ---@type unit_session
|
||||
@@ -823,6 +895,14 @@ function facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
end
|
||||
|
||||
if all or type == RTU_UNIT_TYPE.SPS then
|
||||
build.sps = {}
|
||||
for i = 1, #self.sps do
|
||||
local sps = self.sps[i] ---@type unit_session
|
||||
build.sps[sps.get_device_idx()] = { sps.get_db().formed, sps.get_db().build }
|
||||
end
|
||||
end
|
||||
|
||||
return build
|
||||
end
|
||||
|
||||
@@ -844,7 +924,9 @@ function facility.new(num_reactors, cooling_conf)
|
||||
astat.gen_fault or self.mode == PROCESS.GEN_RATE_FAULT_IDLE,
|
||||
self.status_text[1],
|
||||
self.status_text[2],
|
||||
self.group_map
|
||||
self.group_map,
|
||||
self.current_waste_product,
|
||||
(self.current_waste_product == WASTE.PLUTONIUM) and (self.waste_product ~= WASTE.PLUTONIUM)
|
||||
}
|
||||
end
|
||||
|
||||
@@ -875,6 +957,18 @@ function facility.new(num_reactors, cooling_conf)
|
||||
}
|
||||
end
|
||||
|
||||
-- status of sps
|
||||
status.sps = {}
|
||||
for i = 1, #self.sps do
|
||||
local sps = self.sps[i] ---@type unit_session
|
||||
status.sps[sps.get_device_idx()] = {
|
||||
sps.is_faulted(),
|
||||
sps.get_db().formed,
|
||||
sps.get_db().state,
|
||||
sps.get_db().tanks
|
||||
}
|
||||
end
|
||||
|
||||
-- radiation monitors (environment detectors)
|
||||
status.rad_mon = {}
|
||||
for i = 1, #self.envd do
|
||||
|
||||
@@ -258,6 +258,18 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
|
||||
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
|
||||
facility.ack_all()
|
||||
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, true })
|
||||
elseif cmd == FAC_COMMAND.SET_WASTE_MODE then
|
||||
if pkt.length == 2 then
|
||||
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, facility.set_waste_product(pkt.data[2]) })
|
||||
else
|
||||
log.debug(log_header .. "CRDN set waste mode packet length mismatch")
|
||||
end
|
||||
elseif cmd == FAC_COMMAND.SET_PU_FB then
|
||||
if pkt.length == 2 then
|
||||
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2]) })
|
||||
else
|
||||
log.debug(log_header .. "CRDN set pu fallback packet length mismatch")
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "CRDN facility command unknown")
|
||||
end
|
||||
@@ -417,7 +429,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
|
||||
self.retry_times.f_builds_packet = util.time() + PARTIAL_RETRY_PERIOD
|
||||
self.acks.fac_builds = false
|
||||
|
||||
_send(SCADA_CRDN_TYPE.FAC_BUILDS, { facility.get_build(cmd.val.type == RTU_UNIT_TYPE.IMATRIX) })
|
||||
_send(SCADA_CRDN_TYPE.FAC_BUILDS, { facility.get_build(cmd.val.type) })
|
||||
end
|
||||
else
|
||||
log.error(log_header .. "unsupported data command received in in_queue (this is a bug)", true)
|
||||
|
||||
@@ -165,6 +165,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
|
||||
elseif u_type == RTU_UNIT_TYPE.SPS then
|
||||
-- super-critical phase shifter
|
||||
unit = svrs_sps.new(id, i, unit_advert, self.modbus_q)
|
||||
if type(unit) ~= "nil" then facility.add_sps(unit) end
|
||||
elseif u_type == RTU_UNIT_TYPE.ENV_DETECTOR then
|
||||
-- environment detector
|
||||
unit = svrs_envd.new(id, i, unit_advert, self.modbus_q)
|
||||
|
||||
@@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local svsessions = require("supervisor.session.svsessions")
|
||||
|
||||
local SUPERVISOR_VERSION = "v0.18.0"
|
||||
local SUPERVISOR_VERSION = "v0.19.0"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
||||
@@ -74,6 +74,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
turbines = {},
|
||||
sna = {},
|
||||
envd = {},
|
||||
sna_prod_rate = 0,
|
||||
-- redstone control
|
||||
io_ctl = nil, ---@type rs_controller
|
||||
valves = {}, ---@type unit_valves
|
||||
@@ -91,7 +92,6 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
damage_start = 0,
|
||||
damage_last = 0,
|
||||
damage_est_last = 0,
|
||||
waste_mode = WASTE_MODE.AUTO, ---@type WASTE_MODE
|
||||
waste_product = WASTE.PLUTONIUM, ---@type WASTE_PRODUCT
|
||||
status_text = { "UNKNOWN", "awaiting connection..." },
|
||||
-- logic for alarms
|
||||
@@ -224,7 +224,8 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
degraded = false,
|
||||
blade_count = 0,
|
||||
br100 = 0,
|
||||
lim_br100 = 0
|
||||
lim_br100 = 0,
|
||||
waste_mode = WASTE_MODE.AUTO ---@type WASTE_MODE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -616,7 +617,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
-- set automatic waste product if mode is set to auto
|
||||
---@param product WASTE_PRODUCT waste product to generate
|
||||
function public.auto_set_waste(product)
|
||||
if self.waste_mode == WASTE_MODE.AUTO then
|
||||
if self.db.control.waste_mode == WASTE_MODE.AUTO then
|
||||
self.waste_product = product
|
||||
_set_waste_valves(product)
|
||||
end
|
||||
@@ -669,7 +670,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
-- set waste processing mode
|
||||
---@param mode WASTE_MODE processing mode
|
||||
function public.set_waste_mode(mode)
|
||||
self.waste_mode = mode
|
||||
self.db.control.waste_mode = mode
|
||||
|
||||
if mode == WASTE_MODE.MANUAL_PLUTONIUM then
|
||||
_set_waste_valves(WASTE.PLUTONIUM)
|
||||
@@ -759,6 +760,14 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
return status
|
||||
end
|
||||
|
||||
-- get the current burn rate (actual rate)
|
||||
---@nodiscard
|
||||
function public.get_burn_rate()
|
||||
local rate = 0
|
||||
if self.plc_i ~= nil then rate = self.plc_i.get_status().act_burn_rate end
|
||||
return rate or 0
|
||||
end
|
||||
|
||||
-- get RTU statuses
|
||||
---@nodiscard
|
||||
function public.get_rtu_statuses()
|
||||
@@ -779,7 +788,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
-- status of turbines (including tanks)
|
||||
status.turbines = {}
|
||||
for i = 1, #self.turbines do
|
||||
local turbine = self.turbines[i] ---@type unit_session
|
||||
local turbine = self.turbines[i] ---@type unit_session
|
||||
status.turbines[turbine.get_device_idx()] = {
|
||||
turbine.is_faulted(),
|
||||
turbine.get_db().formed,
|
||||
@@ -788,10 +797,13 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
}
|
||||
end
|
||||
|
||||
-- basic SNA statistical information, don't send everything, it's not necessary
|
||||
status.sna = { #self.sna, public.get_sna_rate() }
|
||||
|
||||
-- radiation monitors (environment detectors)
|
||||
status.rad_mon = {}
|
||||
for i = 1, #self.envd do
|
||||
local envd = self.envd[i] ---@type unit_session
|
||||
local envd = self.envd[i] ---@type unit_session
|
||||
status.rad_mon[envd.get_device_idx()] = {
|
||||
envd.is_faulted(),
|
||||
envd.get_db().radiation
|
||||
@@ -801,6 +813,36 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
return status
|
||||
end
|
||||
|
||||
-- get the current total [max] production rate is
|
||||
---@nodiscard
|
||||
---@return number total_avail_rate
|
||||
function public.get_sna_rate()
|
||||
local total_avail_rate = 0
|
||||
|
||||
for i = 1, #self.sna do
|
||||
local db = self.sna[i].get_db() ---@type sna_session_db
|
||||
total_avail_rate = total_avail_rate + db.state.production_rate
|
||||
end
|
||||
|
||||
return total_avail_rate
|
||||
end
|
||||
|
||||
-- check plutonium and polonium estimated production rates
|
||||
---@nodiscard
|
||||
---@return number pu_rate, number po_rate
|
||||
function public.get_waste_rates()
|
||||
local pu, po = 0.0, 0.0
|
||||
local br = public.get_burn_rate()
|
||||
|
||||
if self.waste_product == WASTE.PLUTONIUM then
|
||||
pu = br / 10.0
|
||||
else
|
||||
po = math.min(br / 10.0, public.get_sna_rate())
|
||||
end
|
||||
|
||||
return pu, po
|
||||
end
|
||||
|
||||
-- get the annunciator status
|
||||
---@nodiscard
|
||||
function public.get_annunciator() return self.db.annunciator end
|
||||
@@ -821,7 +863,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
|
||||
self.status_text[2],
|
||||
self.db.control.ready,
|
||||
self.db.control.degraded,
|
||||
self.waste_mode,
|
||||
self.db.control.waste_mode,
|
||||
self.waste_product
|
||||
}
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user