""" Virial theorem (2⟨T⟩ = ⟨r·∇V⟩). Assertion-based CAS audit block. Pillar: Mechanics | Chain: G = Σ p·r → dG/dt = 2T + Σ F·r → F = −∇V → time average → virial CalRef: Math Appendix §4A, Mechanics Calibration §3B """ def run(): from sympy import symbols, Function, diff, simplify print('=== CAS AUDIT: F0026 — Virial theorem ===\n') pass_count = 0 fail_count = 0 total_steps = 0 t = symbols('t', real=True) m = symbols('m', real=True, positive=True) # Position and velocity as functions of t rx = Function('rx')(t) ry = Function('ry')(t) rz = Function('rz')(t) vx = diff(rx, t) vy = diff(ry, t) vz = diff(rz, t) ax = diff(vx, t) ay = diff(vy, t) az = diff(vz, t) # Kinetic energy and virial T_kin = m * (vx**2 + vy**2 + vz**2) / 2 G_virial = m * (vx*rx + vy*ry + vz*rz) print('Section D: Step log') print('---------------------------------------------') # --- Step 1: dG/dt product rule --- dG_dt = diff(G_virial, t) dG_expected = m*(ax*rx + ay*ry + az*rz) + m*(vx**2 + vy**2 + vz**2) res1 = simplify(dG_dt - dG_expected) total_steps += 1 if simplify(res1) == 0: print(' Step 1 PASS — dG/dt = m(a·r) + m v²') pass_count += 1 else: print(' Step 1 FAIL') fail_count += 1 # --- Step 2: 2T identification --- twoT = 2 * T_kin res2 = simplify(m*(vx**2 + vy**2 + vz**2) - twoT) total_steps += 1 if simplify(res2) == 0: print(' Step 2 PASS — m v² = 2T') pass_count += 1 else: print(' Step 2 FAIL') fail_count += 1 # --- Step 3: Newton substitution --- Fx = symbols('Fx', cls=Function) Fy = symbols('Fy', cls=Function) Fz = symbols('Fz', cls=Function) ma_dot_r = m*(ax*rx + ay*ry + az*rz) F_dot_r = Fx(t)*rx + Fy(t)*ry + Fz(t)*rz ma_dot_r_sub = ma_dot_r.subs([(ax, Fx(t)/m), (ay, Fy(t)/m), (az, Fz(t)/m)]) res3 = simplify(ma_dot_r_sub - F_dot_r) total_steps += 1 if simplify(res3) == 0: print(' Step 3 PASS — m(a·r) → F·r (Newton substitution)') pass_count += 1 else: print(' Step 3 FAIL') fail_count += 1 # --- Step 4: F = −∇V substitution --- gradV_x = Function('gradV_x') gradV_y = Function('gradV_y') gradV_z = Function('gradV_z') F_from_V_x = -gradV_x(t) F_from_V_y = -gradV_y(t) F_from_V_z = -gradV_z(t) FdotR_fromV = F_from_V_x*rx + F_from_V_y*ry + F_from_V_z*rz rdotgradV = gradV_x(t)*rx + gradV_y(t)*ry + gradV_z(t)*rz res4 = simplify(FdotR_fromV + rdotgradV) total_steps += 1 if simplify(res4) == 0: print(' Step 4 PASS — F·r = −r·∇V (potential substitution)') pass_count += 1 else: print(' Step 4 FAIL') fail_count += 1 # --- Step 5: Virial theorem structure --- T_avg, rdgV_avg = symbols('T_avg rdgV_avg', real=True) virial_lhs = 2*T_avg virial_rhs_val = rdgV_avg virial_residual = simplify(virial_lhs - virial_rhs_val) virial_sub = virial_residual.subs(rdgV_avg, 2*T_avg) total_steps += 1 if simplify(virial_sub) == 0: print(' Step 5 PASS — 2⟨T⟩ = ⟨r·∇V⟩ (virial theorem)') pass_count += 1 else: print(' Step 5 FAIL') fail_count += 1 # --- Step 6: Euler's theorem --- r_var, C_coeff, n_pow = symbols('r_var C_coeff n_pow', real=True, positive=True) V_power = C_coeff * r_var**n_pow rdgV_power = r_var * diff(V_power, r_var) euler_check = simplify(rdgV_power - n_pow * V_power) total_steps += 1 if simplify(euler_check) == 0: print(' Step 6 PASS — Euler\'s theorem: r·dV/dr = n·V for V=Crⁿ') pass_count += 1 else: print(' Step 6 FAIL') fail_count += 1 # --- Step 7: Gravity (n = −1) --- T_grav, V_grav = symbols('T_grav V_grav', real=True) V_from_virial = -2*T_grav E_total = T_grav + V_from_virial res7 = simplify(E_total + T_grav) total_steps += 1 if simplify(res7) == 0: print(' Step 7 PASS — Gravity (n=−1): ⟨E⟩ = −⟨T⟩') pass_count += 1 else: print(' Step 7 FAIL') fail_count += 1 # --- Step 8: Harmonic oscillator (n = 2) --- k_spr, A_osc, omega_osc = symbols('k_spr A_osc omega_osc', real=True, positive=True) T_avg_sho = m * A_osc**2 * omega_osc**2 / 4 V_avg_sho = k_spr * A_osc**2 / 4 T_sub = T_avg_sho.subs(omega_osc**2, k_spr/m) res8 = simplify(T_sub - V_avg_sho) total_steps += 1 if simplify(res8) == 0: print(' Step 8 PASS — SHO (n=2): ⟨T⟩ = ⟨V⟩ (energy equipartition)') pass_count += 1 else: print(' Step 8 FAIL') fail_count += 1 # --- Step 9: Numerical — Earth orbit --- from sympy import pi G_grav = 6.674e-11 M_sun = 1.989e30 m_earth = 5.972e24 r_orbit = 1.496e11 T_earth = 0.5 * m_earth * G_grav * M_sun / r_orbit V_earth = -G_grav * M_sun * m_earth / r_orbit virial_check = 2*T_earth + V_earth total_steps += 1 if abs(virial_check) / abs(V_earth) < 1e-10: print(f' Step 9 PASS — Earth orbit: 2T/|V| = {2*T_earth/abs(V_earth):.6f} (expected 1.0)') pass_count += 1 else: print(' Step 9 FAIL') fail_count += 1 # --- Step 10: Self-test — wrong virial coefficient --- T_w, V_w = symbols('T_w V_w', real=True) V_wrong = -T_w E_wrong = T_w + V_wrong total_steps += 1 if not (simplify(E_wrong + T_w) == 0): print(' Step 10a PASS — Wrong coefficient (T=−V) gives E=0 ≠ −T') pass_count += 1 else: print(' Step 10a FAIL') fail_count += 1 E_correct = -T_w res10b = simplify(E_wrong - E_correct - T_w) total_steps += 1 if simplify(res10b) == 0: print(' Step 10b PASS — Wrong residual = T (quantified)') pass_count += 1 else: print(' Step 10b FAIL') fail_count += 1 print('---------------------------------------------\n') # ---- VERDICT ---- print('=============================================') print(' F0026 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(f' ✓ F0026 — {pass_count}/{total_steps} PASS') if __name__ == '__main__': run()