"""
Reverse-engineering of Delphi enthalpy model for the deethanizer (Chapter 6).

CONDENSEUR PARTIEL vs TOTAL
============================
Le modele Python (eq. 5.54 de Deethanizer.py) utilise un CONDENSEUR PARTIEL:
    HD = H[0]   (enthalpy vapeur au condenseur)
    QC = V[1]*H[1] - L[0]*h[0] - D*HD
       = V[1]*(H[1]-H[0]) + L[0]*(H[0]-h[0])

Terme A: V[1]*(H[1]-H[0]) = refroidissement sensible de tout le vapeur
Terme B: L[0]*(H[0]-h[0]) = condensation du reflux L[0] seulement
         (D quitte en VAPEUR, donc n apporte pas de chaleur latente)

BILAN GLOBAL:
    QR = -hF_total + B*h[B] + D*H[0] + QC

PHI (flux d enthalpie montant net dans chaque section adiabatique):
    phi = V[j+1]*H[j+1] - L[j]*h[j]  = const

Pour le condenseur partiel, le bilan cumule depuis le haut:
    D*H[0] + QC = V[1]*H[1] - L[0]*h[0]    [definition QC]
    => phi_rectif = V[1]*H[1] - L[0]*h[0] = D*H[0] + QC

STRATEGIE D ANALYSE:
    1. Decomposer QC en termes A + B pour Python et Delphi
    2. Terme A (refroidissement vapeur): compare H[1]-H[0] Python vs Delphi
    3. Terme B (condensation): compare H[0]-h[0] Python vs Delphi
    4. V[1], L[0], D sont EXACTEMENT les memes => erreur QC = erreur enthalpie pure
    5. Identifier si c est ΔHvap_Watson ou H_PR_departure qui cause l ecart
"""

import sys
import numpy as np

sys.path.insert(0, 'src')

from Distillation.Deethanizer import Deethanizer

# =============================================================================
# PART 1 - Reference data Delphi (Chapitre 6, Tables 6-7)
# =============================================================================

QC_REF = 4_133_587.91   # kJ/h
QR_REF = 22_854_385.49  # kJ/h

T_REF = np.array([
    260.2, 283.6, 293.5, 299.1, 302.9, 320.8, 337.6, 343.1, 345.0, 346.1,
    346.5, 346.7, 346.8, 346.8, 346.9, 346.9, 347.0, 347.0, 347.2, 347.4,
    348.0, 352.3, 353.4, 354.3, 355.6, 357.5, 360.9, 367.1, 380.2, 416.6
])
V_REF = np.array([
    562.1, 868.3, 900.2738, 923.6122, 925.198, 818.9466, 1076.698, 1676.743,
    2072.401, 2544.798, 2485.902, 2429.856, 2400.084, 2377.905, 2368.245,
    2350.846, 2336.727, 2313.368, 2297.692, 2277.709, 2239.937, 1995.84,
    2384.162, 2430.911, 2357.319, 2229.362, 2065.881, 1862.577, 1592.462,
    1156.98
])
L_REF = np.array([
    306.2, 338.1738, 361.5122, 363.098, 428.6541, 1438.504, 2038.548,
    2434.207, 2906.603, 2847.708, 2791.662, 2761.889, 2739.711, 2730.051,
    2712.652, 2698.533, 2675.173, 2659.498, 2639.514, 2601.743, 2395.55,
    3108.562, 3155.311, 3081.719, 2953.762, 2790.281, 2586.977, 2316.862,
    1881.38, 724.4
])

N     = 30
D_REF = V_REF[0]   # 562.1 kmol/h  (distillat vapeur V[0]=D pour condenseur partiel)
B_REF = L_REF[29]  # 724.4 kmol/h

VFC_total = 171.81
LFC_total = 752.10
VFH_total = 37.90
LFH_total = 324.73
FC_T      = 255.15  # K
FH_T      = 388.15  # K
P_BAR     = 27.49   # bar

