"""f26_saft_contributions -- residual Helmholtz contributions a_hs, a_chain,
a_disp, a_assoc as a function of reduced density.

SCHEMATIC (ILLUSTRATIVE): not computed from a real PC-SAFT/SAFT
implementation (no molecular parameters m, sigma, epsilon/k, kappa^AB,
epsilon^AB/k are fitted or supplied). The four curves are smooth,
qualitatively shaped functions chosen only to reproduce the well-known
*ordering and curvature* of the terms (Chapman et al. 1990; Gross &
Sadowski 2001, SPEC.md reference list): a_hs grows steeply and diverges
as random-close packing is approached, a_chain and a_disp are smaller in
magnitude and grow monotonically with density, a_assoc saturates at high
density as sites become fully bonded. No numerical value should be read
off this plot as a real prediction.
"""
import sys
sys.path.insert(0, "/home/claude/eos_lecture/code")
from eosstyle import *

eta = np.linspace(0.001, 0.62, 400)   # reduced (packing) density, eta -> ~0.64 close packing

# illustrative, qualitatively-shaped forms (NOT a real SAFT implementation):
# a_hs grows steeply (smooth power law standing in for the Carnahan-Starling
# divergence near random-close packing) and dominates; a_chain and a_disp
# are smaller, monotonically increasing; a_assoc saturates as sites become
# fully bonded at high density.
a_hs    = 12.0 * eta**1.4
a_chain = 1.6 * eta**1.15
a_disp  = 2.3 * eta**1.35
a_assoc = 1.1 * (1 - np.exp(-6*eta))

fig, ax = newfig(7.2, 4.8)

curves = [
    (r"$a_{hs}$", GRAPHITE, a_hs),
    (r"$a_{disp}$", RUST, a_disp),
    (r"$a_{assoc}$", AMBER, a_assoc),
    (r"$a_{chain}$", TEAL, a_chain),
]
for lbl, col, y in curves:
    ax.plot(eta, y, color=col, lw=2.1)

# staggered direct labels at the right edge (three curves converge there)
ends = sorted([(lbl, col, y[-1]) for lbl, col, y in curves], key=lambda t: -t[2])
min_gap = 0.55
y_floor = 0.55          # keep the lowest label clear of the x-axis spine
ytexts = []
for i, (lbl, col, y) in enumerate(ends):
    yt = y if i == 0 else min(y, ytexts[-1] - min_gap)
    ytexts.append(yt)
# push the stack back up if the staggering drove the bottom label onto the spine
for i in range(len(ytexts) - 1, -1, -1):
    lo = y_floor + (len(ytexts) - 1 - i) * min_gap
    if ytexts[i] < lo:
        ytexts[i] = lo
for (lbl, col, y), yt in zip(ends, ytexts):
    if abs(yt - y) > 1e-6:
        ax.plot([0.62, 0.635], [y, yt], color=col, lw=0.8, alpha=0.7)
    ax.text(0.645, yt, lbl, color=col, fontsize=11.5, va="center", ha="left")

ax.text(0.03, 0.97, "schematic (illustrative)\nnot a real SAFT calculation",
        transform=ax.transAxes, ha="left", va="top", fontsize=10.5, color=RUST,
        weight="bold", linespacing=1.35,
        bbox=dict(boxstyle="round,pad=0.35", fc="white", ec=RUST, lw=1.3))

ax.set_xlabel(r"Reduced (packing) density, $\eta$")
# two lines: the single-line form is taller than the axes and was clipped by
# the top edge of the figure, cutting off the unit in parentheses
ax.set_ylabel("Contribution to $a^{res}/RT$\n(illustrative units)")
ax.set_xlim(0, 0.80)
ax.set_ylim(0, 7.5)
fig.subplots_adjust(right=0.86)

save(fig, "f26_saft_contributions")
