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::{Scalar, TestError, optimize::OptimizeError},
15    mechanics::{Deformation, DeformationError, DeformationGradient},
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: {jacobian:.6e}.\x1b[0;91m\n\
91                        From deformation gradient: {deformation_gradient}.\n\
92                        In constitutive model: {constitutive_model}."
93            )),
94            _ => todo!(),
95        }
96    }
97}
98
99impl From<ConstitutiveError> for TestError {
100    fn from(error: ConstitutiveError) -> Self {
101        Self {
102            message: error.to_string(),
103        }
104    }
105}
106
107impl From<OptimizeError> for ConstitutiveError {
108    fn from(error: OptimizeError) -> Self {
109        match error {
110            OptimizeError::Generic(_) => todo!("Generic"),
111            OptimizeError::MaximumStepsReached(_, _) => todo!("MaximumStepsReached"),
112            OptimizeError::NotMinimum(_, _) => todo!("NotMinimum"),
113            OptimizeError::SingularMatrix => todo!("SingularMatrix"),
114        }
115    }
116}
117
118impl Debug for ConstitutiveError {
119    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
120        let error = match self {
121            Self::Custom(message, deformation_gradient, constitutive_model) => format!(
122                "\x1b[1;91m{message}\x1b[0;91m\n\
123                 From deformation gradient: {deformation_gradient}.\n\
124                 In constitutive model: {constitutive_model}."
125            ),
126            Self::InvalidJacobian(jacobian, deformation_gradient, constitutive_model) => {
127                format!(
128                    "\x1b[1;91mInvalid Jacobian: {jacobian:.6e}.\x1b[0;91m\n\
129                    From deformation gradient: {deformation_gradient}.\n\
130                    In constitutive model: {constitutive_model}."
131                )
132            }
133            Self::MaximumStepsReached(steps, constitutive_model) => {
134                format!(
135                    "\x1b[1;91mMaximum number of steps ({steps}) reached.\x1b[0;91m\n\
136                     In constitutive model: {constitutive_model}."
137                )
138            }
139            Self::NotMinimum(deformation_gradient, constitutive_model) => {
140                format!(
141                    "\x1b[1;91mThe obtained solution is not a minimum.\x1b[0;91m\n\
142                     {deformation_gradient}\nIn constitutive model: {constitutive_model}."
143                )
144            }
145        };
146        write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
147    }
148}
149
150impl Display for ConstitutiveError {
151    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
152        let error = match self {
153            Self::Custom(message, deformation_gradient, constitutive_model) => format!(
154                "\x1b[1;91m{message}\x1b[0;91m\n\
155                 From deformation gradient: {deformation_gradient}.\n\
156                 In constitutive model: {constitutive_model}."
157            ),
158            Self::InvalidJacobian(jacobian, deformation_gradient, constitutive_model) => {
159                format!(
160                    "\x1b[1;91mInvalid Jacobian: {jacobian:.6e}.\x1b[0;91m\n\
161                    From deformation gradient: {deformation_gradient}.\n\
162                    In constitutive model: {constitutive_model}."
163                )
164            }
165            Self::MaximumStepsReached(steps, constitutive_model) => {
166                format!(
167                    "\x1b[1;91mMaximum number of steps ({steps}) reached.\x1b[0;91m\n\
168                     In constitutive model: {constitutive_model}."
169                )
170            }
171            Self::NotMinimum(deformation_gradient, constitutive_model) => {
172                format!(
173                    "\x1b[1;91mThe obtained solution is not a minimum.\x1b[0;91m\n\
174                     {deformation_gradient}\nIn constitutive model: {constitutive_model}."
175                )
176            }
177        };
178        write!(f, "{error}\x1b[0m")
179    }
180}
181
182impl PartialEq for ConstitutiveError {
183    fn eq(&self, other: &Self) -> bool {
184        match self {
185            Self::Custom(a, b, c) => match other {
186                Self::Custom(d, e, f) => a == d && b == e && c == f,
187                _ => false,
188            },
189            Self::InvalidJacobian(a, b, c) => match other {
190                Self::InvalidJacobian(d, e, f) => a == d && b == e && c == f,
191                _ => false,
192            },
193            Self::MaximumStepsReached(_, _) => todo!(),
194            Self::NotMinimum(_, _) => todo!(),
195        }
196    }
197}