use crate::allocators::BiDimAllocator;
use crate::element::{ClosestPoint, FiniteElement, ReferenceFiniteElement};
use crate::geometry::GeometryCollection;
use crate::nalgebra::{Dyn, MatrixViewMut, OMatrix};
use crate::SmallDim;
use fenris_geometry::AxisAlignedBoundingBox;
use nalgebra::{DefaultAllocator, OPoint, Scalar};
mod fixed_interpolator;
mod interpolate;
mod space_impl;
mod spatially_indexed;
pub use fixed_interpolator::{FixedInterpolator, ValuesOrGradients};
pub use interpolate::*;
pub use spatially_indexed::SpatiallyIndexed;
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: BiDimAllocator<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: MatrixViewMut<T, Self::ReferenceDim, Dyn>,
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: BiDimAllocator<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: BiDimAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
}
pub trait GeometricFiniteElementSpace<'a, T>: FiniteElementSpace<T> + GeometryCollection<'a>
where
T: Scalar,
DefaultAllocator: BiDimAllocator<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: BiDimAllocator<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: MatrixViewMut<T, Self::ReferenceDim, Dyn>,
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: BiDimAllocator<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)
}
}
pub trait ClosestPointInElementInSpace<T: Scalar>: FiniteElementSpace<T>
where
DefaultAllocator: BiDimAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
fn closest_point_in_element(
&self,
element_index: usize,
p: &OPoint<T, Self::GeometryDim>,
) -> ClosestPoint<T, Self::ReferenceDim>;
}
pub trait BoundsForElementInSpace<T: Scalar>: FiniteElementSpace<T>
where
DefaultAllocator: BiDimAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
fn bounds_for_element(&self, element_index: usize) -> AxisAlignedBoundingBox<T, Self::GeometryDim>;
fn populate_bounds_for_all_elements(&self, bounds: &mut [AxisAlignedBoundingBox<T, Self::GeometryDim>]) {
assert_eq!(bounds.len(), self.num_elements());
for (i, aabb) in (0..self.num_elements()).zip(bounds) {
*aabb = self.bounds_for_element(i);
}
}
fn bounds_for_all_elements(&self) -> Vec<AxisAlignedBoundingBox<T, Self::GeometryDim>> {
(0..self.num_elements())
.map(|i| self.bounds_for_element(i))
.collect()
}
}
pub trait FindClosestElement<T: Scalar>: FiniteElementSpace<T>
where
DefaultAllocator: BiDimAllocator<T, Self::GeometryDim, Self::ReferenceDim>,
{
fn find_closest_element_and_reference_coords(
&self,
point: &OPoint<T, Self::GeometryDim>,
) -> Option<(usize, OPoint<T, Self::ReferenceDim>)>;
}