Restore three turbines and update controls

This commit is contained in:
Codex Agent
2025-11-22 18:22:24 +01:00
parent 2434034505
commit fef1d32fbe
5 changed files with 10 additions and 8 deletions

View File

@@ -12,7 +12,7 @@ All source code lives under `src/reactor_sim`. Submodules map to plant systems:
- A git remote for `origin` is configured; push changes to `origin/main` once work is complete so dashboards stay in sync. - A git remote for `origin` is configured; push changes to `origin/main` once work is complete so dashboards stay in sync.
## Operations & Control Hooks ## Operations & Control Hooks
Manual commands live in `reactor_sim.commands.ReactorCommand`. Pass a `command_provider` callable to `ReactorSimulation` to adjust rods, pumps, turbine, coolant demand, or the attached `ElectricalConsumer`. Use `ReactorCommand.scram_all()` for full shutdown, `ReactorCommand(consumer_online=True, consumer_demand=600)` to hook the grid, or toggle pumps (`primary_pump_on=False`) to simulate faults. Control helpers in `control.py` expose `set_rods`, `increment_rods`, and `scram`, and you can switch `set_manual_mode(True)` to pause the automatic rod controller. For hands-on runs, launch the curses dashboard (`FISSION_DASHBOARD=1 FISSION_REALTIME=1 python run_simulation.py`) and use the on-screen shortcuts (q quit/save, space SCRAM, p/o pumps, t turbine, 1/2 toggle individual turbines, y/u turbine maintenance, m/n pump maintenance, k core maintenance, c consumer, r reset/clear saved state, +/- rods in 0.05 steps, [/ ] consumer demand, s/d setpoint, `a` toggles auto/manual rods). Recommended startup: enable manual rods (`a`), withdraw to ~0.3 before ramping the turbine/consumer, then re-enable auto control when you want closed-loop operation. Manual commands live in `reactor_sim.commands.ReactorCommand`. Pass a `command_provider` callable to `ReactorSimulation` to adjust rods, pumps, turbine, coolant demand, or the attached `ElectricalConsumer`. Use `ReactorCommand.scram_all()` for full shutdown, `ReactorCommand(consumer_online=True, consumer_demand=600)` to hook the grid, or toggle pumps (`primary_pump_on=False`) to simulate faults. Control helpers in `control.py` expose `set_rods`, `increment_rods`, and `scram`, and you can switch `set_manual_mode(True)` to pause the automatic rod controller. For hands-on runs, launch the curses dashboard (`FISSION_DASHBOARD=1 FISSION_REALTIME=1 python run_simulation.py`) and use the on-screen shortcuts (q quit/save, space SCRAM, p/o pumps, t turbine, 1/2/3 toggle individual turbines, y/u/i turbine maintenance, m/n pump maintenance, k core maintenance, c consumer, r reset/clear saved state, +/- rods in 0.05 steps, [/ ] consumer demand, s/d setpoint, `a` toggles auto/manual rods). Recommended startup: enable manual rods (`a`), withdraw to ~0.3 before ramping the turbine/consumer, then re-enable auto control when you want closed-loop operation.
The plant now boots cold (ambient core temperature, idle pumps); scripts must sequence startup: enable pumps, gradually withdraw rods, connect the consumer after turbine spin-up, and use `ControlSystem.set_power_setpoint` to chase desired output. Set `FISSION_REALTIME=1` to run continuously with real-time pacing; optionally set `FISSION_SIM_DURATION=infinite` for indefinite runs and send SIGINT/Ctrl+C to stop. Use `FISSION_SIM_DURATION=600` (default) for bounded offline batches. The plant now boots cold (ambient core temperature, idle pumps); scripts must sequence startup: enable pumps, gradually withdraw rods, connect the consumer after turbine spin-up, and use `ControlSystem.set_power_setpoint` to chase desired output. Set `FISSION_REALTIME=1` to run continuously with real-time pacing; optionally set `FISSION_SIM_DURATION=infinite` for indefinite runs and send SIGINT/Ctrl+C to stop. Use `FISSION_SIM_DURATION=600` (default) for bounded offline batches.
## Coding Style & Naming Conventions ## Coding Style & Naming Conventions

View File

