ndgrid/traits/io/
gmsh.rs

1//! Gmsh I/O
2use crate::traits::{Builder, Grid};
3use std::fs::{self, File};
4use std::io::{BufRead, BufReader, Read};
5
6pub trait GmshExport: Grid {
7    //! Grid export for Gmsh
8
9    /// Generate the Gmsh string for a grid
10    fn to_gmsh_string(&self) -> String;
11
12    /// Export as Gmsh
13    fn export_as_gmsh(&self, filename: &str) {
14        let gmsh_s = self.to_gmsh_string();
15        fs::write(filename, gmsh_s).expect("Unable to write file");
16    }
17}
18
19pub trait GmshImport: Builder {
20    //! Grid import for Gmsh
21
22    /// Generate grid from a Gmsh v1 string
23    fn import_from_gmsh_v1(&mut self, s: String);
24
25    /// Generate grid from a Gmsh v2 string
26    fn import_from_gmsh_string_v2(&mut self, s: String);
27
28    /// Generate grid from a Gmsh v2 binary
29    fn import_from_gmsh_binary_v2(
30        &mut self,
31        reader: BufReader<File>,
32        data_size: usize,
33        // check endianness.
34        is_le: bool,
35    );
36
37    /// Generate grid from a Gmsh v4 string
38    fn import_from_gmsh_string_v4(&mut self, s: String);
39
40    /// Generate grid from a Gmsh v4 binary
41    fn import_from_gmsh_binary_v4(
42        &mut self,
43        reader: BufReader<File>,
44        data_size: usize,
45        // check endianness.
46        is_le: bool,
47    );
48
49    /// Generate grid from Gmsh
50    fn import_from_gmsh(&mut self, filename: &str) {
51        let f = File::open(filename).expect("Unable to open file");
52        let mut reader = BufReader::new(f);
53
54        let mut line = String::new();
55        reader.read_line(&mut line).expect("Unable to read header");
56
57        if line.starts_with("$NOD") {
58            let mut content = String::new();
59            reader
60                .read_to_string(&mut content)
61                .expect("Unable to read mesh");
62
63            content.replace_range(0..0, "$Nodes\n");
64            for (f, r) in [
65                ("$ENDNOD", "$EndNodes"),
66                ("$ELM", "$Elements"),
67                ("$ENDELM", "$EndElements"),
68            ]
69            .iter()
70            {
71                let Some(offset) = content.find(f) else {
72                    panic!("Invalid file format");
73                };
74                content.replace_range(offset..offset + f.len(), r);
75            }
76
77            self.import_from_gmsh_v1(content);
78            return;
79        }
80
81        reader.read_line(&mut line).expect("Unable to read header");
82
83        let [version, binary_mode, data_size] = line.split("\n").collect::<Vec<_>>()[1]
84            .split(" ")
85            .collect::<Vec<_>>()[..]
86        else {
87            panic!("Unrecognised format");
88        };
89
90        const GMSH_INT_SIZE: usize = 4;
91
92        if binary_mode == "1" {
93            let data_size = data_size
94                .parse::<usize>()
95                .expect("Unable to parse data size");
96
97            assert!(
98                data_size <= std::mem::size_of::<usize>(),
99                "Unsupported data size"
100            );
101
102            let mut buf = [0u8; GMSH_INT_SIZE];
103            reader
104                .read_exact(&mut buf)
105                .expect("Unable to read endianness");
106
107            let is_le = u32::from_le_bytes(buf) == 1;
108
109            if version.starts_with("2") {
110                self.import_from_gmsh_binary_v2(reader, data_size, is_le);
111            } else {
112                self.import_from_gmsh_binary_v4(reader, data_size, is_le);
113            }
114        } else {
115            let mut content = String::new();
116            reader
117                .read_to_string(&mut content)
118                .expect("Unable to read content");
119
120            if version.starts_with("2") {
121                self.import_from_gmsh_string_v2(content);
122            } else {
123                self.import_from_gmsh_string_v4(content);
124            }
125        }
126    }
127}