refactor: organize src modules by category

This commit is contained in:
lujingze committed 2026-06-04 06:42:29 +00:00
1 parent d57c632db8
commit 4a22ef1334
20 files changed
+194 -144

No files matched your search

+17
View File
@@ -1,3 +1,20 @@
# src
Source code for pipe system simulation models and utilities.
## Layout
- `main.py`: compatibility entry point for the tank-pipe simulation.
- `tank_pipe/`: 0D-1D tank-pipe blowdown model, including configuration, tank, pipe, Riemann solver, time solver, and output helpers.
- `cylinder/`: high-pressure gas cylinder model.
- `cryo_tank/`: cryogenic LN2 tank model with helium pressurization, heat leak, solver, output helpers, and module README.
## Entry Points
Run from the repository root:
```bash
python3 src/main.py
python3 src/tank_pipe/main.py
python3 src/cryo_tank/main.py
```
+17
View File
@@ -0,0 +1,17 @@
"""High-pressure gas cylinder models."""
from cylinder.gas_cylinder import (
DEFAULT_FLUID,
DEFAULT_P_INIT,
DEFAULT_T_INIT,
DEFAULT_VOLUME,
HighPressureGasCylinder,
)
__all__ = [
"DEFAULT_FLUID",
"DEFAULT_P_INIT",
"DEFAULT_T_INIT",
"DEFAULT_VOLUME",
"HighPressureGasCylinder",
]
File renamed without changes.
+2 -126
View File
@@ -1,130 +1,6 @@
# src/main.py
"""
Entry point: assemble tanks + pipe from config constants, run the solver,
verify total mass/energy conservation, persist history, and generate
plots + animation.
"""Compatibility entry point for the tank-pipe simulation."""
Run from project root:
python3 src/main.py
"""
import os
import sys
# Ensure imports work when running from project root
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, _HERE)
import numpy as np
from config import (
GAMMA, R_GAS,
V1, P1_INIT, T1_INIT,
V2, P2_INIT, T2_INIT,
L, D, N_CELLS,
MU, ROUGHNESS,
T_END, CFL, RIEMANN_SOLVER,
ANIMATION_STRIDE, OUTPUT_DIR,
)
from tank import Tank
from pipe import Pipe
from solver import run
from output import (
save_history,
plot_tank_pressure,
plot_tank_temperature,
plot_pipe_final_profiles,
make_pipe_animation,
write_summary_report,
)
def _total_mass(tank1, tank2, pipe):
pipe_mass = float(np.sum(pipe.W[0, :] * pipe.area * pipe.dx))
return tank1.mass + tank2.mass + pipe_mass
def _total_energy(tank1, tank2, pipe):
pipe_energy = float(np.sum(pipe.W[2, :] * pipe.area * pipe.dx))
return tank1.U + tank2.U + pipe_energy
def main():
os.makedirs(OUTPUT_DIR, exist_ok=True)
# --- Assemble ---
tank1 = Tank(V=V1, P_init=P1_INIT, T_init=T1_INIT, gamma=GAMMA, R_gas=R_GAS)
tank2 = Tank(V=V2, P_init=P2_INIT, T_init=T2_INIT, gamma=GAMMA, R_gas=R_GAS)
pipe = Pipe(L=L, D=D, N=N_CELLS, P_init=P2_INIT, T_init=T2_INIT,
gamma=GAMMA, R_gas=R_GAS, mu=MU, roughness=ROUGHNESS,
riemann_solver=RIEMANN_SOLVER)
m_init = _total_mass(tank1, tank2, pipe)
U_init = _total_energy(tank1, tank2, pipe)
print(f"Initial total mass: {m_init:.6e} kg")
print(f"Initial total energy: {U_init:.6e} J")
print(f"Initial P1 = {tank1.P/1e6:.3f} MPa, P2 = {tank2.P/1e6:.3f} MPa")
print(f"Pipe: L={L} m, D={D*1e3:.1f} mm, N={N_CELLS} cells, dx={pipe.dx*1e3:.1f} mm")
print(f"Riemann solver: {RIEMANN_SOLVER.upper()}")
if MU > 0:
print(f"Friction: mu={MU:.2e} Pa·s, roughness={ROUGHNESS:.2e} m (eps/D={ROUGHNESS/D:.4f})")
else:
print("Friction: OFF")
print(f"Running to t_end={T_END} s with CFL={CFL}...")
print()
# --- Run ---
history = run(tank1, tank2, pipe,
t_end=T_END, cfl=CFL,
verbose=True, log_every=200)
n_steps = len(history['t'])
print()
print(f"Simulation complete: {n_steps} steps")
# --- Conservation sanity check (per spec §6.1, §8) ---
m_final = _total_mass(tank1, tank2, pipe)
U_final = _total_energy(tank1, tank2, pipe)
rel_err_m = abs(m_final - m_init) / m_init
rel_err_U = abs(U_final - U_init) / U_init
print(f"Final total mass: {m_final:.6e} kg (rel err = {rel_err_m:.2e})")
print(f"Final total energy: {U_final:.6e} J (rel err = {rel_err_U:.2e})")
print(f"Final P1 = {tank1.P/1e6:.3f} MPa, P2 = {tank2.P/1e6:.3f} MPa")
assert rel_err_m < 1e-10, f"Total mass not conserved: rel_err={rel_err_m:.2e}"
assert rel_err_U < 1e-10, f"Total energy not conserved: rel_err={rel_err_U:.2e}"
# --- Persist + visualize ---
save_history(history, pipe,
os.path.join(OUTPUT_DIR, "history.npz"),
GAMMA, R_GAS)
plot_tank_pressure(history,
os.path.join(OUTPUT_DIR, "tank_pressure.png"))
plot_tank_temperature(history,
os.path.join(OUTPUT_DIR, "tank_temperature.png"))
plot_pipe_final_profiles(history, pipe,
os.path.join(OUTPUT_DIR, "pipe_final_profiles.png"),
GAMMA, R_GAS)
make_pipe_animation(history, pipe,
os.path.join(OUTPUT_DIR, "pipe_animation.gif"),
GAMMA, R_GAS, stride=ANIMATION_STRIDE)
write_summary_report(
history, pipe,
os.path.join(OUTPUT_DIR, "summary_report.html"),
GAMMA, R_GAS,
config={
'V1': V1, 'P1_INIT': P1_INIT, 'T1_INIT': T1_INIT,
'V2': V2, 'P2_INIT': P2_INIT, 'T2_INIT': T2_INIT,
'L': L, 'D': D, 'N_CELLS': N_CELLS,
'T_END': T_END, 'CFL': CFL,
},
)
print(f"Outputs written to {OUTPUT_DIR}/")
print(f" - history.npz")
print(f" - tank_pressure.png")
print(f" - tank_temperature.png")
print(f" - pipe_final_profiles.png")
print(f" - pipe_animation.gif")
print(f" - summary_report.html")
from tank_pipe.main import main
if __name__ == "__main__":
+1
View File
@@ -0,0 +1 @@
"""0D-1D tank-pipe blowdown simulation package."""
File renamed without changes.
File renamed without changes.
+130
View File
@@ -0,0 +1,130 @@
# src/tank_pipe/main.py
"""
Entry point: assemble tanks + pipe from config constants, run the solver,
verify total mass/energy conservation, persist history, and generate
plots + animation.
Run from project root:
python3 src/tank_pipe/main.py
"""
import os
import sys
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(_HERE))
import numpy as np
from tank_pipe.config import (
GAMMA, R_GAS,
V1, P1_INIT, T1_INIT,
V2, P2_INIT, T2_INIT,
L, D, N_CELLS,
MU, ROUGHNESS,
T_END, CFL, RIEMANN_SOLVER,
ANIMATION_STRIDE, OUTPUT_DIR,
)
from tank_pipe.tank import Tank
from tank_pipe.pipe import Pipe
from tank_pipe.solver import run
from tank_pipe.output import (
save_history,
plot_tank_pressure,
plot_tank_temperature,
plot_pipe_final_profiles,
make_pipe_animation,
write_summary_report,
)
def _total_mass(tank1, tank2, pipe):
pipe_mass = float(np.sum(pipe.W[0, :] * pipe.area * pipe.dx))
return tank1.mass + tank2.mass + pipe_mass
def _total_energy(tank1, tank2, pipe):
pipe_energy = float(np.sum(pipe.W[2, :] * pipe.area * pipe.dx))
return tank1.U + tank2.U + pipe_energy
def main():
os.makedirs(OUTPUT_DIR, exist_ok=True)
# --- Assemble ---
tank1 = Tank(V=V1, P_init=P1_INIT, T_init=T1_INIT, gamma=GAMMA, R_gas=R_GAS)
tank2 = Tank(V=V2, P_init=P2_INIT, T_init=T2_INIT, gamma=GAMMA, R_gas=R_GAS)
pipe = Pipe(L=L, D=D, N=N_CELLS, P_init=P2_INIT, T_init=T2_INIT,
gamma=GAMMA, R_gas=R_GAS, mu=MU, roughness=ROUGHNESS,
riemann_solver=RIEMANN_SOLVER)
m_init = _total_mass(tank1, tank2, pipe)
U_init = _total_energy(tank1, tank2, pipe)
print(f"Initial total mass: {m_init:.6e} kg")
print(f"Initial total energy: {U_init:.6e} J")
print(f"Initial P1 = {tank1.P/1e6:.3f} MPa, P2 = {tank2.P/1e6:.3f} MPa")
print(f"Pipe: L={L} m, D={D*1e3:.1f} mm, N={N_CELLS} cells, dx={pipe.dx*1e3:.1f} mm")
print(f"Riemann solver: {RIEMANN_SOLVER.upper()}")
if MU > 0:
print(f"Friction: mu={MU:.2e} Pa·s, roughness={ROUGHNESS:.2e} m (eps/D={ROUGHNESS/D:.4f})")
else:
print("Friction: OFF")
print(f"Running to t_end={T_END} s with CFL={CFL}...")
print()
# --- Run ---
history = run(tank1, tank2, pipe,
t_end=T_END, cfl=CFL,
verbose=True, log_every=200)
n_steps = len(history['t'])
print()
print(f"Simulation complete: {n_steps} steps")
# --- Conservation sanity check (per spec §6.1, §8) ---
m_final = _total_mass(tank1, tank2, pipe)
U_final = _total_energy(tank1, tank2, pipe)
rel_err_m = abs(m_final - m_init) / m_init
rel_err_U = abs(U_final - U_init) / U_init
print(f"Final total mass: {m_final:.6e} kg (rel err = {rel_err_m:.2e})")
print(f"Final total energy: {U_final:.6e} J (rel err = {rel_err_U:.2e})")
print(f"Final P1 = {tank1.P/1e6:.3f} MPa, P2 = {tank2.P/1e6:.3f} MPa")
assert rel_err_m < 1e-10, f"Total mass not conserved: rel_err={rel_err_m:.2e}"
assert rel_err_U < 1e-10, f"Total energy not conserved: rel_err={rel_err_U:.2e}"
# --- Persist + visualize ---
save_history(history, pipe,
os.path.join(OUTPUT_DIR, "history.npz"),
GAMMA, R_GAS)
plot_tank_pressure(history,
os.path.join(OUTPUT_DIR, "tank_pressure.png"))
plot_tank_temperature(history,
os.path.join(OUTPUT_DIR, "tank_temperature.png"))
plot_pipe_final_profiles(history, pipe,
os.path.join(OUTPUT_DIR, "pipe_final_profiles.png"),
GAMMA, R_GAS)
make_pipe_animation(history, pipe,
os.path.join(OUTPUT_DIR, "pipe_animation.gif"),
GAMMA, R_GAS, stride=ANIMATION_STRIDE)
write_summary_report(
history, pipe,
os.path.join(OUTPUT_DIR, "summary_report.html"),
GAMMA, R_GAS,
config={
'V1': V1, 'P1_INIT': P1_INIT, 'T1_INIT': T1_INIT,
'V2': V2, 'P2_INIT': P2_INIT, 'T2_INIT': T2_INIT,
'L': L, 'D': D, 'N_CELLS': N_CELLS,
'T_END': T_END, 'CFL': CFL,
},
)
print(f"Outputs written to {OUTPUT_DIR}/")
print(f" - history.npz")
print(f" - tank_pressure.png")
print(f" - tank_temperature.png")
print(f" - pipe_final_profiles.png")
print(f" - pipe_animation.gif")
print(f" - summary_report.html")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -1,4 +1,4 @@
# src/output.py
# src/tank_pipe/output.py
"""
Output helpers: persistence (.npz), static plots (.png/.html), animation (.gif).
Uses matplotlib's Agg backend so it works in headless environments.
+3 -3
View File
@@ -1,4 +1,4 @@
# src/pipe.py
# src/tank_pipe/pipe.py
"""
1D finite-volume pipe for compressible Euler equations:
dW/dt + dF(W)/dx = 0
@@ -12,8 +12,8 @@ Discretization:
"""
import numpy as np
from riemann import hll_flux, get_riemann_solver
from friction import darcy_friction_factor
from tank_pipe.riemann import hll_flux, get_riemann_solver
from tank_pipe.friction import darcy_friction_factor
class Pipe:
+1 -1
View File
@@ -1,4 +1,4 @@
# src/riemann.py
# src/tank_pipe/riemann.py
"""
Riemann flux solvers for the 1D compressible Euler equations.
File renamed without changes.
+1 -1
View File
@@ -1,4 +1,4 @@
# src/tank.py
# src/tank_pipe/tank.py
"""
0D lumped-parameter tank for ideal gas. The tank's *primary* state is
(mass, U) where U is total internal energy in joules. Pressure, temperature,