use nalgebra::DVector;
use cartan_core::Manifold;
use cartan_manifolds::euclidean::Euclidean;
use crate::error::DecError;
use crate::mesh::{FlatMesh, Mesh};
pub struct HodgeStar {
pub star: Vec<DVector<f64>>,
}
impl HodgeStar {
pub fn from_mesh(mesh: &FlatMesh, _manifold: &Euclidean<2>) -> Self {
let nv = mesh.n_vertices();
let ne = mesh.n_boundaries();
let nt = mesh.n_simplices();
let mut s2 = DVector::<f64>::zeros(nt);
for t in 0..nt {
let area = mesh.triangle_area_flat(t).abs();
s2[t] = if area > 1e-30 { 1.0 / area } else { 0.0 };
}
let mut s0 = DVector::<f64>::zeros(nv);
for t in 0..nt {
let area = mesh.triangle_area_flat(t).abs();
for &v in &mesh.simplices[t] {
s0[v] += area / 3.0;
}
}
let mut s1 = DVector::<f64>::zeros(ne);
for e in 0..ne {
let primal_len = mesh.edge_length_flat(e);
if primal_len < 1e-30 {
s1[e] = 0.0;
continue;
}
let cofaces = &mesh.boundary_simplices[e];
let dual_len = match cofaces.len() {
2 => {
let c1 = mesh.circumcenter_flat(cofaces[0]);
let c2 = mesh.circumcenter_flat(cofaces[1]);
(c2 - c1).norm()
}
1 => {
let c = mesh.circumcenter_flat(cofaces[0]);
let mid = mesh.edge_midpoint(e);
(c - mid).norm()
}
_ => 0.0,
};
s1[e] = dual_len / primal_len;
}
Self {
star: vec![s0, s1, s2],
}
}
pub fn from_mesh_generic<M: Manifold, const K: usize, const B: usize>(
mesh: &Mesh<M, K, B>,
manifold: &M,
) -> Result<Self, DecError> {
assert_eq!(K, 3, "from_mesh_generic currently supports K=3 only");
assert_eq!(B, 2, "from_mesh_generic currently supports B=2 only");
let nv = mesh.n_vertices();
let ne = mesh.n_boundaries();
let nt = mesh.n_simplices();
let mut s2 = DVector::<f64>::zeros(nt);
for t in 0..nt {
let area = mesh.simplex_volume(manifold, t);
s2[t] = if area > 1e-30 { 1.0 / area } else { 0.0 };
}
let mut s0 = DVector::<f64>::zeros(nv);
for t in 0..nt {
let area = mesh.simplex_volume(manifold, t);
for &v in &mesh.simplices[t] {
s0[v] += area / 3.0;
}
}
let mut s1 = DVector::<f64>::zeros(ne);
for e in 0..ne {
let primal_len = mesh.boundary_volume(manifold, e);
if primal_len < 1e-30 {
s1[e] = 0.0;
continue;
}
let cofaces = &mesh.boundary_simplices[e];
let dual_len = match cofaces.len() {
2 => {
let c1 = mesh.simplex_circumcenter(manifold, cofaces[0]);
let c2 = mesh.simplex_circumcenter(manifold, cofaces[1]);
manifold.dist(&c1, &c2).unwrap_or(0.0)
}
1 => {
let c = mesh.simplex_circumcenter(manifold, cofaces[0]);
let mid = mesh.boundary_circumcenter(manifold, e);
manifold.dist(&c, &mid).unwrap_or(0.0)
}
_ => 0.0,
};
s1[e] = dual_len / primal_len;
}
Ok(Self {
star: vec![s0, s1, s2],
})
}
pub fn star_k(&self, k: usize) -> &DVector<f64> {
&self.star[k]
}
pub fn star_k_inv(&self, k: usize) -> DVector<f64> {
self.star[k].map(|x| if x.abs() > 1e-30 { 1.0 / x } else { 0.0 })
}
pub fn star0(&self) -> &DVector<f64> {
&self.star[0]
}
pub fn star1(&self) -> &DVector<f64> {
&self.star[1]
}
pub fn star2(&self) -> &DVector<f64> {
&self.star[2]
}
pub fn star0_inv(&self) -> DVector<f64> {
self.star_k_inv(0)
}
pub fn star1_inv(&self) -> DVector<f64> {
self.star_k_inv(1)
}
pub fn star2_inv(&self) -> DVector<f64> {
self.star_k_inv(2)
}
}