use crate::data::constrained_section::{ConstraintSet, apply_constraints_to_section};
#[allow(unused_imports)]
use crate::data::refine::delta::SliceDelta;
use crate::data::section::Section;
use crate::data::storage::{Storage, VecStorage};
use crate::overlap::delta::CopyDelta;
use crate::topology::point::PointId;
use crate::topology::sieve::Sieve;
use crate::topology::stack::{InMemoryStack, Stack};
use core::marker::PhantomData;
pub trait SliceReducer<V>: Sync {
fn make_zero(&self, len: usize) -> Vec<V>;
fn accumulate(&self, acc: &mut [V], src: &[V])
-> Result<(), crate::mesh_error::MeshSieveError>;
fn finalize(
&self,
_acc: &mut [V],
_count: usize,
) -> Result<(), crate::mesh_error::MeshSieveError> {
Ok(())
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct AverageReducer;
impl<V> SliceReducer<V> for AverageReducer
where
V: Clone
+ Default
+ num_traits::FromPrimitive
+ core::ops::AddAssign
+ core::ops::Div<Output = V>,
{
fn make_zero(&self, len: usize) -> Vec<V> {
vec![V::default(); len]
}
fn accumulate(
&self,
acc: &mut [V],
src: &[V],
) -> Result<(), crate::mesh_error::MeshSieveError> {
use crate::mesh_error::MeshSieveError;
if acc.len() != src.len() {
return Err(MeshSieveError::ReducerLengthMismatch {
expected: acc.len(),
found: src.len(),
});
}
for (dst, s) in acc.iter_mut().zip(src.iter()) {
*dst += s.clone();
}
Ok(())
}
fn finalize(
&self,
acc: &mut [V],
count: usize,
) -> Result<(), crate::mesh_error::MeshSieveError> {
use crate::mesh_error::MeshSieveError;
if count == 0 {
return Ok(());
}
let denom: V = num_traits::FromPrimitive::from_usize(count)
.ok_or(MeshSieveError::SievedArrayPrimitiveConversionFailure(count))?;
for v in acc.iter_mut() {
*v = v.clone() / denom.clone();
}
Ok(())
}
}
pub struct Bundle<V, S: Storage<V> = VecStorage<V>, D = CopyDelta> {
pub stack: InMemoryStack<PointId, PointId, crate::topology::arrow::Polarity>,
pub section: Section<V, S>,
pub delta: D,
#[doc(hidden)]
pub _marker: PhantomData<V>,
}
impl<V, S: Storage<V>, D> Bundle<V, S, D>
where
V: Clone + Default,
D: crate::overlap::delta::ValueDelta<V, Part = V>,
{
pub fn refine(
&mut self,
bases: impl IntoIterator<Item = PointId>,
) -> Result<(), crate::mesh_error::MeshSieveError> {
for b in self.stack.base().closure(bases) {
self.section.try_restrict(b)?;
for (cap, orientation) in self.stack.lift(b) {
self.section
.try_apply_delta_between_points(b, cap, &orientation)?;
}
}
Ok(())
}
pub fn apply_constraints<C>(
&mut self,
constraints: &C,
) -> Result<(), crate::mesh_error::MeshSieveError>
where
V: Clone,
C: ConstraintSet<V>,
{
apply_constraints_to_section(&mut self.section, constraints)
}
pub fn refine_with_constraints<C>(
&mut self,
bases: impl IntoIterator<Item = PointId>,
constraints: &C,
) -> Result<(), crate::mesh_error::MeshSieveError>
where
V: Clone,
C: ConstraintSet<V>,
{
self.refine(bases)?;
self.apply_constraints(constraints)
}
pub fn assemble_with<R: SliceReducer<V>>(
&mut self,
bases: impl IntoIterator<Item = PointId>,
reducer: &R,
) -> Result<(), crate::mesh_error::MeshSieveError> {
use crate::mesh_error::MeshSieveError;
for b in self.stack.base().closure(bases) {
let mut caps_iter = self.stack.lift(b).map(|(cap, _)| cap);
let first_cap = match caps_iter.next() {
Some(c) => c,
None => continue,
};
let base_len = self.section.try_restrict(b)?.len();
let first_slice = self.section.try_restrict(first_cap)?;
if first_slice.len() != base_len {
return Err(MeshSieveError::SliceLengthMismatch {
point: first_cap,
expected: base_len,
found: first_slice.len(),
});
}
let mut acc = reducer.make_zero(base_len);
reducer.accumulate(&mut acc, first_slice)?;
let mut count = 1usize;
for cap in caps_iter {
let sl = self.section.try_restrict(cap)?;
if sl.len() != base_len {
return Err(MeshSieveError::SliceLengthMismatch {
point: cap,
expected: base_len,
found: sl.len(),
});
}
reducer.accumulate(&mut acc, sl)?;
count += 1;
}
reducer.finalize(&mut acc, count)?;
self.section.try_set(b, &acc)?;
}
Ok(())
}
pub fn assemble_with_constraints<R, C>(
&mut self,
bases: impl IntoIterator<Item = PointId>,
reducer: &R,
constraints: &C,
) -> Result<(), crate::mesh_error::MeshSieveError>
where
V: Clone,
R: SliceReducer<V>,
C: ConstraintSet<V>,
{
self.assemble_with(bases, reducer)?;
self.apply_constraints(constraints)
}
pub fn assemble(
&mut self,
bases: impl IntoIterator<Item = PointId>,
) -> Result<(), crate::mesh_error::MeshSieveError>
where
V: Clone
+ Default
+ num_traits::FromPrimitive
+ std::ops::AddAssign
+ std::ops::Div<Output = V>,
{
self.assemble_with(bases, &AverageReducer)
}
pub fn assemble_with_constraints_default<C>(
&mut self,
bases: impl IntoIterator<Item = PointId>,
constraints: &C,
) -> Result<(), crate::mesh_error::MeshSieveError>
where
V: Clone
+ Default
+ num_traits::FromPrimitive
+ std::ops::AddAssign
+ std::ops::Div<Output = V>,
C: ConstraintSet<V>,
{
self.assemble_with_constraints(bases, &AverageReducer, constraints)
}
pub fn dofs<'a>(
&'a self,
p: PointId,
) -> impl Iterator<Item = Result<(PointId, &'a [V]), crate::mesh_error::MeshSieveError>> + 'a
{
self.stack
.lift(p)
.map(move |(cap, _)| self.section.try_restrict(cap).map(|sl| (cap, sl)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::data::atlas::Atlas;
use crate::data::storage::VecStorage;
use crate::overlap::delta::CopyDelta;
use crate::topology::arrow::Polarity;
use core::marker::PhantomData;
#[test]
fn bundle_basic_refine_and_assemble() {
let mut atlas = Atlas::default();
atlas.try_insert(PointId::new(1).unwrap(), 1).unwrap();
atlas.try_insert(PointId::new(2).unwrap(), 1).unwrap();
atlas.try_insert(PointId::new(101).unwrap(), 1).unwrap(); atlas.try_insert(PointId::new(102).unwrap(), 1).unwrap(); let mut section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
section.try_set(PointId::new(1).unwrap(), &[10]).unwrap();
section.try_set(PointId::new(2).unwrap(), &[20]).unwrap();
let mut stack = InMemoryStack::<PointId, PointId, Polarity>::new();
stack
.base_mut()
.unwrap()
.add_arrow(PointId::new(1).unwrap(), PointId::new(1).unwrap(), ());
stack
.base_mut()
.unwrap()
.add_arrow(PointId::new(2).unwrap(), PointId::new(2).unwrap(), ());
stack.cap_mut().unwrap().add_arrow(
PointId::new(101).unwrap(),
PointId::new(101).unwrap(),
(),
);
stack.cap_mut().unwrap().add_arrow(
PointId::new(102).unwrap(),
PointId::new(102).unwrap(),
(),
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(101).unwrap(),
Polarity::Forward,
);
let _ = stack.add_arrow(
PointId::new(2).unwrap(),
PointId::new(102).unwrap(),
Polarity::Forward,
);
let mut bundle = Bundle {
stack,
section,
delta: CopyDelta,
_marker: PhantomData,
};
bundle
.refine([PointId::new(1).unwrap(), PointId::new(2).unwrap()])
.unwrap();
assert_eq!(
bundle
.section
.try_restrict(PointId::new(101).unwrap())
.unwrap(),
&[10]
);
assert_eq!(
bundle
.section
.try_restrict(PointId::new(102).unwrap())
.unwrap(),
&[20]
);
bundle
.section
.try_set(PointId::new(101).unwrap(), &[30])
.unwrap();
bundle
.section
.try_set(PointId::new(102).unwrap(), &[40])
.unwrap();
bundle
.assemble([PointId::new(1).unwrap(), PointId::new(2).unwrap()])
.unwrap();
assert_eq!(
bundle
.section
.try_restrict(PointId::new(1).unwrap())
.unwrap(),
&[30]
);
assert_eq!(
bundle
.section
.try_restrict(PointId::new(2).unwrap())
.unwrap(),
&[40]
);
}
#[test]
fn empty_bundle_noop() {
let atlas = Atlas::default();
let section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
let stack = InMemoryStack::<PointId, PointId, Polarity>::new();
let mut bundle = Bundle {
stack,
section,
delta: CopyDelta,
_marker: PhantomData,
};
bundle.refine(std::iter::empty::<PointId>()).unwrap();
bundle.assemble(std::iter::empty::<PointId>()).unwrap();
}
#[test]
fn multiple_dofs_only_first_moved() {
let mut atlas = Atlas::default();
atlas.try_insert(PointId::new(1).unwrap(), 2).unwrap();
atlas.try_insert(PointId::new(101).unwrap(), 2).unwrap();
let mut section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
section
.try_set(PointId::new(1).unwrap(), &[10, 20])
.unwrap();
let mut stack = InMemoryStack::<PointId, PointId, Polarity>::new();
stack
.base_mut()
.unwrap()
.add_arrow(PointId::new(1).unwrap(), PointId::new(1).unwrap(), ());
stack.cap_mut().unwrap().add_arrow(
PointId::new(101).unwrap(),
PointId::new(101).unwrap(),
(),
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(101).unwrap(),
Polarity::Forward,
);
let mut bundle = Bundle {
stack,
section,
delta: CopyDelta,
_marker: PhantomData,
};
bundle.refine([PointId::new(1).unwrap()]).unwrap();
let vals = bundle
.section
.try_restrict(PointId::new(101).unwrap())
.unwrap();
assert_eq!(vals, &[10, 20]);
}
#[test]
fn reverse_orientation_refine() {
let mut atlas = Atlas::default();
atlas.try_insert(PointId::new(1).unwrap(), 2).unwrap();
atlas.try_insert(PointId::new(101).unwrap(), 2).unwrap();
let mut section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
section.try_set(PointId::new(1).unwrap(), &[1, 2]).unwrap();
let mut stack = InMemoryStack::<PointId, PointId, Polarity>::new();
stack
.base_mut()
.unwrap()
.add_arrow(PointId::new(1).unwrap(), PointId::new(1).unwrap(), ());
stack.cap_mut().unwrap().add_arrow(
PointId::new(101).unwrap(),
PointId::new(101).unwrap(),
(),
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(101).unwrap(),
Polarity::Reverse,
);
let mut bundle = Bundle {
stack,
section,
delta: CopyDelta,
_marker: PhantomData,
};
bundle.refine([PointId::new(1).unwrap()]).unwrap();
assert_eq!(
bundle
.section
.try_restrict(PointId::new(101).unwrap())
.unwrap(),
&[2, 1]
);
}
#[test]
fn assemble_with_add_delta() {
use crate::overlap::delta::AddDelta;
let mut atlas = Atlas::default();
atlas.try_insert(PointId::new(1).unwrap(), 1).unwrap();
atlas.try_insert(PointId::new(101).unwrap(), 1).unwrap();
atlas.try_insert(PointId::new(102).unwrap(), 1).unwrap();
let mut section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
section.try_set(PointId::new(101).unwrap(), &[5]).unwrap();
section.try_set(PointId::new(102).unwrap(), &[7]).unwrap();
let mut stack = InMemoryStack::<PointId, PointId, Polarity>::new();
stack
.base_mut()
.unwrap()
.add_arrow(PointId::new(1).unwrap(), PointId::new(1).unwrap(), ());
stack.cap_mut().unwrap().add_arrow(
PointId::new(101).unwrap(),
PointId::new(101).unwrap(),
(),
);
stack.cap_mut().unwrap().add_arrow(
PointId::new(102).unwrap(),
PointId::new(102).unwrap(),
(),
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(101).unwrap(),
Polarity::Forward,
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(102).unwrap(),
Polarity::Forward,
);
let mut bundle = Bundle {
stack,
section,
delta: AddDelta,
_marker: PhantomData,
};
bundle.assemble([PointId::new(1).unwrap()]).unwrap();
assert_eq!(
bundle
.section
.try_restrict(PointId::new(1).unwrap())
.unwrap(),
&[6]
);
}
#[test]
fn dofs_iterator() {
let mut atlas = Atlas::default();
atlas.try_insert(PointId::new(1).unwrap(), 1).unwrap();
atlas.try_insert(PointId::new(101).unwrap(), 1).unwrap();
atlas.try_insert(PointId::new(102).unwrap(), 1).unwrap();
let mut section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
section.try_set(PointId::new(101).unwrap(), &[8]).unwrap();
section.try_set(PointId::new(102).unwrap(), &[9]).unwrap();
let mut stack = InMemoryStack::<PointId, PointId, Polarity>::new();
stack
.base_mut()
.unwrap()
.add_arrow(PointId::new(1).unwrap(), PointId::new(1).unwrap(), ());
stack.cap_mut().unwrap().add_arrow(
PointId::new(101).unwrap(),
PointId::new(101).unwrap(),
(),
);
stack.cap_mut().unwrap().add_arrow(
PointId::new(102).unwrap(),
PointId::new(102).unwrap(),
(),
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(101).unwrap(),
Polarity::Forward,
);
let _ = stack.add_arrow(
PointId::new(1).unwrap(),
PointId::new(102).unwrap(),
Polarity::Forward,
);
let bundle = Bundle {
stack,
section,
delta: CopyDelta,
_marker: PhantomData,
};
let vec: Vec<_> = bundle.dofs(PointId::new(1).unwrap()).collect();
let mut vec = vec.into_iter().collect::<Result<Vec<_>, _>>().unwrap();
vec.sort_by_key(|(cap, _)| cap.get());
assert_eq!(
vec,
vec![
(PointId::new(101).unwrap(), &[8][..]),
(PointId::new(102).unwrap(), &[9][..]),
]
);
}
#[test]
fn refine_unknown_base_errors() {
let atlas = Atlas::default();
let section = Section::<i32, VecStorage<i32>>::new(atlas.clone());
let stack = InMemoryStack::<PointId, PointId, Polarity>::new();
let mut bundle = Bundle {
stack,
section,
delta: CopyDelta,
_marker: PhantomData,
};
let err = bundle.refine([PointId::new(999).unwrap()]).unwrap_err();
assert!(
matches!(err, crate::mesh_error::MeshSieveError::PointNotInAtlas(pid) if pid.get() == 999)
);
}
}