Skip to main content

conspire/domain/fem/thermal/conduction/
mod.rs

1use crate::{
2    fem::{
3        Blocks, ElementModel, ElementModelError, Elements, FirstOrderMinimize, FirstOrderRoot,
4        Model, SecondOrderMinimize, ZerothOrderRoot,
5        block::{
6            finalize_node_neighbors, solver_from_neighbors,
7            thermal::{
8                NodalTemperatures,
9                conduction::{NodalForcesThermal, NodalStiffnessesThermal},
10            },
11        },
12    },
13    math::{
14        Quantity, Tensor,
15        optimize::{
16            EqualityConstraint, FirstOrderOptimization, FirstOrderRootFinding, OptimizationError,
17            SecondOrderOptimization, ZerothOrderRootFinding,
18        },
19    },
20    units::PowerTemperature,
21};
22
23pub trait ThermalConductionElements
24where
25    Self: Elements,
26{
27    fn potential(
28        &self,
29        nodal_temperatures: &NodalTemperatures,
30    ) -> Result<Quantity<PowerTemperature>, ElementModelError>;
31    fn nodal_forces_into(
32        &self,
33        nodal_temperatures: &NodalTemperatures,
34        nodal_forces: &mut NodalForcesThermal,
35    ) -> Result<(), ElementModelError>;
36    fn nodal_forces(
37        &self,
38        nodal_temperatures: &NodalTemperatures,
39    ) -> Result<NodalForcesThermal, ElementModelError> {
40        let mut nodal_forces = NodalForcesThermal::zero(nodal_temperatures.len());
41        self.nodal_forces_into(nodal_temperatures, &mut nodal_forces)?;
42        Ok(nodal_forces)
43    }
44    fn nodal_stiffnesses_into(
45        &self,
46        nodal_temperatures: &NodalTemperatures,
47        nodal_stiffnesses: &mut NodalStiffnessesThermal,
48    ) -> Result<(), ElementModelError>;
49    fn nodal_stiffnesses(
50        &self,
51        nodal_temperatures: &NodalTemperatures,
52    ) -> Result<NodalStiffnessesThermal, ElementModelError> {
53        let mut nodal_stiffnesses = NodalStiffnessesThermal::zero(nodal_temperatures.len());
54        self.nodal_stiffnesses_into(nodal_temperatures, &mut nodal_stiffnesses)?;
55        Ok(nodal_stiffnesses)
56    }
57}
58
59impl<B, const D: usize> ThermalConductionElements for Model<B, D>
60where
61    B: ThermalConductionElements,
62{
63    fn potential(
64        &self,
65        nodal_temperatures: &NodalTemperatures,
66    ) -> Result<Quantity<PowerTemperature>, ElementModelError> {
67        self.blocks.potential(nodal_temperatures)
68    }
69    fn nodal_forces_into(
70        &self,
71        nodal_temperatures: &NodalTemperatures,
72        nodal_forces: &mut NodalForcesThermal,
73    ) -> Result<(), ElementModelError> {
74        self.blocks
75            .nodal_forces_into(nodal_temperatures, nodal_forces)
76    }
77    fn nodal_stiffnesses_into(
78        &self,
79        nodal_temperatures: &NodalTemperatures,
80        nodal_stiffnesses: &mut NodalStiffnessesThermal,
81    ) -> Result<(), ElementModelError> {
82        self.blocks
83            .nodal_stiffnesses_into(nodal_temperatures, nodal_stiffnesses)
84    }
85}
86
87impl<B1, B2> ThermalConductionElements for Blocks<B1, B2>
88where
89    B1: ThermalConductionElements,
90    B2: ThermalConductionElements,
91{
92    fn potential(
93        &self,
94        nodal_temperatures: &NodalTemperatures,
95    ) -> Result<Quantity<PowerTemperature>, ElementModelError> {
96        Ok(self.0.potential(nodal_temperatures)? + self.1.potential(nodal_temperatures)?)
97    }
98    fn nodal_forces_into(
99        &self,
100        nodal_temperatures: &NodalTemperatures,
101        nodal_forces: &mut NodalForcesThermal,
102    ) -> Result<(), ElementModelError> {
103        self.0.nodal_forces_into(nodal_temperatures, nodal_forces)?;
104        self.1.nodal_forces_into(nodal_temperatures, nodal_forces)
105    }
106    fn nodal_stiffnesses_into(
107        &self,
108        nodal_temperatures: &NodalTemperatures,
109        nodal_stiffnesses: &mut NodalStiffnessesThermal,
110    ) -> Result<(), ElementModelError> {
111        self.0
112            .nodal_stiffnesses_into(nodal_temperatures, nodal_stiffnesses)?;
113        self.1
114            .nodal_stiffnesses_into(nodal_temperatures, nodal_stiffnesses)
115    }
116}
117
118impl<B, const D: usize> ZerothOrderRoot<NodalForcesThermal, NodalTemperatures> for Model<B, D>
119where
120    B: ThermalConductionElements,
121{
122    fn root(
123        &self,
124        equality_constraint: EqualityConstraint,
125        solver: impl ZerothOrderRootFinding<NodalForcesThermal, NodalTemperatures>,
126    ) -> Result<NodalTemperatures, OptimizationError> {
127        solver.root(
128            |nodal_temperatures: &NodalTemperatures| Ok(self.nodal_forces(nodal_temperatures)?),
129            NodalTemperatures::zero(self.coordinates().len()),
130            equality_constraint,
131        )
132    }
133}
134
135impl<B, const D: usize>
136    FirstOrderRoot<NodalForcesThermal, NodalStiffnessesThermal, NodalTemperatures> for Model<B, D>
137where
138    B: ThermalConductionElements,
139{
140    fn root(
141        &self,
142        equality_constraint: EqualityConstraint,
143        solver: impl FirstOrderRootFinding<
144            NodalForcesThermal,
145            NodalStiffnessesThermal,
146            NodalTemperatures,
147        >,
148    ) -> Result<NodalTemperatures, OptimizationError> {
149        let mut neighbors = vec![Vec::new(); self.coordinates().len()];
150        self.node_neighbors(&mut neighbors);
151        finalize_node_neighbors(&mut neighbors);
152        let sparse = solver_from_neighbors(&neighbors, &equality_constraint, 1, true);
153        solver.root(
154            |nodal_temperatures: &NodalTemperatures| Ok(self.nodal_forces(nodal_temperatures)?),
155            |nodal_temperatures: &NodalTemperatures| {
156                Ok(self.nodal_stiffnesses(nodal_temperatures)?)
157            },
158            NodalTemperatures::zero(self.coordinates().len()),
159            equality_constraint,
160            Some(sparse),
161        )
162    }
163}
164
165impl<B, const D: usize>
166    FirstOrderMinimize<Quantity<PowerTemperature>, NodalForcesThermal, NodalTemperatures>
167    for Model<B, D>
168where
169    B: ThermalConductionElements,
170{
171    fn minimize(
172        &self,
173        equality_constraint: EqualityConstraint,
174        solver: impl FirstOrderOptimization<
175            Quantity<PowerTemperature>,
176            NodalForcesThermal,
177            NodalTemperatures,
178        >,
179    ) -> Result<NodalTemperatures, OptimizationError> {
180        solver.minimize(
181            |nodal_temperatures: &NodalTemperatures| Ok(self.potential(nodal_temperatures)?),
182            |nodal_temperatures: &NodalTemperatures| Ok(self.nodal_forces(nodal_temperatures)?),
183            NodalTemperatures::zero(self.coordinates().len()),
184            equality_constraint,
185        )
186    }
187}
188
189impl<B, const D: usize>
190    SecondOrderMinimize<
191        Quantity<PowerTemperature>,
192        NodalForcesThermal,
193        NodalStiffnessesThermal,
194        NodalTemperatures,
195    > for Model<B, D>
196where
197    B: ThermalConductionElements,
198{
199    fn minimize(
200        &self,
201        equality_constraint: EqualityConstraint,
202        solver: impl SecondOrderOptimization<
203            Quantity<PowerTemperature>,
204            NodalForcesThermal,
205            NodalStiffnessesThermal,
206            NodalTemperatures,
207        >,
208    ) -> Result<NodalTemperatures, OptimizationError> {
209        let mut neighbors = vec![Vec::new(); self.coordinates().len()];
210        self.node_neighbors(&mut neighbors);
211        finalize_node_neighbors(&mut neighbors);
212        let sparse = solver_from_neighbors(&neighbors, &equality_constraint, 1, true);
213        solver.minimize(
214            |nodal_temperatures: &NodalTemperatures| {
215                Ok(self
216                    .potential(nodal_temperatures)?)
217            },
218            |nodal_temperatures: &NodalTemperatures| Ok(self.nodal_forces(nodal_temperatures)?),
219            |nodal_temperatures: &NodalTemperatures| {
220                Ok(self.nodal_stiffnesses(nodal_temperatures)?)
221            },
222            NodalTemperatures::zero(self.coordinates().len()),
223            equality_constraint,
224            Some(sparse),
225        )
226    }
227}