1#[cfg(test)]
2mod test;
3
4pub mod element;
5pub mod solid;
6pub mod surface;
7pub mod thermal;
8
9use crate::{
10 defeat_message,
11 fem::{
12 NodalReferenceCoordinates,
13 block::element::{ElementNodalReferenceCoordinates, FiniteElement},
14 },
15 math::{
16 Banded, Scalar, Scalars, Tensor, TestError,
17 optimize::{
18 EqualityConstraint, FirstOrderOptimization, FirstOrderRootFinding, OptimizationError,
19 SecondOrderOptimization, ZerothOrderRootFinding,
20 },
21 },
22 mechanics::{CoordinateList, Coordinates},
23};
24use std::{
25 any::type_name,
26 fmt::{self, Debug, Display, Formatter},
27 iter::repeat_n,
28};
29
30pub type Connectivity<const N: usize> = Vec<[usize; N]>;
31
32pub struct Block<C, F, const G: usize, const M: usize, const N: usize, const P: usize> {
33 constitutive_model: C,
34 connectivity: Connectivity<N>,
35 coordinates: NodalReferenceCoordinates,
36 elements: Vec<F>,
37}
38
39impl<C, F, const G: usize, const M: usize, const N: usize, const P: usize> Block<C, F, G, M, N, P>
40where
41 F: FiniteElement<G, M, N, P>,
42{
43 fn constitutive_model(&self) -> &C {
44 &self.constitutive_model
45 }
46 fn connectivity(&self) -> &Connectivity<N> {
47 &self.connectivity
48 }
49 fn coordinates(&self) -> &NodalReferenceCoordinates {
50 &self.coordinates
51 }
52 fn elements(&self) -> &[F] {
53 &self.elements
54 }
55 fn element_coordinates<const I: usize>(
56 coordinates: &Coordinates<I>,
57 nodes: &[usize; N],
58 ) -> CoordinateList<I, N> {
59 nodes
60 .iter()
61 .map(|&node| coordinates[node].clone())
62 .collect()
63 }
64 pub fn minimum_scaled_jacobians<const I: usize>(
65 &self,
66 coordinates: &Coordinates<I>,
67 ) -> Scalars {
68 self.connectivity()
69 .iter()
70 .map(|nodes| F::minimum_scaled_jacobian(Self::element_coordinates(coordinates, nodes)))
71 .collect()
72 }
73 pub fn volume(&self) -> Scalar {
74 self.elements().iter().map(|element| element.volume()).sum()
75 }
76}
77
78impl<C, F, const G: usize, const M: usize, const N: usize, const P: usize> Debug
79 for Block<C, F, G, M, N, P>
80where
81 F: FiniteElement<G, M, N, P>,
82{
83 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
84 write!(
85 f,
86 "Block {{ constitutive model: {}, {} elements }}",
87 type_name::<C>()
88 .rsplit("::")
89 .next()
90 .unwrap()
91 .split("<")
92 .next()
93 .unwrap(),
94 self.elements().len()
95 )
96 }
97}
98
99pub trait FiniteElementBlock<C, F, const G: usize, const N: usize>
100where
101 Self: From<(C, Connectivity<N>, NodalReferenceCoordinates)>,
102{
103 fn reset(&mut self);
104}
105
106impl<C, F, const G: usize, const N: usize, const P: usize>
107 From<(C, Connectivity<N>, NodalReferenceCoordinates)> for Block<C, F, G, 3, N, P>
108where
109 F: FiniteElement<G, 3, N, P> + From<ElementNodalReferenceCoordinates<N>>,
110{
111 fn from(
112 (constitutive_model, connectivity, coordinates): (
113 C,
114 Connectivity<N>,
115 NodalReferenceCoordinates,
116 ),
117 ) -> Self {
118 let elements = connectivity
119 .iter()
120 .map(|nodes| Self::element_coordinates(&coordinates, nodes).into())
121 .collect();
122 Self {
123 constitutive_model,
124 connectivity,
125 coordinates,
126 elements,
127 }
128 }
129}
130
131impl<C, F, const G: usize, const N: usize, const P: usize> FiniteElementBlock<C, F, G, N>
132 for Block<C, F, G, 3, N, P>
133where
134 F: Default + FiniteElement<G, 3, N, P> + From<ElementNodalReferenceCoordinates<N>>,
135{
136 fn reset(&mut self) {
137 self.elements
138 .iter_mut()
139 .for_each(|element| *element = F::default())
140 }
141}
142
143pub enum FiniteElementBlockError {
144 Upstream(String, String),
145}
146
147impl From<FiniteElementBlockError> for String {
148 fn from(error: FiniteElementBlockError) -> Self {
149 match error {
150 FiniteElementBlockError::Upstream(error, block) => {
151 format!(
152 "{error}\x1b[0;91m\n\
153 In finite element block: {block}."
154 )
155 }
156 }
157 }
158}
159
160impl From<FiniteElementBlockError> for TestError {
161 fn from(error: FiniteElementBlockError) -> Self {
162 Self {
163 message: error.to_string(),
164 }
165 }
166}
167
168impl Debug for FiniteElementBlockError {
169 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
170 let error = match self {
171 Self::Upstream(error, block) => {
172 format!(
173 "{error}\x1b[0;91m\n\
174 In block: {block}."
175 )
176 }
177 };
178 write!(f, "\n{error}\n\x1b[0;2;31m{}\x1b[0m\n", defeat_message())
179 }
180}
181
182impl Display for FiniteElementBlockError {
183 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
184 let error = match self {
185 Self::Upstream(error, block) => {
186 format!(
187 "{error}\x1b[0;91m\n\
188 In block: {block}."
189 )
190 }
191 };
192 write!(f, "{error}\x1b[0m")
193 }
194}
195
196pub trait ZerothOrderRoot<C, E, const G: usize, const M: usize, const N: usize, X> {
197 fn root(
198 &self,
199 equality_constraint: EqualityConstraint,
200 solver: impl ZerothOrderRootFinding<X>,
201 ) -> Result<X, OptimizationError>;
202}
203
204pub trait FirstOrderRoot<C, E, const G: usize, const M: usize, const N: usize, F, J, X> {
205 fn root(
206 &self,
207 equality_constraint: EqualityConstraint,
208 solver: impl FirstOrderRootFinding<F, J, X>,
209 ) -> Result<X, OptimizationError>;
210}
211
212pub trait FirstOrderMinimize<C, E, const G: usize, const M: usize, const N: usize, X> {
213 fn minimize(
214 &self,
215 equality_constraint: EqualityConstraint,
216 solver: impl FirstOrderOptimization<Scalar, X>,
217 ) -> Result<X, OptimizationError>;
218}
219
220pub trait SecondOrderMinimize<C, E, const G: usize, const M: usize, const N: usize, J, H, X> {
221 fn minimize(
222 &self,
223 equality_constraint: EqualityConstraint,
224 solver: impl SecondOrderOptimization<Scalar, J, H, X>,
225 ) -> Result<X, OptimizationError>;
226}
227
228fn band<const N: usize>(
229 connectivity: &Connectivity<N>,
230 equality_constraint: &EqualityConstraint,
231 number_of_nodes: usize,
232 dimension: usize,
233) -> Banded {
234 match equality_constraint {
235 EqualityConstraint::Fixed(indices) => {
236 let neighbors: Vec<Vec<usize>> = invert(connectivity, number_of_nodes)
237 .iter()
238 .map(|elements| {
239 let mut nodes: Vec<usize> = elements
240 .iter()
241 .flat_map(|&element| connectivity[element])
242 .collect();
243 nodes.sort();
244 nodes.dedup();
245 nodes
246 })
247 .collect();
248 let structure: Vec<Vec<bool>> = neighbors
249 .iter()
250 .map(|nodes| (0..number_of_nodes).map(|b| nodes.contains(&b)).collect())
251 .collect();
252 let structure_nd: Vec<Vec<bool>> = structure
253 .iter()
254 .flat_map(|row| {
255 repeat_n(
256 row.iter()
257 .flat_map(|entry| repeat_n(*entry, dimension))
258 .collect(),
259 dimension,
260 )
261 })
262 .collect();
263 let mut keep = vec![true; structure_nd.len()];
264 indices.iter().for_each(|&index| keep[index] = false);
265 let banded = structure_nd
266 .into_iter()
267 .zip(keep.iter())
268 .filter(|(_, keep)| **keep)
269 .map(|(structure_nd_a, _)| {
270 structure_nd_a
271 .into_iter()
272 .zip(keep.iter())
273 .filter(|(_, keep)| **keep)
274 .map(|(structure_nd_ab, _)| structure_nd_ab)
275 .collect::<Vec<bool>>()
276 })
277 .collect::<Vec<Vec<bool>>>();
278 Banded::from(banded)
279 }
280 EqualityConstraint::Linear(matrix, _) => {
281 let neighbors: Vec<Vec<usize>> = invert(connectivity, number_of_nodes)
282 .iter()
283 .map(|elements| {
284 let mut nodes: Vec<usize> = elements
285 .iter()
286 .flat_map(|&element| connectivity[element])
287 .collect();
288 nodes.sort();
289 nodes.dedup();
290 nodes
291 })
292 .collect();
293 let structure: Vec<Vec<bool>> = neighbors
294 .iter()
295 .map(|nodes| (0..number_of_nodes).map(|b| nodes.contains(&b)).collect())
296 .collect();
297 let structure_nd: Vec<Vec<bool>> = structure
298 .iter()
299 .flat_map(|row| {
300 repeat_n(
301 row.iter()
302 .flat_map(|entry| repeat_n(*entry, dimension))
303 .collect(),
304 dimension,
305 )
306 })
307 .collect();
308 let num_coords = dimension * number_of_nodes;
309 assert_eq!(matrix.width(), num_coords);
310 let num_dof = matrix.len() + matrix.width();
311 let mut banded = vec![vec![false; num_dof]; num_dof];
312 structure_nd
313 .iter()
314 .zip(banded.iter_mut())
315 .for_each(|(structure_nd_i, banded_i)| {
316 structure_nd_i
317 .iter()
318 .zip(banded_i.iter_mut())
319 .for_each(|(structure_nd_ij, banded_ij)| *banded_ij = *structure_nd_ij)
320 });
321 let mut index = num_coords;
322 matrix.iter().for_each(|matrix_i| {
323 matrix_i.iter().enumerate().for_each(|(j, matrix_ij)| {
324 if matrix_ij != &0.0 {
325 banded[index][j] = true;
326 banded[j][index] = true;
327 index += 1;
328 }
329 })
330 });
331 Banded::from(banded)
332 }
333 EqualityConstraint::None => {
334 let neighbors: Vec<Vec<usize>> = invert(connectivity, number_of_nodes)
335 .iter()
336 .map(|elements| {
337 let mut nodes: Vec<usize> = elements
338 .iter()
339 .flat_map(|&element| connectivity[element])
340 .collect();
341 nodes.sort();
342 nodes.dedup();
343 nodes
344 })
345 .collect();
346 let structure: Vec<Vec<bool>> = neighbors
347 .iter()
348 .map(|nodes| (0..number_of_nodes).map(|b| nodes.contains(&b)).collect())
349 .collect();
350 let structure_nd: Vec<Vec<bool>> = structure
351 .iter()
352 .flat_map(|row| {
353 repeat_n(
354 row.iter()
355 .flat_map(|entry| repeat_n(*entry, dimension))
356 .collect(),
357 dimension,
358 )
359 })
360 .collect();
361 Banded::from(structure_nd)
362 }
363 }
364}
365
366fn invert<const N: usize>(
367 connectivity: &Connectivity<N>,
368 number_of_nodes: usize,
369) -> Vec<Vec<usize>> {
370 let mut inverse_connectivity = vec![vec![]; number_of_nodes];
371 connectivity
372 .iter()
373 .enumerate()
374 .for_each(|(element, nodes)| {
375 nodes
376 .iter()
377 .for_each(|&node| inverse_connectivity[node].push(element))
378 });
379 inverse_connectivity
380}