# =============================================================================
# PART 2 - Modele Python, Cas 1
# =============================================================================
print("\n" + "=" * 65)
print("PYTHON MODEL - Case 1 convergence")
print("=" * 65)

col = Deethanizer()
col.solve(case=1, max_outer=20, tol=1.0, verbose=True)

T_PY = col.T.copy()
V_PY = col.V.copy()
L_PY = col.L.copy()
QC_PY = abs(col.QC)
QR_PY = abs(col.QR)
P_Pa  = col.P  # Pa (stored in Pa internally)
P_bar = P_Pa / 1e5

# Fractions molaires converges
l_conv = col.l    # shape (nc, N)
v_conv = col.v
x_PY   = np.zeros_like(l_conv)
y_PY   = np.zeros_like(v_conv)
for j in range(N):
    Lj = l_conv[:, j].sum()
    Vj = v_conv[:, j].sum()
    if Lj > 1e-10:
        x_PY[:, j] = l_conv[:, j] / Lj
    if Vj > 1e-10:
        y_PY[:, j] = v_conv[:, j] / Vj

# =============================================================================
# PART 3 - Enthalpies Python par etage (etat converge)
# =============================================================================
h_PY = np.zeros(N)   # kJ/kmol, liquide
H_PY = np.zeros(N)   # kJ/kmol, vapeur

for j in range(N):
    h_PY[j] = col.eos.pure_component_enthalpy(T_PY[j], P_Pa, x_PY[:, j], "liquid")
    H_PY[j] = col.eos.mixture_enthalpy(T_PY[j], P_Pa, y_PY[:, j], "vapor")

# Verification: QC_PY doit = V[1]*(H[1]-H[0]) + L[0]*(H[0]-h[0])
# Pour condenseur PARTIEL:  D quitte en vapeur => HD = H[0]
A_term_py = V_PY[1] * (H_PY[1] - H_PY[0])   # refroidissement sensible
B_term_py = L_PY[0] * (H_PY[0] - h_PY[0])   # condensation reflux
QC_check   = A_term_py + B_term_py

print(f"\n  Verification formule condenseur partiel:")
print(f"    Terme A = V[1]*(H[1]-H[0]) = {A_term_py:>12,.1f} kJ/h  ({A_term_py/QC_PY*100:.1f}%)")
print(f"    Terme B = L[0]*(H[0]-h[0]) = {B_term_py:>12,.1f} kJ/h  ({B_term_py/QC_PY*100:.1f}%)")
print(f"    QC_check = A+B             = {QC_check:>12,.1f} kJ/h")
print(f"    QC_py (solver)             = {QC_PY:>12,.1f} kJ/h")
print(f"    Ecart: {QC_check - QC_PY:+.1f} kJ/h  (doit etre ~0)")

print(f"\n  H[1]-H[0] = {H_PY[1]-H_PY[0]:>8.2f} kJ/kmol  (refroidissement vapeur {T_PY[1]:.1f}K -> {T_PY[0]:.1f}K)")
print(f"  H[0]-h[0] = {H_PY[0]-h_PY[0]:>8.2f} kJ/kmol  (chaleur latente de condensation a T[0]={T_PY[0]:.1f}K)")

# =============================================================================
# PART 4 - Decomposition de l erreur QC: Terme A vs Terme B
# =============================================================================
print("\n" + "=" * 70)
print("DECOMPOSITION ERREUR QC: refroidissement sensible vs condensation")
print("=" * 70)

D_val  = D_REF   # = V_REF[0] = 562.1 kmol/h
L0_val = L_REF[0]  # = 306.2 kmol/h
V1_val = V_REF[1]  # = 868.3 kmol/h

# Terme A Python (refroidissement sensible vapeur dV1 de T[1] a T[0])
A_py = V_PY[1] * (H_PY[1] - H_PY[0])
B_py = L_PY[0] * (H_PY[0] - h_PY[0])

