#[path = "util/mod.rs"]
mod util;
use {
derham::{cochain::Cochain, project::derham_map, section::CoordFieldExt},
formoniq::{
problems::wave::{cfl_dt, solve_wave, WaveState},
whitney_complex::WhitneyComplex,
},
simplicial::gen::cartesian::CartesianGrid,
simplicial::linalg::Vector,
util::{BoundaryCondition, BoxEigenform},
};
use std::f64::consts::{PI, TAU};
fn main() {
tracing_subscriber::fmt::init();
const NBOXES: usize = 8;
const DURATION: f64 = TAU;
const CFL_FRACTION: f64 = 0.2;
const WAVE_SPEED: f64 = 1.0;
println!("Wave u_tt = -Δu on [0,π]^n, relative (Dirichlet) BC — Gauss-Legendre.");
println!("Energy E = ½(‖δu‖² + ‖du‖² + ‖u̇‖²) is conserved.\n");
println!(
"| {:>3} | {:>5} | {:>10} | {:>10} | {:>10} | {:>8} |",
"dim", "grade", "E(0)", "E(½T)", "E(T)", "drift",
);
for dim in 1..=3 {
let grid = CartesianGrid::new_unit_scaled(dim, NBOXES, PI);
let (topology, coords) = grid.triangulate();
let metric = coords.to_edge_lengths_sq(&topology);
let whitney = WhitneyComplex::new(&topology, &metric);
for grade in 0..=dim {
let form = BoxEigenform::new(dim, grade, BoundaryCondition::Relative);
let initial = derham_map(
&form.solution().pullback_on(&topology, &coords),
&topology,
3,
);
let state = WaveState::new(initial.into_coeffs(), Vector::zeros(whitney.ndofs(grade)));
let relative = whitney.relative();
let dt = CFL_FRACTION * cfl_dt(&metric, WAVE_SPEED);
let nsteps = (DURATION / dt).ceil() as usize;
let times: Vec<f64> = (0..=nsteps)
.map(|i| DURATION * i as f64 / nsteps as f64)
.collect();
let force = Cochain::new(grade, Vector::zeros(whitney.ndofs(grade)));
let solution = solve_wave(&relative, grade, ×, state, force);
let energies: Vec<f64> = solution
.iter()
.map(|s| s.energy(&relative, grade))
.collect();
let e0 = energies[0];
let e_half = energies[nsteps / 2];
let e_final = *energies.last().unwrap();
let drift = if e0 > 1e-14 {
energies.iter().map(|&e| (e - e0).abs()).fold(0.0, f64::max) / e0
} else {
0.0
};
println!(
"| {dim:>3} | {grade:>5} | {e0:>10.3e} | {e_half:>10.3e} | {e_final:>10.3e} | {drift:>8.1e} |",
);
}
}
}