conspire/constitutive/
mod.rs

1//! Constitutive model library.
2
3#[cfg(test)]
4pub mod test;
5
6pub mod fluid;
7pub mod hybrid;
8pub mod multiphysics;
9pub mod solid;
10pub mod thermal;
11
12use crate::{
13    defeat_message,
14    math::{TestError, optimize::OptimizeError},
15    mechanics::{Deformation, DeformationError, DeformationGradient, Scalar},
16};
17use std::{
18    fmt::{self, Debug, Display, Formatter},
19    ops::{Index, RangeFrom},
20};
21
22/// Methods for lists of constitutive model parameters.
23pub trait Parameters
24where
25    Self: Copy + fmt::Debug,
26{
27    fn get(&self, index: usize) -> &Scalar;
28    fn get_slice(&self, index: RangeFrom<usize>) -> &[Scalar];
29}
30
31impl<const N: usize> Parameters for [Scalar; N] {
32    fn get(&self, index: usize) -> &Scalar {
33        self.index(index)
34    }
35    fn get_slice(&self, index: RangeFrom<usize>) -> &[Scalar] {
36        self.index(index)
37    }
38}
39
40impl<const N: usize> Parameters for &[Scalar; N] {
41    fn get(&self, index: usize) -> &Scalar {
42        self.index(index)
43    }
44    fn get_slice(&self, index: RangeFrom<usize>) -> &[Scalar] {
45        self.index(index)
46    }
47}
48
49/// Required methods for constitutive models.
50pub trait Constitutive<P>
51where
52    Self: Debug,
53{
54    /// Calculates and returns the Jacobian.
55    fn jacobian(
56        &self,
57        deformation_gradient: &DeformationGradient,
58    ) -> Result<Scalar, ConstitutiveError> {
59        match deformation_gradient.jacobian() {
60            Err(DeformationError::InvalidJacobian(jacobian, deformation_gradient)) => {
61                Err(ConstitutiveError::InvalidJacobian(
62                    jacobian,
63                    deformation_gradient,
64                    format!("{:?}", self),
65                ))
66            }
67            Ok(jacobian) => Ok(jacobian),
68        }
69    }
70    /// Constructs and returns a new constitutive model.
71    fn new(parameters: P) -> Self;
72}
73
74/// Possible errors encountered in constitutive models.
75pub enum ConstitutiveError {
76    Custom(String, DeformationGradient, String),
77    InvalidJacobian(Scalar, DeformationGradient, String),
78    MaximumStepsReached(usize, String),
79    NotMinimum(String, String),
80}
81
82impl From<ConstitutiveError> for OptimizeError {
83    fn from(error: ConstitutiveError) -> OptimizeError {
84        match error {
85            ConstitutiveError::InvalidJacobian(
86                jacobian,
87                deformation_gradient,
88                constitutive_model,
89            ) => OptimizeError::Generic(format!(
90                "\x1b[1;91mInvalid Jacobian: {:.6e}.\x1b[0;91m\n\
91                        From deformation gradient: {}.\n\
92                        In constitutive model: {}.",
93                jacobian, deformation_gradient, constitutive_model
94            )),
95            _ => todo!(),
96        }
97    }
98}
99
100impl From<ConstitutiveError> for TestError {
101    fn from(error: ConstitutiveError) -> Self {
102        Self {
103            message: error.to_string(),
104        }
105    }
106}
107
108impl From<OptimizeError> for ConstitutiveError {
109    fn from(error: OptimizeError) -> Self {
110        match error {
111            OptimizeError::Generic(_) => todo!("Generic"),
112            OptimizeError::MaximumStepsReached(_, _) => todo!("MaximumStepsReached"),
113            OptimizeError::NotMinimum(_, _) => todo!("NotMinimum"),
114            OptimizeError::SingularMatrix => todo!("SingularMatrix"),
115        }
116    }
117}
118
119impl Debug for ConstitutiveError {
120    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
121        let error = match self {
122            Self::Custom(message, deformation_gradient, constitutive_model) => format!(
123                "\x1b[1;91m{}\x1b[0;91m\n\
124                 From deformation gradient: {}.\n\
125                 In constitutive model: {}.",
126                message, deformation_gradient, constitutive_model
127            ),
128            Self::InvalidJacobian(jacobian, deformation_gradient, constitutive_model) => {
129                format!(
130                    "\x1b[1;91mInvalid Jacobian: {:.6e}.\x1b[0;91m\n\
131                    From deformation gradient: {}.\n\
132                    In constitutive model: {}.",
133                    jacobian, deformation_gradient, constitutive_model
134                )
135            }
136            Self::MaximumStepsReached(steps, constitutive_model) => {
137                format!(
138                    "\x1b[1;91mMaximum number of steps ({}) reached.\x1b[0;91m\n\
139                     In constitutive model: {}.",
140                    steps, constitutive_model
141                )
142            }
143            Self::NotMinimum(deformation_gradient, constitutive_model) => {
144                format!(
145                    "\x1b[1;91mThe obtained solution is not a minimum.\x1b[0;91m\n\
146                     {}\nIn constitutive model: {}.",
147                    deformation_gradient, constitutive_model
148                )
149            }
150        };
151        write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
152    }
153}
154
155impl Display for ConstitutiveError {
156    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157        let error = match self {
158            Self::Custom(message, deformation_gradient, constitutive_model) => format!(
159                "\x1b[1;91m{}\x1b[0;91m\n\
160                 From deformation gradient: {}.\n\
161                 In constitutive model: {}.",
162                message, deformation_gradient, constitutive_model
163            ),
164            Self::InvalidJacobian(jacobian, deformation_gradient, constitutive_model) => {
165                format!(
166                    "\x1b[1;91mInvalid Jacobian: {:.6e}.\x1b[0;91m\n\
167                    From deformation gradient: {}.\n\
168                    In constitutive model: {}.",
169                    jacobian, deformation_gradient, constitutive_model
170                )
171            }
172            Self::MaximumStepsReached(steps, constitutive_model) => {
173                format!(
174                    "\x1b[1;91mMaximum number of steps ({}) reached.\x1b[0;91m\n\
175                     In constitutive model: {}.",
176                    steps, constitutive_model
177                )
178            }
179            Self::NotMinimum(deformation_gradient, constitutive_model) => {
180                format!(
181                    "\x1b[1;91mThe obtained solution is not a minimum.\x1b[0;91m\n\
182                     {}\nIn constitutive model: {}.",
183                    deformation_gradient, constitutive_model
184                )
185            }
186        };
187        write!(f, "{}\x1b[0m", error)
188    }
189}
190
191impl PartialEq for ConstitutiveError {
192    fn eq(&self, other: &Self) -> bool {
193        match self {
194            Self::Custom(a, b, c) => match other {
195                Self::Custom(d, e, f) => a == d && b == e && c == f,
196                _ => false,
197            },
198            Self::InvalidJacobian(a, b, c) => match other {
199                Self::InvalidJacobian(d, e, f) => a == d && b == e && c == f,
200                _ => false,
201            },
202            Self::MaximumStepsReached(_, _) => todo!(),
203            Self::NotMinimum(_, _) => todo!(),
204        }
205    }
206}