print(f"\n  PYTHON (condenseur partiel, V[1]={V_PY[1]:.1f}, L[0]={L_PY[0]:.1f}):")
print(f"    H[1]-H[0] = {H_PY[1]-H_PY[0]:>8.2f} kJ/kmol")
print(f"    H[0]-h[0] = {H_PY[0]-h_PY[0]:>8.2f} kJ/kmol  [ΔHvap eff. condenseur]")
print(f"    Terme A   = {A_py:>12,.1f} kJ/h ({A_py/QC_PY*100:.1f}%)")
print(f"    Terme B   = {B_py:>12,.1f} kJ/h ({B_py/QC_PY*100:.1f}%)")
print(f"    QC_py     = {QC_PY:>12,.1f} kJ/h")

# Terme A et B impliques pour Delphi
# Hypothese 1: seul le terme B differe (H[1]-H[0] identique entre Python et Delphi)
# => B_delphi = QC_ref - A_py
B_delphi_h1  = QC_REF - A_py
HH_delphi_h1 = B_delphi_h1 / L0_val

# Hypothese 2: seul le terme A differe (H[0]-h[0] identique)
A_delphi_h2 = QC_REF - B_py
HH_delphi_h2 = A_delphi_h2 / V1_val

# Hypothese 3: erreur proportionnelle (meme ratio sur A et B)
scale_3 = QC_REF / QC_PY

print(f"\n  DELPHI IMPLIQUE (V[1]={V1_val:.1f}, L[0]={L0_val:.1f}, QC_ref={QC_REF:,.1f}):")
print(f"    QC_ref                              = {QC_REF:>12,.1f} kJ/h")
print(f"    Ecart QC (Delphi-Python)            = {QC_REF-QC_PY:>12,.1f} kJ/h ({(QC_REF/QC_PY-1)*100:+.2f}%)")
print(f"")
print(f"    HYPOTHESE 1: H[1]-H[0] identique, seul H[0]-h[0] differe =>")
print(f"      H[0]-h[0]_Delphi = {HH_delphi_h1:>8.2f} kJ/kmol  (Python: {H_PY[0]-h_PY[0]:.2f})")
print(f"      Ecart ΔHvap_Delphi - Python       = {HH_delphi_h1-(H_PY[0]-h_PY[0]):>+8.2f} kJ/kmol  ({(HH_delphi_h1/(H_PY[0]-h_PY[0])-1)*100:+.2f}%)")
print(f"")
print(f"    HYPOTHESE 2: H[0]-h[0] identique, seul H[1]-H[0] differe =>")
print(f"      H[1]-H[0]_Delphi  = {HH_delphi_h2:>8.2f} kJ/kmol  (Python: {H_PY[1]-H_PY[0]:.2f})")
print(f"      Ecart              = {HH_delphi_h2-(H_PY[1]-H_PY[0]):>+8.2f} kJ/kmol  ({(HH_delphi_h2/(H_PY[1]-H_PY[0])-1)*100:+.2f}%)")
print(f"")
print(f"  INTERPRETATION:")
print(f"    Le Terme B domine QC a {B_py/QC_PY*100:.0f}%. Si l ecart est dans le Terme B:")
print(f"    => ΔHvap Watson pour le condenseur est sous-estime de ~{(HH_delphi_h1/(H_PY[0]-h_PY[0])-1)*100:.1f}%")
print(f"    => correspond a ΔHvap trop bas de {HH_delphi_h1-(H_PY[0]-h_PY[0]):+.1f} kJ/kmol")
print(f"    Si l ecart est dans le Terme A:")
print(f"    => H[1]-H[0] (refroidissement vapeur) serait sous-estime de {(HH_delphi_h2/(H_PY[1]-H_PY[0])-1)*100:.1f}%")