@@ -52,8 +52,8 @@ class ReactorDashboard:
DashboardKey("p", "Toggle primary pump"), DashboardKey("p", "Toggle primary pump"),
DashboardKey("o", "Toggle secondary pump"), DashboardKey("o", "Toggle secondary pump"),
DashboardKey("t", "Toggle turbine"), DashboardKey("t", "Toggle turbine"),
DashboardKey("1/2", "Toggle turbine units 1-2"), DashboardKey("1/2/3", "Toggle turbine units 1-3"),
DashboardKey("y/u", "Maintain turbine 1/2"), DashboardKey("y/u/i", "Maintain turbine 1/2/3"),
DashboardKey("c", "Toggle consumer"), DashboardKey("c", "Toggle consumer"),
DashboardKey("r", "Reset & clear state"), DashboardKey("r", "Reset & clear state"),
DashboardKey("m", "Maintain primary pump"), DashboardKey("m", "Maintain primary pump"),
@@ -162,6 +162,8 @@ class ReactorDashboard:
self._queue_command(ReactorCommand.maintain("turbine_1")) self._queue_command(ReactorCommand.maintain("turbine_1"))
elif ch in (ord("u"), ord("U")): elif ch in (ord("u"), ord("U")):
self._queue_command(ReactorCommand.maintain("turbine_2")) self._queue_command(ReactorCommand.maintain("turbine_2"))
elif ch in (ord("i"), ord("I")):
self._queue_command(ReactorCommand.maintain("turbine_3"))
def _queue_command(self, command: ReactorCommand) -> None: def _queue_command(self, command: ReactorCommand) -> None:
if self.pending_command is None: if self.pending_command is None:
@@ -321,8 +323,8 @@ class ReactorDashboard:
tips = [ tips = [
"Start pumps before withdrawing rods.", "Start pumps before withdrawing rods.",
"Bring turbine and consumer online after thermal stabilization.", "Bring turbine and consumer online after thermal stabilization.",
"Toggle turbine units (1/2) for staggered maintenance.", "Toggle turbine units (1/2/3) for staggered maintenance.",
"Use m/n/k/y/u to request maintenance (stop equipment first).", "Use m/n/k/y/u/i to request maintenance (stop equipment first).",
"Press 'r' to reset/clear state if you want a cold start.", "Press 'r' to reset/clear state if you want a cold start.",
"Watch component health to avoid automatic trips.", "Watch component health to avoid automatic trips.",
] ]

View File

@@ -56,7 +56,7 @@ class HealthMonitor:
"primary_pump": ComponentHealth("primary_pump"), "primary_pump": ComponentHealth("primary_pump"),
"secondary_pump": ComponentHealth("secondary_pump"), "secondary_pump": ComponentHealth("secondary_pump"),
} }
for idx in range(2): for idx in range(3):
name = f"turbine_{idx + 1}" name = f"turbine_{idx + 1}"
self.components[name] = ComponentHealth(name) self.components[name] = ComponentHealth(name)
self.failure_log: list[str] = [] self.failure_log: list[str] = []

View File

@@ -59,7 +59,7 @@ class Reactor:
secondary_pump=Pump(nominal_flow=16_000.0, efficiency=0.85), secondary_pump=Pump(nominal_flow=16_000.0, efficiency=0.85),
thermal=ThermalSolver(), thermal=ThermalSolver(),
steam_generator=SteamGenerator(), steam_generator=SteamGenerator(),
turbines=[Turbine() for _ in range(2)], turbines=[Turbine() for _ in range(3)],
atomic_model=atomic_model, atomic_model=atomic_model,
consumer=ElectricalConsumer(name="Grid", demand_mw=800.0, online=False), consumer=ElectricalConsumer(name="Grid", demand_mw=800.0, online=False),
health_monitor=HealthMonitor(), health_monitor=HealthMonitor(),

View File

@@ -37,7 +37,7 @@ def test_health_monitor_flags_core_failure():
reactor = Reactor.default() reactor = Reactor.default()
state = reactor.initial_state() state = reactor.initial_state()
state.core.fuel_temperature = constants.MAX_CORE_TEMPERATURE state.core.fuel_temperature = constants.MAX_CORE_TEMPERATURE
failures = reactor.health_monitor.evaluate(state, True, True, [True, True], dt=200.0) failures = reactor.health_monitor.evaluate(state, True, True, [True, True, True], dt=200.0)
assert "core" in failures assert "core" in failures
reactor._handle_failure("core") reactor._handle_failure("core")
assert reactor.shutdown is True assert reactor.shutdown is True