conspire/domain/fem/thermal/conduction/
mod.rs1use 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}