# =============================================================================
# PART 5 - Phi (flux enthalpique montant) dans chaque section
# =============================================================================
print("\n" + "=" * 70)
print("PHI = net enthalpy flux montant (kJ/h) par section")
print("=" * 70)
print("""
phi[j] = V[j+1]*H[j+1] - L[j]*h[j]  [flux net montant entre j et j+1]

Pour condenseur PARTIEL: distillat D quitte en vapeur avec H[0]
    phi_rectif = D*H[0] + QC   [bilan sur le condenseur: V1*H1 = L0*h0 + D*H0 + QC]

Les alimentations SOUSTRAIENT de phi:
    phi_AB     = phi_rectif - VFC*H_FC
    phi_BC     = phi_AB - LFC*h_FC
    phi_CD     = phi_BC - VFH*H_FH
    phi_strip  = phi_CD - LFH*h_FH
    phi_strip  = QR - B*h[N-1]   [bilan rebouilleur]
""")

# Enthalpies alimentations
xFC_py = col.LFC / col.LFC_total
yFC_py = col.VFC / col.VFC_total
xFH_py = col.LFH / col.LFH_total
yFH_py = col.VFH / col.VFH_total

h_FC_py = col.eos.pure_component_enthalpy(FC_T, P_Pa, xFC_py, "liquid")
H_FC_py = col.eos.mixture_enthalpy(FC_T, P_Pa, yFC_py, "vapor")
h_FH_py = col.eos.pure_component_enthalpy(FH_T, P_Pa, xFH_py, "liquid")
H_FH_py = col.eos.mixture_enthalpy(FH_T, P_Pa, yFH_py, "vapor")

# Phi cumule (condenseur PARTIEL: D*H[0])
phi_rectif = D_val * H_PY[0] + QC_PY
phi_AB     = phi_rectif - VFC_total * H_FC_py
phi_BC     = phi_AB     - LFC_total * h_FC_py
phi_CD     = phi_BC     - VFH_total * H_FH_py
phi_strip  = phi_CD     - LFH_total * h_FH_py
phi_rebck  = QR_PY - B_REF * h_PY[N-1]

# Phi direct
phi_direct = np.array([V_PY[j+1]*H_PY[j+1] - L_PY[j]*h_PY[j] for j in range(N-1)])

print(f"  Section            phi_cumul (kJ/h)    phi_direct (kJ/h)   ecart")
print(f"  {'-'*65}")
sections = [
    ("rectifying (j=0..3)",  phi_rectif, phi_direct[0]),
    ("after VFC (j=4)",      phi_AB,     phi_direct[4]),
    ("mid-col (j=5..19)",    phi_BC,     phi_direct[5]),
    ("after VFH (j=20)",     phi_CD,     phi_direct[20]),
    ("stripping (j=21..28)", phi_strip,  phi_direct[21]),
]
for name, pc, pd in sections:
    print(f"  {name:<25s} {pc:>16,.1f}   {pd:>16,.1f}   {pc-pd:>+10.1f}")

print(f"\n  Closure: phi_strip (cumul) = {phi_strip:>14,.1f}")
print(f"           QR - B*h[B] (reb)  = {phi_rebck:>14,.1f}")
print(f"           Closure error       = {phi_strip - phi_rebck:>+14,.1f} kJ/h")

# =============================================================================
# PART 6 - Tableau enthalpies par etage
# =============================================================================
print("\n" + "=" * 110)
print("TABLEAU ENTHALPIES PAR ETAGE (Python converge)")
print("=" * 110)
print(f"{'j':>3}  {'T_ref':>7}  {'T_py':>7}  "
      f"{'h_py':>10}  {'H_py':>10}  {'H-h(lat)':>10}  "
      f"{'H[j+1]-H[j]':>13}  {'H[j+1]-h[j]':>13}  {'phi_dir':>13}")
print("-" * 110)
for j in range(N):
    lat  = H_PY[j] - h_PY[j]
    sens = H_PY[j+1] - H_PY[j]  if j < N-1 else float('nan')
    driv = H_PY[j+1] - h_PY[j]  if j < N-1 else float('nan')
    phi  = phi_direct[j]         if j < N-1 else float('nan')
    print(f"{j:3d}  {T_REF[j]:7.1f}  {T_PY[j]:7.1f}  "
          f"{h_PY[j]:10.1f}  {H_PY[j]:10.1f}  {lat:10.1f}  "
          f"{sens:13.1f}  {driv:13.1f}  {phi:13.1f}")

