codex/ideal-solution-entropy-and-gibbs-mixing.py

ideal-solution-entropy-and-gibbs-mixing.py
"""Draw mixing functions for the same invented binary model as the VLE figure.

Tested with Python 3.14, NumPy 2.3.5 and Matplotlib 3.10.7.
Run from the desired output directory; writes this script's basename.png there.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np


def main():
    gas_constant = 8.31446261815324
    temperature = 300.0
    amount = 1.0
    x = np.linspace(0, 1, 501)
    s = np.zeros_like(x)
    middle = (x > 0) & (x < 1)
    s[middle] = -x[middle]*np.log(x[middle]) - (1-x[middle])*np.log1p(-x[middle])
    entropy = amount * gas_constant * s
    gibbs = -temperature * entropy / 1000
    selected_entropy = -gas_constant*(.4*np.log(.4)+.6*np.log(.6))
    plt.rcParams.update({"font.size": 11, "axes.spines.top": False,
                         "axes.spines.right": False, "figure.facecolor": "white",
                         "axes.facecolor": "white"})
    fig, axes = plt.subplots(1, 2, figsize=(10.5, 4.65))
    fig.suptitle("Invented A/B ideal solution: mixing 1 mol at 300 K", fontsize=14)
    left, right = axes
    left.plot(x, entropy, color="#217a54", lw=2.5)
    left.scatter([.4], [selected_entropy], c="#217a54", s=45, zorder=4)
    left.annotate(r"$x_A=0.4$"+f"\n{selected_entropy:.3f} J/K", (.4, selected_entropy), xytext=(.12, 3.6),
                  arrowprops={"arrowstyle": "-", "color": "#217a54"})
    left.annotate(r"Maximum: $R\ln 2$", (.5, gas_constant*np.log(2)), xytext=(.53, 6.05), fontsize=10)
    left.set(ylabel=r"$\Delta_{\rm mix}S$ (J/K)", ylim=(0, 6.6), title="Entropy increases")
    right.plot(x, gibbs, color="#7853a6", lw=2.5)
    right.scatter([.4], [-temperature*selected_entropy/1000], c="#7853a6", s=45, zorder=4)
    right.annotate(r"$x_A=0.4$"+f"\n{-temperature*selected_entropy/1000:.3f} kJ", (.4, -temperature*selected_entropy/1000), xytext=(.12, -.8),
                   arrowprops={"arrowstyle": "-", "color": "#7853a6"})
    right.text(.51, -1.91, r"Minimum: $-RT\ln 2$", fontsize=10)
    right.set(ylabel=r"$\Delta_{\rm mix}G$ (kJ)", ylim=(-2.05, .12), title=r"Gibbs energy decreases: $\Delta G=-T\Delta S$")
    for axis in axes:
        axis.axvline(.5, color=".65", ls="--", lw=1)
        axis.axvline(.4, color=".65", ls=":", lw=1)
        axis.axhline(0, color=".6", lw=1)
        axis.set(xlim=(0, 1), xlabel=r"Liquid mole fraction $x_A$")
        axis.set_xticks(np.linspace(0, 1, 6))
        axis.grid(alpha=.15)
    fig.subplots_adjust(left=.075, right=.985, bottom=.19, top=.80, wspace=.25)
    fig.text(.5, .02, "Initially separate pure liquids at a common T and P. Chosen model, no measured data.", ha="center", fontsize=10, color=".3")
    fig.savefig(Path(__file__).stem + ".png", dpi=110, facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()