use nalgebra::DVector;
use cartan_core::Manifold;
use crate::exterior::ExteriorDerivative;
use crate::hodge::HodgeStar;
use crate::mesh::{FlatMesh, Mesh};
pub fn apply_divergence_generic<M: Manifold, const K: usize, const B: usize>(
mesh: &Mesh<M, K, B>,
manifold: &M,
ext: &ExteriorDerivative,
hodge: &HodgeStar,
u: &[M::Tangent],
) -> DVector<f64> {
let nv = mesh.n_vertices();
let nb = mesh.n_boundaries();
assert_eq!(u.len(), nv, "divergence: u must have n_v tangent vectors");
let mut u1form = DVector::<f64>::zeros(nb);
for (b, boundary) in mesh.boundaries.iter().enumerate() {
if B == 2 {
let i = boundary[0];
let j = boundary[1];
let pi = &mesh.vertices[i];
let pj = &mesh.vertices[j];
let edge_vec = match manifold.log(pi, pj) {
Ok(t) => t,
Err(_) => continue,
};
let ui_dot = manifold.inner(pi, &u[i], &edge_vec);
let uj_dot = manifold.inner(pi, &u[j], &edge_vec);
u1form[b] = 0.5 * (ui_dot + uj_dot);
}
}
let star1_u1form = u1form.component_mul(hodge.star1());
let d0t = ext.d0().transpose_view();
let mut d0t_star1_u = DVector::<f64>::zeros(nv);
for (row_idx, row) in d0t.outer_iterator().enumerate() {
let mut sum = 0.0;
for (col_idx, &val) in row.iter() {
sum += val * star1_u1form[col_idx];
}
d0t_star1_u[row_idx] = sum;
}
let star0_inv = hodge.star0_inv();
d0t_star1_u.component_mul(&star0_inv)
}
pub fn apply_divergence(
mesh: &FlatMesh,
ext: &ExteriorDerivative,
hodge: &HodgeStar,
u: &DVector<f64>,
) -> DVector<f64> {
let nv = mesh.n_vertices();
assert_eq!(u.len(), 2 * nv, "divergence: u must have 2*n_v entries");
let u_tangent: Vec<nalgebra::SVector<f64, 2>> = (0..nv)
.map(|v| nalgebra::SVector::<f64, 2>::new(u[v], u[nv + v]))
.collect();
let manifold = cartan_manifolds::euclidean::Euclidean::<2>;
apply_divergence_generic(mesh, &manifold, ext, hodge, &u_tangent)
}
pub fn apply_tensor_divergence(
mesh: &FlatMesh,
ext: &ExteriorDerivative,
hodge: &HodgeStar,
t: &DVector<f64>,
) -> DVector<f64> {
let nv = mesh.n_vertices();
assert_eq!(
t.len(),
3 * nv,
"tensor_divergence: t must have 3*n_v entries"
);
let txx = t.rows(0, nv).into_owned();
let txy = t.rows(nv, nv).into_owned();
let tyy = t.rows(2 * nv, nv).into_owned();
let mut col1 = DVector::<f64>::zeros(2 * nv);
col1.rows_mut(0, nv).copy_from(&txx);
col1.rows_mut(nv, nv).copy_from(&txy);
let mut col2 = DVector::<f64>::zeros(2 * nv);
col2.rows_mut(0, nv).copy_from(&txy);
col2.rows_mut(nv, nv).copy_from(&tyy);
let div_x = apply_divergence(mesh, ext, hodge, &col1);
let div_y = apply_divergence(mesh, ext, hodge, &col2);
let mut result = DVector::<f64>::zeros(2 * nv);
result.rows_mut(0, nv).copy_from(&div_x);
result.rows_mut(nv, nv).copy_from(&div_y);
result
}