Add generator power model and meltdown handling
This commit is contained in:
@@ -42,6 +42,7 @@ class ReactorDashboard:
|
||||
self.sim: Optional[ReactorSimulation] = None
|
||||
self.quit_requested = False
|
||||
self.reset_requested = False
|
||||
self._last_state: Optional[PlantState] = None
|
||||
self.log_buffer: deque[str] = deque(maxlen=4)
|
||||
self._log_handler: Optional[logging.Handler] = None
|
||||
self._previous_handlers: list[logging.Handler] = []
|
||||
@@ -49,19 +50,20 @@ class ReactorDashboard:
|
||||
self.keys = [
|
||||
DashboardKey("q", "Quit & save"),
|
||||
DashboardKey("space", "SCRAM"),
|
||||
DashboardKey("p", "Toggle primary pump"),
|
||||
DashboardKey("o", "Toggle secondary pump"),
|
||||
DashboardKey("g", "Toggle primary pump 1"),
|
||||
DashboardKey("h", "Toggle primary pump 2"),
|
||||
DashboardKey("j", "Toggle secondary pump 1"),
|
||||
DashboardKey("k", "Toggle secondary pump 2"),
|
||||
DashboardKey("b", "Toggle generator 1"),
|
||||
DashboardKey("v", "Toggle generator 2"),
|
||||
DashboardKey("t", "Toggle turbine"),
|
||||
DashboardKey("1/2/3", "Toggle turbine units 1-3"),
|
||||
DashboardKey("y/u/i", "Maintain turbine 1/2/3"),
|
||||
DashboardKey("c", "Toggle consumer"),
|
||||
DashboardKey("r", "Reset & clear state"),
|
||||
DashboardKey("m", "Maintain primary pump"),
|
||||
DashboardKey("n", "Maintain secondary pump"),
|
||||
DashboardKey("m/n", "Maintain primary pumps 1/2"),
|
||||
DashboardKey(",/.", "Maintain secondary pumps 1/2"),
|
||||
DashboardKey("B/V", "Maintain generator 1/2"),
|
||||
DashboardKey("k", "Maintain core (requires shutdown)"),
|
||||
DashboardKey("+/-", "Withdraw/insert rods"),
|
||||
DashboardKey("[/]", "Adjust consumer demand −/+50 MW"),
|
||||
@@ -95,6 +97,7 @@ class ReactorDashboard:
|
||||
self.sim.start_state = self.start_state
|
||||
try:
|
||||
for state in self.sim.run():
|
||||
self._last_state = state
|
||||
self._draw(stdscr, state)
|
||||
self._handle_input(stdscr)
|
||||
if self.quit_requested or self.reset_requested:
|
||||
@@ -127,9 +130,10 @@ class ReactorDashboard:
|
||||
if ch == ord(" "):
|
||||
self._queue_command(ReactorCommand.scram_all())
|
||||
elif ch in (ord("p"), ord("P")):
|
||||
self._queue_command(ReactorCommand(primary_pump_on=not self.reactor.primary_pump_active))
|
||||
# Deprecated master toggles ignored.
|
||||
continue
|
||||
elif ch in (ord("o"), ord("O")):
|
||||
self._queue_command(ReactorCommand(secondary_pump_on=not self.reactor.secondary_pump_active))
|
||||
continue
|
||||
elif ch in (ord("g"), ord("G")):
|
||||
self._toggle_primary_pump_unit(0)
|
||||
elif ch in (ord("h"), ord("H")):
|
||||
@@ -138,6 +142,10 @@ class ReactorDashboard:
|
||||
self._toggle_secondary_pump_unit(0)
|
||||
elif ch in (ord("k"), ord("K")):
|
||||
self._toggle_secondary_pump_unit(1)
|
||||
elif ch in (ord("b"), ord("B")):
|
||||
self._toggle_generator_unit(0)
|
||||
elif ch in (ord("v"), ord("V")):
|
||||
self._toggle_generator_unit(1)
|
||||
elif ch in (ord("t"), ord("T")):
|
||||
self._queue_command(ReactorCommand(turbine_on=not self.reactor.turbine_active))
|
||||
elif ord("1") <= ch <= ord("9"):
|
||||
@@ -167,11 +175,19 @@ class ReactorDashboard:
|
||||
elif ch in (ord("a"), ord("A")):
|
||||
self._queue_command(ReactorCommand(rod_manual=not self.reactor.control.manual_control))
|
||||
elif ch in (ord("m"), ord("M")):
|
||||
self._queue_command(ReactorCommand.maintain("primary_pump"))
|
||||
self._queue_command(ReactorCommand.maintain("primary_pump_1"))
|
||||
elif ch in (ord("n"), ord("N")):
|
||||
self._queue_command(ReactorCommand.maintain("secondary_pump"))
|
||||
self._queue_command(ReactorCommand.maintain("primary_pump_2"))
|
||||
elif ch in (ord("k"), ord("K")):
|
||||
self._queue_command(ReactorCommand.maintain("core"))
|
||||
elif ch == ord(","):
|
||||
self._queue_command(ReactorCommand.maintain("secondary_pump_1"))
|
||||
elif ch == ord("."):
|
||||
self._queue_command(ReactorCommand.maintain("secondary_pump_2"))
|
||||
elif ch in (ord("B"),):
|
||||
self._queue_command(ReactorCommand.maintain("generator_1"))
|
||||
elif ch in (ord("V"),):
|
||||
self._queue_command(ReactorCommand.maintain("generator_2"))
|
||||
elif ch in (ord("y"), ord("Y")):
|
||||
self._queue_command(ReactorCommand.maintain("turbine_1"))
|
||||
elif ch in (ord("u"), ord("U")):
|
||||
@@ -216,6 +232,13 @@ class ReactorDashboard:
|
||||
current = self.reactor.secondary_pump_units[index]
|
||||
self._queue_command(ReactorCommand(secondary_pumps={index + 1: not current}))
|
||||
|
||||
def _toggle_generator_unit(self, index: int) -> None:
|
||||
current = False
|
||||
if self._last_state and index < len(self._last_state.generators):
|
||||
gen = self._last_state.generators[index]
|
||||
current = gen.running or gen.starting
|
||||
self._queue_command(ReactorCommand(generator_units={index + 1: not current}))
|
||||
|
||||
def _request_reset(self) -> None:
|
||||
self.reset_requested = True
|
||||
if self.sim:
|
||||
@@ -326,6 +349,12 @@ class ReactorDashboard:
|
||||
("Steam Quality", f"{state.secondary_loop.steam_quality:5.2f}"),
|
||||
],
|
||||
)
|
||||
y = self._draw_section(
|
||||
win,
|
||||
y,
|
||||
"Generators",
|
||||
self._generator_lines(state),
|
||||
)
|
||||
consumer_status = "n/a"
|
||||
consumer_demand = 0.0
|
||||
if self.reactor.consumer:
|
||||
@@ -368,7 +397,7 @@ class ReactorDashboard:
|
||||
"Start pumps before withdrawing rods.",
|
||||
"Bring turbine and consumer online after thermal stabilization.",
|
||||
"Toggle turbine units (1/2/3) for staggered maintenance.",
|
||||
"Use m/n/k/y/u/i to request maintenance (stop equipment first).",
|
||||
"Use m/n/,/. for pump maintenance; B/V for generators.",
|
||||
"Press 'r' to reset/clear state if you want a cold start.",
|
||||
"Watch component health to avoid automatic trips.",
|
||||
]
|
||||
@@ -471,6 +500,17 @@ class ReactorDashboard:
|
||||
return [("Active", "None")]
|
||||
return [(comp, "IN PROGRESS") for comp in sorted(self.reactor.maintenance_active)]
|
||||
|
||||
def _generator_lines(self, state: PlantState) -> list[tuple[str, str]]:
|
||||
if not state.generators:
|
||||
return [("Status", "n/a")]
|
||||
lines: list[tuple[str, str]] = []
|
||||
for idx, gen in enumerate(state.generators):
|
||||
status = "RUN" if gen.running else "START" if gen.starting else "OFF"
|
||||
spool = f" spool {gen.spool_remaining:4.1f}s" if gen.starting else ""
|
||||
lines.append((f"Gen{idx + 1}", f"{status} {gen.power_output_mw:6.1f} MW{spool}"))
|
||||
lines.append((f" Battery", f"{gen.battery_charge*100:5.1f}%"))
|
||||
return lines
|
||||
|
||||
def _draw_health_bars(self, win: "curses._CursesWindow", start_y: int) -> int:
|
||||
height, width = win.getmaxyx()
|
||||
inner_width = width - 4
|
||||
|
||||
Reference in New Issue
Block a user