"""f28_electrolyte_terms -- schematic of an ion in solvent: Born solvation
cavity, Debye-Huckel ionic atmosphere, primary hydration shell, contact ion
pair, each mapped to its Helmholtz contribution label (a_Born, a_DH/MSA,
a_hydration, a_assoc). Pure schematic (matplotlib primitives only).

Layout: left column holds the concentric-shell diagram of a solvated ion
plus a small contact-ion-pair inset below it; right column holds a matched
colour-coded legend. Colours are shared between diagram and legend so no
long leader lines are needed across the canvas.
"""
import sys
sys.path.insert(0, "/home/claude/eos_lecture/code")
from eosstyle import *
from matplotlib.patches import Ellipse

# Canvas deliberately kept small (9.2 x 5.9 in) so the legend point sizes
# below are large relative to the figure width -- the figure is projected
# about 6 in wide, so legibility follows the font-size / canvas-width ratio.
W, H = 9.2, 5.9
fig, ax = blank(W, H)
ASPECT = W / H

FS_TITLE = 15.5     # figure title
FS_LEG_T = 13.0     # legend entry headings (incl. the -> a_x tags)
FS_LEG_D = 12.2     # legend entry descriptions
FS_CAP = 12.0       # diagram caption

def circ(cx, cy, r, **kw):
    e = Ellipse((cx, cy), width=2*r, height=2*r*ASPECT, **kw)
    ax.add_patch(e)
    return e

cx, cy = 0.215, 0.575

# --- concentric shells, outside in: DH atmosphere, hydration shell, Born cavity, ion
r_dh, r_hyd, r_born, r_ion = 0.185, 0.131, 0.079, 0.029

circ(cx, cy, r_dh, facecolor=SKYBLUE, edgecolor=SKYBLUE, alpha=0.12, lw=1.4,
     linestyle="--", zorder=1)
circ(cx, cy, r_hyd, facecolor=TEAL, edgecolor=TEAL, alpha=0.16, lw=1.4,
     linestyle="--", zorder=2)
circ(cx, cy, r_born, facecolor=RUST, edgecolor=RUST, alpha=0.20, lw=1.6, zorder=3)
circ(cx, cy, r_ion, facecolor=NAVY, edgecolor=GRAPHITE, lw=1.5, zorder=6)
ax.text(cx, cy, "+", ha="center", va="center", fontsize=13.5, color="white", weight="bold", zorder=7)

# co-ions dotted in the DH atmosphere (illustrative positions, kept inside r_dh)
for ang_deg, rad_frac, sign in [(30, 0.75, "-"), (110, 0.82, "-"), (200, 0.78, "-"),
                                  (280, 0.85, "-"), (335, 0.55, "-"), (155, 0.50, "+")]:
    ang = np.deg2rad(ang_deg)
    rr = rad_frac * r_dh
    x, y = cx + rr*np.cos(ang), cy + rr*ASPECT*np.sin(ang)
    col = RUST if sign == "-" else NAVY
    circ(x, y, 0.0125, facecolor=col, edgecolor=GRAPHITE, lw=0.8, zorder=5)
    ax.text(x, y, sign, ha="center", va="center", fontsize=10.5, color="white", zorder=6)

# hydration-shell water molecules, between r_born and r_hyd
for ang_deg in [15, 75, 135, 195, 255, 315]:
    ang = np.deg2rad(ang_deg)
    rr = 0.5*(r_born + r_hyd)
    x, y = cx + rr*np.cos(ang), cy + rr*ASPECT*np.sin(ang)
    circ(x, y, 0.0115, facecolor="#F4F6F7", edgecolor=GRAPHITE, lw=0.9, zorder=5)

ax.text(cx, cy - r_dh*ASPECT - 0.05, "solvated cation, concentric view",
        ha="center", va="top", fontsize=FS_CAP, color=GRAPHITE, style="italic")

# ---- right column: colour-coded legend ------------------------------------
legend_x = 0.435
legend_items = [
    (RUST,    r"Born solvation cavity  $\rightarrow\; a_{Born}$",
     "continuum dielectric charging\nof the bare-ion cavity"),
    (SKYBLUE, r"Debye-Huckel ionic atmosphere  $\rightarrow\; a_{DH/MSA}$",
     "diffuse cloud of counter-ions that\nscreens the central charge"),
    (TEAL,    r"Primary hydration shell  $\rightarrow\; a_{hydration}$",
     "oriented solvent molecules bound\nto the ion at short range"),
    (GRAPHITE, r"Contact ion pairing  $\rightarrow\; a_{assoc}$",
     "ion pairs with no solvent between them,\nespecially at high concentration"),
]
ys = np.linspace(0.855, 0.155, len(legend_items))
sw = 0.026
for k, ((col, title, desc), y) in enumerate(zip(legend_items, ys)):
    if k < 3:
        ax.add_patch(plt.Rectangle((legend_x, y - sw*ASPECT/2), sw, sw*ASPECT, facecolor=col,
                                     edgecolor=GRAPHITE, lw=0.9))
    else:
        # mini contact-ion-pair icon in place of a plain swatch
        r_mini = 0.0105
        p0x, p0y = legend_x + r_mini, y
        circ(p0x, p0y, r_mini, facecolor=NAVY, edgecolor=GRAPHITE, lw=0.9, zorder=6)
        p1x = p0x + r_mini*1.7
        circ(p1x, p0y, r_mini*0.85, facecolor=RUST, edgecolor=GRAPHITE, lw=0.9, zorder=6)
    ax.text(legend_x + sw + 0.018, y + 0.030, title, ha="left", va="bottom",
            fontsize=FS_LEG_T, color=INK, weight="bold")
    ax.text(legend_x + sw + 0.018, y - 0.030, desc, ha="left", va="top",
            fontsize=FS_LEG_D, color=SLATE, linespacing=1.3)

ax.text(0.5, 0.995, "Electrolyte EOS: physics around a solvated ion", ha="center", va="top",
        fontsize=FS_TITLE, color=NAVY, weight="bold")

save(fig, "f28_electrolyte_terms")
