1#[cfg(all(test, feature = "vem"))]
4mod test;
5
6pub(crate) mod block;
7#[cfg(feature = "cbm")]
8pub mod cbm;
9#[cfg(feature = "fem")]
10pub mod fem;
11pub(crate) mod from;
12pub(crate) mod solid;
13#[cfg(feature = "vem")]
14pub mod vem;
15
16use crate::{
17 domain::block::element::Elements,
18 geometry::Coordinates,
19 math::{
20 Current, Reference, Style, StyledError, TensorRank1Vec, TensorRank1Vec2D,
21 assert::AssertionError,
22 optimize::{
23 EqualityConstraint, FirstOrderOptimization, FirstOrderRootFinding, OptimizationError,
24 SecondOrderOptimization, ZerothOrderRootFinding,
25 },
26 styled_error,
27 },
28 units::{Length, Velocity},
29};
30use std::fmt::{Debug, Display};
31
32pub(crate) fn nodal_coordinates<const D: usize>(
33 coordinates: Coordinates<D>,
34) -> NodalReferenceCoordinates<D> {
35 coordinates
36 .into_iter()
37 .map(|coordinate| coordinate.with_unit())
38 .collect()
39}
40
41pub type NodalCoordinates<const D: usize> = TensorRank1Vec<D, Current, Length>;
42#[cfg_attr(not(any(feature = "fem", feature = "vem")), allow(dead_code))]
43pub type NodalCoordinatesHistory<const D: usize> = TensorRank1Vec2D<D, Current, Length>;
44pub type NodalReferenceCoordinates<const D: usize> = TensorRank1Vec<D, Reference, Length>;
45pub type NodalVelocities<const D: usize> = TensorRank1Vec<D, Current, Velocity>;
46#[cfg_attr(not(any(feature = "fem", feature = "vem")), allow(dead_code))]
47pub type NodalVelocitiesHistory<const D: usize> = TensorRank1Vec2D<D, Current, Velocity>;
48
49#[derive(Debug)]
50pub struct Model<B, const D: usize> {
51 pub(crate) blocks: B,
52 pub(crate) coordinates: NodalReferenceCoordinates<D>,
53}
54
55#[cfg_attr(not(any(feature = "fem", feature = "vem")), allow(dead_code))]
56#[derive(Debug)]
57pub struct Blocks<B1, B2>(pub(crate) B1, pub(crate) B2);
58
59#[cfg_attr(not(any(feature = "fem", feature = "vem")), allow(dead_code))]
60#[derive(Debug)]
61pub struct ElasticViscoplasticAndElastic<B1, B2>(pub(crate) B1, pub(crate) B2);
62
63pub trait ElementModel<const D: usize>
64where
65 Self: Debug,
66{
67 fn coordinates(&self) -> &NodalReferenceCoordinates<D>;
68}
69
70impl<B, const D: usize> Elements for Model<B, D>
71where
72 B: Elements,
73{
74 fn node_neighbors(&self, neighbors: &mut [Vec<usize>]) {
75 self.blocks.node_neighbors(neighbors)
76 }
77}
78
79impl<B1, B2> Elements for Blocks<B1, B2>
80where
81 B1: Elements,
82 B2: Elements,
83{
84 fn node_neighbors(&self, neighbors: &mut [Vec<usize>]) {
85 self.0.node_neighbors(neighbors);
86 self.1.node_neighbors(neighbors)
87 }
88}
89
90impl<B1, B2> Elements for ElasticViscoplasticAndElastic<B1, B2>
91where
92 B1: Elements,
93 B2: Elements,
94{
95 fn node_neighbors(&self, neighbors: &mut [Vec<usize>]) {
96 self.0.node_neighbors(neighbors);
97 self.1.node_neighbors(neighbors)
98 }
99}
100
101impl<B, const D: usize> Model<B, D> {
102 pub fn blocks(&self) -> &B {
103 &self.blocks
104 }
105}
106
107impl<B, const D: usize> ElementModel<D> for Model<B, D>
108where
109 B: Debug,
110{
111 fn coordinates(&self) -> &NodalReferenceCoordinates<D> {
112 &self.coordinates
113 }
114}
115
116pub enum ElementModelError {
117 Upstream(String, String),
118}
119
120impl ElementModelError {
121 pub fn upstream(error: impl Display, context: &(impl Debug + ?Sized)) -> Self {
122 Self::Upstream(format!("{error}"), format!("{context:?}"))
123 }
124}
125
126impl From<ElementModelError> for String {
127 fn from(error: ElementModelError) -> Self {
128 error.message(&Style::detect())
129 }
130}
131
132impl StyledError for ElementModelError {
133 fn message(&self, style: &Style) -> String {
134 let c = style.frame;
135 match self {
136 Self::Upstream(error, model) => format!(
137 "{error}{c}\n\
138 In element model: {model}."
139 ),
140 }
141 }
142}
143
144styled_error!(ElementModelError);
145
146pub trait ZerothOrderRoot<F, X> {
147 fn root(
148 &self,
149 equality_constraint: EqualityConstraint,
150 solver: impl ZerothOrderRootFinding<F, X>,
151 ) -> Result<X, OptimizationError>;
152}
153
154pub trait FirstOrderRoot<F, J, X> {
155 fn root(
156 &self,
157 equality_constraint: EqualityConstraint,
158 solver: impl FirstOrderRootFinding<F, J, X>,
159 ) -> Result<X, OptimizationError>;
160}
161
162#[cfg_attr(not(any(feature = "fem", feature = "vem")), allow(dead_code))]
163pub trait FirstOrderMinimize<F, J, X> {
164 fn minimize(
165 &self,
166 equality_constraint: EqualityConstraint,
167 solver: impl FirstOrderOptimization<F, J, X>,
168 ) -> Result<X, OptimizationError>;
169}
170
171#[cfg_attr(not(any(feature = "fem", feature = "vem")), allow(dead_code))]
172pub trait SecondOrderMinimize<F, J, H, X> {
173 fn minimize(
174 &self,
175 equality_constraint: EqualityConstraint,
176 solver: impl SecondOrderOptimization<F, J, H, X>,
177 ) -> Result<X, OptimizationError>;
178}
179
180impl<B, const D: usize> From<(B, NodalReferenceCoordinates<D>)> for Model<B, D> {
181 fn from((blocks, coordinates): (B, NodalReferenceCoordinates<D>)) -> Self {
182 Self {
183 blocks,
184 coordinates,
185 }
186 }
187}
188
189impl From<ElementModelError> for AssertionError {
190 fn from(error: ElementModelError) -> Self {
191 Self {
192 message: error.to_string(),
193 }
194 }
195}