carapace_core/analysis/
builder.rs1use slotmap::Key;
2
3use crate::model::{Domain, ElementOps, ModelError, NodeId};
4
5use super::bordered::BorderedSolver;
6use super::{Algorithm, Analysis, ConstraintHandler, ConvergenceTest, Integrator, SparseSolver};
7
8pub struct AnalysisBuilder<S = Unwired> {
20 state: S,
21}
22
23pub struct Unwired;
24
25pub struct WithConstraintHandler {
26 constraint_handler: ConstraintHandler,
27}
28
29pub struct WithIntegrator<NId = NodeId> {
30 constraint_handler: ConstraintHandler,
31 integrator: Integrator<NId>,
32}
33
34pub struct WithAlgorithm<NId = NodeId> {
35 constraint_handler: ConstraintHandler,
36 integrator: Integrator<NId>,
37 algorithm: Algorithm,
38}
39
40pub struct Ready<NId = NodeId> {
41 constraint_handler: ConstraintHandler,
42 integrator: Integrator<NId>,
43 algorithm: Algorithm,
44 test: ConvergenceTest,
45}
46
47impl Default for AnalysisBuilder<Unwired> {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53impl AnalysisBuilder<Unwired> {
54 pub fn new() -> Self {
55 AnalysisBuilder { state: Unwired }
56 }
57
58 pub fn constraint_handler(
59 self,
60 constraint_handler: ConstraintHandler,
61 ) -> AnalysisBuilder<WithConstraintHandler> {
62 AnalysisBuilder {
63 state: WithConstraintHandler { constraint_handler },
64 }
65 }
66}
67
68impl AnalysisBuilder<WithConstraintHandler> {
69 pub fn integrator<NId>(
70 self,
71 integrator: Integrator<NId>,
72 ) -> AnalysisBuilder<WithIntegrator<NId>> {
73 AnalysisBuilder {
74 state: WithIntegrator {
75 constraint_handler: self.state.constraint_handler,
76 integrator,
77 },
78 }
79 }
80}
81
82impl<NId> AnalysisBuilder<WithIntegrator<NId>> {
83 pub fn algorithm(self, algorithm: Algorithm) -> AnalysisBuilder<WithAlgorithm<NId>> {
84 AnalysisBuilder {
85 state: WithAlgorithm {
86 constraint_handler: self.state.constraint_handler,
87 integrator: self.state.integrator,
88 algorithm,
89 },
90 }
91 }
92}
93
94impl<NId> AnalysisBuilder<WithAlgorithm<NId>> {
95 pub fn test(self, test: ConvergenceTest) -> AnalysisBuilder<Ready<NId>> {
96 AnalysisBuilder {
97 state: Ready {
98 constraint_handler: self.state.constraint_handler,
99 integrator: self.state.integrator,
100 algorithm: self.state.algorithm,
101 test,
102 },
103 }
104 }
105}
106
107impl<NId: Copy> AnalysisBuilder<Ready<NId>> {
108 pub fn build<const NDIM: usize, const NDOF: usize, E>(
125 self,
126 domain: Domain<NDIM, NDOF, NId, E>,
127 ) -> Analysis<NDIM, NDOF, NId, E>
128 where
129 NId: Key,
130 E: ElementOps<NDIM, NDOF, NId>,
131 {
132 self.try_build(domain)
133 .unwrap_or_else(|error| panic!("invalid model: {error}"))
134 }
135
136 pub fn try_build<const NDIM: usize, const NDOF: usize, E>(
141 self,
142 mut domain: Domain<NDIM, NDOF, NId, E>,
143 ) -> Result<Analysis<NDIM, NDOF, NId, E>, ModelError>
144 where
145 NId: Key,
146 E: ElementOps<NDIM, NDOF, NId>,
147 {
148 assert!(
149 !(matches!(self.state.constraint_handler, ConstraintHandler::Plain) && domain.has_mp_constraints()),
150 "ConstraintHandler::Plain can't resolve multi-point constraints (equal_dof/rigid_diaphragm) — use ConstraintHandler::Transformation"
151 );
152 domain.validate()?;
153 Ok(Analysis {
154 domain,
155 constraint_handler: self.state.constraint_handler,
156 integrator: self.state.integrator,
157 algorithm: self.state.algorithm,
158 test: self.state.test,
159 solver: SparseSolver::new(),
160 step_count: 0,
161 load_factor: 0.0,
162 cached_factorization: None,
163 arc: None,
164 bordered: BorderedSolver::default(),
165 })
166 }
167}