# =============================================================================
# PART 7 - Comparaison des quantites cles
# =============================================================================
print("\n" + "=" * 70)
print("COMPARAISON QUANTITES CLES (Python vs Delphi reference)")
print("=" * 70)
print(f"\n  {'Quantite':<42}  {'Delphi ref':>12}  {'Python':>12}  {'err%':>7}")
print(f"  {'-'*80}")

rows = [
    ("QC  (kJ/h)",                      QC_REF,           QC_PY),
    ("QR  (kJ/h)",                       QR_REF,           QR_PY),
    ("V[1]  (kmol/h)",                   V_REF[1],         V_PY[1]),
    ("L[0]  (kmol/h)",                   L_REF[0],         L_PY[0]),
    ("V[29] (kmol/h)",                   V_REF[29],        V_PY[29]),
    ("T[0]  (K)",                        T_REF[0],         T_PY[0]),
    ("T[1]  (K)",                        T_REF[1],         T_PY[1]),
    ("T[28] (K)",                        T_REF[28],        T_PY[28]),
    ("T[29] (K)",                        T_REF[29],        T_PY[29]),
    ("H[1]-H[0] (kJ/kmol) [refroid. v]", float('nan'),    H_PY[1]-H_PY[0]),
    ("H[0]-h[0] (kJ/kmol) [ΔHvap eff]",  float('nan'),    H_PY[0]-h_PY[0]),
    ("H[28]-h[28] (kJ/kmol) [latente]",  float('nan'),    H_PY[28]-h_PY[28]),
]
for label, ref_v, py_v in rows:
    if np.isnan(ref_v):
        print(f"  {label:<42}  {'(inconnu)':>12}  {py_v:>12,.2f}  {'---':>7}")
    else:
        err = (py_v/ref_v - 1.0)*100 if ref_v else float('nan')
        print(f"  {label:<42}  {ref_v:>12,.2f}  {py_v:>12,.2f}  {err:>+7.2f}%")

# Valeurs Watson directement (j=0)
print(f"\n  ΔHvap Watson implique Delphi (hyp. seul B differe) = {HH_delphi_h1:>10.2f} kJ/kmol")
print(f"  ΔHvap Watson Python (H[0]-h[0])                   = {H_PY[0]-h_PY[0]:>10.2f} kJ/kmol")
print(f"  Erreur relative                                    = {(HH_delphi_h1/(H_PY[0]-h_PY[0])-1)*100:>+9.2f}%")

# =============================================================================
# PART 8 - Analyse ΔHvap Watson composant par composant a T[0]
# =============================================================================
print("\n" + "=" * 70)
print("ANALYSE ΔHvap WATSON par composant a T[0]")
print("=" * 70)
print(f"  T[0] = {T_PY[0]:.2f} K, P = {P_bar:.2f} bar")
print(f"  (ΔHvap impacte h_py[0] = H_ig[0] - sum(x_i * ΔHvap_i))")
print(f"  Contribution totale au terme B = L[0]*sum(x_i*ΔHvap_i)")
print()

# Compute individual ΔHvap: h = H_ig - ΔHvap  =>  ΔHvap = H_ig - h
# H_ig at T[0] (limit P->0, vapor)
# Use pure_component_enthalpy with x=[1...0...] to get single component contribution
nc = l_conv.shape[0]
names = ["C1","C2","C3","iC4","nC4","iC5","nC5","C6","C7","C8","C9","C10","C11","C12","CO2","N2"]

# Get overall x[0] composition
x0 = x_PY[:, 0]
print(f"  {'Comp':>5}  {'x[0]':>8}  {'ΔHvap_i (approx)':>18}  {'x*ΔHvap_i':>14}")
print(f"  {'-'*55}")

