diff --git a/src/reactor_sim/dashboard.py b/src/reactor_sim/dashboard.py index b6ee139..7a63a58 100644 --- a/src/reactor_sim/dashboard.py +++ b/src/reactor_sim/dashboard.py @@ -557,6 +557,11 @@ class ReactorDashboard: lines.append(fmt("Xe", "Xe (xenon)", getattr(state.core, "xenon_inventory", 0.0))) lines.append(fmt("Sm", "Sm (samarium)", inventory.get("Sm", 0.0))) lines.append(fmt("I", "I (iodine)", getattr(state.core, "iodine_inventory", 0.0))) + try: + xe_penalty = -self.reactor.neutronics.xenon_penalty(state.core) + lines.append(("Xe Δρ", f"{xe_penalty:+.4f}")) + except Exception: + pass lines.append(("Neutrons (src)", f"{particles.get('n', 0.0):9.2e}")) lines.append(("Gammas", f"{particles.get('gamma', 0.0):9.2e}")) lines.append(("Alphas", f"{particles.get('alpha', 0.0):9.2e}")) diff --git a/src/reactor_sim/neutronics.py b/src/reactor_sim/neutronics.py index 8ad312d..7a67cd4 100644 --- a/src/reactor_sim/neutronics.py +++ b/src/reactor_sim/neutronics.py @@ -50,7 +50,7 @@ class NeutronDynamics: rod_term + temperature_feedback(state.fuel_temperature) - fuel_reactivity_penalty(state.burnup) - - self._xenon_penalty(state) + - self.xenon_penalty(state) ) return rho @@ -96,5 +96,9 @@ class NeutronDynamics: decay_Xe = state.xenon_inventory * self.xenon_decay_const state.xenon_inventory = max(0.0, state.xenon_inventory + (prod_Xe - decay_Xe - burn_Xe) * dt) + def xenon_penalty(self, state: CoreState) -> float: + """Return delta-rho penalty from xenon inventory (positive magnitude).""" + return self._xenon_penalty(state) + def _xenon_penalty(self, state: CoreState) -> float: return min(0.03, state.xenon_inventory * self.xenon_reactivity_coeff) diff --git a/tests/test_neutronics.py b/tests/test_neutronics.py index 298a762..3a15ce7 100644 --- a/tests/test_neutronics.py +++ b/tests/test_neutronics.py @@ -1,3 +1,5 @@ +import pytest + from reactor_sim.neutronics import NeutronDynamics from reactor_sim.state import CoreState @@ -32,3 +34,12 @@ def test_poisons_accumulate_under_power(): dynamics.update_poisons(state, dt=100.0) assert state.iodine_inventory > 0.0 assert state.xenon_inventory > 0.0 + + +def test_xenon_penalty_caps(): + dynamics = NeutronDynamics() + state = _core_state() + state.xenon_inventory = 50.0 + assert dynamics.xenon_penalty(state) == 0.03 + state.xenon_inventory = 5.0 + assert dynamics.xenon_penalty(state) == pytest.approx(0.01)