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