1use carapace_core::model::{Material, Pinching4DmgCyc};
7use serde::{Deserialize, Serialize};
8
9use super::error::DecodeError;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, tsify::Tsify)]
15#[serde(rename_all = "camelCase")]
16pub enum Pinching4DmgCycSpec {
17 EnergyBased,
18 CycleBased,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, tsify::Tsify)]
24#[serde(
25 tag = "kind",
26 rename_all = "camelCase",
27 rename_all_fields = "camelCase"
28)]
29pub enum MaterialSpec {
30 Elastic {
31 e: f64,
32 },
33 ElasticPp {
34 e: f64,
35 eyp: f64,
36 },
37 Gap {
38 e: f64,
39 gap: f64,
40 },
41 Ent {
42 e: f64,
43 },
44 Steel01 {
45 fy: f64,
46 e0: f64,
47 b: f64,
48 a1: f64,
49 a2: f64,
50 a3: f64,
51 a4: f64,
52 },
53 Concrete01 {
54 fpc: f64,
55 epsc0: f64,
56 fpcu: f64,
57 epscu: f64,
58 },
59 #[allow(clippy::too_many_arguments)]
60 Steel02 {
61 fy: f64,
62 e0: f64,
63 b: f64,
64 r0: f64,
65 cr1: f64,
66 cr2: f64,
67 a1: f64,
68 a2: f64,
69 a3: f64,
70 a4: f64,
71 },
72 Concrete02 {
73 fc: f64,
74 epsc0: f64,
75 fcu: f64,
76 epscu: f64,
77 rat: f64,
78 ft: f64,
79 ets: f64,
80 },
81 Parallel {
83 children: Vec<(u32, f64)>,
84 },
85 Series {
89 children: Vec<u32>,
90 },
91 MinMax {
92 inner: u32,
93 min_strain: f64,
94 max_strain: f64,
95 },
96 #[allow(clippy::too_many_arguments)]
100 Hysteretic {
101 mom1p: f64,
102 rot1p: f64,
103 mom2p: f64,
104 rot2p: f64,
105 mom3p: f64,
106 rot3p: f64,
107 mom1n: f64,
108 rot1n: f64,
109 mom2n: f64,
110 rot2n: f64,
111 mom3n: f64,
112 rot3n: f64,
113 pinch_x: f64,
114 pinch_y: f64,
115 damfc1: f64,
116 damfc2: f64,
117 beta: f64,
118 },
119 #[allow(clippy::too_many_arguments)]
123 Pinching4 {
124 stress1p: f64,
125 strain1p: f64,
126 stress2p: f64,
127 strain2p: f64,
128 stress3p: f64,
129 strain3p: f64,
130 stress4p: f64,
131 strain4p: f64,
132 stress1n: f64,
133 strain1n: f64,
134 stress2n: f64,
135 strain2n: f64,
136 stress3n: f64,
137 strain3n: f64,
138 stress4n: f64,
139 strain4n: f64,
140 r_disp_p: f64,
141 r_force_p: f64,
142 u_force_p: f64,
143 r_disp_n: f64,
144 r_force_n: f64,
145 u_force_n: f64,
146 gamma_k_params: [f64; 4],
147 gamma_k_limit: f64,
148 gamma_d_params: [f64; 4],
149 gamma_d_limit: f64,
150 gamma_f_params: [f64; 4],
151 gamma_f_limit: f64,
152 gamma_e: f64,
153 dmg_cyc: Pinching4DmgCycSpec,
154 },
155}
156
157pub fn resolve_materials(arena: &[MaterialSpec]) -> Result<Vec<Material>, DecodeError> {
162 let mut resolved: Vec<Option<Material>> = vec![None; arena.len()];
163 for index in 0..arena.len() {
164 resolve_one(arena, index, &mut resolved, &mut Vec::new())?;
165 }
166 Ok(resolved
167 .into_iter()
168 .map(|m| m.expect("every arena index visited above"))
169 .collect())
170}
171
172fn resolve_one(
173 arena: &[MaterialSpec],
174 index: usize,
175 resolved: &mut [Option<Material>],
176 stack: &mut Vec<usize>,
177) -> Result<Material, DecodeError> {
178 if let Some(material) = &resolved[index] {
179 return Ok(material.clone());
180 }
181 if stack.contains(&index) {
182 return Err(DecodeError::CyclicMaterialReference {
183 index: index as u32,
184 });
185 }
186 let spec = arena.get(index).ok_or(DecodeError::UnknownMaterialIndex {
187 table: "materials",
188 row: index as u32,
189 })?;
190
191 stack.push(index);
192 let material = match spec {
193 MaterialSpec::Elastic { e } => Material::Elastic { e: *e },
194 MaterialSpec::ElasticPp { e, eyp } => Material::elastic_pp(*e, *eyp),
195 MaterialSpec::Gap { e, gap } => Material::Gap { e: *e, gap: *gap },
196 MaterialSpec::Ent { e } => Material::Ent { e: *e },
197 MaterialSpec::Steel01 {
198 fy,
199 e0,
200 b,
201 a1,
202 a2,
203 a3,
204 a4,
205 } => Material::steel01(*fy, *e0, *b, *a1, *a2, *a3, *a4),
206 MaterialSpec::Concrete01 {
207 fpc,
208 epsc0,
209 fpcu,
210 epscu,
211 } => Material::concrete01(*fpc, *epsc0, *fpcu, *epscu),
212 MaterialSpec::Steel02 {
213 fy,
214 e0,
215 b,
216 r0,
217 cr1,
218 cr2,
219 a1,
220 a2,
221 a3,
222 a4,
223 } => Material::steel02(*fy, *e0, *b, *r0, *cr1, *cr2, *a1, *a2, *a3, *a4),
224 MaterialSpec::Concrete02 {
225 fc,
226 epsc0,
227 fcu,
228 epscu,
229 rat,
230 ft,
231 ets,
232 } => Material::concrete02(*fc, *epsc0, *fcu, *epscu, *rat, *ft, *ets),
233 MaterialSpec::Parallel { children } => {
234 let mut resolved_children = Vec::with_capacity(children.len());
235 for (child_index, factor) in children {
236 let child = resolve_one(arena, *child_index as usize, resolved, stack)?;
237 resolved_children.push((child, *factor));
238 }
239 Material::Parallel(resolved_children)
240 }
241 MaterialSpec::Series { children } => {
242 let resolved_children = children
243 .iter()
244 .map(|child_index| resolve_one(arena, *child_index as usize, resolved, stack))
245 .collect::<Result<Vec<_>, _>>()?;
246 Material::series(resolved_children)
247 }
248 MaterialSpec::MinMax {
249 inner,
250 min_strain,
251 max_strain,
252 } => {
253 let inner = resolve_one(arena, *inner as usize, resolved, stack)?;
254 Material::min_max(inner, *min_strain, *max_strain)
255 }
256 MaterialSpec::Hysteretic {
257 mom1p,
258 rot1p,
259 mom2p,
260 rot2p,
261 mom3p,
262 rot3p,
263 mom1n,
264 rot1n,
265 mom2n,
266 rot2n,
267 mom3n,
268 rot3n,
269 pinch_x,
270 pinch_y,
271 damfc1,
272 damfc2,
273 beta,
274 } => Material::hysteretic(
275 *mom1p, *rot1p, *mom2p, *rot2p, *mom3p, *rot3p, *mom1n, *rot1n, *mom2n, *rot2n, *mom3n,
276 *rot3n, *pinch_x, *pinch_y, *damfc1, *damfc2, *beta,
277 ),
278 MaterialSpec::Pinching4 {
279 stress1p,
280 strain1p,
281 stress2p,
282 strain2p,
283 stress3p,
284 strain3p,
285 stress4p,
286 strain4p,
287 stress1n,
288 strain1n,
289 stress2n,
290 strain2n,
291 stress3n,
292 strain3n,
293 stress4n,
294 strain4n,
295 r_disp_p,
296 r_force_p,
297 u_force_p,
298 r_disp_n,
299 r_force_n,
300 u_force_n,
301 gamma_k_params,
302 gamma_k_limit,
303 gamma_d_params,
304 gamma_d_limit,
305 gamma_f_params,
306 gamma_f_limit,
307 gamma_e,
308 dmg_cyc,
309 } => Material::pinching4(
310 *stress1p,
311 *strain1p,
312 *stress2p,
313 *strain2p,
314 *stress3p,
315 *strain3p,
316 *stress4p,
317 *strain4p,
318 *stress1n,
319 *strain1n,
320 *stress2n,
321 *strain2n,
322 *stress3n,
323 *strain3n,
324 *stress4n,
325 *strain4n,
326 *r_disp_p,
327 *r_force_p,
328 *u_force_p,
329 *r_disp_n,
330 *r_force_n,
331 *u_force_n,
332 *gamma_k_params,
333 *gamma_k_limit,
334 *gamma_d_params,
335 *gamma_d_limit,
336 *gamma_f_params,
337 *gamma_f_limit,
338 *gamma_e,
339 match dmg_cyc {
340 Pinching4DmgCycSpec::EnergyBased => Pinching4DmgCyc::EnergyBased,
341 Pinching4DmgCycSpec::CycleBased => Pinching4DmgCyc::CycleBased,
342 },
343 ),
344 };
345 stack.pop();
346
347 resolved[index] = Some(material.clone());
348 Ok(material)
349}