Skip to main content

oxiphysics_io/exodus/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5#![allow(clippy::manual_div_ceil)]
6#[allow(unused_imports)]
7use super::functions::*;
8#[allow(unused_imports)]
9use super::functions_2::*;
10/// The primary mesh data structure for Exodus II format.
11#[allow(dead_code)]
12pub struct ExodusMesh {
13    /// Node coordinates as (x, y, z) triples.
14    pub coordinates: Vec<[f64; 3]>,
15    /// Element blocks.
16    pub blocks: Vec<ExodusBlock>,
17    /// Node sets.
18    pub node_sets: Vec<ExodusNodeSet>,
19    /// Side sets.
20    pub side_sets: Vec<ExodusSideSet>,
21    /// Mesh title string.
22    pub title: String,
23}
24impl ExodusMesh {
25    /// Create a new empty mesh with the given title.
26    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    /// Add a node and return its 1-based ID.
36    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    /// Add an element block and return its index in `self.blocks`.
41    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    /// Add an element to the specified block using the provided node IDs (1-based).
58    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    /// Add a node set.
64    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    /// Return the total number of nodes.
72    pub fn node_count(&self) -> usize {
73        self.coordinates.len()
74    }
75    /// Return the total number of elements across all blocks.
76    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/// A complete Exodus result combining mesh topology with time-dependent data.
89#[allow(dead_code)]
90pub struct ExodusResult {
91    /// The mesh topology.
92    pub mesh: ExodusMesh,
93    /// All time steps with associated variable data.
94    pub time_steps: Vec<ExodusTimeStep>,
95}
96impl ExodusResult {
97    /// Generate a human-readable summary string.
98    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/// An element block containing elements of the same type.
119#[allow(dead_code)]
120pub struct ExodusBlock {
121    /// Unique identifier for this block.
122    pub id: u32,
123    /// Human-readable name.
124    pub name: String,
125    /// Element type string, e.g. "HEX8", "TET4", "QUAD4".
126    pub element_type: String,
127    /// Number of nodes per element.
128    pub n_nodes_per_elem: usize,
129    /// Flattened connectivity array (node IDs, 1-based).
130    pub connectivity: Vec<usize>,
131}
132/// Quality metric result for a single element.
133#[allow(dead_code)]
134#[derive(Debug, Clone)]
135pub struct ElementQuality {
136    /// Block id the element belongs to.
137    pub block_id: u32,
138    /// Zero-based element index within the block.
139    pub element_index: usize,
140    /// Aspect ratio (min_edge / max_edge for simplices).
141    pub aspect_ratio: f64,
142    /// Scaled Jacobian for volume elements (1.0 = ideal).
143    pub scaled_jacobian: f64,
144    /// Minimum edge length.
145    pub min_edge: f64,
146    /// Maximum edge length.
147    pub max_edge: f64,
148}
149/// Partition result: a list of sub-meshes and their owning partition ids.
150#[allow(dead_code)]
151pub struct MeshPartition {
152    /// Partition index (0-based).
153    pub partition_id: usize,
154    /// The sub-mesh for this partition.
155    pub mesh: ExodusMesh,
156}
157/// Result of mesh validation.
158#[allow(dead_code)]
159#[derive(Debug, Clone, Default)]
160pub struct MeshValidationReport {
161    /// True if no errors were found.
162    pub is_valid: bool,
163    /// List of error messages.
164    pub errors: Vec<String>,
165    /// List of warning messages.
166    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/// A named set of nodes (boundary condition set).
178#[allow(dead_code)]
179pub struct ExodusNodeSet {
180    /// Unique identifier for this node set.
181    pub id: u32,
182    /// Human-readable name.
183    pub name: String,
184    /// List of node IDs (1-based) in this set.
185    pub node_ids: Vec<usize>,
186}
187/// Statistics over a scalar field defined on nodes or elements.
188#[allow(dead_code)]
189#[derive(Debug, Clone)]
190pub struct FieldStats {
191    /// Minimum value.
192    pub min: f64,
193    /// Maximum value.
194    pub max: f64,
195    /// Arithmetic mean.
196    pub mean: f64,
197    /// Population standard deviation.
198    pub std_dev: f64,
199    /// Number of values.
200    pub count: usize,
201}
202/// A time step containing variable data.
203#[allow(dead_code)]
204pub struct ExodusTimeStep {
205    /// Simulation time for this step.
206    pub time: f64,
207    /// Variables defined at this time step.
208    pub variables: Vec<ExodusVariable>,
209}
210/// A named set of element sides (face boundary conditions).
211#[allow(dead_code)]
212pub struct ExodusSideSet {
213    /// Unique identifier for this side set.
214    pub id: u32,
215    /// Human-readable name.
216    pub name: String,
217    /// Element IDs (1-based) for each side entry.
218    pub element_ids: Vec<usize>,
219    /// Local side IDs within each element.
220    pub side_ids: Vec<usize>,
221}
222/// A global simulation variable (scalar value valid for the whole domain).
223#[allow(dead_code)]
224pub struct ExodusGlobalVariable {
225    /// Variable name.
226    pub name: String,
227    /// Simulation time.
228    pub time: f64,
229    /// Scalar value.
230    pub value: f64,
231}
232/// A single scalar/vector variable attached to an entity (node or element).
233#[allow(dead_code)]
234pub struct ExodusVariable {
235    /// Variable name.
236    pub name: String,
237    /// Entity type: "node" or "element".
238    pub entity_type: String,
239    /// Variable values, one per entity.
240    pub values: Vec<f64>,
241}
242/// Represents a boundary side set with element/side ID pairs and an optional
243/// distance field (e.g. wall-normal distance).
244#[allow(dead_code)]
245pub struct ExodusSideSetData {
246    /// Side-set identifier.
247    pub id: u32,
248    /// Human-readable name.
249    pub name: String,
250    /// Element IDs (1-based) in the set.
251    pub element_ids: Vec<usize>,
252    /// Local side IDs within each element.
253    pub side_ids: Vec<usize>,
254    /// Optional per-side scalar distribution factor.
255    pub dist_factors: Vec<f64>,
256}
257/// Higher-level writing helpers for Exodus-II results.
258#[allow(dead_code)]
259pub struct ExodusWriter;
260#[allow(dead_code)]
261impl ExodusWriter {
262    /// Append a time-step nodal variable record to a text buffer.
263    ///
264    /// The record format is:
265    /// ```text
266    /// NODAL_VAR `name` STEP `step` TIME `time`
267    /// `v0` `v1` ... `vN`
268    /// END_NODAL_VAR
269    /// ```
270    ///
271    /// Returns a formatted `String`.
272    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    /// Serialize a global simulation variable to a one-line text record.
290    ///
291    /// Format:
292    /// ```text
293    /// GLOBAL_VAR `name` TIME `time` VALUE `value`
294    /// ```
295    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    /// Serialize an `ExodusSideSetData` to a text block.
302    ///
303    /// Format:
304    /// ```text
305    /// SIDE_SET_DATA `id` `name` `count`
306    /// `eid0` `sid0`
307    /// `eid1` `sid1`
308    /// ...
309    /// [DIST_FACTORS
310    /// `f0` `f1` ...]
311    /// END_SIDE_SET_DATA
312    /// ```
313    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}