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},
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)) => Err(
61                ConstitutiveError::InvalidJacobian(jacobian, format!("{self:?}")),
62            ),
63            Ok(jacobian) => Ok(jacobian),
64        }
65    }
66    /// Constructs and returns a new constitutive model.
67    fn new(parameters: P) -> Self;
68}
69
70/// Possible errors encountered in constitutive models.
71pub enum ConstitutiveError {
72    Custom(String, String),
73    InvalidJacobian(Scalar, String),
74    Upstream(String, String),
75}
76
77impl From<ConstitutiveError> for String {
78    fn from(error: ConstitutiveError) -> Self {
79        match error {
80            ConstitutiveError::InvalidJacobian(jacobian, constitutive_model) => format!(
81                "\x1b[1;91mInvalid Jacobian: {jacobian:.6e}.\x1b[0;91m\n\
82                        In constitutive model: {constitutive_model}."
83            ),
84            _ => todo!(),
85        }
86    }
87}
88
89impl From<ConstitutiveError> for TestError {
90    fn from(error: ConstitutiveError) -> Self {
91        Self {
92            message: error.to_string(),
93        }
94    }
95}
96
97impl Debug for ConstitutiveError {
98    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
99        let error = match self {
100            Self::Custom(message, constitutive_model) => format!(
101                "\x1b[1;91m{message}\x1b[0;91m\n\
102                 In constitutive model: {constitutive_model}."
103            ),
104            Self::InvalidJacobian(jacobian, constitutive_model) => {
105                format!(
106                    "\x1b[1;91mInvalid Jacobian: {jacobian:.6e}.\x1b[0;91m\n\
107                    In constitutive model: {constitutive_model}."
108                )
109            }
110            Self::Upstream(error, constitutive_model) => {
111                format!(
112                    "{error}\x1b[0;91m\n\
113                    In constitutive model: {constitutive_model}."
114                )
115            }
116        };
117        write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
118    }
119}
120
121impl Display for ConstitutiveError {
122    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
123        let error = match self {
124            Self::Custom(message, constitutive_model) => format!(
125                "\x1b[1;91m{message}\x1b[0;91m\n\
126                 In constitutive model: {constitutive_model}."
127            ),
128            Self::InvalidJacobian(jacobian, constitutive_model) => {
129                format!(
130                    "\x1b[1;91mInvalid Jacobian: {jacobian:.6e}.\x1b[0;91m\n\
131                    In constitutive model: {constitutive_model}."
132                )
133            }
134            Self::Upstream(error, constitutive_model) => {
135                format!(
136                    "{error}\x1b[0;91m\n\
137                    In constitutive model: {constitutive_model}."
138                )
139            }
140        };
141        write!(f, "{error}\x1b[0m")
142    }
143}
144
145impl PartialEq for ConstitutiveError {
146    fn eq(&self, other: &Self) -> bool {
147        match self {
148            Self::Custom(a, b) => match other {
149                Self::Custom(c, d) => a == c && b == d,
150                _ => false,
151            },
152            Self::InvalidJacobian(a, b) => match other {
153                Self::InvalidJacobian(c, d) => a == c && b == d,
154                _ => false,
155            },
156            Self::Upstream(a, b) => match other {
157                Self::Upstream(c, d) => a == c && b == d,
158                _ => false,
159            },
160        }
161    }
162}