# tests/cryo_tank/test_integration.py """Integration tests for the cryogenic tank simulation.""" import numpy as np from cryo_tank.tank_model import CryoTank from cryo_tank.heat_leak import MLIHeatLeak from cryo_tank.solver import run from cryo_tank.config import ( V_TOTAL, H_TANK, P_WORKING, T_INIT, ULLAGE_FRACTION, MDOT_IN_LN2, T_IN_LN2, MDOT_OUT_LN2, T_IN_HE, H_CONV_SURFACE, T_ENV, A_TOTAL, ) def _make_tank(**overrides): """Create a tank with default config, allowing overrides.""" 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 TestMassConservation: def test_liquid_mass_change_matches_net_flow(self): """Over a short run, dm_liq should equal (mdot_in - mdot_out) * dt.""" tank = _make_tank() history = run(tank, t_end=10.0, max_step=1.0) m_liq_0 = history['m_liq'][0] m_liq_f = history['m_liq'][-1] t_f = history['t'][-1] expected_dm = (MDOT_IN_LN2 - MDOT_OUT_LN2) * t_f actual_dm = m_liq_f - m_liq_0 rel_err = abs(actual_dm - expected_dm) / abs(expected_dm) assert rel_err < 1e-6, f"Mass conservation error: rel_err={rel_err:.2e}" class TestSteadyState: def test_zero_flow_zero_leak_is_static(self): """With no flow and no heat leak, state should not change.""" tank = _make_tank( mdot_in_ln2=0.0, mdot_out_ln2=0.0, h_conv=0.0, heat_leak_model=MLIHeatLeak(A_total=A_TOTAL, q_mli=0.0), ) history = run(tank, t_end=100.0, max_step=10.0) T_liq = history['T_liq'] T_ull = history['T_ull'] assert abs(T_liq[-1] - T_liq[0]) < 0.01, f"T_liq drifted: {T_liq[0]:.3f} -> {T_liq[-1]:.3f}" assert abs(T_ull[-1] - T_ull[0]) < 0.1, f"T_ull drifted: {T_ull[0]:.3f} -> {T_ull[-1]:.3f}" class TestPhysicalBehavior: def test_liquid_level_decreases(self): """With net outflow, liquid level should decrease.""" tank = _make_tank() history = run(tank, t_end=60.0, max_step=5.0) assert history['fill_fraction'][-1] < history['fill_fraction'][0] def test_he_flow_rate_positive(self): """He should always flow in (pressurization), not out.""" tank = _make_tank() history = run(tank, t_end=60.0, max_step=5.0) assert np.all(history['mdot_He'] >= -1e-10) # allow tiny numerical noise