"""f09_Z_meaning -- Z vs P for CO2 (PR) at several temperatures, showing
initial negative slope, minimum, and crossover to Z > 1; annotate
"attraction dominates" (rust) and "repulsion dominates" (teal).
"""
import sys
sys.path.insert(0, "/home/claude/eos_lecture/code")
from eosstyle import *

sp = "CO2"
Ts = [250, 310, 450, 700]   # subcritical, near-critical, supercritical, well supercritical
P = np.linspace(2, 400, 400)

fig, ax = newfig()

shades = [NAVY, SKYBLUE, AMBER, TEAL]
curves = {}
for T, col in zip(Ts, shades):
    Z = np.array([Zroots("pr", sp, T, p)[-1] for p in P])
    curves[T] = Z
    ax.plot(P, Z, color=col, lw=2.0)

ax.axhline(1.0, color=GRAPHITE, lw=1.3, linestyle=":", zorder=2)

# direct end labels, staggered where curves converge on the right edge
end_vals = [(T, curves[T][-1]) for T in Ts]
end_vals.sort(key=lambda t: -t[1])
min_gap = 0.085
ytexts = []
for i, (T, Z) in enumerate(end_vals):
    yt = Z if i == 0 else min(Z, ytexts[-1] - min_gap)
    ytexts.append(yt)
colmap = dict(zip(Ts, shades))
for (T, Z), yt in zip(end_vals, ytexts):
    if abs(yt - Z) > 1e-6:
        ax.plot([400, 406], [Z, yt], color=colmap[T], lw=0.8, alpha=0.7)
    ax.text(409, yt, f"{T} K", color=colmap[T], fontsize=10.5, va="center", ha="left", weight="bold")

# annotate attraction-dominated (Z<1, negative initial slope) using the
# 450 K curve minimum as the example of "attraction and repulsion balance"
Z450 = curves[450]
imin = np.argmin(Z450)
ax.plot([P[imin]], [Z450[imin]], marker="o", ms=6.5, color=RUST, zorder=5,
        markeredgecolor="white", markeredgewidth=0.8)
ax.annotate("minimum: attraction and\nrepulsion balance", xy=(P[imin], Z450[imin]),
            xytext=(195, 0.70), fontsize=10.5, color=INK, linespacing=1.25,
            ha="left", va="center",
            arrowprops=dict(arrowstyle="-", color=GRAPHITE, lw=1.0))

ax.annotate("attraction dominates\n($Z<1$, $dZ/dP<0$)", xy=(30, curves[310][np.argmin(np.abs(P-30))]),
            xytext=(70, 0.55), fontsize=10.5, color=RUST, linespacing=1.3,
            arrowprops=dict(arrowstyle="-", color=RUST, lw=1.1))
ax.annotate("repulsion dominates\n($Z>1$)", xy=(300, curves[700][np.argmin(np.abs(P-300))]),
            xytext=(155, 1.12), fontsize=10.5, color=TEAL, linespacing=1.3,
            arrowprops=dict(arrowstyle="-", color=TEAL, lw=1.1))

ax.text(15, 1.02, "$Z=1$", color=GRAPHITE, fontsize=10.5, va="bottom")

ax.set_xlim(0, 400)
ax.set_ylim(0.0, 1.22)
ax.set_xlabel("Pressure, $P$ / bar")
ax.set_ylabel("Compressibility factor, $Z$")
fig.subplots_adjust(right=0.86)

save(fig, "f09_Z_meaning")
