%% CAS_F0012_VERIFY.m -- Gravitational energy density (rho_g = -(grad Phi)^2/(8*pi*G))
%  Assertion-based CAS audit block
%  Pillar: Mechanics | Chain: Poisson -> potential energy -> IBP -> energy density
%  CalRef: Mathematical Bridge S8A, Mechanics Calibration S3C
%
%  Structure mirrors cas_F11.txt (= F0012) sections A-E.
%  Verifies:
%    1. Poisson substitution: rho = (1/(4*pi*G))*Laplacian(Phi)
%    2. Coefficient chain: (1/2)*(1/(4*pi*G)) = 1/(8*pi*G)
%    3. IBP identity: (Lap Phi)*Phi = div(Phi*grad Phi) - |grad Phi|^2
%    4. After IBP (surface terms drop): integral = -integral |grad Phi|^2
%    5. Final: rho_g = -|grad Phi|^2/(8*pi*G)
%    6. Sign: rho_g <= 0 for real Phi (gravitational binding)
%    7. Concrete: point mass Phi = -GM/r
%    8. Dimensional consistency
%
%  HARDENING: isAlways(..., 'Unknown', 'false') throughout.

clear; clc;
fprintf('=== CAS AUDIT: F0012 -- Gravitational energy density ===\n\n');

pass_count = 0;
fail_count = 0;
total_steps = 0;

%% ---- A. INPUTS ----
% g = -grad(Phi)
% Poisson: Lap(Phi) = 4*pi*G*rho
% U = (1/2)*integral(rho*Phi d^3r)
% Goal: rho_g = -(grad Phi)^2/(8*pi*G)

syms G_grav positive         % gravitational constant
syms x y z real              % Cartesian coordinates
syms Phi(x, y, z)            % gravitational potential (symfun)

fprintf('Section A: Inputs defined.\n');
fprintf('  Phi(x,y,z), G, Poisson equation, potential energy integral\n\n');

%% ---- B. ASSUMPTIONS / DOMAINS ----
fprintf('Section B: Static Newtonian gravity, fields smooth, vanish at infinity.\n\n');

%% ---- C. ALLOWED LEMMAS ----
fprintf('Section C: Lemmas declared.\n');
fprintf('  C.1: Poisson: Lap(Phi) = 4*pi*G*rho\n');
fprintf('  C.2: IBP: integral (Lap Phi)*Phi = -integral |grad Phi|^2 (surface terms drop)\n');
fprintf('  C.3: div(Phi*grad Phi) = (grad Phi)^2 + Phi*Lap(Phi)\n\n');

%% ---- D. STEP LOG ----
fprintf('Section D: Step log\n');
fprintf('---------------------------------------------\n');

% --- Step 1: Laplacian of Phi ---
% Lap(Phi) = d^2Phi/dx^2 + d^2Phi/dy^2 + d^2Phi/dz^2
Lap_Phi = diff(Phi, x, 2) + diff(Phi, y, 2) + diff(Phi, z, 2);

% Gradient components
grad_Phi_x = diff(Phi, x);
grad_Phi_y = diff(Phi, y);
grad_Phi_z = diff(Phi, z);

% |grad Phi|^2
grad_Phi_sq = grad_Phi_x^2 + grad_Phi_y^2 + grad_Phi_z^2;

% Verify Laplacian has 3 terms (structural)
% Check: Lap_Phi involves second derivatives in x, y, z
% We verify by checking that Lap_Phi - (Phi_xx + Phi_yy + Phi_zz) = 0
Phi_xx = diff(Phi, x, 2);
Phi_yy = diff(Phi, y, 2);
Phi_zz = diff(Phi, z, 2);

step1_residual = simplify(Lap_Phi - (Phi_xx + Phi_yy + Phi_zz));

total_steps = total_steps + 1;
if isAlways(step1_residual == 0, 'Unknown', 'false')
    fprintf('  Step 1  PASS  Lap(Phi) = Phi_xx + Phi_yy + Phi_zz\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 1  FAIL  Laplacian residual: %s\n', char(step1_residual));
    fail_count = fail_count + 1;
