use super::CellGeometry;
use crate::assembly::common::RlstArray;
use rlst::RlstScalar;
use rlst::UnsafeRandomAccessByRef;
use std::marker::PhantomData;
pub trait Access1D {
type T;
unsafe fn get(&self, i: usize) -> Self::T;
}
pub trait Access2D {
type T;
unsafe fn get(&self, i: usize, j: usize) -> Self::T;
}
pub trait GeometryAccess {
type T;
unsafe fn point(&self, i: usize) -> Self::T;
unsafe fn normal(&self, i: usize) -> Self::T;
unsafe fn jacobian(&self, i: usize) -> Self::T;
unsafe fn jdet(&self) -> Self::T;
}
struct NonSingularKernel<'a, T: RlstScalar> {
k: &'a RlstArray<T, 3>,
test_point_index: usize,
trial_point_index: usize,
}
impl<'a, T: RlstScalar> NonSingularKernel<'a, T> {
fn new(k: &'a RlstArray<T, 3>, test_point_index: usize, trial_point_index: usize) -> Self {
Self {
k,
test_point_index,
trial_point_index,
}
}
}
impl<'a, T: RlstScalar> Access1D for NonSingularKernel<'a, T> {
type T = T;
unsafe fn get(&self, i: usize) -> Self::T {
*self
.k
.get_unchecked([i, self.test_point_index, self.trial_point_index])
}
}
struct SingularKernel<'a, T: RlstScalar> {
k: &'a RlstArray<T, 2>,
point_index: usize,
}
impl<'a, T: RlstScalar> SingularKernel<'a, T> {
fn new(k: &'a RlstArray<T, 2>, point_index: usize) -> Self {
Self { k, point_index }
}
}
impl<'a, T: RlstScalar> Access1D for SingularKernel<'a, T> {
type T = T;
unsafe fn get(&self, i: usize) -> Self::T {
*self.k.get_unchecked([i, self.point_index])
}
}
struct Table<'a, T: RlstScalar> {
table: &'a RlstArray<T, 4>,
point_index: usize,
basis_index: usize,
}
impl<'a, T: RlstScalar> Table<'a, T> {
fn new(table: &'a RlstArray<T, 4>, point_index: usize, basis_index: usize) -> Self {
Self {
table,
point_index,
basis_index,
}
}
}
impl<'a, T: RlstScalar> Access2D for Table<'a, T> {
type T = T;
unsafe fn get(&self, i: usize, j: usize) -> Self::T {
*self
.table
.get_unchecked([i, self.point_index, self.basis_index, j])
}
}
struct Geometry<'a, T: RlstScalar, G: CellGeometry<T = T::Real>> {
geometry: &'a G,
point_index: usize,
_t: PhantomData<T>,
}
impl<'a, T: RlstScalar, G: CellGeometry<T = T::Real>> Geometry<'a, T, G> {
fn new(geometry: &'a G, point_index: usize) -> Self {
Self {
geometry,
point_index,
_t: PhantomData,
}
}
}
impl<'a, T: RlstScalar, G: CellGeometry<T = T::Real>> GeometryAccess for Geometry<'a, T, G> {
type T = T;
unsafe fn point(&self, i: usize) -> Self::T {
T::from(*self.geometry.points().get_unchecked([i, self.point_index])).unwrap()
}
unsafe fn normal(&self, i: usize) -> Self::T {
T::from(*self.geometry.normals().get_unchecked([i, self.point_index])).unwrap()
}
unsafe fn jacobian(&self, i: usize) -> Self::T {
T::from(
*self
.geometry
.jacobians()
.get_unchecked([i, self.point_index]),
)
.unwrap()
}
unsafe fn jdet(&self) -> Self::T {
T::from(*self.geometry.jdets().get_unchecked(self.point_index)).unwrap()
}
}
pub unsafe trait BoundaryIntegrand {
type T: RlstScalar;
fn evaluate(
&self,
k: &impl Access1D<T = Self::T>,
test_table: &impl Access2D<T = Self::T>,
trial_table: &impl Access2D<T = Self::T>,
test_geometry: &impl GeometryAccess<T = Self::T>,
trial_geometry: &impl GeometryAccess<T = Self::T>,
) -> Self::T;
#[allow(clippy::too_many_arguments)]
fn evaluate_nonsingular(
&self,
test_table: &RlstArray<Self::T, 4>,
trial_table: &RlstArray<Self::T, 4>,
test_point_index: usize,
trial_point_index: usize,
test_basis_index: usize,
trial_basis_index: usize,
k: &RlstArray<Self::T, 3>,
test_geometry: &impl CellGeometry<T = <Self::T as RlstScalar>::Real>,
trial_geometry: &impl CellGeometry<T = <Self::T as RlstScalar>::Real>,
) -> Self::T {
self.evaluate(
&NonSingularKernel::new(k, test_point_index, trial_point_index),
&Table::new(test_table, test_point_index, test_basis_index),
&Table::new(trial_table, trial_point_index, trial_basis_index),
&Geometry::new(test_geometry, test_point_index),
&Geometry::new(trial_geometry, trial_point_index),
)
}
#[allow(clippy::too_many_arguments)]
fn evaluate_singular(
&self,
test_table: &RlstArray<Self::T, 4>,
trial_table: &RlstArray<Self::T, 4>,
point_index: usize,
test_basis_index: usize,
trial_basis_index: usize,
k: &RlstArray<Self::T, 2>,
test_geometry: &impl CellGeometry<T = <Self::T as RlstScalar>::Real>,
trial_geometry: &impl CellGeometry<T = <Self::T as RlstScalar>::Real>,
) -> Self::T {
self.evaluate(
&SingularKernel::new(k, point_index),
&Table::new(test_table, point_index, test_basis_index),
&Table::new(trial_table, point_index, trial_basis_index),
&Geometry::new(test_geometry, point_index),
&Geometry::new(trial_geometry, point_index),
)
}
}