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#[derive(Clone, Copy, Debug, PartialEq)]
13pub enum Enforcement {
14 Elimination,
16 Multipliers,
18}
19
20#[derive(Clone, Debug, PartialEq)]
21enum Target<'m> {
22 Set(&'m NodeSet),
23 Nodes(Vec<usize>),
24}
25
26#[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 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 pub fn prescription(&self) -> Prescription {
52 self.prescription
53 }
54 pub fn enforcement(&self) -> Enforcement {
56 self.enforcement
57 }
58}
59
60pub 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn conditions(&self) -> &[BoundaryCondition<'m>] {
235 &self.conditions
236 }
237 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}