codexideal-vapor-pressure-and-inverse-temperature.py
ideal-vapor-pressure-and-inverse-temperature.py
"""Pressure and logarithmic plots of a stipulated constant-latent-heat model.
Run from _media with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
gas_constant, latent_heat, reference_t, reference_p = 8.314, 40000, 300, 10
temperature = np.linspace(280, 340, 400)
log_ratio = latent_heat / gas_constant * (1 / reference_t - 1 / temperature)
pressure = reference_p * np.exp(log_ratio)
plt.rcParams.update({"font.size": 12, "axes.spines.top": False,
"axes.spines.right": False, "figure.facecolor": "white",
"axes.facecolor": "white"})
fig, (left, right) = plt.subplots(1, 2, figsize=(10.8, 5.6))
fig.subplots_adjust(left=0.08, right=0.97, bottom=0.21, top=0.75, wspace=0.32)
fig.suptitle("Idealized vapor pressure: one model, two views", fontsize=19, y=0.97)
fig.text(0.5, 0.87,
r"$L_m=40.0\ \mathrm{kJ\,mol^{-1}},\quad p_1=10.0\ \mathrm{kPa},\quad T_1=300\ \mathrm{K}$",
ha="center", fontsize=14)
left.plot(temperature, pressure, color="#146a92", lw=3, label="Integrated model")
slope = reference_p * latent_heat / (gas_constant * reference_t**2)
left.plot(temperature, reference_p + slope * (temperature - reference_t),
"--", color="0.45", lw=1.6, label="Tangent at 300 K")
left.set(xlabel="Temperature (K)", ylabel="Saturation pressure (kPa)",
title="Curved on ordinary axes", xlim=(280, 340), ylim=(0, 75))
left.legend(loc="upper left", fontsize=10, frameon=False)
right.plot(1000 / temperature, log_ratio, color="#146a92", lw=3)
right.set(xlabel=r"Inverse temperature $1/T$ ($10^{-3}\ \mathrm{K^{-1}}$)",
ylabel=r"$\ln(p/p_1)$", title="Linear at constant latent heat")
for temp, offset in [(300, (-18, 14)), (330, (-50, 14))]:
logr = latent_heat / gas_constant * (1 / reference_t - 1 / temp)
p = reference_p * np.exp(logr)
left.scatter(temp, p, color="#a74828", s=35, zorder=5)
right.scatter(1000 / temp, logr, color="#a74828", s=35, zorder=5)
left.annotate(f"{temp} K\n{p:.2f} kPa", (temp, p), xytext=offset,
textcoords="offset points", fontsize=11)
right.annotate(f"{temp} K", (1000 / temp, logr), xytext=(10, -20),
textcoords="offset points", fontsize=11)
for ax in (left, right):
ax.grid(alpha=0.18)
fig.text(0.5, 0.095,
r"$\ln(p/p_1)=(L_m/R)(1/T_1-1/T)$; slope against $1/T$: $-L_m/R=-4811.16\ \mathrm{K}$",
ha="center", fontsize=13)
fig.text(0.5, 0.04, "Stipulated pure-substance model over 280–340 K; not experimental water data.",
ha="center", fontsize=12)
fig.savefig(Path(__file__).with_suffix(".png").name, dpi=100,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()