Skip to main content

conspire/domain/boundary/condition/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    domain::boundary::{Component, Layout, Prescribable},
6    geometry::mesh::NodeSet,
7    math::optimize::{EqualityConstraint, EqualityConstraints, Prescription},
8};
9use std::marker::PhantomData;
10
11/// How degrees of freedom are held.
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub enum Enforcement {
14    /// They are eliminated from the system.
15    Elimination,
16    /// They are held by Lagrange multipliers.
17    Multipliers,
18}
19
20#[derive(Clone, Debug, PartialEq)]
21enum Target<'m> {
22    Set(&'m NodeSet),
23    Nodes(Vec<usize>),
24}
25
26/// A component of some nodes held fixed or at a value, as `stride * node + offset`.
27///
28/// The nodes are a set that the condition borrows, or are listed.
29#[derive(Clone, Debug, PartialEq)]
30pub struct BoundaryCondition<'m> {
31    target: Target<'m>,
32    stride: usize,
33    offset: usize,
34    prescription: Prescription,
35    enforcement: Enforcement,
36}
37
38impl BoundaryCondition<'_> {
39    /// The degrees of freedom held.
40    pub fn indices(&self) -> Vec<usize> {
41        let nodes = match &self.target {
42            Target::Set(set) => set.nodes(),
43            Target::Nodes(nodes) => nodes,
44        };
45        nodes
46            .iter()
47            .map(|&node| self.stride * node + self.offset)
48            .collect()
49    }
50    /// What the degrees of freedom are held at.
51    pub fn prescription(&self) -> Prescription {
52        self.prescription
53    }
54    /// How the degrees of freedom are held.
55    pub fn enforcement(&self) -> Enforcement {
56        self.enforcement
57    }
58}
59
60/// Degrees of freedom held fixed or at a value, chosen by node and component.
61///
62/// The components a layout has are the only ones that can be held, and an axis that a layout
63/// does not have is an error when compiling. The conditions borrow the sets they hold, such as
64/// those of the model they are for, so they cannot outlive them. Each is eliminated from the
65/// system unless it is made to be held by multipliers.
66pub struct BoundaryConditions<'m, L> {
67    conditions: Vec<BoundaryCondition<'m>>,
68    layout: PhantomData<L>,
69}
70
71impl<L> Default for BoundaryConditions<'_, L> {
72    fn default() -> Self {
73        Self {
74            conditions: Vec::new(),
75            layout: PhantomData,
76        }
77    }
78}
79
80impl<'m, L> BoundaryConditions<'m, L>
81where
82    L: Layout,
83{
84    pub fn new() -> Self {
85        Self::default()
86    }
87    fn hold<C, I>(
88        mut self,
89        target: Target<'m>,
90        prescription: Prescription,
91        enforcement: Enforcement,
92    ) -> Self
93    where
94        C: Component<L, I>,
95    {
96        self.conditions.push(BoundaryCondition {
97            target,
98            stride: L::STRIDE,
99            offset: <C as Component<L, I>>::OFFSET,
100            prescription,
101            enforcement,
102        });
103        self
104    }
105    /// Holds a component of every node in a set at its initial value.
106    pub fn fix<C, I>(self, component: C, nodes: &'m NodeSet) -> Self
107    where
108        C: Component<L, I>,
109    {
110        self.fix_by(Enforcement::Elimination, component, nodes)
111    }
112    /// Holds a component of every node in a set at its initial value, the way given.
113    pub fn fix_by<C, I>(self, enforcement: Enforcement, _: C, nodes: &'m NodeSet) -> Self
114    where
115        C: Component<L, I>,
116    {
117        self.hold::<C, I>(Target::Set(nodes), Prescription::Initial, enforcement)
118    }
119    /// Holds a component of the listed nodes at its initial value.
120    pub fn fix_nodes<C, I>(self, component: C, nodes: impl IntoIterator<Item = usize>) -> Self
121    where
122        C: Component<L, I>,
123    {
124        self.fix_nodes_by(Enforcement::Elimination, component, nodes)
125    }
126    /// Holds a component of the listed nodes at its initial value, the way given.
127    pub fn fix_nodes_by<C, I>(
128        self,
129        enforcement: Enforcement,
130        _: C,
131        nodes: impl IntoIterator<Item = usize>,
132    ) -> Self
133    where
134        C: Component<L, I>,
135    {
136        self.hold::<C, I>(
137            Target::Nodes(nodes.into_iter().collect()),
138            Prescription::Initial,
139            enforcement,
140        )
141    }
142    /// Holds a component of a node at its initial value.
143    pub fn fix_node<C, I>(self, component: C, node: usize) -> Self
144    where
145        C: Component<L, I>,
146    {
147        self.fix_node_by(Enforcement::Elimination, component, node)
148    }
149    /// Holds a component of a node at its initial value, the way given.
150    pub fn fix_node_by<C, I>(self, enforcement: Enforcement, _: C, node: usize) -> Self
151    where
152        C: Component<L, I>,
153    {
154        self.hold::<C, I>(
155            Target::Nodes(vec![node]),
156            Prescription::Initial,
157            enforcement,
158        )
159    }
160    /// Holds a component of every node in a set at a value.
161    pub fn prescribe<C, I>(self, component: C, nodes: &'m NodeSet, value: C::Value) -> Self
162    where
163        C: Component<L, I> + Prescribable,
164    {
165        self.prescribe_by(Enforcement::Elimination, component, nodes, value)
166    }
167    /// Holds a component of every node in a set at a value, the way given.
168    pub fn prescribe_by<C, I>(
169        self,
170        enforcement: Enforcement,
171        _: C,
172        nodes: &'m NodeSet,
173        value: C::Value,
174    ) -> Self
175    where
176        C: Component<L, I> + Prescribable,
177    {
178        self.hold::<C, I>(Target::Set(nodes), C::prescription(value), enforcement)
179    }
180    /// Holds a component of the listed nodes at a value.
181    pub fn prescribe_nodes<C, I>(
182        self,
183        component: C,
184        nodes: impl IntoIterator<Item = usize>,
185        value: C::Value,
186    ) -> Self
187    where
188        C: Component<L, I> + Prescribable,
189    {
190        self.prescribe_nodes_by(Enforcement::Elimination, component, nodes, value)
191    }
192    /// Holds a component of the listed nodes at a value, the way given.
193    pub fn prescribe_nodes_by<C, I>(
194        self,
195        enforcement: Enforcement,
196        _: C,
197        nodes: impl IntoIterator<Item = usize>,
198        value: C::Value,
199    ) -> Self
200    where
201        C: Component<L, I> + Prescribable,
202    {
203        self.hold::<C, I>(
204            Target::Nodes(nodes.into_iter().collect()),
205            C::prescription(value),
206            enforcement,
207        )
208    }
209    /// Holds a component of a node at a value.
210    pub fn prescribe_node<C, I>(self, component: C, node: usize, value: C::Value) -> Self
211    where
212        C: Component<L, I> + Prescribable,
213    {
214        self.prescribe_node_by(Enforcement::Elimination, component, node, value)
215    }
216    /// Holds a component of a node at a value, the way given.
217    pub fn prescribe_node_by<C, I>(
218        self,
219        enforcement: Enforcement,
220        _: C,
221        node: usize,
222        value: C::Value,
223    ) -> Self
224    where
225        C: Component<L, I> + Prescribable,
226    {
227        self.hold::<C, I>(
228            Target::Nodes(vec![node]),
229            C::prescription(value),
230            enforcement,
231        )
232    }
233    /// The conditions, in the order they were made.
234    pub fn conditions(&self) -> &[BoundaryCondition<'m>] {
235        &self.conditions
236    }
237    /// The constraints holding the degrees of freedom, one for each condition.
238    ///
239    /// A condition eliminated at its initial values is fixed, with the indices in ascending
240    /// order and without repeats, and any other eliminated is prescribed. One held by
241    /// multipliers has the indices as they are.
242    pub fn constraint(&self) -> EqualityConstraints {
243        self.conditions
244            .iter()
245            .map(|condition| {
246                let mut indices = condition.indices();
247                let prescription = condition.prescription;
248                match condition.enforcement {
249                    Enforcement::Multipliers => EqualityConstraint::Multipliers(
250                        indices
251                            .into_iter()
252                            .map(|index| (index, prescription))
253                            .collect(),
254                    ),
255                    Enforcement::Elimination if prescription == Prescription::Initial => {
256                        indices.sort_unstable();
257                        indices.dedup();
258                        EqualityConstraint::Fixed(indices)
259                    }
260                    Enforcement::Elimination => EqualityConstraint::Prescribed(
261                        indices
262                            .into_iter()
263                            .map(|index| (index, prescription))
264                            .collect(),
265                    ),
266                }
267            })
268            .collect()
269    }
270}