Add generator power model and meltdown handling
This commit is contained in:
68
src/reactor_sim/generator.py
Normal file
68
src/reactor_sim/generator.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""Auxiliary diesel generator model with spool dynamics."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from . import constants
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class GeneratorState:
|
||||
running: bool
|
||||
starting: bool
|
||||
spool_remaining: float
|
||||
power_output_mw: float
|
||||
battery_charge: float
|
||||
|
||||
|
||||
@dataclass
|
||||
class DieselGenerator:
|
||||
rated_output_mw: float = 50.0
|
||||
spool_time: float = constants.GENERATOR_SPOOL_TIME
|
||||
|
||||
def start(self, state: GeneratorState) -> None:
|
||||
if state.running or state.starting:
|
||||
return
|
||||
if state.battery_charge <= 0.05:
|
||||
LOGGER.warning("Generator start failed: insufficient battery")
|
||||
return
|
||||
state.starting = True
|
||||
state.spool_remaining = self.spool_time
|
||||
LOGGER.info("Generator starting (spool %.0fs)", self.spool_time)
|
||||
|
||||
def stop(self, state: GeneratorState) -> None:
|
||||
if not (state.running or state.starting):
|
||||
return
|
||||
state.running = False
|
||||
state.starting = False
|
||||
state.spool_remaining = 0.0
|
||||
state.power_output_mw = 0.0
|
||||
LOGGER.info("Generator stopped")
|
||||
|
||||
def step(self, state: GeneratorState, load_demand_mw: float, dt: float) -> float:
|
||||
"""Advance generator dynamics and return delivered power."""
|
||||
if state.starting:
|
||||
state.spool_remaining = max(0.0, state.spool_remaining - dt)
|
||||
state.power_output_mw = self.rated_output_mw * (1.0 - state.spool_remaining / max(self.spool_time, 1e-6))
|
||||
if state.spool_remaining <= 0.0:
|
||||
state.starting = False
|
||||
state.running = True
|
||||
LOGGER.info("Generator online at %.1f MW", self.rated_output_mw)
|
||||
elif state.running:
|
||||
available = self.rated_output_mw
|
||||
state.power_output_mw = min(available, load_demand_mw)
|
||||
else:
|
||||
state.power_output_mw = 0.0
|
||||
|
||||
if state.running:
|
||||
state.battery_charge = min(1.0, state.battery_charge + 0.02 * dt)
|
||||
elif state.starting:
|
||||
state.battery_charge = max(0.0, state.battery_charge - 0.01 * dt)
|
||||
else:
|
||||
state.battery_charge = max(0.0, state.battery_charge - 0.001 * dt)
|
||||
|
||||
return state.power_output_mw
|
||||
Reference in New Issue
Block a user