63 lines
2.6 KiB
Python
63 lines
2.6 KiB
Python
"""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,
|
|
)
|