feat: add reactor control persistence and tests

This commit is contained in:
Andrii Prokhorov
2025-11-21 17:11:00 +02:00
commit cc7fba4e7a
43 changed files with 1435 additions and 0 deletions

56
src/reactor_sim/fuel.py Normal file
View File

@@ -0,0 +1,56 @@
"""Fuel behavior, burnup, and decay heat modeling."""
from __future__ import annotations
from dataclasses import dataclass, field
import logging
from . import constants
from .atomic import Atom, AtomicPhysics, FissionEvent, make_atom
from .state import CoreState
LOGGER = logging.getLogger(__name__)
def fuel_reactivity_penalty(burnup: float) -> float:
"""Simplistic model that penalizes reactivity as burnup increases."""
# Burnup is 0-1, penalty grows quadratically to mimic depletion.
return 0.4 * burnup**2
def decay_heat_fraction(burnup: float) -> float:
"""Return remaining decay heat fraction relative to nominal power."""
return min(0.07 + 0.2 * burnup, 0.15)
@dataclass
class FuelAssembly:
enrichment: float # fraction U-235
mass_kg: float
fissile_atom: Atom = field(default_factory=lambda: make_atom(92, 143))
atomic_physics: AtomicPhysics = field(default_factory=AtomicPhysics)
def available_energy_j(self, state: CoreState) -> float:
fraction_remaining = max(0.0, 1.0 - state.burnup)
return self.mass_kg * constants.FUEL_ENERGY_DENSITY * fraction_remaining
def simulate_electron_hit(self) -> FissionEvent:
return self.atomic_physics.electron_induced_fission(self.fissile_atom)
def prompt_energy_rate(self, flux: float, control_fraction: float) -> tuple[float, FissionEvent]:
"""Compute MW thermal from prompt fission by sampling atomic physics."""
event = self.simulate_electron_hit()
effective_flux = max(0.0, flux * max(0.0, 1.0 - control_fraction))
atoms = self.mass_kg / self.fissile_atom.atomic_mass_kg
event_rate = effective_flux * constants.ELECTRON_FISSION_CROSS_SECTION * atoms * self.enrichment
power_watts = event_rate * event.energy_mev * constants.MEV_TO_J
power_mw = power_watts / constants.MEGAWATT
LOGGER.debug(
"Prompt fission products %s-%d + %s-%d yielding %.2f MW",
event.products[0].symbol,
event.products[0].mass_number,
event.products[1].symbol,
event.products[1].mass_number,
power_mw,
)
return max(0.0, power_mw), event