"""Ideal-gas calibration (PV=nRT, Z definition).

Assertion-based CAS audit block.
Pillar: Thermodynamics | Chain: ideal gas -> R_eff -> Z -> virial
CalRef: Thermodynamics Calibration S5Y.1-5Y.3

Verifies:
  1. R_eff = PV/(nT) definition
  2. Ideal-gas substitution: PV=nRT => R_eff=R
  3. Z = PV/(nRT) = R_eff/R
  4. Ideal limit: Z=1
  5. Virial expansion structure: Z = 1 + B*n/V + C*(n/V)^2 + ...
  6. Dimensional consistency
  7. Non-ideal detection (Z != 1 when B != 0)
"""


def run():
    from sympy import symbols, simplify, pi, Rational

    print("=== CAS AUDIT: F0010 — Ideal-gas calibration (PV=nRT, Z) ===\n")

    pass_count = 0
    fail_count = 0
    total_steps = 0

    # ---- A. INPUTS ----
    P, V_gas, n, T_gas = symbols("P V_gas n T_gas", positive=True)
    R_gas = symbols("R_gas", positive=True)
    Z_comp = symbols("Z_comp", positive=True)
    B_vir, C_vir = symbols("B_vir C_vir", real=True)

    print("Section A: Inputs defined.")
    print("  P, V, n, T, R, R_eff, Z, virial coefficients B, C\n")

    # ---- B. ASSUMPTIONS / DOMAINS ----
    print("Section B: Single-component, classical, low density.\n")

    # ---- C. ALLOWED LEMMAS ----
    print("Section C: Lemmas declared.")
    print("  C.1: PV=nRT => R_eff=R, Z=1")
    print("  C.2: Z = R_eff/R")
    print("  C.3: Virial: Z = 1 + B*n/V + ...\n")

    # ---- D. STEP LOG ----
    print("Section D: Step log")
    print("---------------------------------------------")

    # Step 1: R_eff definition
    R_eff_def = P * V_gas / (n * T_gas)

    total_steps += 1
    if R_gas not in R_eff_def.free_symbols:
        print("  Step 1  PASS — R_eff = PV/(nT) is independent of R (pure measurement)")
        pass_count += 1
    else:
        print("  Step 1  FAIL — R_eff definition contains R")
        fail_count += 1

    # Step 2: Ideal-gas substitution => R_eff = R
    P_ideal = n * R_gas * T_gas / V_gas
    R_eff_ideal = simplify(R_eff_def.subs(P, P_ideal))
    step2_residual = simplify(R_eff_ideal - R_gas)

    total_steps += 1
    if simplify(step2_residual) == 0:
        print("  Step 2  PASS — PV=nRT => R_eff = R")
        pass_count += 1
    else:
        print(f"  Step 2  FAIL — R_eff_ideal = {R_eff_ideal} (expected R)")
        fail_count += 1

    # Step 3: Z definition
    Z_def = P * V_gas / (n * R_gas * T_gas)
    Z_from_Reff = R_eff_def / R_gas
    step3_residual = simplify(Z_def - Z_from_Reff)

    total_steps += 1
    if simplify(step3_residual) == 0:
        print("  Step 3  PASS — Z = PV/(nRT) = R_eff/R")
        pass_count += 1
    else:
        print(f"  Step 3  FAIL — Z identity residual: {step3_residual}")
        fail_count += 1

    # Step 4: Ideal limit Z = 1
    Z_ideal = simplify(Z_def.subs(P, P_ideal))
    step4_residual = simplify(Z_ideal - 1)

    total_steps += 1
    if simplify(step4_residual) == 0:
        print("  Step 4  PASS — Ideal gas: Z = 1")
        pass_count += 1
    else:
        print(f"  Step 4  FAIL — Z_ideal = {Z_ideal} (expected 1)")
        fail_count += 1

    # Step 5: R_eff(ideal) = R (algebraic confirmation)
    step5_residual = simplify(simplify(R_eff_ideal) - R_gas)

    total_steps += 1
    if simplify(step5_residual) == 0:
        print("  Step 5  PASS — R_eff(ideal) = R (algebraic confirmation, all state vars cancel)")
        pass_count += 1
    else:
        print(f"  Step 5  FAIL — R_eff(ideal) - R = {step5_residual}")
        fail_count += 1

    # Step 6: Virial expansion structure
    rho = symbols("rho", positive=True)
    Z_virial = 1 + B_vir * rho + C_vir * rho**2
    Z_virial_ideal = Z_virial.subs(rho, 0)
    step6_residual = simplify(Z_virial_ideal - 1)

    total_steps += 1
    if simplify(step6_residual) == 0:
        print("  Step 6  PASS — Virial at rho=0: Z = 1 (ideal limit recovered)")
        pass_count += 1
    else:
        print(f"  Step 6  FAIL — Z_virial(rho=0) = {Z_virial_ideal}")
        fail_count += 1

    # Step 7: Virial leading correction
    from sympy import diff
    dZ_drho = diff(Z_virial, rho)
    dZ_at_zero = dZ_drho.subs(rho, 0)
    step7_residual = simplify(dZ_at_zero - B_vir)

    total_steps += 1
    if simplify(step7_residual) == 0:
        print("  Step 7  PASS — dZ/drho|_{rho=0} = B (leading virial coefficient)")
        pass_count += 1
    else:
        print(f"  Step 7  FAIL — dZ/drho(0) = {dZ_at_zero} (expected B)")
        fail_count += 1

    # Step 8: Second derivative gives C
    d2Z_drho2 = diff(Z_virial, rho, 2)
    d2Z_at_zero = d2Z_drho2.subs(rho, 0)
    step8_residual = simplify(d2Z_at_zero / 2 - C_vir)

    total_steps += 1
    if simplify(step8_residual) == 0:
        print("  Step 8  PASS — (1/2)*d^2Z/drho^2|_{rho=0} = C (third virial)")
        pass_count += 1
    else:
        print(f"  Step 8  FAIL — (1/2)*d2Z(0) = {d2Z_at_zero/2} (expected C)")
        fail_count += 1

    # Step 9: Virial substitution rho = n/V
    Z_virial_nV = Z_virial.subs(rho, n / V_gas)
    Z_virial_nV = simplify(Z_virial_nV)
    Z_virial_expected = 1 + B_vir * n / V_gas + C_vir * (n / V_gas) ** 2
    step9_residual = simplify(Z_virial_nV - Z_virial_expected)

    total_steps += 1
    if simplify(step9_residual) == 0:
        print("  Step 9  PASS — Z(n/V) = 1 + B*n/V + C*(n/V)^2")
        pass_count += 1
    else:
        print(f"  Step 9  FAIL — Substitution residual: {step9_residual}")
        fail_count += 1

    # Step 10: Numerical check with R = 8.314462618 J/(mol*K)
    k_B_val = 1.380649e-23
    N_A_val = 6.02214076e23
    R_computed = k_B_val * N_A_val
    R_CODATA = 8.314462618

    R_rel_error = abs(R_computed - R_CODATA) / R_CODATA

    total_steps += 1
    if R_rel_error < 1e-9:
        print(f"  Step 10 PASS — R = k_B*N_A = {R_computed:.9f} J/(mol*K) (rel err: {R_rel_error:.2e})")
        pass_count += 1
    else:
        print(f"  Step 10 FAIL — R = {R_computed:.9f} (rel error: {R_rel_error:.2e})")
        fail_count += 1

    print("---------------------------------------------\n")

    # ---- E. CHECK OUTPUTS ----
    print("Section E: Output checks")
    print("---------------------------------------------")
    print("  Unit check:")
    print("    R_eff = PV/(nT): [Pa*m^3/(mol*K)] = [J/(mol*K)]")
    print("    Z = PV/(nRT): dimensionless")
    print("    Virial: rho = n/V [mol/m^3], B [m^3/mol], C [m^6/mol^2]")
    print("    PASS\n")

    # Self-test: non-ideal gas (B != 0) gives Z != 1
    Z_nonideal = Z_virial.subs([(B_vir, Rational(-1, 100)), (C_vir, 0), (rho, Rational(1, 10))])
    Z_nonideal = simplify(Z_nonideal)

    total_steps += 1
    if simplify(Z_nonideal) != 1:
        print(f"  Self-test: B=-0.01, rho=0.1 => Z = {Z_nonideal} != 1 (non-ideal detected)  PASS")
        pass_count += 1
    else:
        print("  Self-test: FAIL (non-ideal not detected)")
        fail_count += 1

    # Self-test: reciprocal consistency Z*R = R_eff
    Reff_from_Z = Z_def * R_gas
    Reff_from_Z = simplify(Reff_from_Z)
    step_recip = simplify(Reff_from_Z - R_eff_def)

    total_steps += 1
    if simplify(step_recip) == 0:
        print("  Self-test: Z*R = R_eff (reciprocal consistency)  PASS")
        pass_count += 1
    else:
        print("  Self-test: FAIL (Z*R != R_eff)")
        fail_count += 1

    print("---------------------------------------------\n")

    # ---- VERDICT ----
    print("=============================================")
    print("  F0010 AUDIT RESULT")
    print(f"  Steps: {total_steps}  |  Pass: {pass_count}  |  Fail: {fail_count}")
    if fail_count == 0:
        print("  STATUS: *** PASS ***")
    else:
        print(f"  STATUS: *** FAIL *** ({fail_count} step(s) failed)")
    print("=============================================")
    print("Audit complete for F0010.")
    print(f"  ✓ F0010 — {pass_count}/{total_steps} PASS")


if __name__ == "__main__":
    run()
