%% CAS_F0029_VERIFY.m — Partition function linkage (Z → F, U, S, Cv)
%  Pillar : Thermodynamics
%  CalRef : Math Appendix §5A, Thermodynamics Calibration §6A
%  Chain  : Z(β) → F = −lnZ/β → U = −∂lnZ/∂β → S = kB(lnZ+βU) → Cv
%  Hardening: isAlways(..., 'Unknown', 'false') on every symbolic assertion
%            symvar-based presence checks; solver and has-function avoided

clear; clc;
fprintf('\n=== CAS F0029 : Partition function linkage ===\n\n');

%% ── Symbols ──────────────────────────────────────────────────
syms beta kB T real positive
syms lnZ(beta)                       % ln Z as symfun of beta

%% ── A. Inputs ────────────────────────────────────────────────
%  β = 1/(kB T)
%  F = −(1/β)·ln Z = −kB T ln Z
%  U = −∂(ln Z)/∂β

F_free = -lnZ / beta;
U_int = -diff(lnZ, beta);

%% ── Step 1: F = −(1/β)·ln Z structure ──────────────────────
%  Verify F = −kB T ln Z when β = 1/(kB T) → 1/β = kB T
F_kBT = -kB * T * lnZ;
%  Substitute β = 1/(kB T) into F_free:
F_sub = subs(F_free, beta, 1/(kB*T));
%  Need lnZ(1/(kBT)) — compare structurally by checking coefficient
%  Instead: verify −lnZ/β = −kBT·lnZ when β = 1/(kBT)
res1 = simplify(F_sub + kB*T*lnZ(1/(kB*T)));
assert(isAlways(res1 == 0, 'Unknown', 'false'), ...
    'FAIL Step 1: F ≠ −kBT·lnZ');
fprintf('Step 1  PASS — F = −(1/β)·lnZ = −kBT·lnZ\n');

%% ── Step 2: U = −∂lnZ/∂β ───────────────────────────────────
%  This is the definition. Verify structure: U depends on derivative of lnZ.
%  For a concrete Z: Z = exp(−β·E₀) → lnZ = −β·E₀ → U = E₀
syms E0 real positive
lnZ_concrete = -beta * E0;
U_concrete = -diff(lnZ_concrete, beta);
res2 = simplify(U_concrete - E0);
assert(isAlways(res2 == 0, 'Unknown', 'false'), ...
    'FAIL Step 2: single-state U ≠ E₀');
fprintf('Step 2  PASS — Single state: Z=e^{−βE₀} → U = E₀\n');

%% ── Step 3: F from concrete Z ──────────────────────────────
%  F = −lnZ/β = −(−βE₀)/β = E₀
F_concrete = -lnZ_concrete / beta;
res3 = simplify(F_concrete - E0);
assert(isAlways(res3 == 0, 'Unknown', 'false'), ...
    'FAIL Step 3: single-state F ≠ E₀');
fprintf('Step 3  PASS — Single state: F = E₀ (= U, zero entropy)\n');

%% ── Step 4: S = kB(lnZ + βU) ───────────────────────────────
%  Derive: S = −∂F/∂T = (U − F)/T
%  From F = −lnZ/β and U = −∂lnZ/∂β:
%  S = (U − F)/T = (−∂lnZ/∂β + lnZ/β) / T
%  With β = 1/(kBT) → T = 1/(kBβ):
%  S = kBβ · (−∂lnZ/∂β + lnZ/β) = kB(lnZ + βU)
%  Verify algebraically:
S_formula = kB * (lnZ + beta * U_int);

%  Alternative: S = (U − F)/T with T = 1/(kBβ)
S_thermo = (U_int - F_free) * kB * beta;  % (U−F)/T = (U−F)·kBβ
res4 = simplify(S_formula - S_thermo);
assert(isAlways(res4 == 0, 'Unknown', 'false'), ...
    'FAIL Step 4: S = kB(lnZ+βU) ≠ (U−F)/T');
fprintf('Step 4  PASS — S = kB(lnZ + βU) = (U−F)/T\n');

%% ── Step 5: S for single state = 0 ─────────────────────────
%  Single state: lnZ = −βE₀, U = E₀
%  S = kB(−βE₀ + β·E₀) = kB·0 = 0
S_single = kB * (lnZ_concrete + beta * E0);
res5 = simplify(S_single);
assert(isAlways(res5 == 0, 'Unknown', 'false'), ...
    'FAIL Step 5: single-state S ≠ 0');
fprintf('Step 5  PASS — Single state: S = 0 (no degeneracy → zero entropy)\n');

%% ── Step 6: Two-level system ────────────────────────────────
%  E₁ = 0, E₂ = ε: Z = 1 + e^{−βε}
%  lnZ = ln(1 + e^{−βε})
%  U = −∂lnZ/∂β = ε·e^{−βε}/(1 + e^{−βε})
syms epsilon real positive
Z_two = 1 + exp(-beta*epsilon);
lnZ_two = log(Z_two);
U_two = simplify(-diff(lnZ_two, beta));
U_two_expected = epsilon * exp(-beta*epsilon) / (1 + exp(-beta*epsilon));
res6 = simplify(U_two - U_two_expected);
assert(isAlways(res6 == 0, 'Unknown', 'false'), ...
    'FAIL Step 6: two-level U mismatch');
