Show per-pump status and per-turbine output

This commit is contained in:
Codex Agent
2025-11-22 18:43:53 +01:00
parent 5bd9992ed0
commit f626c99f44
3 changed files with 73 additions and 6 deletions

View File

@@ -275,7 +275,8 @@ class ReactorDashboard:
y, y,
"Primary Loop", "Primary Loop",
[ [
("Pump", "ON" if self.reactor.primary_pump_active else "OFF"), ("Pump1", self._pump_status(state.primary_pumps, 0)),
("Pump2", self._pump_status(state.primary_pumps, 1)),
("Flow", f"{state.primary_loop.mass_flow_rate:7.0f} kg/s"), ("Flow", f"{state.primary_loop.mass_flow_rate:7.0f} kg/s"),
("Inlet Temp", f"{state.primary_loop.temperature_in:7.1f} K"), ("Inlet Temp", f"{state.primary_loop.temperature_in:7.1f} K"),
("Outlet Temp", f"{state.primary_loop.temperature_out:7.1f} K"), ("Outlet Temp", f"{state.primary_loop.temperature_out:7.1f} K"),
@@ -287,7 +288,8 @@ class ReactorDashboard:
y, y,
"Secondary Loop", "Secondary Loop",
[ [
("Pump", "ON" if self.reactor.secondary_pump_active else "OFF"), ("Pump1", self._pump_status(state.secondary_pumps, 0)),
("Pump2", self._pump_status(state.secondary_pumps, 1)),
("Flow", f"{state.secondary_loop.mass_flow_rate:7.0f} kg/s"), ("Flow", f"{state.secondary_loop.mass_flow_rate:7.0f} kg/s"),
("Inlet Temp", f"{state.secondary_loop.temperature_in:7.1f} K"), ("Inlet Temp", f"{state.secondary_loop.temperature_in:7.1f} K"),
("Pressure", f"{state.secondary_loop.pressure:5.2f} MPa"), ("Pressure", f"{state.secondary_loop.pressure:5.2f} MPa"),
@@ -305,6 +307,15 @@ class ReactorDashboard:
"Turbine / Grid", "Turbine / Grid",
[ [
("Turbines", " ".join(self._turbine_status_lines())), ("Turbines", " ".join(self._turbine_status_lines())),
("Unit1 Elec", f"{state.turbines[0].electrical_output_mw:7.1f} MW" if state.turbines else "n/a"),
(
"Unit2 Elec",
f"{state.turbines[1].electrical_output_mw:7.1f} MW" if len(state.turbines) > 1 else "n/a",
),
(
"Unit3 Elec",
f"{state.turbines[2].electrical_output_mw:7.1f} MW" if len(state.turbines) > 2 else "n/a",
),
("Electrical", f"{state.total_electrical_output():7.1f} MW"), ("Electrical", f"{state.total_electrical_output():7.1f} MW"),
("Load", f"{self._total_load_supplied(state):7.1f}/{self._total_load_demand(state):7.1f} MW"), ("Load", f"{self._total_load_supplied(state):7.1f}/{self._total_load_demand(state):7.1f} MW"),
("Consumer", f"{consumer_status}"), ("Consumer", f"{consumer_status}"),
@@ -421,6 +432,12 @@ class ReactorDashboard:
return [("Active", "None")] return [("Active", "None")]
return [(comp, "IN PROGRESS") for comp in sorted(self.reactor.maintenance_active)] return [(comp, "IN PROGRESS") for comp in sorted(self.reactor.maintenance_active)]
def _pump_status(self, pumps: list, index: int) -> str:
if index >= len(pumps):
return "n/a"
state = pumps[index]
return f"{'ON ' if state.active else 'OFF'} {state.flow_rate:6.0f} kg/s"
def _draw_health_bar(self, win: "curses._CursesWindow", start_y: int) -> None: def _draw_health_bar(self, win: "curses._CursesWindow", start_y: int) -> None:
height, width = win.getmaxyx() height, width = win.getmaxyx()
if start_y >= height - 2: if start_y >= height - 2:

View File

@@ -14,7 +14,7 @@ from .control import ControlSystem
from .failures import HealthMonitor from .failures import HealthMonitor
from .fuel import FuelAssembly, decay_heat_fraction from .fuel import FuelAssembly, decay_heat_fraction
from .neutronics import NeutronDynamics from .neutronics import NeutronDynamics
from .state import CoolantLoopState, CoreState, PlantState, TurbineState from .state import CoolantLoopState, CoreState, PlantState, PumpState, TurbineState
from .thermal import ThermalSolver, heat_transfer from .thermal import ThermalSolver, heat_transfer
from .turbine import SteamGenerator, Turbine from .turbine import SteamGenerator, Turbine
@@ -102,6 +102,8 @@ class Reactor:
mass_flow_rate=0.0, mass_flow_rate=0.0,
steam_quality=0.0, steam_quality=0.0,
) )
primary_pumps = [PumpState(active=self.primary_pump_active, flow_rate=0.0, pressure=0.5) for _ in range(2)]
secondary_pumps = [PumpState(active=self.secondary_pump_active, flow_rate=0.0, pressure=0.5) for _ in range(2)]
turbine_states = [ turbine_states = [
TurbineState( TurbineState(
steam_enthalpy=2_000.0, steam_enthalpy=2_000.0,
@@ -113,7 +115,14 @@ class Reactor:
) )
for _ in self.turbines for _ in self.turbines
] ]
return PlantState(core=core, primary_loop=primary, secondary_loop=secondary, turbines=turbine_states) return PlantState(
core=core,
primary_loop=primary,
secondary_loop=secondary,
turbines=turbine_states,
primary_pumps=primary_pumps,
secondary_pumps=secondary_pumps,
)
def step(self, state: PlantState, dt: float, command: ReactorCommand | None = None) -> None: def step(self, state: PlantState, dt: float, command: ReactorCommand | None = None) -> None:
if self.shutdown: if self.shutdown:
@@ -151,15 +160,41 @@ class Reactor:
pump_demand = overrides.get("coolant_demand", self.control.coolant_demand(state.primary_loop)) pump_demand = overrides.get("coolant_demand", self.control.coolant_demand(state.primary_loop))
if self.primary_pump_active: if self.primary_pump_active:
self.primary_pump.step(state.primary_loop, pump_demand) total_flow = 0.0
pressure = 12.0 * pump_demand + 2.0
for pump_state in state.primary_pumps:
flow = self.primary_pump.flow_rate(pump_demand)
pump_state.active = True
pump_state.flow_rate = flow
pump_state.pressure = pressure
total_flow += flow
state.primary_loop.mass_flow_rate = total_flow
state.primary_loop.pressure = pressure
else: else:
state.primary_loop.mass_flow_rate = 0.0 state.primary_loop.mass_flow_rate = 0.0
state.primary_loop.pressure = 0.5 state.primary_loop.pressure = 0.5
for pump_state in state.primary_pumps:
pump_state.active = False
pump_state.flow_rate = 0.0
pump_state.pressure = state.primary_loop.pressure
if self.secondary_pump_active: if self.secondary_pump_active:
self.secondary_pump.step(state.secondary_loop, 0.75) total_flow = 0.0
pressure = 12.0 * 0.75 + 2.0
for pump_state in state.secondary_pumps:
flow = self.secondary_pump.flow_rate(0.75)
pump_state.active = True
pump_state.flow_rate = flow
pump_state.pressure = pressure
total_flow += flow
state.secondary_loop.mass_flow_rate = total_flow
state.secondary_loop.pressure = pressure
else: else:
state.secondary_loop.mass_flow_rate = 0.0 state.secondary_loop.mass_flow_rate = 0.0
state.secondary_loop.pressure = 0.5 state.secondary_loop.pressure = 0.5
for pump_state in state.secondary_pumps:
pump_state.active = False
pump_state.flow_rate = 0.0
pump_state.pressure = state.secondary_loop.pressure
self.thermal.step_core(state.core, state.primary_loop, total_power, dt) self.thermal.step_core(state.core, state.primary_loop, total_power, dt)
if not self.secondary_pump_active or state.secondary_loop.mass_flow_rate <= 1.0: if not self.secondary_pump_active or state.secondary_loop.mass_flow_rate <= 1.0:

View File

@@ -54,12 +54,21 @@ class TurbineState:
load_supplied_mw: float = 0.0 load_supplied_mw: float = 0.0
@dataclass
class PumpState:
active: bool
flow_rate: float
pressure: float
@dataclass @dataclass
class PlantState: class PlantState:
core: CoreState core: CoreState
primary_loop: CoolantLoopState primary_loop: CoolantLoopState
secondary_loop: CoolantLoopState secondary_loop: CoolantLoopState
turbines: list[TurbineState] turbines: list[TurbineState]
primary_pumps: list[PumpState] = field(default_factory=list)
secondary_pumps: list[PumpState] = field(default_factory=list)
time_elapsed: float = field(default=0.0) time_elapsed: float = field(default=0.0)
def snapshot(self) -> dict[str, float]: def snapshot(self) -> dict[str, float]:
@@ -73,6 +82,8 @@ class PlantState:
"turbine_electric": self.total_electrical_output(), "turbine_electric": self.total_electrical_output(),
"products": self.core.fission_product_inventory, "products": self.core.fission_product_inventory,
"particles": self.core.emitted_particles, "particles": self.core.emitted_particles,
"primary_pumps": [pump.active for pump in self.primary_pumps],
"secondary_pumps": [pump.active for pump in self.secondary_pumps],
} }
def total_electrical_output(self) -> float: def total_electrical_output(self) -> float:
@@ -92,10 +103,14 @@ class PlantState:
old_turbine = data.get("turbine") old_turbine = data.get("turbine")
turbines_blob = [old_turbine] if old_turbine else [] turbines_blob = [old_turbine] if old_turbine else []
turbines = [TurbineState(**t) for t in turbines_blob] turbines = [TurbineState(**t) for t in turbines_blob]
prim_pumps_blob = data.get("primary_pumps", [])
sec_pumps_blob = data.get("secondary_pumps", [])
return cls( return cls(
core=CoreState(**core_blob, fission_product_inventory=inventory, emitted_particles=particles), core=CoreState(**core_blob, fission_product_inventory=inventory, emitted_particles=particles),
primary_loop=CoolantLoopState(**data["primary_loop"]), primary_loop=CoolantLoopState(**data["primary_loop"]),
secondary_loop=CoolantLoopState(**data["secondary_loop"]), secondary_loop=CoolantLoopState(**data["secondary_loop"]),
turbines=turbines, turbines=turbines,
primary_pumps=[PumpState(**p) for p in prim_pumps_blob],
secondary_pumps=[PumpState(**p) for p in sec_pumps_blob],
time_elapsed=data.get("time_elapsed", 0.0), time_elapsed=data.get("time_elapsed", 0.0),
) )