1#![allow(clippy::manual_div_ceil)]
6#[allow(unused_imports)]
7use super::functions::*;
8#[allow(unused_imports)]
9use super::functions_2::*;
10#[allow(dead_code)]
12pub struct ExodusMesh {
13 pub coordinates: Vec<[f64; 3]>,
15 pub blocks: Vec<ExodusBlock>,
17 pub node_sets: Vec<ExodusNodeSet>,
19 pub side_sets: Vec<ExodusSideSet>,
21 pub title: String,
23}
24impl ExodusMesh {
25 pub fn new(title: &str) -> Self {
27 ExodusMesh {
28 coordinates: Vec::new(),
29 blocks: Vec::new(),
30 node_sets: Vec::new(),
31 side_sets: Vec::new(),
32 title: title.to_string(),
33 }
34 }
35 pub fn add_node(&mut self, x: f64, y: f64, z: f64) -> usize {
37 self.coordinates.push([x, y, z]);
38 self.coordinates.len()
39 }
40 pub fn add_block(
42 &mut self,
43 id: u32,
44 name: &str,
45 etype: &str,
46 n_nodes_per_elem: usize,
47 ) -> usize {
48 self.blocks.push(ExodusBlock {
49 id,
50 name: name.to_string(),
51 element_type: etype.to_string(),
52 n_nodes_per_elem,
53 connectivity: Vec::new(),
54 });
55 self.blocks.len() - 1
56 }
57 pub fn add_element_to_block(&mut self, block_idx: usize, node_ids: &[usize]) {
59 self.blocks[block_idx]
60 .connectivity
61 .extend_from_slice(node_ids);
62 }
63 pub fn add_node_set(&mut self, id: u32, name: &str, nodes: Vec<usize>) {
65 self.node_sets.push(ExodusNodeSet {
66 id,
67 name: name.to_string(),
68 node_ids: nodes,
69 });
70 }
71 pub fn node_count(&self) -> usize {
73 self.coordinates.len()
74 }
75 pub fn element_count(&self) -> usize {
77 self.blocks
78 .iter()
79 .map(|b| {
80 b.connectivity
81 .len()
82 .checked_div(b.n_nodes_per_elem)
83 .unwrap_or(0)
84 })
85 .sum()
86 }
87}
88#[allow(dead_code)]
90pub struct ExodusResult {
91 pub mesh: ExodusMesh,
93 pub time_steps: Vec<ExodusTimeStep>,
95}
96impl ExodusResult {
97 pub fn write_summary(&self) -> String {
99 let mut s = String::new();
100 s.push_str(&format!("Title: {}\n", self.mesh.title));
101 s.push_str(&format!("Nodes: {}\n", self.mesh.node_count()));
102 s.push_str(&format!("Elements: {}\n", self.mesh.element_count()));
103 s.push_str(&format!("Blocks: {}\n", self.mesh.blocks.len()));
104 s.push_str(&format!("Node Sets: {}\n", self.mesh.node_sets.len()));
105 s.push_str(&format!("Side Sets: {}\n", self.mesh.side_sets.len()));
106 s.push_str(&format!("Time Steps: {}\n", self.time_steps.len()));
107 for (i, ts) in self.time_steps.iter().enumerate() {
108 s.push_str(&format!(
109 " Step {}: t={:.6}, vars={}\n",
110 i,
111 ts.time,
112 ts.variables.len()
113 ));
114 }
115 s
116 }
117}
118#[allow(dead_code)]
120pub struct ExodusBlock {
121 pub id: u32,
123 pub name: String,
125 pub element_type: String,
127 pub n_nodes_per_elem: usize,
129 pub connectivity: Vec<usize>,
131}
132#[allow(dead_code)]
134#[derive(Debug, Clone)]
135pub struct ElementQuality {
136 pub block_id: u32,
138 pub element_index: usize,
140 pub aspect_ratio: f64,
142 pub scaled_jacobian: f64,
144 pub min_edge: f64,
146 pub max_edge: f64,
148}
149#[allow(dead_code)]
151pub struct MeshPartition {
152 pub partition_id: usize,
154 pub mesh: ExodusMesh,
156}
157#[allow(dead_code)]
159#[derive(Debug, Clone, Default)]
160pub struct MeshValidationReport {
161 pub is_valid: bool,
163 pub errors: Vec<String>,
165 pub warnings: Vec<String>,
167}
168impl MeshValidationReport {
169 pub(super) fn add_error(&mut self, msg: String) {
170 self.errors.push(msg);
171 self.is_valid = false;
172 }
173 pub(super) fn add_warning(&mut self, msg: String) {
174 self.warnings.push(msg);
175 }
176}
177#[allow(dead_code)]
179pub struct ExodusNodeSet {
180 pub id: u32,
182 pub name: String,
184 pub node_ids: Vec<usize>,
186}
187#[allow(dead_code)]
189#[derive(Debug, Clone)]
190pub struct FieldStats {
191 pub min: f64,
193 pub max: f64,
195 pub mean: f64,
197 pub std_dev: f64,
199 pub count: usize,
201}
202#[allow(dead_code)]
204pub struct ExodusTimeStep {
205 pub time: f64,
207 pub variables: Vec<ExodusVariable>,
209}
210#[allow(dead_code)]
212pub struct ExodusSideSet {
213 pub id: u32,
215 pub name: String,
217 pub element_ids: Vec<usize>,
219 pub side_ids: Vec<usize>,
221}
222#[allow(dead_code)]
224pub struct ExodusGlobalVariable {
225 pub name: String,
227 pub time: f64,
229 pub value: f64,
231}
232#[allow(dead_code)]
234pub struct ExodusVariable {
235 pub name: String,
237 pub entity_type: String,
239 pub values: Vec<f64>,
241}
242#[allow(dead_code)]
245pub struct ExodusSideSetData {
246 pub id: u32,
248 pub name: String,
250 pub element_ids: Vec<usize>,
252 pub side_ids: Vec<usize>,
254 pub dist_factors: Vec<f64>,
256}
257#[allow(dead_code)]
259pub struct ExodusWriter;
260#[allow(dead_code)]
261impl ExodusWriter {
262 pub fn write_nodal_variable_step(
273 var_name: &str,
274 step: usize,
275 time: f64,
276 values: &[f64],
277 ) -> String {
278 let mut s = String::new();
279 s.push_str(&format!(
280 "NODAL_VAR {} STEP {} TIME {:.8e}\n",
281 var_name, step, time
282 ));
283 let vals: Vec<String> = values.iter().map(|v| format!("{:.8e}", v)).collect();
284 s.push_str(&vals.join(" "));
285 s.push('\n');
286 s.push_str("END_NODAL_VAR\n");
287 s
288 }
289 pub fn write_global_variable(var: &ExodusGlobalVariable) -> String {
296 format!(
297 "GLOBAL_VAR {} TIME {:.8e} VALUE {:.8e}\n",
298 var.name, var.time, var.value
299 )
300 }
301 pub fn write_side_set(data: &ExodusSideSetData) -> String {
314 let mut s = String::new();
315 let count = data.element_ids.len();
316 s.push_str(&format!(
317 "SIDE_SET_DATA {} {} {}\n",
318 data.id, data.name, count
319 ));
320 for i in 0..count {
321 s.push_str(&format!("{} {}\n", data.element_ids[i], data.side_ids[i]));
322 }
323 if !data.dist_factors.is_empty() {
324 s.push_str("DIST_FACTORS\n");
325 let fs: Vec<String> = data
326 .dist_factors
327 .iter()
328 .map(|f| format!("{:.6e}", f))
329 .collect();
330 s.push_str(&fs.join(" "));
331 s.push('\n');
332 }
333 s.push_str("END_SIDE_SET_DATA\n");
334 s
335 }
336}