conspire/domain/partition/feti/
mod.rs1#![allow(dead_code)]
2
3#[cfg(test)]
4mod test;
5
6pub(crate) mod block;
7pub(crate) mod dual;
8pub(crate) mod dual_primal;
9pub(crate) mod interface;
10pub(crate) mod parallel;
11pub(crate) mod pcg;
12pub(crate) mod solid;
13pub(crate) mod subdomain;
14#[cfg(feature = "fem")]
15pub(crate) mod thermal;
16
17pub use block::element::{DecomposableElements, ElementSystems};
18#[cfg(feature = "fem")]
19pub use block::solve::SolveError;
20#[cfg(feature = "fem")]
21pub use dual_primal::BoundaryConditions;
22#[cfg(feature = "fem")]
23pub use pcg::Preconditioner;
24
25#[cfg(feature = "fem")]
26use crate::domain::NodalCoordinates;
27#[cfg(feature = "fem")]
28use crate::{
29 geometry::mesh::Partition,
30 math::{
31 Scalar, Vector,
32 optimize::{Krylov, KrylovMethod, LinearSolver},
33 },
34};
35#[cfg(feature = "fem")]
36use block::solve::solve_local_systems;
37
38pub(crate) const THREADS: usize = 1;
39
40#[cfg(feature = "fem")]
46pub const GMRES: KrylovMethod = KrylovMethod::Gmres(100);
47
48#[cfg(feature = "fem")]
69#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
70pub enum Formulation {
71 Classical,
73 #[default]
75 DualPrimal,
76}
77
78#[cfg(feature = "fem")]
94#[derive(Clone, Debug)]
95pub struct Feti {
96 pub formulation: Formulation,
97 pub method: KrylovMethod,
98 pub partition: Partition,
99 pub preconditioner: Preconditioner,
100 pub rel_tol: Scalar,
101}
102
103#[cfg(feature = "fem")]
104impl Default for Feti {
105 fn default() -> Self {
106 Self {
107 method: KrylovMethod::ConjugateGradients,
108 formulation: Formulation::DualPrimal,
109 partition: Partition::default(),
110 preconditioner: Preconditioner::Dirichlet,
111 rel_tol: Krylov::default().rel_tol,
112 }
113 }
114}
115
116#[cfg(feature = "fem")]
117impl Feti {
118 pub fn solve<B>(
119 &self,
120 block: &B,
121 nodal_coordinates: &NodalCoordinates<3>,
122 boundary_conditions: &BoundaryConditions,
123 ) -> Result<Vector, SolveError>
124 where
125 B: DecomposableElements,
126 {
127 let systems = block.element_systems(nodal_coordinates)?;
128 self.solve_systems(&systems, boundary_conditions)
129 }
130 fn solve_systems(
131 &self,
132 systems: &ElementSystems,
133 boundary_conditions: &BoundaryConditions,
134 ) -> Result<Vector, SolveError> {
135 let (stiffnesses, forces) = systems
136 .subdomains(&self.partition)
137 .map_err(SolveError::Partition)?;
138 solve_local_systems(
139 &self.partition,
140 boundary_conditions,
141 stiffnesses,
142 forces,
143 systems.positions(),
144 self.preconditioner,
145 self.rel_tol,
146 self.method,
147 self.formulation,
148 )
149 }
150}
151
152#[cfg(feature = "fem")]
153impl LinearSolver for Feti {
154 type Tangent = ElementSystems;
155 fn solve(
156 &self,
157 tangent: ElementSystems,
158 retained: &[usize],
159 _residual: &Vector,
160 ) -> Result<Vector, String> {
161 let mut fixed = vec![true; 3 * tangent.positions().len()];
162 retained.iter().for_each(|&dof| fixed[dof] = false);
163 let boundary_conditions = BoundaryConditions::new(
164 fixed
165 .iter()
166 .enumerate()
167 .filter(|&(_, &pinned)| pinned)
168 .map(|(dof, _)| (dof / 3, dof % 3))
169 .collect(),
170 );
171 let solution = self
172 .solve_systems(&tangent, &boundary_conditions)
173 .map_err(|error| error.to_string())?;
174 Ok(retained.iter().map(|&dof| solution[dof]).collect())
175 }
176}