fprintf('Step 6  PASS — Two-level: U = ε·e^{−βε}/(1+e^{−βε})\n');

%% ── Step 7: Two-level high-T limit ─────────────────────────
%  β→0: Z→2, U→ε/2, S→kB·ln2
%  Check U(β→0): ε·1/(1+1) = ε/2
U_highT = limit(U_two, beta, 0);
res7 = simplify(U_highT - epsilon/2);
assert(isAlways(res7 == 0, 'Unknown', 'false'), ...
    'FAIL Step 7: high-T U ≠ ε/2');
fprintf('Step 7  PASS — Two-level high-T: U → ε/2\n');

%% ── Step 8: F = U − TS consistency ─────────────────────────
%  Verify: F = U − TS → F − U + TS = 0
%  Using F = −lnZ/β, S = kB(lnZ + βU):
%  F − U + T·S = −lnZ/β − U + (1/(kBβ))·kB(lnZ + βU)
%  = −lnZ/β − U + lnZ/β + U = 0
FmUTS = F_free - U_int + (1/(kB*beta)) * S_formula;
res8 = simplify(FmUTS);
assert(isAlways(res8 == 0, 'Unknown', 'false'), ...
    'FAIL Step 8: F ≠ U − TS');
fprintf('Step 8  PASS — F = U − TS (Legendre consistency)\n');

%% ── Step 9: Cv = −kBβ² ∂U/∂β ───────────────────────────────
%  Cv = ∂U/∂T = (∂U/∂β)(∂β/∂T) = (∂U/∂β)(−β²kB) [since ∂β/∂T = −1/(kBT²) = −kBβ²]
%  Wait: ∂β/∂T = −1/(kBT²) and β² = 1/(kBT)² → kBβ² = 1/(kBT²) → ∂β/∂T = −kBβ²
%  Actually: β = 1/(kBT) → ∂β/∂T = −1/(kBT²) = −β²·kB
%  So Cv = (∂U/∂β)·(−β²·kB)
%  Verify for two-level system:
dU_dbeta_two = diff(U_two, beta);
Cv_two = simplify(-kB * beta^2 * dU_dbeta_two);
%  Cv should be kBβ²ε² · e^{−βε}/(1+e^{−βε})²
Cv_expected = kB * beta^2 * epsilon^2 * exp(-beta*epsilon) / (1 + exp(-beta*epsilon))^2;
res9 = simplify(Cv_two - Cv_expected);
assert(isAlways(res9 == 0, 'Unknown', 'false'), ...
    'FAIL Step 9: two-level Cv mismatch');
fprintf('Step 9  PASS — Cv = kBβ²ε²·e^{−βε}/(1+e^{−βε})² (Schottky anomaly)\n');

%% ── Step 10: Numerical — two-level at kBT = ε ──────────────
%  β = 1/ε (setting kB=1 for numerical check)
%  U = ε·e⁻¹/(1+e⁻¹) ≈ ε·0.2689
%  Cv = β²ε²·e⁻¹/(1+e⁻¹)² ≈ 0.1966 (in units of kB)
e_inv = exp(-1);
U_num = e_inv / (1 + e_inv);       % in units of ε
Cv_num = e_inv / (1 + e_inv)^2;    % in units of kB
U_expected_num = 0.2689;
Cv_expected_num = 0.1966;   % e^{-1}/(1+e^{-1})^2 at βε=1
assert(abs(U_num - U_expected_num) < 0.001, 'FAIL Step 10a: U numerical');
assert(abs(Cv_num - Cv_expected_num) < 0.001, 'FAIL Step 10b: Cv numerical');
fprintf('Step 10 PASS — kBT=ε: U/ε=%.4f, Cv/kB=%.4f (Schottky at βε=1)\n', U_num, Cv_num);

%% ── Step 11: Self-test — wrong sign in F ────────────────────
%  Wrong: F = +(1/β)·lnZ (positive instead of negative)
F_wrong = lnZ / beta;
%  Then U−F+TS ≠ 0
S_from_wrong = kB * (lnZ + beta * U_int);  % S formula unchanged
FmUTS_wrong = F_wrong - U_int + (1/(kB*beta)) * S_from_wrong;
res11 = simplify(FmUTS_wrong);
assert(~isAlways(res11 == 0, 'Unknown', 'false'), ...
    'FAIL Step 11: wrong F sign not detected');
fprintf('Step 11 PASS — Wrong F = +lnZ/β breaks Legendre relation\n');

%% ── Summary ─────────────────────────────────────────────────
fprintf('\n✓ ALL 11 ASSERTIONS PASSED — F0029 audit complete.\n');
fprintf('  Chain: Z(β) → F=−lnZ/β → U=−∂lnZ/∂β → S=kB(lnZ+βU) → Cv\n');
fprintf('  Cross-ref: F0016 (entropy production), F0017 (Cp−Cv)\n');
