codexregular-solution-liquid-coexistence.py
regular-solution-liquid-coexistence.py
"""Original symmetric regular-solution plots; writes a PNG in the current directory."""
from pathlib import Path
import math
import matplotlib.pyplot as plt
import numpy as np
def mixing_free_energy(x, chi):
x = np.asarray(x, dtype=float)
log_x = np.zeros_like(x)
log_other = np.zeros_like(x)
np.log(x, out=log_x, where=x > 0)
np.log(1 - x, out=log_other, where=x < 1)
return x * log_x + (1 - x) * log_other + chi * x * (1 - x)
def low_binodal(chi):
assert chi >= 2
if chi == 2:
return 0.5
low = 1e-12
high = (1 - math.sqrt(1 - 2 / chi)) / 2
for _ in range(100):
middle = (low + high) / 2
derivative = math.log(middle / (1 - middle)) + chi * (1 - 2 * middle)
if derivative > 0:
high = middle
else:
low = middle
return (low + high) / 2
def main():
alpha = low_binodal(3)
beta = 1 - alpha
z = 0.30
phase_fraction = (z - alpha) / (beta - alpha)
np.testing.assert_allclose((1 - phase_fraction) * alpha + phase_fraction * beta, z)
assert 0 < phase_fraction < 1
for chi in (2.1, 3, 4):
endpoint = low_binodal(chi)
np.testing.assert_allclose(
math.log(endpoint / (1 - endpoint)) + chi * (1 - 2 * endpoint),
0, atol=1e-12,
)
np.testing.assert_allclose(
mixing_free_energy(endpoint, chi), mixing_free_energy(1 - endpoint, chi),
atol=1e-14,
)
x = np.linspace(0, 1, 1201)
minimum = float(mixing_free_energy(alpha, 3))
assert np.all(mixing_free_energy(x, 3) >= minimum - 1e-12)
assert minimum < float(mixing_free_energy(z, 3))
plt.rcParams.update({"font.size": 11, "axes.titlesize": 11})
fig, (energy, diagram) = plt.subplots(1, 2, figsize=(9.6, 4.8), dpi=100,
facecolor="white")
fig.subplots_adjust(left=0.105, right=0.985, bottom=0.16, top=0.80, wspace=0.28)
fig.suptitle("Symmetric regular solution: coexistence and local stability",
fontsize=15, y=0.97)
fig.text(0.5, 0.885,
r"$h(x)=x\ln x+(1-x)\ln(1-x)+\chi x(1-x)$; original model calculation",
ha="center", fontsize=12)
energy.plot(x, mixing_free_energy(x, 3), color="#0072b2", lw=2.2,
label="homogeneous liquid")
energy.plot([alpha, beta], [minimum, minimum], color="#d55e00", lw=2.5,
label="two-phase minimum")
energy.plot([alpha, beta], [minimum, minimum], "o", color="#d55e00")
energy.plot(z, mixing_free_energy(z, 3), "o", color="#333333", ms=5)
energy.annotate("overall z = 0.30", xy=(z, mixing_free_energy(z, 3)),
xytext=(0.04, 0.067), fontsize=10,
arrowprops={"arrowstyle": "->", "color": "#666666"})
energy.text(alpha, minimum - 0.008, r"$x_\alpha$", ha="center", va="top")
energy.text(beta, minimum - 0.008, r"$x_\beta$", ha="center", va="top")
energy.set(xlabel="Mole fraction x", ylabel=r"Mixing free energy $h=g_{mix}/(RT)$",
title=r"Supporting common tangent at $\chi=3$",
xlim=(0, 1), ylim=(-0.08, 0.09))
energy.legend(loc="upper right", fontsize=9)
chi = np.linspace(2, 4, 301)
binodal = np.array([low_binodal(c) for c in chi])
spinodal = (1 - np.sqrt(1 - 2 / chi)) / 2
diagram.plot(binodal, chi, color="#0072b2", lw=2.2, label="binodal: coexistence")
diagram.plot(1 - binodal, chi, color="#0072b2", lw=2.2)
diagram.plot(spinodal, chi, color="#cc79a7", lw=2, ls="--",
label="spinodal: local stability")
diagram.plot(1 - spinodal, chi, color="#cc79a7", lw=2, ls="--")
diagram.plot([alpha, beta], [3, 3], color="#777777", lw=1, ls=":")
diagram.plot([alpha, beta], [3, 3], "o", color="#0072b2", ms=4)
diagram.set(xlabel="Mole fraction x", ylabel=r"Interaction parameter $\chi$",
title="Binodal and spinodal in the model",
xlim=(0, 1), ylim=(1.95, 4.05))
diagram.legend(loc="upper center", fontsize=9)
for ax in (energy, diagram):
ax.grid(alpha=0.20)
ax.set_facecolor("white")
ax.spines[["top", "right"]].set_visible(False)
fig.savefig(Path.cwd() / "regular-solution-liquid-coexistence.png", dpi=100,
transparent=False, facecolor="white")
plt.close(fig)
print(f"chi=3: x_alpha={alpha:.10f}, x_beta={beta:.10f}, "
f"beta mole fraction at z=0.30: {phase_fraction:.10f}")
if __name__ == "__main__":
main()