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            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}