use crate::allocators::FiniteElementAllocator;
use crate::element::{FiniteElement, ReferenceFiniteElement};
use crate::geometry::GeometryCollection;
use crate::nalgebra::{Dynamic, MatrixSliceMut, OMatrix};
use crate::SmallDim;
use nalgebra::{DefaultAllocator, OPoint, Scalar};
pub trait FiniteElementConnectivity {
fn num_elements(&self) -> usize;
fn num_nodes(&self) -> usize;
fn element_node_count(&self, element_index: usize) -> usize;
fn populate_element_nodes(&self, nodes: &mut [usize], element_index: usize);
}
pub trait FiniteElementSpace<T: Scalar>: FiniteElementConnectivity
where
DefaultAllocator: FiniteElementAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
type GeometryDim: SmallDim;
type ReferenceDim: SmallDim;
fn populate_element_basis(
&self,
element_index: usize,
basis_values: &mut [T],
reference_coords: &OPoint<T, Self::ReferenceDim>,
);
fn populate_element_gradients(
&self,
element_index: usize,
gradients: MatrixSliceMut<T, Self::ReferenceDim, Dynamic>,
reference_coords: &OPoint<T, Self::ReferenceDim>,
);
fn element_reference_jacobian(
&self,
element_index: usize,
reference_coords: &OPoint<T, Self::ReferenceDim>,
) -> OMatrix<T, Self::GeometryDim, Self::ReferenceDim>;
fn map_element_reference_coords(
&self,
element_index: usize,
reference_coords: &OPoint<T, Self::ReferenceDim>,
) -> OPoint<T, Self::GeometryDim>;
fn diameter(&self, element_index: usize) -> T;
}
pub trait VolumetricFiniteElementSpace<T>:
FiniteElementSpace<T, GeometryDim = <Self as FiniteElementSpace<T>>::ReferenceDim>
where
T: Scalar,
DefaultAllocator: FiniteElementAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
}
impl<T, S> VolumetricFiniteElementSpace<T> for S
where
T: Scalar,
S: FiniteElementSpace<T, GeometryDim = <Self as FiniteElementSpace<T>>::ReferenceDim>,
DefaultAllocator: FiniteElementAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
}
pub trait GeometricFiniteElementSpace<'a, T>: FiniteElementSpace<T> + GeometryCollection<'a>
where
T: Scalar,
DefaultAllocator: FiniteElementAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
}
#[derive(Debug)]
pub struct ElementInSpace<'a, Space> {
space: &'a Space,
element_index: usize,
}
impl<'a, Space> ElementInSpace<'a, Space> {
pub fn from_space_and_element_index(space: &'a Space, element_index: usize) -> Self {
Self { space, element_index }
}
}
impl<'a, T, Space> ReferenceFiniteElement<T> for ElementInSpace<'a, Space>
where
T: Scalar,
Space: FiniteElementSpace<T>,
DefaultAllocator: FiniteElementAllocator<T, Space::GeometryDim, Space::ReferenceDim>,
{
type ReferenceDim = Space::ReferenceDim;
fn num_nodes(&self) -> usize {
self.space.element_node_count(self.element_index)
}
fn populate_basis(&self, basis_values: &mut [T], reference_coords: &OPoint<T, Self::ReferenceDim>) {
self.space
.populate_element_basis(self.element_index, basis_values, reference_coords)
}
fn populate_basis_gradients(
&self,
basis_gradients: MatrixSliceMut<T, Self::ReferenceDim, Dynamic>,
reference_coords: &OPoint<T, Self::ReferenceDim>,
) {
self.space
.populate_element_gradients(self.element_index, basis_gradients, reference_coords)
}
}
impl<'a, T, Space> FiniteElement<T> for ElementInSpace<'a, Space>
where
T: Scalar,
Space: FiniteElementSpace<T>,
DefaultAllocator: FiniteElementAllocator<T, Space::GeometryDim, Space::ReferenceDim>,
{
type GeometryDim = Space::GeometryDim;
fn reference_jacobian(
&self,
reference_coords: &OPoint<T, Self::ReferenceDim>,
) -> OMatrix<T, Self::GeometryDim, Self::ReferenceDim> {
self.space
.element_reference_jacobian(self.element_index, reference_coords)
}
fn map_reference_coords(&self, reference_coords: &OPoint<T, Self::ReferenceDim>) -> OPoint<T, Self::GeometryDim> {
self.space
.map_element_reference_coords(self.element_index, reference_coords)
}
fn diameter(&self) -> T {
self.space.diameter(self.element_index)
}
}