Chi-Tech
unpartmesh_01e_readfrommsh.cc
Go to the documentation of this file.
2
3#include "chi_runtime.h"
4#include "chi_log.h"
5
6#include "chi_mpi.h"
7
8#include <map>
9#include <fstream>
10
11//###################################################################
12/**Reads an unpartitioned mesh from a gmesh .msh legacy ASCII format 2 file.*/
14{
15 const std::string fname = "chi_mesh::UnpartitionedMesh::ReadFromMsh";
16
17 //===================================================== Opening the file
18 std::ifstream file;
19 file.open(options.file_name);
20 if (!file.is_open())
21 {
23 << "Failed to open file: "<< options.file_name<<" in call "
24 << "to ReadFromMsh \n";
25 Chi::Exit(EXIT_FAILURE);
26 }
27
28 Chi::log.Log() << "Making Unpartitioned mesh from msh format file "
29 << options.file_name;
31
32 //===================================================== Declarations
33 std::string file_line;
34 std::istringstream iss;
35 const std::string node_section_name="$Nodes";
36 const std::string elements_section_name = "$Elements";
37 const std::string format_section_name = "$MeshFormat";
38
39 //=================================================== Check the format of this input
40 // Role file forward until "$MeshFormat" line is encountered.
41 while (std::getline(file, file_line))
42 if ( format_section_name == file_line ) break;
43
44 std::getline(file, file_line);
45 iss = std::istringstream(file_line);
46 double format;
47 if ( !(iss >> format) )
48 throw std::logic_error(fname + ": Failed to read the file format.");
49 else if (format != 2.2)
50 throw std::logic_error(fname + ": Currently, only msh format 2.2 is supported.");
51
52 //=================================================== Find section with node
53 // information and then
54 // read the nodes
55 file.seekg(0);
56 while (std::getline(file, file_line))
57 if ( node_section_name == file_line ) break;
58
59 std::getline(file, file_line);
60 iss = std::istringstream(file_line);
61 int num_nodes;
62 if ( !(iss >> num_nodes) )
63 throw std::logic_error(fname + ": Failed while trying to read "
64 "the number of nodes.");
65
66 vertices_.clear();
67 vertices_.resize(num_nodes);
68
69 for (int n=0; n<num_nodes; n++)
70 {
71 std::getline(file, file_line);
72 iss = std::istringstream(file_line);
73
74 int vert_index;
75 if ( !(iss >> vert_index) )
76 throw std::logic_error(fname + ": Failed to read vertex index.");
77
78 if (!(iss >> vertices_[vert_index - 1].x
79 >> vertices_[vert_index - 1].y
80 >> vertices_[vert_index - 1].z))
81 throw std::logic_error(fname + ": Failed while reading the vertex "
82 "coordinates.");
83 }
84
85 //================================================== Define utility lambdas
86 /**Lambda for reading nodes.*/
87 auto ReadNodes = [&iss,&fname](int num_nodes)
88 {
89 std::vector<int> raw_nodes(num_nodes,0);
90 for (int i=0; i<num_nodes; ++i)
91 if ( !(iss >> raw_nodes[i]) )
92 throw std::logic_error(fname + ": Failed when reading element "
93 "node index.");
94
95 std::vector<uint64_t> nodes(num_nodes,0);
96 for (int i=0; i<num_nodes; ++i)
97 if ((raw_nodes[i]-1)>=0)
98 nodes[i] = raw_nodes[i]-1;
99 return nodes;
100 };
101
102 /**Lamda for checking if an element is 1D.*/
103 auto IsElementType1D = [](int element_type)
104 {
105 if (element_type == 1)
106 return true;
107
108 return false;
109 };
110
111 /**Lamda for checking if an element is 2D.*/
112 auto IsElementType2D = [](int element_type)
113 {
114 if (element_type == 2 or element_type == 3)
115 return true;
116
117 return false;
118 };
119
120 /**Lamda for checking if an element is 2D.*/
121 auto IsElementType3D = [](int element_type)
122 {
123 if (element_type >= 4 and element_type <= 7)
124 return true;
125
126 return false;
127 };
128
129 /**Lambda for checking supported elements.*/
130 auto IsElementSupported = [](int element_type)
131 {
132 if (element_type >= 1 and element_type <= 7)
133 return true;
134
135 return false;
136 };
137
138 /**Lambda giving the cell subtype, given the MSH cell type.*/
139 auto CellTypeFromMSHTypeID = [](int element_type)
140 {
141 CellType cell_type = CellType::GHOST;
142
143 if (element_type == 1) cell_type = CellType::SLAB;
144 else if (element_type == 2) cell_type = CellType::TRIANGLE;
145 else if (element_type == 3) cell_type = CellType::QUADRILATERAL;
146 else if (element_type == 4) cell_type = CellType::TETRAHEDRON;
147 else if (element_type == 5) cell_type = CellType::HEXAHEDRON;
148 else if (element_type == 6 or //Prism
149 element_type == 7) cell_type = CellType::POLYHEDRON; //Pyramid
150
151 return cell_type;
152 };
153
154 //================================================== Determine mesh type 2D/3D
155 // Only 2D and 3D meshes are supported. If the mesh
156 // is 1D then no elements will be read but the state
157 // would still be safe.
158 // This section will run through all the elements
159 // looking for a 3D element. It will not process
160 // any elements.
161 bool mesh_is_2D_assumption = true;
162 file.seekg(0);
163 while (std::getline(file, file_line))
164 if ( elements_section_name == file_line ) break;
165
166 std::getline(file, file_line);
167 iss = std::istringstream(file_line);
168 int num_elems;
169 if (!(iss >> num_elems))
170 throw std::logic_error(fname + ": Failed to read number of elements.");
171
172 for (int n=0; n<num_elems; n++)
173 {
174 int elem_type, num_tags, physical_reg, tag, element_index;
175
176 std::getline(file, file_line);
177 iss = std::istringstream(file_line);
178
179 if ( !(iss >> element_index >> elem_type >> num_tags) )
180 throw std::logic_error(fname + ": Failed while reading element index, "
181 "element type, and number of tags.");
182
183 if( !(iss>>physical_reg) )
184 throw std::logic_error(fname + ": Failed while reading physical region.");
185
186 for (int i=1; i<num_tags; i++)
187 if( !(iss >> tag) )
188 throw std::logic_error(fname + ": Failed when reading tags.");
189
190 if (IsElementType3D(elem_type))
191 {
192 mesh_is_2D_assumption = false;
193 Chi::log.Log() << "Mesh identified as 3D.";
194 break; //have the answer now leave loop
195 }
196
197 if (elem_type == 15) //skip point type element
198 continue;
199
200 if (not IsElementSupported(elem_type))
201 throw std::logic_error(fname + ": Unsupported element encountered.");
202 }//for n
203
204 //================================================== Return to the element
205 // listing section
206 // Now we will actually read the elements.
207 file.seekg(0);
208 while (std::getline(file, file_line))
209 if ( elements_section_name == file_line ) break;
210
211 std::getline(file, file_line);
212 iss = std::istringstream(file_line);
213 if (!(iss >> num_elems))
214 throw std::logic_error(fname + ": Failed to read number of elements.");
215
216 for (int n=0; n<num_elems; n++)
217 {
218 int elem_type, num_tags, physical_reg, tag, element_index;
219
220 std::getline(file, file_line);
221 iss = std::istringstream(file_line);
222
223 if ( !(iss >> element_index >> elem_type >> num_tags) )
224 throw std::logic_error(fname + ": Failed while reading element index, "
225 "element type, and number of tags.");
226
227 if( !(iss>>physical_reg) )
228 throw std::logic_error(fname + ": Failed while reading physical region.");
229
230 for (int i=1; i<num_tags; i++)
231 if ( !(iss >> tag) )
232 throw std::logic_error(fname + ": Failed when reading tags.");
233
234 if (elem_type == 15) //skip point type elements
235 continue;
236
237 if (not IsElementSupported(elem_type))
238 throw std::logic_error(fname + ": Unsupported element encountered.");
239
240 Chi::log.Log0Verbose2() << "Reading element: " << file_line
241 << " type: " << elem_type;
242
243 int num_cell_nodes;
244 if (elem_type == 1)
245 num_cell_nodes = 2;
246 else if (elem_type == 2) //3-node triangle
247 num_cell_nodes = 3;
248 else if (elem_type == 3 or elem_type == 4) //4-node quadrangle or tet
249 num_cell_nodes = 4;
250 else if (elem_type == 5) //8-node hexahedron
251 num_cell_nodes = 8;
252 else
253 continue;
254
255 //====================================== Make the cell on either the volume
256 // or the boundary
257 LightWeightCell* raw_cell = nullptr;
258 if (mesh_is_2D_assumption)
259 {
260 if (IsElementType1D(elem_type))
261 {
263 raw_boundary_cells_.push_back(raw_cell);
264 Chi::log.Log0Verbose2() << "Added to raw_boundary_cells.";
265 }
266 else if (IsElementType2D(elem_type))
267 {
268 raw_cell = new LightWeightCell(CellType::POLYGON,
269 CellTypeFromMSHTypeID(elem_type));
270 raw_cells_.push_back(raw_cell);
271 Chi::log.Log0Verbose2() << "Added to raw_cells.";
272 }
273 }
274 else
275 {
276 if (IsElementType2D(elem_type))
277 {
278 raw_cell = new LightWeightCell(CellType::POLYGON,
279 CellTypeFromMSHTypeID(elem_type));
280 raw_boundary_cells_.push_back(raw_cell);
281 Chi::log.Log0Verbose2() << "Added to raw_boundary_cells.";
282 }
283 else if (IsElementType3D(elem_type))
284 {
286 CellTypeFromMSHTypeID(elem_type));
287 raw_cells_.push_back(raw_cell);
288 Chi::log.Log0Verbose2() << "Added to raw_cells.";
289 }
290 }
291
292 if (raw_cell == nullptr) continue;
293
294 auto& cell = *raw_cell;
295 cell.material_id = physical_reg;
296 cell.vertex_ids = ReadNodes(num_cell_nodes);
297
298 //====================================== Populate faces
299 if (elem_type == 1) // 2-node edge
300 {
301 LightWeightFace face0;
302 LightWeightFace face1;
303
304 face0.vertex_ids = {cell.vertex_ids.at(0)};
305 face1.vertex_ids = {cell.vertex_ids.at(1)};
306
307 cell.faces.push_back(face0);
308 cell.faces.push_back(face1);
309 }
310 else if (elem_type == 2 or elem_type == 3) //3-node triangle or 4-node quadrangle
311 {
312 size_t num_verts = cell.vertex_ids.size();
313 for (size_t e=0; e<num_verts; e++)
314 {
315 size_t ep1 = (e<(num_verts-1))? e+1 : 0;
316 LightWeightFace face;
317
318 face.vertex_ids = {cell.vertex_ids[e], cell.vertex_ids[ep1]};
319
320 cell.faces.push_back(std::move(face));
321 }//for e
322 }//if 2D elements
323 else if (elem_type == 4) // 4-node tetrahedron
324 {
325 auto& v = cell.vertex_ids;
326 std::vector<LightWeightFace> lw_faces(4);
327 lw_faces[0].vertex_ids = {v[0], v[2], v[1]}; //base-face
328 lw_faces[1].vertex_ids = {v[0], v[3], v[2]};
329 lw_faces[2].vertex_ids = {v[3], v[1], v[2]};
330 lw_faces[3].vertex_ids = {v[3], v[0], v[1]};
331
332 for (auto& lw_face : lw_faces) cell.faces.push_back(lw_face);
333 }
334 else if (elem_type == 5) //8-node hexahedron
335 {
336 auto& v = cell.vertex_ids;
337 std::vector<LightWeightFace> lw_faces(6);
338 lw_faces[0].vertex_ids = {v[5], v[1], v[2], v[6]}; //East face
339 lw_faces[1].vertex_ids = {v[0], v[4], v[7], v[3]}; //West face
340 lw_faces[2].vertex_ids = {v[0], v[3], v[2], v[1]}; //North face
341 lw_faces[3].vertex_ids = {v[4], v[5], v[6], v[7]}; //South face
342 lw_faces[4].vertex_ids = {v[2], v[3], v[7], v[6]}; //Top face
343 lw_faces[5].vertex_ids = {v[0], v[1], v[5], v[4]}; //Bottom face
344
345 for (auto& lw_face : lw_faces) cell.faces.push_back(lw_face);
346 }
347 else
348 throw std::runtime_error(fname + ": Unsupported cell type");
349
350 }//for elements
351
352 file.close();
353
354 //======================================== Remap material-ids
355 std::set<int> material_ids_set_as_read;
356 std::map<int,int> material_mapping;
357
358 for (auto& cell : raw_cells_)
359 material_ids_set_as_read.insert(cell->material_id);
360
361 std::set<int> boundary_ids_set_as_read;
362 std::map<int,int> boundary_mapping;
363
364 for (auto& cell : raw_boundary_cells_)
365 boundary_ids_set_as_read.insert(cell->material_id);
366
367 {
368 int m=0;
369 for (const auto& mat_id : material_ids_set_as_read)
370 material_mapping.insert(std::make_pair(mat_id,m++));
371
372 int b=0;
373 for (const auto& bndry_id : boundary_ids_set_as_read)
374 boundary_mapping.insert(std::make_pair(bndry_id,b++));
375 }
376
377 for (auto& cell : raw_cells_)
378 cell->material_id = material_mapping[cell->material_id];
379
380 for (auto& cell : raw_boundary_cells_)
381 cell->material_id = boundary_mapping[cell->material_id];
382
383 //======================================== Always do this
385 if (not mesh_is_2D_assumption) dimension = DIMENSION_3;
386
387 attributes_ = dimension | UNSTRUCTURED;
388
391
392 Chi::log.Log() << "Done processing " << options.file_name << ".\n"
393 << "Number of nodes read: " << vertices_.size() << "\n"
394 << "Number of cells read: " << raw_cells_.size();
395}
396
397
398
static void Exit(int error_code)
Definition: chi_runtime.cc:342
static chi::ChiLog & log
Definition: chi_runtime.h:81
static chi::MPI_Info & mpi
Definition: chi_runtime.h:78
LogStream LogAllError()
Definition: chi_log.h:239
LogStream Log0Verbose2()
Definition: chi_log.h:235
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
void Barrier() const
Definition: mpi_info.cc:38
std::vector< chi_mesh::Vertex > vertices_
void ReadFromMsh(const Options &options)
std::vector< LightWeightCell * > raw_cells_
std::vector< LightWeightCell * > raw_boundary_cells_
CellType
Definition: cell.h:12
MeshAttributes
Definition: chi_mesh.h:70
@ UNSTRUCTURED
Definition: chi_mesh.h:77
@ DIMENSION_2
Definition: chi_mesh.h:73
@ DIMENSION_3
Definition: chi_mesh.h:74