end

% --- Step 2: Poisson substitution coefficient ---
% rho = (1/(4*pi*G)) * Lap(Phi)
% U = (1/2)*integral(rho*Phi) = (1/2)*(1/(4*pi*G))*integral(Lap(Phi)*Phi)
% Coefficient: (1/2)*(1/(4*pi*G)) = 1/(8*pi*G)
coeff_U = sym(1)/sym(2) * sym(1)/(sym(4)*sym(pi)*G_grav);
expected_coeff = sym(1)/(sym(8)*sym(pi)*G_grav);

step2_residual = simplify(coeff_U - expected_coeff);

total_steps = total_steps + 1;
if isAlways(step2_residual == 0, 'Unknown', 'false')
    fprintf('  Step 2  PASS  (1/2)*(1/(4*pi*G)) = 1/(8*pi*G)\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 2  FAIL  Coefficient residual: %s\n', char(step2_residual));
    fail_count = fail_count + 1;
end

% --- Step 3: IBP algebraic identity ---
% div(Phi * grad Phi) = |grad Phi|^2 + Phi * Lap(Phi)
% Therefore: Phi * Lap(Phi) = div(Phi * grad Phi) - |grad Phi|^2
%
% Verify componentwise:
% div(Phi * grad Phi) = d/dx(Phi * Phi_x) + d/dy(Phi * Phi_y) + d/dz(Phi * Phi_z)
div_Phi_gradPhi = diff(Phi * grad_Phi_x, x) + diff(Phi * grad_Phi_y, y) + diff(Phi * grad_Phi_z, z);

% Expand: d/dx(Phi*Phi_x) = Phi_x^2 + Phi*Phi_xx (product rule), etc.
% So div(Phi*grad Phi) = (Phi_x^2 + Phi_y^2 + Phi_z^2) + Phi*(Phi_xx + Phi_yy + Phi_zz)
%                       = |grad Phi|^2 + Phi*Lap(Phi)

step3_residual = simplify(div_Phi_gradPhi - grad_Phi_sq - Phi * Lap_Phi);

total_steps = total_steps + 1;
if isAlways(step3_residual == 0, 'Unknown', 'false')
    fprintf('  Step 3  PASS  div(Phi*grad Phi) = |grad Phi|^2 + Phi*Lap(Phi)\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 3  FAIL  IBP identity residual: %s\n', char(step3_residual));
    fail_count = fail_count + 1;
end

% --- Step 4: Rearranged IBP identity ---
% Phi * Lap(Phi) = div(Phi*grad Phi) - |grad Phi|^2
% After integration and dropping surface terms:
% integral(Phi * Lap Phi) = -integral(|grad Phi|^2)
%
% Verify the algebraic rearrangement:
Phi_Lap_Phi = Phi * Lap_Phi;
rearranged = div_Phi_gradPhi - grad_Phi_sq;

step4_residual = simplify(Phi_Lap_Phi - rearranged);

total_steps = total_steps + 1;
if isAlways(step4_residual == 0, 'Unknown', 'false')
    fprintf('  Step 4  PASS  Phi*Lap(Phi) = div(Phi*grad Phi) - |grad Phi|^2\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 4  FAIL  Rearrangement residual: %s\n', char(step4_residual));
    fail_count = fail_count + 1;
end

% --- Step 5: Full coefficient chain to energy density ---
% U = (1/(8*pi*G)) * integral(Lap(Phi)*Phi)
%   = (1/(8*pi*G)) * (-integral(|grad Phi|^2))    [after IBP]
%   = -1/(8*pi*G) * integral(|grad Phi|^2)
%
% So rho_g = -|grad Phi|^2 / (8*pi*G)
%
% Verify: rho_g * (8*pi*G) + |grad Phi|^2 = 0
syms rho_g_expr
rho_g_expr = -grad_Phi_sq / (sym(8)*sym(pi)*G_grav);

step5_check = simplify(rho_g_expr * (sym(8)*sym(pi)*G_grav) + grad_Phi_sq);

