use crate::allocators::BiDimAllocator;
use crate::nalgebra::allocator::Allocator;
use crate::nalgebra::{DMatrixSliceMut, DVectorSlice, DefaultAllocator, DimName, OMatrix, OVector, RealField, Scalar};
use crate::{SmallDim, Symmetry};
mod laplace;
pub use laplace::*;
use nalgebra::min;
pub trait Operator<T, GeometryDim> {
type SolutionDim: SmallDim;
type Parameters: Default + Clone + 'static;
}
pub trait EllipticOperator<T, GeometryDim>: Operator<T, GeometryDim>
where
T: Scalar,
GeometryDim: SmallDim,
DefaultAllocator: Allocator<T, GeometryDim, Self::SolutionDim>,
{
fn compute_elliptic_operator(
&self,
gradient: &OMatrix<T, GeometryDim, Self::SolutionDim>,
parameters: &Self::Parameters,
) -> OMatrix<T, GeometryDim, Self::SolutionDim>;
}
pub trait EllipticContraction<T, GeometryDim>: Operator<T, GeometryDim>
where
T: RealField,
GeometryDim: SmallDim,
DefaultAllocator: BiDimAllocator<T, GeometryDim, Self::SolutionDim>,
{
fn contract(
&self,
gradient: &OMatrix<T, GeometryDim, Self::SolutionDim>,
a: &OVector<T, GeometryDim>,
b: &OVector<T, GeometryDim>,
parameters: &Self::Parameters,
) -> OMatrix<T, Self::SolutionDim, Self::SolutionDim>;
fn symmetry(&self) -> Symmetry {
Symmetry::NonSymmetric
}
#[allow(non_snake_case)]
fn accumulate_contractions_into(
&self,
mut output: DMatrixSliceMut<T>,
alpha: T,
gradient: &OMatrix<T, GeometryDim, Self::SolutionDim>,
a: DVectorSlice<T>,
b: DVectorSlice<T>,
parameters: &Self::Parameters,
) {
let d = GeometryDim::dim();
let s = Self::SolutionDim::dim();
assert!(a.len() % d == 0, "Dimension of a must be divisible by d (GeometryDim)");
assert!(b.len() % d == 0, "Dimension of b must be divisible by d (GeometryDim)");
let M = a.len() / d;
let N = b.len() / d;
assert_eq!(
output.nrows(),
s * M,
"Number of rows in output matrix is not consistent with a"
);
assert_eq!(
output.ncols(),
s * N,
"Number of columns in output matrix is not consistent with b"
);
let s_times_s = (Self::SolutionDim::name(), Self::SolutionDim::name());
let symmetry = self.symmetry();
for J in 0..N {
let row_range = match symmetry {
Symmetry::Symmetric => min(J + 1, M),
Symmetry::NonSymmetric => M,
};
for I in 0..row_range {
let a_I = a.rows_generic(d * I, GeometryDim::name()).clone_owned();
let b_J = b.rows_generic(d * J, GeometryDim::name()).clone_owned();
let mut c_IJ = output.generic_slice_mut((s * I, s * J), s_times_s);
let contraction = self.contract(gradient, &a_I, &b_J, parameters);
c_IJ += contraction * alpha;
}
}
}
}
pub trait EllipticEnergy<T, GeometryDim>: Operator<T, GeometryDim>
where
T: RealField,
GeometryDim: SmallDim,
DefaultAllocator: BiDimAllocator<T, GeometryDim, Self::SolutionDim>,
{
fn compute_energy(&self, gradient: &OMatrix<T, GeometryDim, Self::SolutionDim>, parameters: &Self::Parameters)
-> T;
}