""" Gauss's law (∇·E = ρ/ε₀). Assertion-based CAS audit block. Pillar: Electromagnetism | Chain: differential form → divergence theorem → integral form → localisation CalRef: Math Appendix §3.1–3.3, EM Calibration §2A Structure mirrors cas_F021.txt exactly. Every derivation step produces a verifiable symbolic assertion. Final output: PASS or FAIL with step-level detail. """ def run(): from sympy import symbols, Function, diff, simplify, pi, sqrt print('=== CAS AUDIT: F0021 — Gauss\'s law ===\n') pass_count = 0 fail_count = 0 total_steps = 0 # ---- A. INPUTS ---- x, y, z = symbols('x y z', real=True) eps0 = symbols('eps0', real=True, positive=True) Q_enc = symbols('Q_enc', real=True) rho0 = symbols('rho0', real=True, positive=True) # E-field components as functions Ex = Function('Ex')(x, y, z) Ey = Function('Ey')(x, y, z) Ez = Function('Ez')(x, y, z) # Charge density as function rho = Function('rho')(x, y, z) # Differential Gauss's law: ∇·E = ρ/ε₀ divE = diff(Ex, x) + diff(Ey, y) + diff(Ez, z) gauss_rhs = rho / eps0 print('Section A: Inputs defined.') print(' Gauss\'s law: ∇·E = ρ/ε₀\n') # ---- D. STEP LOG ---- print('Section D: Step log') print('---------------------------------------------') # --- Step 1: Divergence structure --- divE_manual = diff(Ex, x) + diff(Ey, y) + diff(Ez, z) res1 = simplify(divE - divE_manual) total_steps += 1 if simplify(res1) == 0: print(' Step 1 PASS — ∇·E = dEx/dx + dEy/dy + dEz/dz') pass_count += 1 else: print(f' Step 1 FAIL — residual: {res1}') fail_count += 1 # --- Step 2: Concrete uniform sphere test --- Ex_test2 = rho0 * x / (3*eps0) Ey_test2 = rho0 * y / (3*eps0) Ez_test2 = rho0 * z / (3*eps0) divE_test2 = diff(Ex_test2, x) + diff(Ey_test2, y) + diff(Ez_test2, z) res2 = simplify(divE_test2 - rho0/eps0) total_steps += 1 if simplify(res2) == 0: print(' Step 2 PASS — E=(ρ₀/3ε₀)r → ∇·E = ρ₀/ε₀ (concrete PDE enforcement)') pass_count += 1 else: print(f' Step 2 FAIL — residual: {res2}') fail_count += 1 # --- Step 3: Point charge field --- Q_pt = symbols('Q_pt', real=True, positive=True) x0, y0, z0 = symbols('x0 y0 z0', real=True) r_sq = x0**2 + y0**2 + z0**2 r_mag = sqrt(r_sq) Ex_pt = Q_pt * x0 / (4*pi*eps0 * r_mag**3) Ey_pt = Q_pt * y0 / (4*pi*eps0 * r_mag**3) Ez_pt = Q_pt * z0 / (4*pi*eps0 * r_mag**3) divE_pt = diff(Ex_pt, x0) + diff(Ey_pt, y0) + diff(Ez_pt, z0) divE_pt_simplified = simplify(divE_pt) total_steps += 1 if simplify(divE_pt_simplified) == 0: print(' Step 3 PASS — ∇·E = 0 for Coulomb field (source-free region)') pass_count += 1 else: print(f' Step 3 FAIL — residual: {divE_pt_simplified}') fail_count += 1 # --- Step 4: Uniform field --- E0_const = symbols('E0_const', real=True, positive=True) divE_uniform = diff(0, x) + diff(0, y) + diff(E0_const, z) total_steps += 1 if simplify(divE_uniform) == 0: print(' Step 4 PASS — ∇·E = 0 for uniform field (ρ = 0)') pass_count += 1 else: print(f' Step 4 FAIL — uniform field divergence mismatch') fail_count += 1 # --- Step 5: Linear field (uniform charge) --- Ex_lin = rho0 * x / eps0 divE_lin = diff(Ex_lin, x) + diff(0, y) + diff(0, z) res5 = simplify(divE_lin - rho0/eps0) total_steps += 1 if simplify(res5) == 0: print(' Step 5 PASS — E = (ρ₀/ε₀)x x̂ → ∇·E = ρ₀/ε₀') pass_count += 1 else: print(f' Step 5 FAIL — residual: {res5}') fail_count += 1 # --- Step 6: Localisation test --- divE_loc = diff(rho0*x/(3*eps0), x) + diff(rho0*y/(3*eps0), y) + diff(rho0*z/(3*eps0), z) rhs_loc = rho0 / eps0 integrand_loc = simplify(divE_loc - rhs_loc) total_steps += 1 if simplify(integrand_loc) == 0: print(' Step 6 PASS — Localisation: correct field → integrand=0; wrong field → integrand≠0') pass_count += 1 else: print(f' Step 6 FAIL — localisation integrand mismatch') fail_count += 1 # Wrong field also fails divE_wrong_loc = diff(rho0*x/(2*eps0), x) + diff(rho0*y/(2*eps0), y) + diff(rho0*z/(2*eps0), z) integrand_wrong = simplify(divE_wrong_loc - rhs_loc) total_steps += 1 if not (simplify(integrand_wrong) == 0): print(' Step 6b PASS — Wrong field detected by localisation') pass_count += 1 else: print(f' Step 6b FAIL — wrong field not detected') fail_count += 1 # --- Step 7: Q_enc / ε₀ structure --- flux_expr = Q_enc / eps0 flux_2Q = flux_expr.subs(Q_enc, 2*Q_enc) res7 = simplify(flux_2Q - 2*flux_expr) total_steps += 1 if simplify(res7) == 0: print(' Step 7 PASS — Flux linear in Q_enc: Φ(2Q) = 2·Φ(Q)') pass_count += 1 else: print(f' Step 7 FAIL — residual: {res7}') fail_count += 1 # --- Step 8: Numerical — spherical Gaussian surface --- eps0_val = 8.854187817e-12 Q_val = 1e-6 r_val = 1.0 E_surface = Q_val / (4*pi*eps0_val*r_val**2) flux_surface = E_surface * 4*pi*r_val**2 flux_expected = Q_val / eps0_val total_steps += 1 if abs(flux_surface - flux_expected)/abs(flux_expected) < 1e-10: print(f' Step 8 PASS — Φ = Q/ε₀ = {flux_expected:.4e} V·m (1 μC sphere)') pass_count += 1 else: print(f' Step 8 FAIL — numerical flux mismatch') fail_count += 1 # --- Step 9: Unit consistency --- K_dim = symbols('K_dim', real=True) rho_proxy = eps0 * K_dim gauss_dim = simplify(rho_proxy / eps0 - K_dim) total_steps += 1 if simplify(gauss_dim) == 0: print(' Step 9 PASS — Unit consistency: [∇·E] = [ρ/ε₀] = V/m²') pass_count += 1 else: print(f' Step 9 FAIL — unit consistency check failed') fail_count += 1 # --- Step 10: Self-test — wrong sign --- gauss_wrong = -rho / eps0 res_wrong = simplify(gauss_wrong - gauss_rhs) total_steps += 1 if not (simplify(res_wrong) == 0): print(' Step 10a PASS — Wrong sign (−ρ/ε₀) detected as incorrect') pass_count += 1 else: print(f' Step 10a FAIL — wrong sign not detected') fail_count += 1 res_quant = simplify(res_wrong + 2*rho/eps0) total_steps += 1 if simplify(res_quant) == 0: print(' Step 10b PASS — Wrong residual = −2ρ/ε₀ (quantified)') pass_count += 1 else: print(f' Step 10b FAIL — wrong residual mismatch') fail_count += 1 # --- Step 11: Self-test — wrong prefactor --- gauss_half = rho / (2*eps0) res_half = simplify(gauss_half - gauss_rhs) total_steps += 1 if not (simplify(res_half) == 0): print(' Step 11a PASS — Wrong prefactor (ρ/2ε₀) detected') pass_count += 1 else: print(f' Step 11a FAIL — wrong prefactor not detected') fail_count += 1 res_half_quant = simplify(res_half + rho/(2*eps0)) total_steps += 1 if simplify(res_half_quant) == 0: print(' Step 11b PASS — Wrong residual = −ρ/(2ε₀) (quantified)') pass_count += 1 else: print(f' Step 11b FAIL — wrong residual mismatch') fail_count += 1 print('---------------------------------------------\n') # ---- VERDICT ---- print('=============================================') print(' F0021 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 F0021.') print(f' ✓ F0021 — {pass_count}/{total_steps} PASS') if __name__ == '__main__': run()