conspire/domain/fem/block/solid/elastic/internal_variables/
mod.rs1use std::ops::{Div, Mul};
2
3use crate::{
4 constitutive::solid::elastic::internal_variables::ElasticIV,
5 fem::{
6 ElementModelError, NodalCoordinates,
7 block::{
8 Block,
9 element::{
10 FiniteElementError, solid::elastic::internal_variables::ElasticIVFiniteElement,
11 },
12 },
13 solid::{
14 NodalForcesSolid, NodalStiffnessesSolid,
15 elastic::internal_variables::{ElasticIVElements, InternalVariablesField},
16 },
17 },
18 math::{
19 Erase, Jacobian, Matrix, Quantity, Scalar, Solution, Tensor, Vector,
20 optimize::NewtonRaphson,
21 },
22 units::{Dimensionless, UnitDiv},
23};
24
25impl<C, F, const G: usize, const M: usize, const N: usize, const P: usize, V, E>
26 ElasticIVElements<G, V, 3> for Block<C, F, G, M, N, P>
27where
28 C: ElasticIV<V>,
29 C::Residual: Erase<Erased = E>,
30 F: ElasticIVFiniteElement<C, G, M, N, P, V, E>,
31 E: Tensor,
32 for<'a> &'a C::Residual: Div<C::TangentVv, Output = V>,
33 for<'a> &'a V: Mul<Quantity<Dimensionless>, Output = V> + Mul<Scalar, Output = V>,
34 for<'a> &'a Matrix: Mul<&'a V, Output = Vector>,
35 V: Erase<Erased = E> + Jacobian + Solution,
36 <V as Tensor>::Unit: UnitDiv<<V as Tensor>::Unit, Output = Dimensionless>,
37{
38 fn internal_variables_initial(&self) -> InternalVariablesField<G, V> {
39 self.elements()
40 .iter()
41 .map(|element| element.internal_variables_initial(self.constitutive_model()))
42 .collect()
43 }
44 fn internal_variables_increment(
45 &self,
46 nodal_coordinates: &NodalCoordinates<3>,
47 internal_variables: &InternalVariablesField<G, V>,
48 nodal_decrement: &NodalCoordinates<3>,
49 step: Scalar,
50 ) -> Result<InternalVariablesField<G, V>, ElementModelError> {
51 self.elements()
52 .iter()
53 .zip(self.connectivity())
54 .zip(internal_variables)
55 .map(|((element, nodes), internal_variables_element)| {
56 element.internal_variables_increment(
57 self.constitutive_model(),
58 &Self::element_coordinates(nodal_coordinates, nodes),
59 internal_variables_element,
60 &Self::element_coordinates(nodal_decrement, nodes),
61 step,
62 )
63 })
64 .collect::<Result<InternalVariablesField<G, V>, _>>()
65 .map_err(|error| ElementModelError::upstream(error, self))
66 }
67 fn internal_variables_root(
68 &self,
69 local_solver: &NewtonRaphson,
70 nodal_coordinates: &NodalCoordinates<3>,
71 internal_variables: &InternalVariablesField<G, V>,
72 ) -> Result<InternalVariablesField<G, V>, ElementModelError> {
73 self.elements()
74 .iter()
75 .zip(self.connectivity())
76 .zip(internal_variables)
77 .map(|((element, nodes), internal_variables_element)| {
78 element.internal_variables_root(
79 local_solver,
80 self.constitutive_model(),
81 &Self::element_coordinates(nodal_coordinates, nodes),
82 internal_variables_element,
83 )
84 })
85 .collect::<Result<InternalVariablesField<G, V>, _>>()
86 .map_err(|error| ElementModelError::upstream(error, self))
87 }
88 fn nodal_forces_into(
89 &self,
90 nodal_coordinates: &NodalCoordinates<3>,
91 internal_variables: &InternalVariablesField<G, V>,
92 nodal_forces: &mut NodalForcesSolid<3>,
93 ) -> Result<(), ElementModelError> {
94 self.elements()
95 .iter()
96 .zip(self.connectivity())
97 .zip(internal_variables)
98 .try_for_each(|((element, nodes), internal_variables_element)| {
99 element
100 .nodal_forces(
101 self.constitutive_model(),
102 &Self::element_coordinates(nodal_coordinates, nodes),
103 internal_variables_element,
104 )?
105 .into_iter()
106 .zip(nodes)
107 .for_each(|(nodal_force, &node)| nodal_forces[node] += nodal_force);
108 Ok::<(), FiniteElementError>(())
109 })
110 .map_err(|error| ElementModelError::upstream(error, self))
111 }
112 fn nodal_forces_eliminated_into(
113 &self,
114 nodal_coordinates: &NodalCoordinates<3>,
115 internal_variables: &InternalVariablesField<G, V>,
116 nodal_forces: &mut NodalForcesSolid<3>,
117 ) -> Result<(), ElementModelError> {
118 self.elements()
119 .iter()
120 .zip(self.connectivity())
121 .zip(internal_variables)
122 .try_for_each(|((element, nodes), internal_variables_element)| {
123 element
124 .nodal_forces_eliminated(
125 self.constitutive_model(),
126 &Self::element_coordinates(nodal_coordinates, nodes),
127 internal_variables_element,
128 )?
129 .into_iter()
130 .zip(nodes)
131 .for_each(|(nodal_force, &node)| nodal_forces[node] += nodal_force);
132 Ok::<(), FiniteElementError>(())
133 })
134 .map_err(|error| ElementModelError::upstream(error, self))
135 }
136 fn nodal_stiffnesses_into(
137 &self,
138 nodal_coordinates: &NodalCoordinates<3>,
139 internal_variables: &InternalVariablesField<G, V>,
140 nodal_stiffnesses: &mut NodalStiffnessesSolid<3>,
141 ) -> Result<(), ElementModelError> {
142 self.elements()
143 .iter()
144 .zip(self.connectivity())
145 .zip(internal_variables)
146 .try_for_each(|((element, nodes), internal_variables_element)| {
147 element
148 .nodal_stiffnesses(
149 self.constitutive_model(),
150 &Self::element_coordinates(nodal_coordinates, nodes),
151 internal_variables_element,
152 )?
153 .into_iter()
154 .zip(nodes)
155 .for_each(|(object, &node_a)| {
156 object
157 .into_iter()
158 .zip(nodes)
159 .for_each(|(nodal_stiffness, &node_b)| {
160 nodal_stiffnesses[node_a][node_b] += nodal_stiffness
161 })
162 });
163 Ok::<(), FiniteElementError>(())
164 })
165 .map_err(|error| ElementModelError::upstream(error, self))
166 }
167}