codexheat-engine-efficiency-temperature-model.py
heat-engine-efficiency-temperature-model.py
"""Generate heat-engine-efficiency-temperature-model.png in the current directory.
Run from _media with MPLBACKEND=Agg and
MPLCONFIGDIR=/tmp/codex-wiki-matplotlib.
Tested with Python 3.14.4, matplotlib 3.10.7 and numpy 2.3.5.
The lower curve is stipulated at 80% of the reversible bound, not measured.
"""
from fractions import Fraction
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.ticker import PercentFormatter
import numpy as np
def main():
t_cold = 300
t_hot = np.linspace(t_cold, 900, 401)
carnot = 1 - t_cold / t_hot
model = 0.8 * carnot
for temperature, expected in [(300, Fraction(0)), (450, Fraction(1, 3)),
(600, Fraction(1, 2)), (900, Fraction(2, 3))]:
assert 1 - Fraction(t_cold, temperature) == expected
assert np.all(model <= carnot) and np.all(model >= 0)
assert np.all(np.diff(carnot) > 0)
plt.rcParams.update({"font.size": 12, "axes.spines.top": False,
"axes.spines.right": False, "savefig.facecolor": "white"})
fig, ax = plt.subplots(figsize=(8.2, 5.6), dpi=110, facecolor="white")
ax.fill_between(t_hot, carnot, 0.8, color="#f6e6e5")
ax.fill_between(t_hot, 0, carnot, color="#edf3f8")
ax.plot(t_hot, carnot, color="#204a87", lw=2.5,
label=r"Reversible bound: $\eta_C=1-300/T_h$")
ax.plot(t_hot, model, color="#287749", lw=2.3, ls="--",
label=r"Stipulated model: $\eta=0.8\eta_C$")
ax.plot([600, 600], [0, 0.5], color="#666666", lw=1.1, ls=":")
ax.scatter([600, 600], [0.5, 0.4], s=48,
c=["#204a87", "#287749"], zorder=4)
ax.annotate("600 K: 50%", (600, 0.5), xytext=(655, 0.48),
fontsize=11, color="#204a87",
arrowprops={"arrowstyle": "-", "color": "#204a87"})
ax.annotate("600 K: 40%", (600, 0.4), xytext=(655, 0.31),
fontsize=11, color="#287749",
arrowprops={"arrowstyle": "-", "color": "#287749"})
ax.text(735, 0.71, "Above bound: forbidden", color="#922f2f",
ha="center", fontsize=11)
ax.text(735, 0.15, "Below the bound", color="#35536c", ha="center", fontsize=11)
ax.set(xlim=(300, 900), ylim=(0, 0.8),
xlabel=r"Hot-reservoir temperature $T_h$ (K)",
ylabel=r"Thermal efficiency $\eta$",
title="Fixed cold reservoir at 300 K")
ax.set_xticks([300, 450, 600, 750, 900])
ax.yaxis.set_major_formatter(PercentFormatter(1))
ax.grid(axis="y", alpha=0.18)
ax.legend(loc="upper left", bbox_to_anchor=(0.0, 1.0), fontsize=10,
framealpha=1, facecolor="white", edgecolor="#dddddd")
fig.text(0.5, 0.027,
"Calculated curves, not data • Cyclic device • Heat exchange only with two fixed reservoirs",
ha="center", fontsize=9.5)
fig.subplots_adjust(left=0.12, right=0.965, top=0.89, bottom=0.18)
fig.savefig("heat-engine-efficiency-temperature-model.png",
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()