Surface protection warnings in dashboard

This commit is contained in:
Codex Agent
2025-11-23 10:45:10 +01:00
parent 4f4e966d1d
commit 710459b521

View File

@@ -44,7 +44,7 @@ class ReactorDashboard:
self.reset_requested = False self.reset_requested = False
self._last_state: Optional[PlantState] = None self._last_state: Optional[PlantState] = None
self._trend_history: deque[tuple[float, float, float]] = deque(maxlen=120) self._trend_history: deque[tuple[float, float, float]] = deque(maxlen=120)
self.log_buffer: deque[str] = deque(maxlen=4) self.log_buffer: deque[str] = deque(maxlen=8)
self._log_handler: Optional[logging.Handler] = None self._log_handler: Optional[logging.Handler] = None
self._previous_handlers: list[logging.Handler] = [] self._previous_handlers: list[logging.Handler] = []
self._logger = logging.getLogger("reactor_sim") self._logger = logging.getLogger("reactor_sim")
@@ -297,7 +297,7 @@ class ReactorDashboard:
def _draw(self, stdscr: "curses._CursesWindow", state: PlantState) -> None: def _draw(self, stdscr: "curses._CursesWindow", state: PlantState) -> None:
stdscr.erase() stdscr.erase()
height, width = stdscr.getmaxyx() height, width = stdscr.getmaxyx()
min_status = 4 min_status = 6
if height < min_status + 12 or width < 70: if height < min_status + 12 or width < 70:
stdscr.addstr( stdscr.addstr(
0, 0,
@@ -308,8 +308,9 @@ class ReactorDashboard:
stdscr.refresh() stdscr.refresh()
return return
status_height = min_status log_rows = max(2, min(len(self.log_buffer) + 2, 8))
data_height = height - status_height status_height = min(height - 1, max(min_status, min_status + log_rows))
data_height = max(1, height - status_height)
right_width = max(28, width // 3) right_width = max(28, width // 3)
left_width = width - right_width left_width = width - right_width
if left_width < 50: if left_width < 50:
@@ -442,6 +443,7 @@ class ReactorDashboard:
) )
right_y = self._draw_section(right_win, right_y, "Generators", self._generator_lines(state)) right_y = self._draw_section(right_win, right_y, "Generators", self._generator_lines(state))
right_y = self._draw_section(right_win, right_y, "Power Stats", self._power_lines(state)) right_y = self._draw_section(right_win, right_y, "Power Stats", self._power_lines(state))
right_y = self._draw_section(right_win, right_y, "Protections / Warnings", self._protection_lines(state))
right_y = self._draw_section(right_win, right_y, "Maintenance", self._maintenance_lines()) right_y = self._draw_section(right_win, right_y, "Maintenance", self._maintenance_lines())
self._draw_health_bars(right_win, right_y) self._draw_health_bars(right_win, right_y)
@@ -487,6 +489,8 @@ class ReactorDashboard:
f"Failures: {', '.join(self.reactor.health_monitor.failure_log)}", f"Failures: {', '.join(self.reactor.health_monitor.failure_log)}",
curses.color_pair(4) | curses.A_BOLD, curses.color_pair(4) | curses.A_BOLD,
) )
log_y = 4
else:
log_y = 3 log_y = 3
for record in list(self.log_buffer): for record in list(self.log_buffer):
if log_y >= win.getmaxyx()[0] - 1: if log_y >= win.getmaxyx()[0] - 1:
@@ -599,6 +603,40 @@ class ReactorDashboard:
] ]
return lines return lines
def _protection_lines(self, state: PlantState) -> list[tuple[str, str]]:
lines: list[tuple[str, str]] = []
lines.append(("SCRAM", "ACTIVE" if self.reactor.shutdown else "CLEAR"))
if self.reactor.meltdown:
lines.append(("Meltdown", "IN PROGRESS"))
sec_flow_low = state.secondary_loop.mass_flow_rate <= 1.0 or not self.reactor.secondary_pump_active
heat_sink_risk = sec_flow_low and state.core.power_output_mw > 50.0
if heat_sink_risk:
heat_text = "TRIPPED low secondary flow >50 MW"
elif sec_flow_low:
heat_text = "ARMED (secondary off/low flow)"
else:
heat_text = "OK"
lines.append(("Heat sink", heat_text))
draws = getattr(state, "aux_draws", {}) or {}
demand = draws.get("total_demand", 0.0)
supplied = draws.get("supplied", 0.0)
if demand > 0.1 and supplied + 1e-6 < demand:
aux_text = f"DEFICIT {supplied:5.1f}/{demand:5.1f} MW"
elif demand > 0.1:
aux_text = f"OK {supplied:5.1f}/{demand:5.1f} MW"
else:
aux_text = "Idle"
lines.append(("Aux power", aux_text))
reliefs = []
if self.reactor.primary_relief_open:
reliefs.append("Primary")
if self.reactor.secondary_relief_open:
reliefs.append("Secondary")
lines.append(("Relief valves", ", ".join(reliefs) if reliefs else "Closed"))
return lines
def _steam_pressure(self, state: PlantState) -> float: def _steam_pressure(self, state: PlantState) -> float:
# Only report steam pressure if quality/flow indicate steam is present. # Only report steam pressure if quality/flow indicate steam is present.
if state.secondary_loop.steam_quality < 0.05 or state.secondary_loop.mass_flow_rate < 100.0: if state.secondary_loop.steam_quality < 0.05 or state.secondary_loop.mass_flow_rate < 100.0: