"""Thermal hydraulics approximations.""" from __future__ import annotations from dataclasses import dataclass import logging import math from . import constants from .state import CoolantLoopState, CoreState LOGGER = logging.getLogger(__name__) def heat_transfer(primary: CoolantLoopState, secondary: CoolantLoopState, core_power_mw: float) -> float: """Return MW transferred to the secondary loop.""" delta_t = max(0.0, primary.temperature_out - secondary.temperature_in) conductance = 0.15 # steam generator effectiveness efficiency = 1.0 - math.exp(-conductance * delta_t) transferred = min(core_power_mw, core_power_mw * efficiency) LOGGER.debug("Heat transfer %.2f MW with ΔT=%.1fK", transferred, delta_t) return transferred def temperature_rise(power_mw: float, mass_flow: float) -> float: if mass_flow <= 0: return 0.0 return (power_mw * constants.MEGAWATT) / (mass_flow * constants.COOLANT_HEAT_CAPACITY) @dataclass class ThermalSolver: primary_volume_m3: float = 300.0 def step_core(self, core: CoreState, primary: CoolantLoopState, power_mw: float, dt: float) -> None: temp_rise = temperature_rise(power_mw, primary.mass_flow_rate) primary.temperature_out = primary.temperature_in + temp_rise # Fuel heats from any power not immediately convected away, and cools toward the primary outlet. heating = 0.005 * max(0.0, power_mw - temp_rise) * dt cooling = 0.05 * max(0.0, core.fuel_temperature - primary.temperature_out) * dt core.fuel_temperature += heating - cooling # Keep fuel temperature bounded and never below the coolant outlet temperature. core.fuel_temperature = min(max(primary.temperature_out, core.fuel_temperature), constants.MAX_CORE_TEMPERATURE) LOGGER.debug( "Primary loop: flow=%.0f kg/s temp_out=%.1fK core_temp=%.1fK", primary.mass_flow_rate, primary.temperature_out, core.fuel_temperature, ) def step_secondary(self, secondary: CoolantLoopState, transferred_mw: float) -> None: delta_t = temperature_rise(transferred_mw, secondary.mass_flow_rate) secondary.temperature_out = secondary.temperature_in + delta_t secondary.steam_quality = min(1.0, max(0.0, delta_t / 100.0)) secondary.pressure = min(constants.MAX_PRESSURE, 6.0 + delta_t * 0.01) LOGGER.debug( "Secondary loop: transferred=%.1fMW temp_out=%.1fK quality=%.2f", transferred_mw, secondary.temperature_out, secondary.steam_quality, )