use crate::kernels::mhd::quantities::{AlfvenSpeed, MagneticPressure};
use crate::{Density, PhysicalField, PhysicsError};
use core::fmt::Debug;
use deep_causality_multivector::MultiVector;
use deep_causality_num::{FromPrimitive, RealField};
use deep_causality_sparse::CsrMatrix;
use deep_causality_tensor::CausalTensor;
use deep_causality_topology::{SimplicialComplex, SimplicialManifold};
use std::collections::HashMap;
pub fn alfven_speed_kernel<R>(
b_field: &PhysicalField<R>,
density: &Density<R>,
permeability: R,
) -> Result<AlfvenSpeed<R>, PhysicsError>
where
R: RealField,
{
let b_mag = b_field.inner().squared_magnitude().sqrt();
let rho = density.value();
if permeability <= R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Permeability must be positive".into(),
));
}
if rho < R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Density cannot be negative".into(),
));
}
if rho == R::zero() {
return Err(PhysicsError::Singularity(
"Zero density in Alfven speed".into(),
));
}
let denom = (permeability * rho).sqrt();
let va = b_mag / denom;
AlfvenSpeed::new(va)
}
pub fn magnetic_pressure_kernel<R>(
b_field: &PhysicalField<R>,
permeability: R,
) -> Result<MagneticPressure<R>, PhysicsError>
where
R: RealField + FromPrimitive,
{
let b_sq = b_field.inner().squared_magnitude();
if permeability <= R::zero() {
return Err(PhysicsError::PhysicalInvariantBroken(
"Permeability must be positive".into(),
));
}
let two = R::from_f64(2.0)
.ok_or_else(|| PhysicsError::NumericalInstability("R::from_f64(2.0) failed".into()))?;
let pb = b_sq / (two * permeability);
MagneticPressure::new(pb)
}
pub fn ideal_induction_kernel<R>(
v_manifold: &SimplicialManifold<R, R>,
b_manifold: &SimplicialManifold<R, R>,
) -> Result<CausalTensor<R>, PhysicsError>
where
R: RealField + FromPrimitive + Default + PartialEq + Debug,
{
let complex = v_manifold.complex();
let skeletons = complex.skeletons();
if skeletons.len() < 3 {
return Err(PhysicsError::DimensionMismatch(
"Manifold must be at least 2D (preferably 3D) for induction".into(),
));
}
let n0 = skeletons[0].simplices().len();
let n1 = skeletons[1].simplices().len();
let n2 = skeletons[2].simplices().len();
if v_manifold.data().len() < n0 + n1 + n2 {
return Err(PhysicsError::DimensionMismatch(
"v_manifold data too small".into(),
));
}
let v_offset = n0;
let v_slice = &v_manifold.data().as_slice()[v_offset..v_offset + n1];
let b_offset = n0 + n1;
let b_slice = &b_manifold.data().as_slice()[b_offset..b_offset + n2];
let hodge_ops = complex
.hodge_star_operators()
.map_err(|e| PhysicsError::CalculationError(format!("Hodge ⋆ unavailable: {}", e)))?;
if hodge_ops.len() <= 2 {
return Err(PhysicsError::CalculationError(
"Hodge star operator for 2-forms not available".into(),
));
}
let h_star_2 = &hodge_ops[2];
let star_b_data = apply_csr_real(h_star_2, b_slice);
let wedge_data = wedge_product_1form_1form(v_slice, &star_b_data, complex)?;
let iv_b_data = apply_csr_real(h_star_2, &wedge_data);
if complex.coboundary_operators().len() <= 1 {
return Err(PhysicsError::CalculationError(
"Coboundary operator for 1-forms not available".into(),
));
}
let d_1 = &complex.coboundary_operators()[1];
let dt_b_neg_data = apply_csr_i8(d_1, &iv_b_data);
let result_len = dt_b_neg_data.len();
CausalTensor::new(dt_b_neg_data, vec![result_len]).map_err(PhysicsError::from)
}
fn apply_csr_real<R: RealField>(matrix: &CsrMatrix<R>, vector: &[R]) -> Vec<R> {
let (rows, _cols) = matrix.shape();
let mut result = vec![R::zero(); rows];
let row_indices = matrix.row_indices();
let col_indices = matrix.col_indices();
let values = matrix.values();
for i in 0..rows {
let start = row_indices[i];
let end = row_indices[i + 1];
let mut sum = R::zero();
for idx in start..end {
let col = col_indices[idx];
let val = values[idx];
if col < vector.len() {
sum += val * vector[col];
}
}
result[i] = sum;
}
result
}
fn apply_csr_i8<R: RealField + FromPrimitive>(matrix: &CsrMatrix<i8>, vector: &[R]) -> Vec<R> {
let (rows, _cols) = matrix.shape();
let mut result = vec![R::zero(); rows];
let row_indices = matrix.row_indices();
let col_indices = matrix.col_indices();
let values = matrix.values();
for i in 0..rows {
let start = row_indices[i];
let end = row_indices[i + 1];
let mut sum = R::zero();
for idx in start..end {
let col = col_indices[idx];
let val_i8 = values[idx];
if col < vector.len() {
let val = R::from_f64(val_i8 as f64).expect("R::from_f64(i8) failed");
sum += val * vector[col];
}
}
result[i] = sum;
}
result
}
fn wedge_product_1form_1form<R>(
alpha: &[R],
beta: &[R],
complex: &SimplicialComplex<R>,
) -> Result<Vec<R>, PhysicsError>
where
R: RealField,
{
let skeletons = complex.skeletons();
if skeletons.len() < 3 {
return Err(PhysicsError::DimensionMismatch(
"Complex must have 2-simplices".into(),
));
}
let edges = skeletons[1].simplices();
let faces = skeletons[2].simplices();
let mut edge_map = HashMap::with_capacity(edges.len());
for (idx, edge_simplex) in edges.iter().enumerate() {
let verts = edge_simplex.vertices();
if verts.len() >= 2 {
edge_map.insert((verts[0], verts[1]), idx);
}
}
let zero = R::zero();
let mut result = Vec::with_capacity(faces.len());
for face in faces {
let verts = face.vertices(); if verts.len() != 3 {
result.push(zero);
continue;
}
let v0 = verts[0];
let v1 = verts[1];
let v2 = verts[2];
let e01_idx = edge_map.get(&(v0, v1));
let e12_idx = edge_map.get(&(v1, v2));
if let (Some(&idx01), Some(&idx12)) = (e01_idx, e12_idx) {
let val_alpha_01 = *alpha.get(idx01).unwrap_or(&zero);
let val_beta_12 = *beta.get(idx12).unwrap_or(&zero);
let val_beta_01 = *beta.get(idx01).unwrap_or(&zero);
let val_alpha_12 = *alpha.get(idx12).unwrap_or(&zero);
let term1 = val_alpha_01 * val_beta_12;
let term2 = val_beta_01 * val_alpha_12;
result.push(term1 - term2);
} else {
result.push(zero);
}
}
Ok(result)
}