1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use super::Mesh;
use crate::StrError;
use std::ffi::OsStr;
use std::fmt::Write;
use std::fs::{self, File};
use std::io::Write as IoWrite;
use std::path::Path;
impl Mesh {
/// Writes a text file with the mesh description
///
/// # File format
///
/// The text file format includes three sections:
///
/// 1. The header with the space dimension (`ndim`), number of points (`npoint`), and number of cells (`ncell`);
/// 2. The points list where each line contains the `id` of the point, which must be **equal to the position** in the list,
/// followed by the `x` and `y` (and `z`) coordinates;
/// 3. The cells list where each line contains the `id` of the cell, which must be **equal to the position** in the list,
/// the `marker` of the cell, the `kind` of the cell, followed by the IDs of the points that define the cell (connectivity).
///
/// The text looks like this (the `#` character indicates a comment):
///
/// ```text
/// # header
/// # ndim npoint ncell nmarked_edge nmarked_face
/// 3 8 5 3 2
///
/// # points
/// # id marker x y {z}
/// 0 0 0.0 0.0 0.0
/// 1 0 0.5 0.0 0.0
/// 2 0 1.0 0.0 0.0
/// # ... more points should follow
///
/// # cells
/// # id marker kind points
/// 0 1 tri3 0 1 3
/// 1 1 qua4 1 4 6 3
/// 2 2 tet4 0 3 7 2
/// # ... more cells should follow
///
/// # marked edges
/// # marker p1 p2
/// -100 0 1
/// -100 9 8
/// -200 8 3
///
/// # marked faces
/// # marker p1 p2 p3 {p4}
/// -10 4 7 4
/// -10 1 2 3
/// ```
///
/// where we can see that different cell (shape) kinds can be present in the same mesh.
/// However, this function does not check for element compatibility as required by finite element analyses.
///
/// See [crate::shapes::GeoKind::from] for the keys used to identify the cell kind (the keys are **lowercase**).
///
/// # Input
///
/// * `full_path` -- may be a String, &str, or Path
pub fn write<P>(&self, full_path: &P) -> Result<(), StrError>
where
P: AsRef<OsStr> + ?Sized,
{
let ncell = self.cells.len();
if ncell < 1 {
return Err("there are no cells to write");
}
// output buffer
let mut buffer = String::new();
write!(&mut buffer, "{}", self).map_err(|_| "cannot write to buffer")?;
// create directory
let path = Path::new(full_path);
if let Some(p) = path.parent() {
fs::create_dir_all(p).map_err(|_| "cannot create directory")?;
}
// write file
let mut file = File::create(path).map_err(|_| "cannot create file")?;
file.write_all(buffer.as_bytes()).map_err(|_| "cannot write file")?;
// force sync
file.sync_all().map_err(|_| "cannot sync file")?;
Ok(())
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
use crate::{mesh::Samples, StrError};
use std::fs;
#[test]
fn write_handles_unavailable_types() {
assert_eq!(
Samples::lin_cells().write_vtu("/tmp/gemlab/nothing.vtu").err(),
Some("cannot generate VTU file because VTK cell type is not available")
);
assert_eq!(
Samples::tri_cells().write_vtu("/tmp/gemlab/nothing.vtu").err(),
Some("cannot generate VTU file because VTK cell type is not available")
);
assert_eq!(
Samples::qua_cells().write_vtu("/tmp/gemlab/nothing.vtu").err(),
Some("cannot generate VTU file because VTK cell type is not available")
);
}
#[test]
fn write_works_qua8_tri6_lin2() -> Result<(), StrError> {
let mesh = Samples::qua8_tri6_lin2();
let file_path = "/tmp/gemlab/test_qua8_tri6_lin2.msh";
mesh.write(file_path)?;
let contents = fs::read_to_string(file_path).map_err(|_| "cannot open file")?;
assert_eq!(
contents,
"# header\n\
# ndim npoint ncell nmarked_edge nmarked_face\n\
2 11 4 0 0\n\
\n\
# points\n\
# id marker x y {z}\n\
0 -100 0.0 0.0\n\
1 0 0.5 0.0\n\
2 -200 1.0 0.0\n\
3 0 1.433 0.25\n\
4 -300 1.866 0.5\n\
5 0 1.433 0.75\n\
6 -400 1.0 1.0\n\
7 0 0.5 1.0\n\
8 -500 0.0 1.0\n\
9 0 0.0 0.5\n\
10 0 1.0 0.5\n\
\n\
# cells\n\
# id marker kind points\n\
0 1 qua8 0 2 6 8 1 10 7 9\n\
1 2 tri6 2 4 6 3 5 10\n\
2 3 lin2 2 10\n\
3 3 lin2 10 6\n"
);
Ok(())
}
}