Skip to main content

conspire/domain/partition/feti/dual_primal/
mod.rs

1pub(crate) mod coarse;
2pub(crate) mod condense;
3pub(crate) mod corner;
4pub(crate) mod rigid;
5pub(crate) mod rigid_projector;
6#[cfg(test)]
7mod test;
8
9use crate::geometry::mesh::Partition;
10use std::collections::HashSet;
11
12pub(crate) use corner::{CornerDofs, CornerSelection};
13
14/// Which (global node, component) pairs are prescribed rather than free.
15///
16/// Only zero-displacement (homogeneous) Dirichlet conditions are supported:
17/// a fixed DOF is simply excluded from both the primal and dual sets, never
18/// appears in any local solve or scatter, and so is left at its
19/// zero-initialized value everywhere — which is exactly correct for a
20/// zero prescribed displacement, and needs no force-correction term the way
21/// a nonzero prescribed value would.
22pub struct BoundaryConditions {
23    fixed: HashSet<(usize, usize)>,
24}
25
26impl BoundaryConditions {
27    pub fn new(fixed: Vec<(usize, usize)>) -> Self {
28        Self {
29            fixed: fixed.into_iter().collect(),
30        }
31    }
32    pub fn none() -> Self {
33        Self {
34            fixed: HashSet::new(),
35        }
36    }
37    fn is_fixed(&self, node: usize, component: usize) -> bool {
38        self.fixed.contains(&(node, component))
39    }
40}
41
42/// A subdomain's local DOFs split into corner (primal) and the rest (dual).
43///
44/// `primal` numbers corner DOFs in this subdomain's own local numbering;
45/// `primal_global` numbers the same DOFs, in the same order, in the global
46/// corner-DOF numbering they share with every other subdomain that touches
47/// that corner.
48pub(crate) struct DualPrimalSplit {
49    primal: Vec<usize>,
50    primal_global: Vec<usize>,
51    dual: Vec<usize>,
52}
53
54impl DualPrimalSplit {
55    #[cfg(test)]
56    pub(crate) fn new(primal: Vec<usize>, dual: Vec<usize>) -> Self {
57        let primal_global = primal.clone();
58        Self {
59            primal,
60            primal_global,
61            dual,
62        }
63    }
64    fn from_subdomain_nodes(
65        subdomain_nodes: &[usize],
66        corner_dofs: &CornerDofs,
67        boundary_conditions: &BoundaryConditions,
68        dimension: usize,
69    ) -> Self {
70        let mut primal = Vec::new();
71        let mut primal_global = Vec::new();
72        let mut dual = Vec::new();
73        subdomain_nodes
74            .iter()
75            .enumerate()
76            .for_each(|(local, &node)| {
77                (0..dimension).for_each(|component| {
78                    if boundary_conditions.is_fixed(node, component) {
79                        return;
80                    }
81                    let dof = dimension * local + component;
82                    if let Some(global) = corner_dofs.global_index(node, component) {
83                        primal.push(dof);
84                        primal_global.push(global);
85                    } else {
86                        dual.push(dof);
87                    }
88                })
89            });
90        Self {
91            primal,
92            primal_global,
93            dual,
94        }
95    }
96    pub(crate) fn primal(&self) -> &[usize] {
97        &self.primal
98    }
99    pub(crate) fn primal_global(&self) -> &[usize] {
100        &self.primal_global
101    }
102    pub(crate) fn dual(&self) -> &[usize] {
103        &self.dual
104    }
105}
106
107pub(crate) fn build_splits(
108    partition: &Partition,
109    corners: &CornerSelection,
110    boundary_conditions: &BoundaryConditions,
111    dimension: usize,
112) -> (Vec<DualPrimalSplit>, CornerDofs) {
113    let corner_dofs = CornerDofs::new(corners, boundary_conditions, dimension);
114    let splits = partition
115        .parts_nodes()
116        .iter()
117        .map(|nodes| {
118            DualPrimalSplit::from_subdomain_nodes(
119                nodes,
120                &corner_dofs,
121                boundary_conditions,
122                dimension,
123            )
124        })
125        .collect();
126    (splits, corner_dofs)
127}