total_steps = total_steps + 1;
if isAlways(step5_check == 0, 'Unknown', 'false')
    fprintf('  Step 5  PASS  rho_g = -|grad Phi|^2/(8*pi*G)\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 5  FAIL  Energy density residual: %s\n', char(step5_check));
    fail_count = fail_count + 1;
end

% --- Step 6: Sign check ---
% |grad Phi|^2 >= 0 always, G > 0, 8*pi > 0
% Therefore rho_g <= 0 (gravitational binding energy is negative)
%
% Verify with concrete positive |grad Phi|^2:
syms grad_sq_val positive  % represents |grad Phi|^2 > 0
rho_g_sign_test = -grad_sq_val / (sym(8)*sym(pi)*G_grav);

total_steps = total_steps + 1;
if isAlways(rho_g_sign_test < 0, 'Unknown', 'false')
    fprintf('  Step 6  PASS  rho_g < 0 when |grad Phi|^2 > 0 (binding energy negative)\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 6  FAIL  Sign check\n');
    fail_count = fail_count + 1;
end

% --- Step 7: Concrete test -- point mass ---
% Phi = -G*M/r, r = sqrt(x^2+y^2+z^2)
% grad Phi = G*M*r_hat/r^2
% |grad Phi|^2 = G^2*M^2/r^4
% rho_g = -G^2*M^2/(8*pi*G*r^4) = -G*M^2/(8*pi*r^4)
syms M_mass positive
syms r_rad positive   % radial coordinate

Phi_point = -G_grav * M_mass / r_rad;
dPhi_dr = diff(Phi_point, r_rad);  % = G*M/r^2
grad_Phi_sq_point = dPhi_dr^2;     % = G^2*M^2/r^4 (spherical symmetry)

rho_g_point = simplify(-grad_Phi_sq_point / (sym(8)*sym(pi)*G_grav));
rho_g_expected = -G_grav * M_mass^2 / (sym(8)*sym(pi)*r_rad^4);

step7_residual = simplify(rho_g_point - rho_g_expected);

total_steps = total_steps + 1;
if isAlways(step7_residual == 0, 'Unknown', 'false')
    fprintf('  Step 7  PASS  Point mass: rho_g = -G*M^2/(8*pi*r^4)\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 7  FAIL  Point mass residual: %s\n', char(step7_residual));
    fail_count = fail_count + 1;
end

% --- Step 8: Point mass total energy integral ---
% U = integral_{r_min}^{inf} rho_g * 4*pi*r^2 dr  (spherical shell)
% U = integral -G*M^2/(8*pi*r^4) * 4*pi*r^2 dr = integral -G*M^2/(2*r^2) dr
% U = -G*M^2/(2) * [-1/r]_{r_min}^{inf} = -G*M^2/(2*r_min)
%
% This matches the self-energy of a shell at radius r_min.
syms r_min positive
integrand_shell = rho_g_point * 4 * sym(pi) * r_rad^2;
integrand_shell = simplify(integrand_shell);

U_total = int(integrand_shell, r_rad, r_min, inf);
U_expected = -G_grav * M_mass^2 / (sym(2) * r_min);

step8_residual = simplify(U_total - U_expected);

total_steps = total_steps + 1;
if isAlways(step8_residual == 0, 'Unknown', 'false')
    fprintf('  Step 8  PASS  Total energy: U = -G*M^2/(2*r_min)\n');
    pass_count = pass_count + 1;
else
    fprintf('  Step 8  FAIL  Total energy residual: %s\n', char(step8_residual));
    fail_count = fail_count + 1;
end

% --- Step 9: Numerical check with Earth parameters ---
% G = 6.67430e-11 m^3 kg^-1 s^-2
% M_earth = 5.972e24 kg, R_earth = 6.371e6 m
% rho_g at surface: -G*M^2/(8*pi*R^4)
G_val = 6.67430e-11;
M_earth = 5.972e24;
R_earth = 6.371e6;

