extern crate nalgebra as na;
use derham::{project::derham_map, section::CoordFieldExt};
use formoniq::{
problems::dirac::{solve_dirac, HodgeDirac, MixedField},
whitney_complex::WhitneyComplex,
};
use glatt::field::DiffFormClosure;
use simplicial::gen::cartesian::CartesianGrid;
use std::f64::consts::PI;
fn main() {
let dim = 3;
let nboxes_per_dim = 4;
let grid = CartesianGrid::new_unit_scaled(dim, nboxes_per_dim, PI);
let (topology, coords) = grid.triangulate();
let metric = coords.to_edge_lengths_sq(&topology);
let whitney = WhitneyComplex::new(&topology, &metric);
let pec = whitney.relative();
let dirac = HodgeDirac::assemble(&whitney);
println!(
"PEC cavity [0,pi]^{dim} (Hodge-Dirac, full de Rham complex):\n \
dofs per grade: {} verts, {} edges (E), {} faces (B), {} cells",
whitney.ndofs(0),
whitney.ndofs(1),
whitney.ndofs(2),
whitney.ndofs(3),
);
let e_field = DiffFormClosure::one_form(
|p| {
na::dvector![
p[1].sin() * p[2].sin(),
p[2].sin() * p[0].sin(),
p[0].sin() * p[1].sin(),
]
},
dim,
);
let e0 = derham_map(&e_field.pullback_on(&topology, &coords), &topology, 3);
let initial = MixedField::from_grade(&whitney, e0);
let cfl_fraction = 0.2;
let dt = cfl_fraction * metric.mesh_width_min();
let end_time = 6.0;
let nsteps = (end_time / dt).ceil() as usize;
let times: Vec<f64> = (0..=nsteps).map(|i| dt * i as f64).collect();
println!(" dt = {dt:.4}, steps = {nsteps}\n");
let solution = solve_dirac(&pec, ×, initial);
println!(
"{:>5} | {:>6} | {:>10} | {:>10} | {:>10} | {:>10} | {:>12} | {:>10}",
"step", "t", "grade0", "E (g1)", "B (g2)", "grade3", "total", "drift"
);
let energy0 = dirac.energy(&solution[0]);
let report_every = (nsteps / 20).max(1);
for (istep, state) in solution.iter().enumerate() {
if istep % report_every != 0 && istep != nsteps {
continue;
}
let total = dirac.energy(state);
let drift = (total - energy0).abs() / energy0;
println!(
"{:>5} | {:>6.3} | {:>10.2e} | {:>10.6} | {:>10.6} | {:>10.2e} | {:>12.8} | {:>10.2e}",
istep,
times[istep],
dirac.grade_energy(state, 0),
dirac.grade_energy(state, 1),
dirac.grade_energy(state, 2),
dirac.grade_energy(state, 3),
total,
drift
);
}
println!(
"\nTotal energy flat to ~1e-15 relative (symplectic, no drift). The magnetic\n\
Gauss law dif B = 0 (grade 3) is exact to roundoff by dif.dif = 0; the\n\
electric Gauss law delta E = 0 (grade 0) holds weakly. The four Maxwell\n\
equations are the four grades of one Dirac field D = dif - delta.\n"
);
}