PeriDEM 0.2.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
mshReader.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2024 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE)
9 */
10
11#include "mshReader.h"
12#include "util/io.h"
13
14#include <fstream>
15#include <iostream>
16
17#include "util/feElementDefs.h"
18
19rw::reader::MshReader::MshReader(const std::string &filename)
20 : d_filename(filename){};
21
23 std::vector<util::Point> *nodes,
24 size_t &element_type, size_t &num_elems,
25 std::vector<size_t> *enc,
26 std::vector<std::vector<size_t>> *nec,
27 std::vector<double> *volumes, bool is_fd) {
28
29 if (util::io::isFileEmpty(d_filename)) {
30 std::cerr << "Error: Filename = " << d_filename <<
31 " in MshReader is either nonexistent or empty.\n";
32 exit(EXIT_FAILURE);
33 }
34
35 // open file
36 if (d_file) d_file.close();
37
38 d_file.open(d_filename);
39
40 if (!d_file) {
41 std::cerr << "Error: Can not open file = " << d_filename + ".msh"
42 << ".\n";
43 exit(1);
44 }
45
46 std::string line;
47 int format = 0;
48 int size = 0;
49 double version = 1.0;
50
51 // clear data
52 nodes->clear();
53 enc->clear();
54 nec->clear();
55 volumes->clear();
56
57 // specify type of element to read
58 if (dim != 2 and dim != 3) {
59 std::cerr << "Error: MshReader currently only supports reading of "
60 "triangle/quadrangle elements in dimension 2 and tetragonal "
61 "elements in 3.\n";
62 exit(1);
63 }
64
65 unsigned int num_nodes_con = 0;
66 bool read_nodes = false;
67 bool read_elements = false;
68
69 while (true) {
70 std::getline(d_file, line);
71 if (d_file) {
72 // // read $MeshFormat block
73 if (line.find("$MeshFormat") == static_cast<std::string::size_type>(0)) {
74 d_file >> version >> format >> size;
75 if ((version != 2.0) && (version != 2.1) && (version != 2.2)) {
76 std::cerr << "Error: Unknown .msh file version " << version << "\n";
77 exit(1);
78 }
79
80 // we only support reading of ascii format, so issue error if this
81 // condition is not met
82 if (format) {
83 std::cerr << "Error: Format of .msh is possibly binary which is not"
84 " supported currently.\n ";
85 exit(1);
86 }
87 }
88 // read $Nodes block
89 if (line.find("$NOD") == static_cast<std::string::size_type>(0) ||
90 line.find("$NOE") == static_cast<std::string::size_type>(0) ||
91 line.find("$Nodes") == static_cast<std::string::size_type>(0)) {
92 read_nodes = true;
93 unsigned int num_nodes = 0;
94 d_file >> num_nodes;
95
96 // allocate space
97 nodes->resize(num_nodes);
98 nec->resize(num_nodes);
99
100 // read in the nodal coordinates and form points.
101 double x, y, z;
102 unsigned int id;
103
104 // add the nodal coordinates to the d_file
105 for (unsigned int i = 0; i < num_nodes; ++i) {
106 d_file >> id >> x >> y >> z;
107 (*nodes)[id - 1] = util::Point(x, y, z);
108 }
109 // read the $ENDNOD delimiter
110 std::getline(d_file, line);
111 } // end of reading nodes
112 // Read the element block
113 else if (line.find("$ELM") == static_cast<std::string::size_type>(0) ||
114 line.find("$Elements") ==
115 static_cast<std::string::size_type>(0)) {
116 read_elements = true;
117
118 // For reading the number of elements and the node ids from the stream
119 unsigned int num_elem = 0;
120 unsigned int node_id = 0;
121
122 // read how many elements are there
123 // this includes point element, line element also
124 d_file >> num_elem;
125
126 // As of version 2.2, the format for each element line is:
127 // elm-number elm-type number-of-tags < tag > ... node-number-list
128
129 // read the elements
130 size_t elem_counter = 0;
131 bool found_tri = false;
132 bool found_quad = false;
133 bool found_tet = false;
134 for (unsigned int iel = 0; iel < num_elem; ++iel) {
135 unsigned int id;
136 unsigned int type;
137 unsigned int ntags;
138 int tag;
139 d_file >> id >> type >> ntags;
140 for (unsigned int j = 0; j < ntags; j++) d_file >> tag;
141
142 // we will read only those elements which we support
143 bool read_this_element = false;
144
145 // read element type we desire and for other element type
146 // perform dummy read
147 if (type == util::msh_type_triangle and dim == 2) {
148 read_this_element = true;
149 found_tri = true;
150 element_type = util::vtk_type_triangle;
151 num_nodes_con =
153 } else if (type == util::msh_type_quadrangle and dim == 2) {
154 read_this_element = true;
155 found_quad = true;
156 element_type = util::vtk_type_quad;
157 num_nodes_con =
159 } else if (type == util::msh_type_tetrahedron and dim == 3) {
160 read_this_element = true;
161 found_tet = true;
162 element_type = util::vtk_type_tetra;
163 num_nodes_con =
165 }
166
167 // std::vector<size_t> e_nodes;
168 if (read_this_element) {
169 // read vertex of this element
170 for (unsigned int i = 0; i < num_nodes_con; i++) {
171 d_file >> node_id;
172 // add to the element-node connectivity
173 // substract 1 to correct the numbering convention
174 enc->push_back(node_id - 1);
175
176 // e_nodes.push_back(node_id - 1);
177
178 // fill the node-element connectivity table
179 (*nec)[node_id - 1].push_back(elem_counter);
180 }
181
182 // debug
183 // std::cout << "(" << id << ", " << type << ", " << elem_counter
184 // << ") = ";
185 // for (auto enode: e_nodes)
186 // std::cout << enode << ";";
187 // std::cout << "\n";
188
189 // increment the element counter
190 elem_counter++;
191 } else {
192 // these are the type of elements we need to ignore.
193 size_t n = util::msh_map_element_to_num_nodes[type];
194 // dummy read
195 for (unsigned int i = 0; i < n; i++) d_file >> node_id;
196 }
197 } // element loop
198
199 // check if mesh contains both triangle and quadrangle elements
200 if (found_quad and found_tri) {
201 std::cerr << "Error: Check mesh file. It appears to have both "
202 "quadrangle elements and triangle elements. "
203 "Currently we only support one kind of elements.\n";
204 exit(1);
205 }
206
207 // write the number of elements
208 num_elems = elem_counter;
209
210 // read the $ENDELM delimiter
211 std::getline(d_file, line);
212 } // end of reading elements
213 } // if d_file
214
215 // If !d_file, check to see if EOF was set. If so, break out
216 // of while loop.
217 if (d_file.eof()) break;
218
219 if (read_nodes and read_elements) break;
220
221 // If !d_file and !d_file.eof(), stream is in a bad state!
222 // std::cerr<<"Error: Stream is bad! Perhaps the file does not exist?\n";
223 // exit(1);
224 } // while true
225
226 // close file
227 d_file.close();
228}
229
230void rw::reader::MshReader::readNodes(std::vector<util::Point> *nodes) {
231
232 if (util::io::isFileEmpty(d_filename)) {
233 std::cerr << "Error: Filename = " << d_filename <<
234 " in MshReader is either nonexistent or empty.\n";
235 exit(EXIT_FAILURE);
236 }
237
238 // open file
239 if (d_file) d_file.close();
240
241 d_file.open(d_filename);
242
243 if (!d_file) {
244 std::cerr << "Error: Can not open file = " << d_filename + ".msh.\n";
245 exit(1);
246 }
247
248 std::string line;
249 int format = 0;
250 int size = 0;
251 double version = 1.0;
252
253 // clear data
254 nodes->clear();
255 bool read_nodes = false;
256
257 while (true) {
258 std::getline(d_file, line);
259 if (d_file) {
260 // // read $MeshFormat block
261 if (line.find("$MeshFormat") == static_cast<std::string::size_type>(0)) {
262 d_file >> version >> format >> size;
263 if ((version != 2.0) && (version != 2.1) && (version != 2.2)) {
264 std::cerr << "Error: Unknown .msh file version " << version << "\n";
265 exit(1);
266 }
267
268 // we only support reading of ascii format, so issue error if this
269 // condition is not met
270 if (format) {
271 std::cerr << "Error: Format of .msh is possibly binary which is not"
272 " supported currently.\n ";
273 exit(1);
274 }
275 }
276 // read $Nodes block
277 if (line.find("$NOD") == static_cast<std::string::size_type>(0) ||
278 line.find("$NOE") == static_cast<std::string::size_type>(0) ||
279 line.find("$Nodes") == static_cast<std::string::size_type>(0)) {
280 read_nodes = true;
281 unsigned int num_nodes = 0;
282 d_file >> num_nodes;
283
284 // allocate space
285 nodes->resize(num_nodes);
286
287 // read in the nodal coordinates and form points.
288 double x, y, z;
289 unsigned int id;
290
291 // add the nodal coordinates to the d_file
292 for (unsigned int i = 0; i < num_nodes; ++i) {
293 d_file >> id >> x >> y >> z;
294 (*nodes)[id - 1] = util::Point(x, y, z);
295 }
296 // read the $ENDNOD delimiter
297 std::getline(d_file, line);
298 } // end of reading nodes
299 } // if d_file
300
301 // If !d_file, check to see if EOF was set. If so, break out
302 // of while loop.
303 if (d_file.eof()) break;
304
305 if (read_nodes) break;
306
307 // If !d_file and !d_file.eof(), stream is in a bad state!
308 // std::cerr<<"Error: Stream is bad! Perhaps the file does not exist?\n";
309 // exit(1);
310 } // while true
311
312 // close file
313 d_file.close();
314}
315
316void rw::reader::MshReader::readCells(size_t dim, size_t &element_type,
317 size_t &num_elems, std::vector<size_t> *enc,
318 std::vector<std::vector<size_t>> *nec) {
319
320 if (util::io::isFileEmpty(d_filename)) {
321 std::cerr << "Error: Filename = " << d_filename <<
322 " in MshReader is either nonexistent or empty.\n";
323 exit(EXIT_FAILURE);
324 }
325
326 // open file
327 if (d_file) d_file.close();
328
329 d_file.open(d_filename);
330
331 if (!d_file) {
332 std::cerr << "Error: Can not open file = " << d_filename + ".msh"
333 << ".\n";
334 exit(1);
335 }
336
337 std::string line;
338 int format = 0;
339 int size = 0;
340 double version = 1.0;
341
342 // clear data
343 enc->clear();
344 nec->clear();
345
346 // specify type of element to read
347 if (dim != 2 and dim != 3) {
348 std::cerr << "Error: MshReader currently only supports reading of "
349 "triangle/quadrangle elements in dimension 2 and tetragonal "
350 "elements in 3.\n";
351 exit(1);
352 }
353
354 unsigned int num_nodes_con = 0;
355 bool read_elements = false;
356
357 while (true) {
358 std::getline(d_file, line);
359 if (d_file) {
360 // // read $MeshFormat block
361 if (line.find("$MeshFormat") == static_cast<std::string::size_type>(0)) {
362 d_file >> version >> format >> size;
363 if ((version != 2.0) && (version != 2.1) && (version != 2.2)) {
364 std::cerr << "Error: Unknown .msh file version " << version << "\n";
365 exit(1);
366 }
367
368 // we only support reading of ascii format, so issue error if this
369 // condition is not met
370 if (format) {
371 std::cerr << "Error: Format of .msh is possibly binary which is not"
372 " supported currently.\n ";
373 exit(1);
374 }
375 }
376 // Read the element block
377 if (line.find("$ELM") == static_cast<std::string::size_type>(0) ||
378 line.find("$Elements") ==
379 static_cast<std::string::size_type>(0)) {
380 read_elements = true;
381
382 // For reading the number of elements and the node ids from the stream
383 unsigned int num_elem = 0;
384 unsigned int node_id = 0;
385
386 // read how many elements are there
387 // this includes point element, line element also
388 d_file >> num_elem;
389
390 // As of version 2.2, the format for each element line is:
391 // elm-number elm-type number-of-tags < tag > ... node-number-list
392
393 // read the elements
394 size_t elem_counter = 0;
395 bool found_tri = false;
396 bool found_quad = false;
397 bool found_tet = false;
398 for (unsigned int iel = 0; iel < num_elem; ++iel) {
399 unsigned int id;
400 unsigned int type;
401 unsigned int ntags;
402 int tag;
403 d_file >> id >> type >> ntags;
404 for (unsigned int j = 0; j < ntags; j++) d_file >> tag;
405
406 // we will read only those elements which we support
407 bool read_this_element = false;
408
409 // read element type we desire and for other element type
410 // perform dummy read
411 if (type == util::msh_type_triangle and dim == 2) {
412 read_this_element = true;
413 found_tri = true;
414 element_type = util::vtk_type_triangle;
415 num_nodes_con =
417 } else if (type == util::msh_type_quadrangle and dim == 2) {
418 read_this_element = true;
419 found_quad = true;
420 element_type = util::vtk_type_quad;
421 num_nodes_con =
423 } else if (type == util::msh_type_tetrahedron and dim == 3) {
424 read_this_element = true;
425 found_tet = true;
426 element_type = util::vtk_type_tetra;
427 num_nodes_con =
429 }
430
431 // std::vector<size_t> e_nodes;
432 if (read_this_element) {
433 // read vertex of this element
434 for (unsigned int i = 0; i < num_nodes_con; i++) {
435 d_file >> node_id;
436 // add to the element-node connectivity
437 // substract 1 to correct the numbering convention
438 enc->push_back(node_id - 1);
439
440 // fill the node-element connectivity table
441 (*nec)[node_id - 1].push_back(elem_counter);
442 }
443
444 // increment the element counter
445 elem_counter++;
446 } else {
447 // these are the type of elements we need to ignore.
448 size_t n = util::msh_map_element_to_num_nodes[type];
449 // dummy read
450 for (unsigned int i = 0; i < n; i++) d_file >> node_id;
451 }
452 } // element loop
453
454 // check if mesh contains both triangle and quadrangle elements
455 if (found_quad and found_tri) {
456 std::cerr << "Error: Check mesh file. It appears to have both "
457 "quadrangle elements and triangle elements. "
458 "Currently we only support one kind of elements.\n";
459 exit(1);
460 }
461
462 // write the number of elements
463 num_elems = elem_counter;
464
465 // read the $ENDELM delimiter
466 std::getline(d_file, line);
467 } // end of reading elements
468 } // if d_file
469
470 // If !d_file, check to see if EOF was set. If so, break out
471 // of while loop.
472 if (d_file.eof()) break;
473
474 if (read_elements) break;
475 } // while true
476
477 // close file
478 d_file.close();
479}
480
481bool rw::reader::MshReader::readPointData(const std::string &name,
482 std::vector<util::Point> *data) {
483 // open file
484 if (!d_file) d_file = std::ifstream(d_filename);
485
486 if (!d_file)
487 if (!d_file) {
488 std::cerr << "Error: Can not open file = " << d_filename + ".msh"
489 << ".\n";
490 exit(1);
491 }
492
493 bool found_data = false;
494 std::string line;
495 while (true) {
496 std::getline(d_file, line);
497 if (d_file) {
498 // read $Nodes block
499 if (line.find("$NodeData") == static_cast<std::string::size_type>(0)) {
500 // get name of data
501 int num_tags = 0;
502 d_file >> num_tags;
503 std::string tag[num_tags];
504 for (size_t i = 0; i < num_tags; i++) d_file >> tag[i];
505
506 // read dummy data
507 d_file >> num_tags;
508 double real_tag = 0.;
509 d_file >> real_tag;
510
511 int tag_number = 0;
512 int field_type = 0;
513 int num_data = 0;
514 d_file >> tag_number >> field_type >> num_data;
515
516 // check we found the data
517 if (tag[0] == name) {
518 // check if data is of desired field type
519 if (field_type != 3) {
520 std::cerr << "Error: Data " << tag[0] << " is of type "
521 << field_type << " but we expect it to be of type " << 3
522 << ".\n";
523 exit(1);
524 }
525
526 found_data = true;
527 data->resize(num_data);
528 }
529
530 // we read through the data irrespective of we found it or not
531 for (size_t i = 0; i < num_data; i++) {
532 double d[field_type];
533 for (size_t j = 0; j < field_type; j++) d_file >> d[j];
534
535 if (found_data) (*data)[i] = util::Point(d[0], d[1], d[2]);
536 }
537 // read the end of data block
538 std::getline(d_file, line);
539 } // end of reading nodes
540 } // if d_file
541
542 if (found_data) break;
543
544 // If !d_file, check to see if EOF was set. If so, break out
545 // of while loop.
546 if (d_file.eof()) break;
547 } // while true
548
549 d_file.close();
550 return found_data;
551}
552
553bool rw::reader::MshReader::readPointData(const std::string &name,
554 std::vector<double> *data) {
555 // open file
556 if (!d_file) d_file = std::ifstream(d_filename);
557
558 if (!d_file)
559 if (!d_file) {
560 std::cerr << "Error: Can not open file = " << d_filename + ".msh"
561 << ".\n";
562 exit(1);
563 }
564
565 bool found_data = false;
566 std::string line;
567 while (true) {
568 std::getline(d_file, line);
569 if (d_file) {
570 // read $Nodes block
571 if (line.find("$NodeData") == static_cast<std::string::size_type>(0)) {
572 // get name of data
573 int num_tags = 0;
574 d_file >> num_tags;
575 std::string tag[num_tags];
576 for (size_t i = 0; i < num_tags; i++) d_file >> tag[i];
577
578 // read dummy data
579 d_file >> num_tags;
580 double real_tag = 0.;
581 d_file >> real_tag;
582
583 int tag_number = 0;
584 int field_type = 0;
585 int num_data = 0;
586 d_file >> tag_number >> field_type >> num_data;
587
588 // check we found the data
589 if (tag[0] == name) {
590 // check if data is of desired field type
591 if (field_type != 1) {
592 std::cerr << "Error: Data " << tag[0] << " is of type "
593 << field_type << " but we expect it to be of type " << 1
594 << ".\n";
595 exit(1);
596 }
597
598 found_data = true;
599 data->resize(num_data);
600 }
601
602 // we read through the data irrespective of we found it or not
603 for (size_t i = 0; i < num_data; i++) {
604 double d[field_type];
605 for (size_t j = 0; j < field_type; j++) d_file >> d[j];
606
607 if (found_data) (*data)[i] = d[0];
608 }
609 // read the end of data block
610 std::getline(d_file, line);
611 } // end of reading nodes
612 } // if d_file
613
614 if (found_data) break;
615
616 // If !d_file, check to see if EOF was set. If so, break out
617 // of while loop.
618 if (d_file.eof()) break;
619 } // while true
620
621 d_file.close();
622 return found_data;
623}
624
void readMesh(size_t dim, std::vector< util::Point > *nodes, size_t &element_type, size_t &num_elems, std::vector< size_t > *enc, std::vector< std::vector< size_t > > *nec, std::vector< double > *volumes, bool is_fd=false)
Reads mesh data into node file and element file.
Definition mshReader.cpp:22
void readCells(size_t dim, size_t &element_type, size_t &num_elems, std::vector< size_t > *enc, std::vector< std::vector< size_t > > *nec)
Reads cell data, i.e. element-node connectivity and node-element connectivity.
bool readPointData(const std::string &name, std::vector< util::Point > *data)
reads point data from .vtu file
void close()
Close the file.
MshReader(const std::string &filename)
Constructor.
Definition mshReader.cpp:19
void readNodes(std::vector< util::Point > *nodes)
Reads nodal position.
static const int msh_type_quadrangle
Integer flag for quadrangle element.
static const int vtk_type_triangle
Integer flag for triangle element.
static const int vtk_type_quad
Integer flag for quad element.
static const int vtk_type_tetra
Integer flag for tetrahedron element.
static int msh_map_element_to_num_nodes[16]
Map from element type to number of nodes (for msh)
static const int msh_type_triangle
Integer flag for triangle element.
static const int msh_type_tetrahedron
Integer flag for tetrahedron element.
bool isFileEmpty(std::string filename)
Check if file is empty or null.
Definition io.h:469
A structure to represent 3d vectors.
Definition point.h:30