total_watson = 0.0
for i in range(nc):
    if x0[i] > 1e-4:
        # Enthalpy pure liquid component i at T[0]
        x_pure = np.zeros(nc); x_pure[i] = 1.0
        h_pure_liq = col.eos.pure_component_enthalpy(T_PY[0], P_Pa, x_pure, "liquid")
        H_pure_vap = col.eos.mixture_enthalpy(T_PY[0], P_Pa, x_pure, "vapor")
        dHvap_i = H_pure_vap - h_pure_liq
        contrib = x0[i] * dHvap_i
        total_watson += contrib
        label = names[i] if i < len(names) else f"C{i}"
        print(f"  {label:>5}  {x0[i]:>8.4f}  {dHvap_i:>18.2f}  {contrib:>14.2f} kJ/kmol")

print(f"  {'SUM':>5}  {x0.sum():>8.4f}  {'--':>18}  {total_watson:>14.2f} kJ/kmol  [= H[0]-h[0] attendu]")
print(f"  calcul direct H[0]-h[0] = {H_PY[0]-h_PY[0]:.2f} kJ/kmol")
print(f"\n  NOTE: total_watson inclut H_dep_PR pure-composant mais PAS H_dep melange!")

# --- Decomposition rigoureuse des 3 termes de H[0]-h[0] ---
# h[0] = H_ig(T, x) - sum(x_i * ΔHvap_i)     <- pure_component_enthalpy, sans H_dep
# H[0] = H_ig(T, y) + H_dep_PR(T, P, y, vap) <- mixture_enthalpy, avec H_dep
# => H[0]-h[0] = [H_ig(y)-H_ig(x)] + H_dep_PR_vap + sum(x_i * ΔHvap_i_WATSON)
H_ig_x0  = col.eos.ideal_gas_enthalpy(T_PY[0], x_PY[:, 0])   # kJ/kmol
H_ig_y0  = col.eos.ideal_gas_enthalpy(T_PY[0], y_PY[:, 0])
H_dep_y0 = col.eos.enthalpy_departure(T_PY[0], P_Pa, y_PY[:, 0], "vapor")
Watson_mix = h_PY[0] - H_ig_x0    # = -sum(x_i * ΔHvap_i) (devrait etre negatif)
# => sum(x_i * ΔHvap_i) = H_ig_x0 - h_PY[0]
sum_watson_pure = H_ig_x0 - h_PY[0]
dHig_comp = H_ig_y0 - H_ig_x0     # effet de composition sur H_ig

print(f"\n  DECOMPOSITION H[0]-h[0] en 3 termes:")
print(f"    H_ig(y[0]) - H_ig(x[0])   = {dHig_comp:>+9.2f} kJ/kmol  [composition y vs x dans gaz ideal]"  )
print(f"    H_dep_PR(y[0], vapeur)     = {H_dep_y0:>+9.2f} kJ/kmol  [correction gaz reel PR, vapeur]")
print(f"    sum(x_i * ΔHvap_i) Watson = {sum_watson_pure:>+9.2f} kJ/kmol  [latente Watson liquide, AUCUN H_dep]")
print(f"    TOTAL = H[0]-h[0]          = {dHig_comp+H_dep_y0+sum_watson_pure:>+9.2f} kJ/kmol  [verification: {H_PY[0]-h_PY[0]:.2f}]")
print(f"\n  IMPORTANT: h[0] = pure_component_enthalpy() utilise ZERO H_dep PR pour le liquide!")
print(f"    => L erreur peut venir du H_dep_PR vapeur (si Delphi utilise SRK/BWRLS au lieu de PR)")
print(f"    => OU de ΔHvap_i Watson (coefficients DIPPR sous-estimes a T~261K)")
print(f"    => OU des deux a la fois")
print(f"\n  Si seul H_dep_PR erreur: H_dep_PR_Delphi = {H_dep_y0 + (HH_delphi_h1 - (H_PY[0]-h_PY[0])):>+9.2f} kJ/kmol"
      f"  (Python: {H_dep_y0:+.2f}, diff: {HH_delphi_h1-(H_PY[0]-h_PY[0]):+.2f})")
