OGS
GmshReader.cpp
Go to the documentation of this file.
1
11#include "GmshReader.h"
12
13#include <algorithm>
14#include <array>
15#include <fstream>
16#include <map>
17#include <type_traits>
18#include <vector>
19
20#include "BaseLib/FileTools.h"
29#include "MeshLib/Mesh.h"
30#include "MeshLib/Node.h"
32
33namespace FileIO
34{
35namespace GMSH
36{
37bool isGMSHMeshFile(const std::string& fname)
38{
39 std::ifstream input(fname.c_str());
40
41 if (!input)
42 {
43 ERR("isGMSHMeshFile(): Could not open file {:s}.", fname);
44 return false;
45 }
46
47 std::string header_first_line;
48 input >> header_first_line;
49 if (header_first_line.find("$MeshFormat") != std::string::npos)
50 {
51 // read version
52 std::string version;
53 std::getline(input, version);
54 std::getline(input, version);
55 INFO("isGMSHMeshFile(): Found GMSH mesh file version: {:s}.", version);
56 input.close();
57 return true;
58 }
59
60 return false;
61}
62
63void readNodeIDs(std::ifstream& in, unsigned n_nodes,
64 std::vector<unsigned>& node_ids,
65 std::map<unsigned, unsigned> const& id_map)
66{
67 unsigned idx;
68 for (unsigned i = 0; i < n_nodes; i++)
69 {
70 in >> idx;
71 node_ids.push_back(id_map.at(idx));
72 }
73}
74
75template <typename ElementType>
76std::pair<MeshLib::Element*, int> createElement(
77 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
78 int const mat_id, std::map<unsigned, unsigned> const& id_map)
79{
80 std::vector<unsigned> node_ids;
81 readNodeIDs(in, ElementType::n_all_nodes, node_ids, id_map);
82
83 std::array<MeshLib::Node*, ElementType::n_all_nodes> element_nodes;
84
85 std::transform(begin(node_ids), end(node_ids), begin(element_nodes),
86 [&nodes](auto const id) { return nodes[id]; });
87
88 return std::make_pair(new ElementType(element_nodes), mat_id);
89}
90
91template <>
92std::pair<MeshLib::Element*, int> createElement<MeshLib::Tri>(
93 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
94 int const mat_id, std::map<unsigned, unsigned> const& id_map)
95{
96 std::vector<unsigned> node_ids;
97 readNodeIDs(in, 3, node_ids, id_map);
98
99 std::array<MeshLib::Node*, 3> element_nodes;
100
101 std::transform(std::rbegin(node_ids), std::rend(node_ids),
102 begin(element_nodes),
103 [&nodes](auto const id) { return nodes[id]; });
104
105 return std::make_pair(new MeshLib::Tri(element_nodes), mat_id);
106}
107
108template <>
109std::pair<MeshLib::Element*, int> createElement<MeshLib::Tet10>(
110 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
111 int const mat_id, std::map<unsigned, unsigned> const& id_map)
112{
113 std::vector<unsigned> node_ids;
114 readNodeIDs(in, MeshLib::Tet10::n_all_nodes, node_ids, id_map);
115
116 std::swap(node_ids[8], node_ids[9]);
117
118 std::array<MeshLib::Node*, MeshLib::Tet10::n_all_nodes> element_nodes;
119
120 std::transform(begin(node_ids), end(node_ids), begin(element_nodes),
121 [&nodes](auto const id) { return nodes[id]; });
122
123 return std::make_pair(new MeshLib::Tet10(element_nodes), mat_id);
124}
125
126template <>
127std::pair<MeshLib::Element*, int> createElement<MeshLib::Hex20>(
128 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
129 int const mat_id, std::map<unsigned, unsigned> const& id_map)
130{
131 std::vector<unsigned> node_ids;
132 readNodeIDs(in, MeshLib::Hex20::n_all_nodes, node_ids, id_map);
133
134 std::array<MeshLib::Node*, MeshLib::Hex20::n_all_nodes> element_nodes;
135
136 constexpr std::array node_order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 11,
137 13, 9, 16, 18, 19, 17, 10, 12, 14, 15};
138
139 std::transform(begin(node_order), end(node_order), begin(element_nodes),
140 [&node_ids, &nodes](auto const id)
141 { return nodes[node_ids[id]]; });
142
143 return std::make_pair(new MeshLib::Hex20(element_nodes), mat_id);
144}
145
146template <>
147std::pair<MeshLib::Element*, int> createElement<MeshLib::Prism15>(
148 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
149 int const mat_id, std::map<unsigned, unsigned> const& id_map)
150{
151 std::vector<unsigned> node_ids;
152 readNodeIDs(in, MeshLib::Prism15::n_all_nodes, node_ids, id_map);
153
154 std::array<MeshLib::Node*, MeshLib::Prism15::n_all_nodes> element_nodes;
155
156 constexpr std::array node_order = {0, 1, 2, 3, 4, 5, 6, 9,
157 7, 12, 14, 13, 8, 10, 11};
158
159 std::transform(begin(node_order), end(node_order), begin(element_nodes),
160 [&node_ids, &nodes](auto const id)
161 { return nodes[node_ids[id]]; });
162
163 return std::make_pair(new MeshLib::Prism15(element_nodes), mat_id);
164}
165
166template <>
167std::pair<MeshLib::Element*, int> createElement<MeshLib::Pyramid13>(
168 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
169 int const mat_id, std::map<unsigned, unsigned> const& id_map)
170{
171 std::vector<unsigned> node_ids;
172 readNodeIDs(in, MeshLib::Pyramid13::n_all_nodes, node_ids, id_map);
173 std::array<MeshLib::Node*, MeshLib::Pyramid13::n_all_nodes> element_nodes;
174
175 constexpr std::array node_order = {0, 1, 2, 3, 4, 5, 8,
176 10, 6, 7, 9, 11, 12};
177
178 std::transform(begin(node_order), end(node_order), begin(element_nodes),
179 [&node_ids, &nodes](auto const id)
180 { return nodes[node_ids[id]]; });
181
182 return std::make_pair(new MeshLib::Pyramid13(element_nodes), mat_id);
183}
184
185std::pair<MeshLib::Element*, int> readElement(
186 std::ifstream& in, std::vector<MeshLib::Node*> const& nodes,
187 std::map<unsigned, unsigned> const& id_map,
188 bool const is_created_with_gmsh2)
189{
190 unsigned idx;
191 unsigned type;
192 unsigned n_tags;
193 unsigned dummy;
194 int mat_id;
195
196 // The element format is structured like this:
197 // Gmsh version 4:
198 // element-id element-type n-tags physical-entity elementary entity node-ids
199 // Gmsh version 2:
200 // element-id element-type n-tags elementary physical-entity entity
201 // node-ids
202
203 in >> idx >> type >> n_tags;
204
205 if (!is_created_with_gmsh2)
206 {
207 in >> mat_id >> dummy;
208 }
209 else // for meshes created by using Gmsh version 2
210 {
211 in >> dummy >> mat_id;
212 }
213
214 switch (type)
215 {
216 case 1:
217 {
218 return createElement<MeshLib::Line>(in, nodes, mat_id, id_map);
219 }
220 case 2:
221 {
222 return createElement<MeshLib::Tri>(in, nodes, mat_id, id_map);
223 }
224 case 3:
225 {
226 return createElement<MeshLib::Quad>(in, nodes, mat_id, id_map);
227 }
228 case 4:
229 {
230 return createElement<MeshLib::Tet>(in, nodes, mat_id, id_map);
231 }
232 case 5:
233 {
234 return createElement<MeshLib::Hex>(in, nodes, mat_id, id_map);
235 }
236 case 6:
237 {
238 return createElement<MeshLib::Prism>(in, nodes, mat_id, id_map);
239 }
240 case 7:
241 {
242 return createElement<MeshLib::Pyramid>(in, nodes, mat_id, id_map);
243 }
244 case 8: // 3-node second order line.
245 {
246 return createElement<MeshLib::Line3>(in, nodes, mat_id, id_map);
247 }
248 case 9: // 6-node second order triangle.
249 {
250 return createElement<MeshLib::Tri6>(in, nodes, mat_id, id_map);
251 }
252 case 10: // 9-node second order quadrangle.
253 {
254 return createElement<MeshLib::Quad9>(in, nodes, mat_id, id_map);
255 }
256 case 11: // 10-node second order tetrahedron.
257 {
258 return createElement<MeshLib::Tet10>(in, nodes, mat_id, id_map);
259 }
260 case 16: // 8-node second order quadrangle.
261 {
262 return createElement<MeshLib::Quad8>(in, nodes, mat_id, id_map);
263 }
264 case 17: // 20-node second order hexahedron.
265 {
266 return createElement<MeshLib::Hex20>(in, nodes, mat_id, id_map);
267 }
268 case 18: // 15-node second order prism.
269 {
270 return createElement<MeshLib::Prism15>(in, nodes, mat_id, id_map);
271 }
272 case 19: // 13-node second order pyramid.
273 {
274 return createElement<MeshLib::Pyramid13>(in, nodes, mat_id, id_map);
275 }
276 case 15:
277 in >> dummy; // skip rest of line
278 break;
279 default:
280 WARN("readGMSHMesh(): Unknown element type {:d}.", type);
281 break;
282 }
283 return std::make_pair(nullptr, -1);
284}
285
286MeshLib::Mesh* readGMSHMesh(std::string const& fname,
287 bool const is_created_with_gmsh2)
288{
289 if (!is_created_with_gmsh2)
290 {
291 WARN(
292 "If the mesh is generated with Gmsh version 2 and it is saved"
293 " (or exported) as \"Version 2 ASCII\" format, the flag"
294 " --gmsh2_physical_id must be used for a correct conversion from "
295 "physical id to MaterialIDs.");
296 }
297
298 std::string line;
299 std::ifstream in(fname.c_str(), std::ios::in);
300 if (!in.is_open())
301 {
302 WARN("readGMSHMesh() - Could not open file {:s}.", fname);
303 return nullptr;
304 }
305
306 std::getline(in, line); // $MeshFormat keyword
307 if (line.find("$MeshFormat") == std::string::npos)
308 {
309 in.close();
310 WARN("No GMSH file format recognized.");
311 return nullptr;
312 }
313
314 std::getline(in, line); // version-number file-type data-size
315 if (line.substr(0, 3) != "2.2")
316 {
317 WARN("Wrong gmsh file format version '{:s}'.", line.substr(0, 3));
318 return nullptr;
319 }
320
321 if (line[4] != '0')
322 {
323 WARN("Currently reading gmsh binary file type is not supported.");
324 return nullptr;
325 }
326 std::getline(in, line); //$EndMeshFormat
327
328 std::vector<MeshLib::Node*> nodes;
329 std::vector<MeshLib::Element*> elements;
330 std::vector<int> materials;
331 std::map<unsigned, unsigned> id_map;
332 while (line.find("$EndElements") == std::string::npos)
333 {
334 // Node data
335 std::getline(in, line); //$Nodes Keywords
336 if (line.find("$Nodes") != std::string::npos)
337 {
338 std::size_t n_nodes(0);
339 long id;
340 double x;
341 double y;
342 double z;
343 in >> n_nodes >> std::ws;
344 nodes.resize(n_nodes);
345 for (std::size_t i = 0; i < n_nodes; i++)
346 {
347 in >> id >> x >> y >> z >> std::ws;
348 id_map.insert(std::map<unsigned, unsigned>::value_type(id, i));
349 nodes[i] = new MeshLib::Node(x, y, z, id);
350 }
351 std::getline(in, line); // End Node keyword $EndNodes
352 }
353
354 // Element data
355 if (line.find("$Elements") != std::string::npos)
356 {
357 std::size_t n_elements(0);
358 if (!(in >> n_elements >> std::ws))
359 { // number-of-elements
360 ERR("Read GMSH mesh does not contain any elements");
361 }
362 elements.reserve(n_elements);
363 materials.reserve(n_elements);
364 for (std::size_t i = 0; i < n_elements; i++)
365 {
366 MeshLib::Element* elem(nullptr);
367 int mat_id(0);
368 std::tie(elem, mat_id) =
369 readElement(in, nodes, id_map, is_created_with_gmsh2);
370
371 if (elem)
372 {
373 elements.push_back(elem);
374 materials.push_back(mat_id);
375 }
376 }
377 std::getline(in, line); // END keyword
378 }
379
380 if (line.find("PhysicalNames") != std::string::npos)
381 {
382 std::size_t n_lines(0);
383 in >> n_lines >> std::ws; // number-of-lines
384 for (std::size_t i = 0; i < n_lines; i++)
385 {
386 std::getline(in, line);
387 }
388 std::getline(in, line); // END keyword
389 }
390 }
391 in.close();
392 if (elements.empty())
393 {
394 for (auto& node : nodes)
395 {
396 delete node;
397 }
398 return nullptr;
399 }
400
402 BaseLib::extractBaseNameWithoutExtension(fname), nodes, elements,
403 true /* compute_element_neighbors */));
404
405 auto* const material_ids =
407 "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
408 if (!material_ids)
409 {
410 WARN("Could not create PropertyVector for MaterialIDs in Mesh.");
411 }
412 else
413 {
414 material_ids->insert(material_ids->end(), materials.cbegin(),
415 materials.cend());
416 }
417
419
420 INFO("\t... finished.");
421 INFO("Nr. Nodes: {:d}.", nodes.size());
422 INFO("Nr. Elements: {:d}.", elements.size());
423
424 return mesh;
425}
426
427} // end namespace GMSH
428} // end namespace FileIO
Definition of the ElementValueModification class.
Definition of the Element class.
Filename manipulation routines.
Definition of the Hex class.
Definition of the Line class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
Definition of the Mesh class.
Definition of the Node class.
Definition of the Prism class.
Definition of the Pyramid class.
Definition of the Quad class.
Definition of the Tet class.
Definition of the Tri class.
Properties & getProperties()
Definition Mesh.h:134
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
static const unsigned n_all_nodes
Constant: The number of all nodes for this element.
static std::size_t condense(MeshLib::Mesh &mesh)
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::pair< MeshLib::Element *, int > createElement< MeshLib::Tri >(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, int const mat_id, std::map< unsigned, unsigned > const &id_map)
MeshLib::Mesh * readGMSHMesh(std::string const &fname, bool const is_created_with_gmsh2)
std::pair< MeshLib::Element *, int > createElement< MeshLib::Prism15 >(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, int const mat_id, std::map< unsigned, unsigned > const &id_map)
std::pair< MeshLib::Element *, int > readElement(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, std::map< unsigned, unsigned > const &id_map, bool const is_created_with_gmsh2)
std::pair< MeshLib::Element *, int > createElement< MeshLib::Pyramid13 >(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, int const mat_id, std::map< unsigned, unsigned > const &id_map)
bool isGMSHMeshFile(const std::string &fname)
std::pair< MeshLib::Element *, int > createElement< MeshLib::Tet10 >(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, int const mat_id, std::map< unsigned, unsigned > const &id_map)
std::pair< MeshLib::Element *, int > createElement< MeshLib::Hex20 >(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, int const mat_id, std::map< unsigned, unsigned > const &id_map)
std::pair< MeshLib::Element *, int > createElement(std::ifstream &in, std::vector< MeshLib::Node * > const &nodes, int const mat_id, std::map< unsigned, unsigned > const &id_map)
void readNodeIDs(std::ifstream &in, unsigned n_nodes, std::vector< unsigned > &node_ids, std::map< unsigned, unsigned > const &id_map)