# tests/cryo_tank/test_tank_model.py """Tests for CryoTank model.""" import pytest import numpy as np from cryo_tank.tank_model import CryoTank from cryo_tank.heat_leak import MLIHeatLeak from cryo_tank.config import ( V_TOTAL, H_TANK, A_CROSS, A_TOTAL, P_WORKING, T_INIT, ULLAGE_FRACTION, MDOT_IN_LN2, T_IN_LN2, MDOT_OUT_LN2, T_IN_HE, H_CONV_SURFACE, T_ENV, ) def _make_tank(**overrides): """Create a CryoTank with default config and MLI heat leak.""" kw = dict( V_total=V_TOTAL, H_tank=H_TANK, P_work=P_WORKING, T_init=T_INIT, ullage_fraction=ULLAGE_FRACTION, mdot_in_ln2=MDOT_IN_LN2, T_in_ln2=T_IN_LN2, mdot_out_ln2=MDOT_OUT_LN2, T_in_he=T_IN_HE, h_conv=H_CONV_SURFACE, T_env=T_ENV, heat_leak_model=MLIHeatLeak(A_total=A_TOTAL, q_mli=1.0), ) kw.update(overrides) return CryoTank(**kw) class TestGeometry: def test_cross_section_area(self): tank = _make_tank() assert abs(tank.A_cross - 0.8402) < 0.001 def test_total_surface_area(self): tank = _make_tank() assert abs(tank.A_total - 3.305) < 0.01 def test_wetted_area_at_70_percent_fill(self): tank = _make_tank() level = 0.7 * H_TANK # 0.35 m A_wet, A_dry = tank.wetted_areas(level) # A_wet = bottom cap + side * level expected_wet = A_CROSS + np.pi * tank.D * level assert abs(A_wet - expected_wet) < 0.01 assert abs(A_wet + A_dry - A_TOTAL) < 0.01 class TestInitialState: def test_initial_liquid_mass(self): tank = _make_tank() y0 = tank.initial_state() m_liq = y0[0] # rho_LN2(78K, 0.17MPa) ~ 803.3 kg/m3, V_liq = 0.2941 m3 assert 235 < m_liq < 237 # ~236.25 kg def test_initial_fill_fraction(self): tank = _make_tank() y0 = tank.initial_state() info = tank.derive(y0) assert abs(info['fill_fraction'] - 0.70) < 0.01 def test_initial_temperatures(self): tank = _make_tank() y0 = tank.initial_state() info = tank.derive(y0) assert abs(info['T_liq'] - T_INIT) < 0.1 assert abs(info['T_ull'] - T_INIT) < 1.0 def test_initial_pressure_is_provided_entirely_by_helium(self): tank = _make_tank() y0 = tank.initial_state() info = tank.derive(y0) P_He = info['P_He'] assert abs(P_He - P_WORKING) / P_WORKING < 1e-12 class TestVolumeRate: def test_ullage_volume_rate_includes_liquid_thermal_expansion(self): tank = _make_tank( mdot_in_ln2=0.0, mdot_out_ln2=0.0, h_conv=0.0, ) y0 = tank.initial_state() info = tank.derive(y0) Q_liq_to_ull = 0.0 Q_leak = tank.heat_leak_model.compute(info['T_liq'], tank.T_env) A_wet, A_dry = tank.wetted_areas(info['liquid_level']) Q_leak_liq = Q_leak * A_wet / (A_wet + A_dry) dU_liq_dt = tank._liquid_energy_rate( info, Q_liq_to_ull, Q_leak_liq ) dV_ull_dt = tank._ullage_volume_rate( info, tank.dm_liq_dt, dU_liq_dt ) y_next = y0.copy() dt = 1.0 y_next[1] += dU_liq_dt * dt finite_difference = ( tank.derive(y_next)['V_ull'] - info['V_ull'] ) / dt assert dV_ull_dt < 0.0 assert abs(dV_ull_dt - finite_difference) / abs(finite_difference) < 1e-5