conspire/domain/partition/feti/pcg/
mod.rs1use crate::{
2 domain::feti::{
3 THREADS,
4 dual::{
5 dual_action, dual_operator, dual_precondition, dual_precondition_dirichlet,
6 dual_precondition_scaled_dirichlet,
7 },
8 dual_primal::{coarse::Coarse, rigid_projector::RigidProjector},
9 subdomain::Subdomain,
10 },
11 math::{
12 Scalar, Tensor, Vector,
13 optimize::{Krylov, KrylovError, KrylovMethod},
14 },
15};
16
17pub(crate) fn projected_pcg<B>(
29 subdomains: &[Subdomain<B>],
30 coarse: &Coarse,
31 rhs: &Vector,
32) -> Result<Vector, KrylovError>
33where
34 B: Sync,
35{
36 projected_pcg_with(
37 subdomains,
38 coarse,
39 rhs,
40 Preconditioner::Dirichlet,
41 Krylov::default().rel_tol,
42 KrylovMethod::default(),
43 )
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub enum Preconditioner {
54 Lumped,
56 Dirichlet,
58}
59
60pub(crate) fn projected_pcg_with<B>(
61 subdomains: &[Subdomain<B>],
62 coarse: &Coarse,
63 rhs: &Vector,
64 preconditioner: Preconditioner,
65 rel_tol: Scalar,
66 method: KrylovMethod,
67) -> Result<Vector, KrylovError>
68where
69 B: Sync,
70{
71 Krylov {
72 rel_tol,
73 method,
74 ..Krylov::default()
75 }
76 .solve(
77 |lambda| dual_operator(subdomains, lambda, coarse, THREADS),
78 |lambda: &Vector| match preconditioner {
79 Preconditioner::Lumped => dual_precondition(subdomains, lambda, THREADS),
80 Preconditioner::Dirichlet => dual_precondition_dirichlet(subdomains, lambda, THREADS),
81 },
82 rhs,
83 )
84}
85
86pub(crate) fn rigid_projected_pcg<B>(
96 subdomains: &[Subdomain<B>],
97 projector: &RigidProjector,
98 d: &Vector,
99 e: &Vector,
100 preconditioner: Preconditioner,
101 rel_tol: Scalar,
102 method: KrylovMethod,
103) -> Result<(Vector, Vector), KrylovError>
104where
105 B: Sync,
106{
107 let particular = projector.particular(e, d.len());
108 let rhs = projector.project(&(d.clone() - dual_action(subdomains, &particular, THREADS)));
109 let correction = Krylov {
110 rel_tol,
111 method,
112 ..Krylov::default()
113 }
114 .solve(
115 |mu: &Vector| projector.project(&dual_action(subdomains, &projector.project(mu), THREADS)),
116 |residual: &Vector| {
117 let residual = projector.project(residual);
118 projector.project(&match preconditioner {
119 Preconditioner::Lumped => dual_precondition(subdomains, &residual, THREADS),
120 Preconditioner::Dirichlet => {
121 dual_precondition_scaled_dirichlet(subdomains, &residual, THREADS)
122 }
123 })
124 },
125 &rhs,
126 )?;
127 let lambda = particular + projector.project(&correction);
128 let alpha = projector.amplitudes(&(dual_action(subdomains, &lambda, THREADS) - d.clone()));
129 Ok((lambda, alpha))
130}
131
132pub(crate) fn primal_recovery<B>(
139 subdomains: &[Subdomain<B>],
140 local_forces: &[Vector],
141 corner_solution: &Vector,
142 lambda: &Vector,
143) -> Vec<Vector> {
144 subdomains
145 .iter()
146 .zip(local_forces.iter())
147 .map(|(subdomain, local_force)| {
148 let multiplier_rhs = subdomain
149 .interface()
150 .apply_transpose(lambda, subdomain.num_local());
151 let combined_rhs = local_force - &multiplier_rhs;
152 let dual_solution = subdomain.local_solve(&combined_rhs);
153 let primal_local = subdomain.gather_primal(corner_solution);
154 let coupling_correction =
155 subdomain.scatter_dual(&(subdomain.dual_map() * &primal_local));
156 dual_solution - coupling_correction + subdomain.scatter_primal(&primal_local)
157 })
158 .collect()
159}