print(f"  Si seul Watson ΔHvap erreur: sum(x*ΔHvap)_Delphi = {sum_watson_pure + (HH_delphi_h1-(H_PY[0]-h_PY[0])):>9.2f} kJ/kmol"
      f"  (Python: {sum_watson_pure:.2f}, diff: {HH_delphi_h1-(H_PY[0]-h_PY[0]):+.2f})")

# =============================================================================
# PART 9 - Recap tous les cas
# =============================================================================
print("\n" + "=" * 70)
print("RESUME TOUS CAS  (condenseur partiel: QC = A + B)")
print("=" * 70)

QC_refs  = {1: 4_133_587.91, 2: 4_125_130.56, 3: 3_340_734.13}
QR_refs  = {1: 22_854_385.49, 2: 22_845_197.41, 3: 22_060_800.98}

print(f"\n  {'Cas':>3}  {'QC_ref':>14}  {'QC_py':>14}  {'err':>7}  "
      f"{'H[1]-H[0]':>12}  {'H[0]-h[0]':>12}  "
      f"{'ΔHvap_impl':>12}  {'err_ΔHvap':>10}")
print(f"  {'-'*100}")

for cn in [1, 2, 3]:
    c_c = Deethanizer()
    c_c.solve(case=cn, max_outer=20, tol=1.0, verbose=False)

    T_c  = c_c.T;  V_c = c_c.V;  L_c = c_c.L
    qc_c = abs(c_c.QC)

    l_c = c_c.l;  v_c = c_c.v
    x_c = np.zeros_like(l_c);  y_c = np.zeros_like(v_c)
    for j in range(N):
        Lj = l_c[:, j].sum();  Vj = v_c[:, j].sum()
        if Lj > 1e-10: x_c[:, j] = l_c[:, j] / Lj
        if Vj > 1e-10: y_c[:, j] = v_c[:, j] / Vj

    h0 = c_c.eos.pure_component_enthalpy(T_c[0], c_c.P, x_c[:, 0], "liquid")
    H0 = c_c.eos.mixture_enthalpy(T_c[0], c_c.P, y_c[:, 0], "vapor")
    H1 = c_c.eos.mixture_enthalpy(T_c[1], c_c.P, y_c[:, 1], "vapor")

    dH_sens = H1 - H0            # kJ/kmol  terme A unitaire
    dH_lat  = H0 - h0            # kJ/kmol  terme B unitaire

    A_c = V_c[1] * dH_sens
    B_c = L_c[0] * dH_lat

    # Implication Delphi: si seul terme B differe
    dH_lat_impl = (QC_refs[cn] - A_c) / L_c[0]
    err_lat = (dH_lat_impl / dH_lat - 1.0) * 100
    err_qc  = (qc_c / QC_refs[cn] - 1.0) * 100

    print(f"  {cn:>3}  {QC_refs[cn]:>14,.1f}  {qc_c:>14,.1f}  {err_qc:>+6.2f}%  "
          f"{dH_sens:>12.2f}  {dH_lat:>12.2f}  "
          f"{dH_lat_impl:>12.2f}  {err_lat:>+9.2f}%")

print(f"""
  COLONNES:
    H[1]-H[0]  : refroidissement sensible vapeur (T[1]->T[0]) en kJ/kmol
    H[0]-h[0]  : chaleur latente effective au condenseur en kJ/kmol (Python Watson)
    ΔHvap_impl : chaleur latente IMPLIQUEE par QC_Delphi si H[1]-H[0] identique
    err_ΔHvap  : erreur relative Watson vs ΔHvap implique Delphi

  CONCLUSION:
    V[1] et L[0] sont exacts => erreur QC = erreur purement dans les enthalpies.
    Le Terme B domine (~87% de QC).
    L ecart ~3-7% dans QC correspond a ~3-7% dans ΔHvap_Watson.
    Pistes: (1) coefficients Watson C2 sous-estimes a T~260K
            (2) correction PR departure differente (Delphi utilise peut-etre BWRLS ou SRK)
            (3) interactions binaires differentes dans le modele de melange
""")
