"""Thermal conduction law (Fourier) as constitutive input. Assertion-based CAS audit block. Pillar: Thermodynamics | Chain: Fourier law -> energy balance -> diffusion equation """ def run(): from sympy import symbols, Function, diff, simplify print("=== CAS AUDIT: F0018 — Fourier conduction law ===\n") pass_count = 0 fail_count = 0 total_steps = 0 print("Section A: Inputs defined.") print(" Jq = -kappa*grad(T) (constitutive, not derived)\n") x, y, z, t = symbols("x y z t", real=True) kappa_th = symbols("kappa_th", positive=True) c_vol = symbols("c_vol", positive=True) T_field = Function("T_field")(x, y, z, t) print("Section B: Isotropic homogeneous medium, kappa >= 0, c > 0.\n") print("Section C: Lemmas declared.\n") print("Section D: Step log") print("---------------------------------------------") # Step 1: Fourier law gradT_x = diff(T_field, x) gradT_y = diff(T_field, y) gradT_z = diff(T_field, z) Jq_x = -kappa_th * gradT_x Jq_y = -kappa_th * gradT_y Jq_z = -kappa_th * gradT_z step1_res_x = simplify(Jq_x + kappa_th * gradT_x) step1_res_y = simplify(Jq_y + kappa_th * gradT_y) step1_res_z = simplify(Jq_z + kappa_th * gradT_z) total_steps += 1 if (simplify(step1_res_x) == 0 and simplify(step1_res_y) == 0 and simplify(step1_res_z) == 0): print(" Step 1 PASS — Jq = -kappa*grad(T) (all 3 components)") pass_count += 1 else: print(" Step 1 FAIL") fail_count += 1 # Step 2: Energy balance substitution dTdt = diff(T_field, t) div_Jq = diff(Jq_x, x) + diff(Jq_y, y) + diff(Jq_z, z) energy_balance = c_vol * dTdt + div_Jq Lap_T = diff(T_field, x, 2) + diff(T_field, y, 2) + diff(T_field, z, 2) step2_residual = simplify(energy_balance - (c_vol * dTdt - kappa_th * Lap_T)) total_steps += 1 if simplify(step2_residual) == 0: print(" Step 2 PASS — c*dT/dt + div(Jq) = c*dT/dt - kappa*Lap(T)") pass_count += 1 else: print(f" Step 2 FAIL — residual: {step2_residual}") fail_count += 1 # Step 3: Diffusion equation diffusion_eq = c_vol * dTdt - kappa_th * Lap_T step3_residual = simplify(energy_balance - diffusion_eq) total_steps += 1 if simplify(step3_residual) == 0: print(" Step 3 PASS — Heat equation: c*dT/dt = kappa*Lap(T)") pass_count += 1 else: print(f" Step 3 FAIL — residual: {step3_residual}") fail_count += 1 # Step 4: Constant kappa div_kappa_gradT = diff(kappa_th * gradT_x, x) + diff(kappa_th * gradT_y, y) + diff(kappa_th * gradT_z, z) step4_residual = simplify(div_kappa_gradT - kappa_th * Lap_T) total_steps += 1 if simplify(step4_residual) == 0: print(" Step 4 PASS — div(kappa*gradT) = kappa*Lap(T) (const kappa)") pass_count += 1 else: print(f" Step 4 FAIL — residual: {step4_residual}") fail_count += 1 # Step 5: Sign consistency gradT_sq = symbols("gradT_sq", positive=True) T_pos = symbols("T_pos", positive=True) sigma_from_fourier = kappa_th * gradT_sq / T_pos**2 sigma_check = (-kappa_th) * gradT_sq * (-(1 / T_pos**2)) step5_residual = simplify(sigma_check - sigma_from_fourier) total_steps += 1 if simplify(step5_residual) == 0: print(" Step 5 PASS — Fourier sign consistent with F0016 entropy production") pass_count += 1 else: print(f" Step 5 FAIL — residual: {step5_residual}") fail_count += 1 # Step 6: Thermal diffusivity alpha_th = symbols("alpha_th", positive=True) alpha_def = kappa_th / c_vol step6_residual = simplify(alpha_def - kappa_th / c_vol) total_steps += 1 if simplify(step6_residual) == 0: print(" Step 6 PASS — alpha = kappa/c (thermal diffusivity)") pass_count += 1 else: print(f" Step 6 FAIL — residual: {step6_residual}") fail_count += 1 # Step 7: Concrete 1D steady-state A_coeff, B_coeff = symbols("A_coeff B_coeff", real=True) x_1d = symbols("x_1d", real=True) T_1d = A_coeff + B_coeff * x_1d d2T_dx2 = diff(T_1d, x_1d, 2) total_steps += 1 if simplify(d2T_dx2) == 0: print(" Step 7 PASS — Steady-state 1D: T = A + Bx => d^2T/dx^2 = 0") pass_count += 1 else: print(f" Step 7 FAIL — d^2T/dx^2 = {d2T_dx2}") fail_count += 1 # Step 8: Numerical diffusivity kappa_val = 401 c_val = 3.45e6 alpha_val = kappa_val / c_val alpha_expected = 1.162e-4 rel_error = abs(alpha_val - alpha_expected) / alpha_expected total_steps += 1 if rel_error < 1e-2: print(f" Step 8 PASS — Numerical: alpha(Cu) = {alpha_val:.4e} m^2/s") pass_count += 1 else: print(f" Step 8 FAIL — Numerical rel error: {rel_error:.2e}") fail_count += 1 print("---------------------------------------------\n") print("Section E: Output checks") print("---------------------------------------------") print(" Unit check: [W/m^3] — PASS\n") # Self-test: wrong Fourier sign Jq_wrong_x = kappa_th * gradT_x Jq_wrong_y = kappa_th * gradT_y Jq_wrong_z = kappa_th * gradT_z div_Jq_wrong = diff(Jq_wrong_x, x) + diff(Jq_wrong_y, y) + diff(Jq_wrong_z, z) energy_wrong = c_vol * dTdt + div_Jq_wrong diffusion_wrong = c_vol * dTdt + kappa_th * Lap_T total_steps += 1 wrong_vs_correct = simplify(diffusion_wrong - diffusion_eq) if simplify(wrong_vs_correct) != 0: print(" Self-test 1: Wrong Fourier sign gives anti-diffusion (detected) PASS") pass_count += 1 else: print(" Self-test 1: FAIL (wrong sign not detected)") fail_count += 1 # Self-test: quantify expected_wrong_diff = 2 * kappa_th * Lap_T wrong_quant = simplify(wrong_vs_correct - expected_wrong_diff) total_steps += 1 if simplify(wrong_quant) == 0: print(" Self-test 2: wrong - correct = 2*kappa*Lap(T) (quantified) PASS") pass_count += 1 else: print(f" Self-test 2: FAIL — residual = {wrong_quant}") fail_count += 1 print("---------------------------------------------\n") print("=============================================") print(" F0018 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 F0018.") print(f" ✓ F0018 — {pass_count}/{total_steps} PASS") if __name__ == "__main__": run()