rho_g_surface = -G_val * M_earth^2 / (8 * pi * R_earth^4);
% Expected: ~ -2.87e5 J/m^3
% g_surface = G*M/R^2 ~ 9.82 m/s^2
% rho_g = -g^2/(8*pi*G) ~ -(9.82)^2/(8*pi*6.674e-11) ~ -5.75e10 J/m^3
% Wait, let me recalculate:
% |grad Phi|^2 at surface = (G*M/R^2)^2
% rho_g = -(G*M/R^2)^2/(8*pi*G) = -G*M^2/(8*pi*R^4)
g_surface = G_val * M_earth / R_earth^2;
rho_g_from_g = -g_surface^2 / (8 * pi * G_val);

rel_error = abs(rho_g_surface - rho_g_from_g) / abs(rho_g_surface);

total_steps = total_steps + 1;
if rel_error < 1e-10
    fprintf('  Step 9  PASS  Numerical: rho_g(Earth surface) = %.4e J/m^3 (two methods agree)\n', rho_g_surface);
    pass_count = pass_count + 1;
else
    fprintf('  Step 9  FAIL  Numerical disagreement: rel error = %.2e\n', rel_error);
    fail_count = fail_count + 1;
end

fprintf('---------------------------------------------\n\n');

%% ---- E. CHECK OUTPUTS ----
fprintf('Section E: Output checks\n');
fprintf('---------------------------------------------\n');

% --- Unit check ---
fprintf('  Unit check:\n');
fprintf('    grad Phi: [m/s^2]\n');
fprintf('    |grad Phi|^2: [m^2/s^4]\n');
fprintf('    1/(8*pi*G): [kg*s^2/m^3]\n');
fprintf('    rho_g: [kg*s^2/m^3]*[m^2/s^4] = [kg/(m*s^2)] = [J/m^3]\n');
fprintf('    PASS\n\n');

% --- Self-test: wrong sign gives positive energy density ---
% If rho_g_wrong = +|grad Phi|^2/(8*pi*G) (wrong sign):
rho_g_wrong = grad_Phi_sq_point / (sym(8)*sym(pi)*G_grav);
wrong_residual = simplify(rho_g_wrong - rho_g_point);
% Should be nonzero: rho_g_wrong - rho_g = 2*|grad Phi|^2/(8*pi*G) = |grad Phi|^2/(4*pi*G)

total_steps = total_steps + 1;
if ~isAlways(wrong_residual == 0, 'Unknown', 'false')
    fprintf('  Self-test: wrong sign (+) detected as different  PASS\n');
    pass_count = pass_count + 1;
else
    fprintf('  Self-test: FAIL (wrong sign not detected)\n');
    fail_count = fail_count + 1;
end

% --- Self-test: quantify wrong residual ---
expected_wrong = sym(2) * grad_Phi_sq_point / (sym(8)*sym(pi)*G_grav);
% = 2*G^2*M^2/(r^4 * 8*pi*G) = G*M^2/(4*pi*r^4)
wrong_quant = simplify(wrong_residual - expected_wrong);

total_steps = total_steps + 1;
if isAlways(wrong_quant == 0, 'Unknown', 'false')
    fprintf('  Self-test: wrong - correct = 2*|grad Phi|^2/(8*pi*G) (quantified)  PASS\n');
    pass_count = pass_count + 1;
else
    fprintf('  Self-test: FAIL (wrong residual = %s)\n', char(wrong_residual));
    fail_count = fail_count + 1;
end

fprintf('---------------------------------------------\n\n');

%% ---- VERDICT ----
fprintf('=============================================\n');
fprintf('  F0012 AUDIT RESULT\n');
fprintf('  Steps: %d  |  Pass: %d  |  Fail: %d\n', total_steps, pass_count, fail_count);
if fail_count == 0
    fprintf('  STATUS: *** PASS ***\n');
else
    fprintf('  STATUS: *** FAIL *** (%d step(s) failed)\n', fail_count);
end
fprintf('=============================================\n');
fprintf('Audit complete for F0012.\n');
