codexhelium-liquefaction-refrigeration-chain.py
helium-liquefaction-refrigeration-chain.py
"""Draw a functional helium refrigeration loop; no dimensions or operating data.
Tested with Python 3.14, matplotlib 3.10.7. Run from _media; output is
helium-liquefaction-refrigeration-chain.png in the current directory.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch
def main():
plt.rcParams.update({"font.size": 11, "font.family": "DejaVu Sans"})
fig, ax = plt.subplots(figsize=(10, 5.6), dpi=110, facecolor="white")
fig.subplots_adjust(left=.025, right=.975, bottom=.04, top=.90)
ax.set(xlim=(0, 10), ylim=(0, 5.1))
ax.axis("off")
fig.suptitle("Helium liquefaction: a functional refrigeration chain", fontsize=16)
blue, teal, red = "#185b9b", "#087f8c", "#bb4631"
def box(x, y, w, h, text, fill="#eef4fa"):
ax.add_patch(FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.06",
facecolor=fill, edgecolor=blue, linewidth=1.4))
ax.text(x+w/2, y+h/2, text, ha="center", va="center", fontsize=11)
def arrow(points, color=blue, style="-", width=1.8):
for a, b in zip(points[:-2], points[1:-1]):
ax.plot([a[0], b[0]], [a[1], b[1]], color=color, lw=width, ls=style)
ax.add_patch(FancyArrowPatch(points[-2], points[-1], arrowstyle="-|>",
mutation_scale=14, color=color, lw=width,
linestyle=style, shrinkA=0, shrinkB=0))
box(.18, 3.35, 1.45, .8, "Compression\n& heat rejection")
box(2.05, 3.35, 1.5, .8, "Liquid-air\nprecooling")
box(4.00, 3.35, 1.55, .8, "Liquid-hydrogen\nprecooling")
box(6.00, 2.65, 1.55, 1.9, "Counterflow\nheat exchanger\n\n\n", "#edf8f7")
box(8.05, 3.35, 1.55, .8, "Throttling\nexpansion")
box(8.05, 1.25, 1.55, .85, "Liquid\ncollection")
for a, b in [(1.69, 1.99), (3.61, 3.94), (5.61, 5.94), (7.61, 7.99)]:
arrow([(a, 3.75), (b, 3.75)])
arrow([(8.82, 3.29), (8.82, 2.16)])
arrow([(8.0, 1.68), (7.80, 1.68), (7.80, 2.95), (7.61, 2.95)], teal)
arrow([(7.48, 2.95), (6.07, 2.95)], teal)
arrow([(5.94, 2.95), (.90, 2.95), (.90, 3.29)], teal)
ax.text(3.25, 2.66, "Cold helium returns to warm recovery", color=teal,
ha="center", va="center")
arrow([(6.78, 3.63), (6.78, 3.17)], red, "--")
ax.text(6.78, 2.78, "heat", color=red, ha="center", fontsize=10)
ax.text(7.8, 1.05, "Vapor returns; liquid remains", ha="center", fontsize=11)
ax.text(4.8, 4.75, "Purified helium →", ha="center", color=blue, fontsize=12)
ax.text(4.8, .35, "Functional paths only • no apparatus geometry or operating settings\n"
"Separate streams exchange heat without mixing", ha="center", va="center",
color="#45515e", fontsize=11)
# Structural checks: a feed path, a return path and separate thermal coupling.
feed = ["compression", "air", "hydrogen", "exchanger", "throttle", "collector"]
returning = ["collector", "exchanger", "compression"]
assert feed.index("hydrogen") < feed.index("exchanger") < feed.index("throttle")
assert returning[0] == feed[-1] and returning[-1] == feed[0]
assert returning.count("exchanger") == feed.count("exchanger") == 1
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()