Improve generator control and status displays

This commit is contained in:
Codex Agent
2025-11-22 20:35:13 +01:00
parent 2856d83600
commit 5d8b617c9e
6 changed files with 110 additions and 19 deletions

View File

@@ -44,6 +44,7 @@ class Reactor:
turbine_unit_active: list[bool] = field(default_factory=lambda: [True, True, True])
shutdown: bool = False
meltdown: bool = False
generator_auto: bool = True
poison_alerts: set[str] = field(default_factory=set)
maintenance_active: set[str] = field(default_factory=set)
@@ -115,10 +116,18 @@ class Reactor:
mass_flow_rate=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)]
primary_pumps = [
PumpState(active=self.primary_pump_active and self.primary_pump_units[idx], flow_rate=0.0, pressure=0.5)
for idx in range(2)
]
secondary_pumps = [
PumpState(active=self.secondary_pump_active and self.secondary_pump_units[idx], flow_rate=0.0, pressure=0.5)
for idx in range(2)
]
generator_states = [
GeneratorState(running=False, starting=False, spool_remaining=0.0, power_output_mw=0.0, battery_charge=1.0)
GeneratorState(
running=False, starting=False, spool_remaining=0.0, power_output_mw=0.0, battery_charge=1.0, status="OFF"
)
for _ in self.generators
]
turbine_states = [
@@ -218,6 +227,14 @@ class Reactor:
pump_state.pressure, desired_pressure, dt, self.primary_pump.spool_time
)
pump_state.active = (unit_enabled and power_ratio > 0.05) or pump_state.flow_rate > 1.0
if unit_enabled and pump_state.flow_rate < max(1.0, desired_flow * 0.8):
pump_state.status = "STARTING"
elif not unit_enabled and pump_state.flow_rate > 1.0:
pump_state.status = "STOPPING"
elif pump_state.active:
pump_state.status = "RUN"
else:
pump_state.status = "OFF"
total_flow += pump_state.flow_rate
loop_pressure = max(loop_pressure, pump_state.pressure)
state.primary_loop.mass_flow_rate = total_flow
@@ -239,6 +256,7 @@ class Reactor:
pump_state.pressure = self._ramp_value(
pump_state.pressure, state.primary_loop.pressure, dt, self.primary_pump.spool_time
)
pump_state.status = "STOPPING" if pump_state.flow_rate > 0 else "OFF"
if self.secondary_pump_active:
total_flow = 0.0
target_pressure = 12.0 * 0.75 + 2.0
@@ -257,6 +275,14 @@ class Reactor:
pump_state.pressure, desired_pressure, dt, self.secondary_pump.spool_time
)
pump_state.active = unit_enabled or pump_state.flow_rate > 1.0
if unit_enabled and pump_state.flow_rate < max(1.0, desired_flow * 0.8):
pump_state.status = "STARTING"
elif not unit_enabled and pump_state.flow_rate > 1.0:
pump_state.status = "STOPPING"
elif pump_state.active:
pump_state.status = "RUN"
else:
pump_state.status = "OFF"
total_flow += pump_state.flow_rate
loop_pressure = max(loop_pressure, pump_state.pressure)
state.secondary_loop.mass_flow_rate = total_flow
@@ -278,6 +304,7 @@ class Reactor:
pump_state.pressure = self._ramp_value(
pump_state.pressure, state.secondary_loop.pressure, dt, self.secondary_pump.spool_time
)
pump_state.status = "STOPPING" if pump_state.flow_rate > 0 else "OFF"
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:
@@ -334,8 +361,13 @@ class Reactor:
turbine_state = state.turbines[idx]
if idx in active_indices:
turbine.step(state.secondary_loop, turbine_state, steam_power_mw=power_per_unit, dt=dt)
if turbine_state.electrical_output_mw < max(1.0, power_per_unit * 0.7):
turbine_state.status = "STARTING"
else:
turbine_state.status = "RUN"
else:
self._spin_down_turbine(turbine_state, dt, turbine.spool_time)
turbine_state.status = "STOPPING" if turbine_state.electrical_output_mw > 0 else "OFF"
self._dispatch_consumer_load(state, active_indices)
def _reset_turbine_state(self, turbine_state: TurbineState) -> None:
@@ -343,6 +375,7 @@ class Reactor:
turbine_state.electrical_output_mw = 0.0
turbine_state.load_demand_mw = 0.0
turbine_state.load_supplied_mw = 0.0
turbine_state.status = "OFF"
@staticmethod
def _ramp_value(current: float, target: float, dt: float, time_constant: float) -> float:
@@ -405,6 +438,8 @@ class Reactor:
self.shutdown = True
overrides["rod_fraction"] = self.control.scram()
self._set_turbine_state(False)
if command.generator_auto is not None:
self.generator_auto = command.generator_auto
if command.power_setpoint is not None:
self.control.set_power_setpoint(command.power_setpoint)
if command.rod_manual is not None:
@@ -512,17 +547,18 @@ class Reactor:
GeneratorState(running=False, starting=False, spool_remaining=0.0, power_output_mw=0.0, battery_charge=1.0)
)
deficit = max(0.0, aux_demand - turbine_electric)
if deficit > 0.0:
for idx, gen_state in enumerate(state.generators):
if not (gen_state.running or gen_state.starting):
self.generators[idx].start(gen_state)
deficit -= self.generators[idx].rated_output_mw
if deficit <= 0:
break
elif turbine_electric > aux_demand:
for idx, gen_state in enumerate(state.generators):
if gen_state.running and not gen_state.starting:
self.generators[idx].stop(gen_state)
if self.generator_auto:
if deficit > 0.0:
for idx, gen_state in enumerate(state.generators):
if not (gen_state.running or gen_state.starting):
self.generators[idx].start(gen_state)
deficit -= self.generators[idx].rated_output_mw
if deficit <= 0:
break
elif turbine_electric > aux_demand:
for idx, gen_state in enumerate(state.generators):
if gen_state.running and not gen_state.starting:
self.generators[idx].stop(gen_state)
total_power = 0.0
remaining = max(0.0, aux_demand - turbine_electric)
@@ -640,6 +676,7 @@ class Reactor:
"turbine_units": self.turbine_unit_active,
"shutdown": self.shutdown,
"meltdown": self.meltdown,
"generator_auto": self.generator_auto,
"maintenance_active": list(self.maintenance_active),
"generators": [
{
@@ -648,6 +685,7 @@ class Reactor:
"spool_remaining": g.spool_remaining,
"power_output_mw": g.power_output_mw,
"battery_charge": g.battery_charge,
"status": g.status,
}
for g in state.generators
],
@@ -671,6 +709,7 @@ class Reactor:
self.turbine_active = metadata.get("turbine_active", any(self.turbine_unit_active))
self.shutdown = metadata.get("shutdown", self.shutdown)
self.meltdown = metadata.get("meltdown", self.meltdown)
self.generator_auto = metadata.get("generator_auto", self.generator_auto)
maint = metadata.get("maintenance_active")
if maint is not None:
self.maintenance_active = set(maint)
@@ -691,7 +730,12 @@ class Reactor:
# Back-fill pump state lists for compatibility.
if not plant.primary_pumps or len(plant.primary_pumps) < 2:
plant.primary_pumps = [
PumpState(active=self.primary_pump_active, flow_rate=plant.primary_loop.mass_flow_rate / 2, pressure=plant.primary_loop.pressure)
PumpState(
active=self.primary_pump_active,
flow_rate=plant.primary_loop.mass_flow_rate / 2,
pressure=plant.primary_loop.pressure,
status="OFF",
)
for _ in range(2)
]
if not plant.secondary_pumps or len(plant.secondary_pumps) < 2:
@@ -700,6 +744,7 @@ class Reactor:
active=self.secondary_pump_active,
flow_rate=plant.secondary_loop.mass_flow_rate / 2,
pressure=plant.secondary_loop.pressure,
status="OFF",
)
for _ in range(2)
]
@@ -726,6 +771,7 @@ class Reactor:
spool_remaining=0.0,
power_output_mw=0.0,
battery_charge=1.0,
status="OFF",
)
)
for idx, gen_state in enumerate(plant.generators):
@@ -736,6 +782,7 @@ class Reactor:
gen_state.spool_remaining = cfg.get("spool_remaining", gen_state.spool_remaining)
gen_state.power_output_mw = cfg.get("power_output_mw", gen_state.power_output_mw)
gen_state.battery_charge = cfg.get("battery_charge", gen_state.battery_charge)
gen_state.status = cfg.get("status", gen_state.status)
return plant
def _handle_heat_sink_loss(self, state: PlantState) -> None: