PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
mesh.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2026 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 "mesh.h"
12#include "util/io.h"
13#include "inp/meshDeck.h"
14#include "inp/modelDeck.h"
15#include "fe/elemIncludes.h"
16#include "rw/reader.h"
17#include "util/feElementDefs.h"
18#include "util/function.h"
20#include "util/parallelUtil.h"
21#include <cstdint>
22#include <cstdlib>
23#include <iostream>
24#include <memory>
25#include <stdexcept>
26#include <taskflow/taskflow/taskflow.hpp>
27#include <taskflow/taskflow/algorithm/for_each.hpp>
28
29namespace mesh {
30
31Mesh::Mesh(size_t dim)
32 : d_numNodes(0), d_numElems(0), d_eType(1), d_eNumVertex(0), d_numDofs(0),
33 d_h(0.), d_dim(dim), d_encDataPopulated(false), d_needEncData(false),
34 d_nPart(0) {}
35
36Mesh::Mesh(const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
37 : d_numNodes(0), d_numElems(0), d_eType(1), d_eNumVertex(0), d_numDofs(0),
38 d_h(0.), d_dim(modelDeck->d_dim),
39 d_spatialDiscretization(modelDeck->d_spatialDiscretization),
40 d_filename(meshDeck->d_filename), d_encDataPopulated(false),
41 d_needEncData(modelDeck->d_populateElementNodeConnectivity),
42 d_nPart(0) {
43
44 // perform check on input data
45 if (d_spatialDiscretization != "finite_difference" and
46 d_spatialDiscretization != "weak_finite_element" and
47 d_spatialDiscretization != "nodal_finite_element" and
48 d_spatialDiscretization != "truss_finite_element") {
49 throw std::runtime_error("Spatial discretization type " + d_spatialDiscretization + " not known. Check input data.");
50 }
51
52 if (d_dim < 0 or d_dim > 3) {
53 throw std::runtime_error(
55 << "Error: Check Dimension in input data.\n");
56 }
57
58 if (d_filename.empty()) {
59 throw std::runtime_error(
61 << "Error: Filename for mesh data not specified.\n");
62 }
63
64 // read mesh data from file
66}
67
68//
69// Utility functions
70//
71void Mesh::createData(const std::string &filename, bool ref_config) {
72
73 util::io::log("Mesh: Reading element data.\n");
74
75 int file_type = -1;
76 // find the extension of file and call correct reader
77 if (util::io::getExtensionFromFile(filename) == "csv")
78 file_type = 0;
79 else if (util::io::getExtensionFromFile(filename) == "msh")
80 file_type = 1;
81 else if (util::io::getExtensionFromFile(filename) == "vtu")
82 file_type = 2;
83 else {
84 throw std::runtime_error(
86 << "Error: Currently only '.csv', '.msg', and '.vtu' "
87 "files are supported for reading mesh.\n");
88 }
89
90 if (d_spatialDiscretization != "finite_difference" and file_type == 0) {
91
92 throw std::runtime_error(
94 << "Error: For discretization = " << d_spatialDiscretization
95 << " .vtu or .msh mesh file is required.\n");
96 }
97
98 //
99 bool is_fd = false;
100 if (d_spatialDiscretization == "finite_difference")
101 is_fd = true;
102
103 // read node and elements
104 if (file_type == 0)
106 else if (file_type == 1) {
108 &d_enc, &d_nec, &d_vol, false);
109 d_encDataPopulated = true;
110 }
111 else if (file_type == 2) {
112 //
113 // old reading of mesh
114 //
115 // rw::reader::readVtuFile(filename, d_dim, &d_nodes, d_eType, d_numElems,
116 // &d_enc, &d_nec, &d_vol, false);
117
118 //
119 // new reading of mesh
120 // We read the data from file one by one depending on what data we need
121 //
122
123 // read node
124 rw::reader::readVtuFileNodes(filename, d_dim, &d_nodes, ref_config);
125
126 // read volume if required
127 bool found_volume_data = false;
128 if (is_fd) {
129 found_volume_data =
130 rw::reader::readVtuFilePointData(filename, "Node_Volume", &d_vol);
131
132 // try another tag for nodal volume
133 if (!found_volume_data)
134 found_volume_data =
135 rw::reader::readVtuFilePointData(filename, "Volume", &d_vol);
136 }
137
138 // read element data (only if this is fe simulation or if we need
139 // element-node connectivity data for nodal volume calculation)
140 if (!is_fd || !found_volume_data) {
142 &d_nec);
143 d_encDataPopulated = true;
144 }
145
146 // check if file has fixity data
147 rw::reader::readVtuFilePointData(filename, "Fixity", &d_fix);
148 }
149
150 // compute data from mesh data
151 d_numNodes = d_nodes.size();
154
155 //
156 // assign default values to fixity
157 //
158 if (d_fix.size() != d_numNodes)
159 d_fix = std::vector<uint8_t>(d_nodes.size(), uint8_t(0));
160
161 //
162 // compute nodal volume if required
163 //
164 bool compute_vol = false;
165 if (is_fd and d_vol.empty()) compute_vol = true;
166
167 // if this is weak finite element simulation then check from policy if
168 // volume is to be computed
169 if (d_spatialDiscretization == "weak_finite_element")
170 compute_vol = false;
171
173 compute_vol, std::string("mesh filename = ") + filename);
174}
175
176void Mesh::loadFromTriangleElements2D(std::vector<util::Point> nodes,
177 std::vector<size_t> enc,
178 const inp::MeshDeck *meshDeck,
179 const inp::ModelDeck *modelDeck) {
180
181 if (enc.size() % 3 != 0)
182 throw std::runtime_error(
183 "Mesh::loadFromTriangleElements2D: connectivity length must be a multiple of 3.");
184
185 d_nodes = std::move(nodes);
186 d_enc = std::move(enc);
188 d_numNodes = d_nodes.size();
189 d_eNumVertex = 3;
190 d_numElems = d_enc.size() / 3;
191 d_dim = modelDeck->d_dim;
193 d_filename = meshDeck->d_filename;
195 d_encDataPopulated = true;
196 d_fix.assign(d_numNodes, 0);
197 d_vol.clear();
198
199 d_nec.assign(d_numNodes, {});
200 for (size_t e = 0; e < d_numElems; ++e) {
201 for (unsigned k = 0; k < 3; ++k) {
202 size_t nid = d_enc[3 * e + k];
203 d_nec[nid].push_back(e);
204 }
205 }
206
208
210 d_spatialDiscretization == "finite_difference",
211 "(in-memory triangle mesh)");
212}
213
214void Mesh::loadFromTetraElements3D(std::vector<util::Point> nodes,
215 std::vector<size_t> enc,
216 const inp::MeshDeck *meshDeck,
217 const inp::ModelDeck *modelDeck) {
218
219 if (enc.size() % 4 != 0)
220 throw std::runtime_error(
221 "Mesh::loadFromTetraElements3D: connectivity length must be a multiple of 4.");
222
223 d_nodes = std::move(nodes);
224 d_enc = std::move(enc);
226 d_numNodes = d_nodes.size();
227 d_eNumVertex = 4;
228 d_numElems = d_enc.size() / 4;
229 d_dim = modelDeck->d_dim;
231 d_filename = meshDeck->d_filename;
233 d_encDataPopulated = true;
234 d_fix.assign(d_numNodes, 0);
235 d_vol.clear();
236
237 d_nec.assign(d_numNodes, {});
238 for (size_t e = 0; e < d_numElems; ++e) {
239 for (unsigned k = 0; k < 4; ++k) {
240 size_t nid = d_enc[4 * e + k];
241 d_nec[nid].push_back(e);
242 }
243 }
244
246
248 d_spatialDiscretization == "finite_difference",
249 "(in-memory tetrahedron mesh)");
250}
251
253 bool compute_vol_from_elements, const std::string &volume_error_note) {
254
256 computeBBox();
257 if (compute_vol_from_elements) {
258 util::io::log("Mesh: Computing nodal volume.\n");
259 computeVol();
260 }
261
263
264 size_t counter = 0;
265 for (const auto &v : d_vol) {
266
267 if (v < 0.01 * std::pow(d_h, d_dim)) {
268
269 std::cerr << "Error: Check nodal volume " << v
270 << " is less than " << 0.01 * std::pow(d_h, d_dim)
271 << ", Node = " << counter << " at position = "
272 << d_nodes[counter].printStr() << "\n";
273 if (!volume_error_note.empty())
274 std::cerr << volume_error_note << "\n";
275 throw std::runtime_error(
277 << printStr() << "\n");
278 }
279
280 counter++;
281 }
282
283 if (d_needEncData and (!d_encDataPopulated or d_enc.empty()))
285}
286
287bool Mesh::readElementData(const std::string &filename) {
288
289 if (d_encDataPopulated and !d_enc.empty()) {
290 util::io::log("Mesh: Element data is populated already.\n");
291 return false;
292 }
293
294 util::io::log("Mesh: Reading element-node connectivity data.\n");
295
296 int file_type = -1;
297 // find the extension of file and call correct reader
298 if (util::io::getExtensionFromFile(filename) == "csv")
299 file_type = 0;
300 else if (util::io::getExtensionFromFile(filename) == "msh")
301 file_type = 1;
302 else if (util::io::getExtensionFromFile(filename) == "vtu")
303 file_type = 2;
304 else {
305 throw std::runtime_error(
307 << "Error: Currently only '.csv', '.msg', and '.vtu' "
308 "files are supported for reading mesh.\n");
309 }
310
311 if (file_type == 0) {
312 throw std::runtime_error(
314 << "Error: readElementData() requires file to be either "
315 ".vtu or .msh mesh file.\n");
316 }
317
318 if (file_type == 1) {
320 &d_enc,
321 &d_nec);
322 d_encDataPopulated = true;
323 // createData() may have skipped cells when Node_Volume was present, leaving
324 // d_eNumVertex from the default element type (1). Refresh after cell read.
326 return true;
327 }
328 else if (file_type == 2) {
330 &d_enc,
331 &d_nec);
332 d_encDataPopulated = true;
334 return true;
335 }
336
337 return false;
338}
339
341
342 auto quads = fe::elem(d_eType, 2);
343 auto *quads_p = quads.get();
344
345 // check if we have valid element-node connectivity data for nodal volume
346 // calculations
347 if (d_nec.size() != d_numNodes || d_enc.empty()) {
348 throw std::runtime_error(
350 << "Error: Can not compute nodal volume for given finite "
351 "element mesh as the element-node connectivity data is "
352 "invalid."
353 << std::endl);
354 }
355
356 if (false) {
357 print(0, 0);
358 std::cout << "\n-------- Node data ----------\n";
359 std::cout << util::io::printStr(d_nodes, 0) << "\n";
360 std::cout << "\n-------- Element data ----------\n";
361 std::cout << util::io::printStr(d_enc, 0) << "\n";
362 }
363
364 //
365 // compute nodal volume
366 //
367 d_vol.resize(d_numNodes);
368
369 tf::Executor executor(util::parallel::getNThreads());
370 tf::Taskflow taskflow;
371
372 taskflow.for_each_index(
373 (std::size_t) 0, this->d_numNodes, (std::size_t) 1, [this, quads_p](std::size_t i) {
374 double v = 0.0;
375
376 for (auto e : this->d_nec[i]) {
377
378 std::vector<size_t> e_ns = this->getElementConnectivity(e);
379
380 // locate global node i in local list of element el
381 int loc_i = -1;
382 for (size_t l = 0; l < e_ns.size(); l++)
383 if (e_ns[l] == i)
384 loc_i = l;
385
386 if (loc_i == -1) {
387 throw std::runtime_error(
389 << "Error: Check node element connectivity.\n");
390 }
391
392 // get quad data
393 std::vector<util::Point> e_nodes;
394 for (auto k : e_ns)
395 e_nodes.emplace_back(this->d_nodes[k]);
396
397 // get volume of element
398 double vol = quads_p->elemSize(e_nodes);
399 double factor = 1.;
400 if (vol < 0.)
401 factor = -1.;
402
403 std::vector<fe::QuadData> qds = quads_p->getQuadDatas(e_nodes);
404
405 // compute V_e and add it to volume
406 for (auto qd : qds)
407 v += qd.d_shapes[loc_i] * factor * qd.d_w;
408 } // loop over elements
409
410 // update
411 this->d_vol[i] = v;
412 }
413 ); // for_each
414
415 executor.run(taskflow).get();
416}
417
419 if (d_dim != 2)
420 return;
421 for (auto &p : d_nodes)
422 p.d_z = 0.;
423}
424
426 std::vector<double> p1(3,0.);
427 std::vector<double> p2(3,0.);
428 for (const auto& x : d_nodes) {
429 if (util::isLess(x.d_x, p1[0]))
430 p1[0] = x.d_x;
431 if (util::isLess(x.d_y, p1[1]))
432 p1[1] = x.d_y;
433 if (util::isLess(x.d_z, p1[2]))
434 p1[2] = x.d_z;
435 if (util::isLess(p2[0], x.d_x))
436 p2[0] = x.d_x;
437 if (util::isLess(p2[1], x.d_y))
438 p2[1] = x.d_y;
439 if (util::isLess(p2[2], x.d_z))
440 p2[2] = x.d_z;
441 }
442
443 d_bbox = std::make_pair(p1, p2);
444}
445
447
448 double guess = 0.;
449 if (d_nodes.size() < 2) {
450 d_h = 0.;
451 return;
452 }
453
454 guess = (d_nodes[0] - d_nodes[1]).length();
455 for (size_t i = 0; i < d_nodes.size(); i++)
456 for (size_t j = 0; j < d_nodes.size(); j++)
457 if (i != j) {
458 double val = d_nodes[i].dist(d_nodes[j]);
459
460 if (util::isLess(val, 1.0E-12)) {
461
462 std::cout << "Check nodes are too close = "
463 << util::io::printStr<util::Point>({d_nodes[i],
464 d_nodes[j]})
465 << "\n";
466 std::cout << "Distance = " << val << ", guess = " << guess << "\n";
467 }
468 if (util::isLess(val, guess))
469 guess = val;
470 }
471
472 d_h = guess;
473}
474
475//
476// Setter functions
477//
478void Mesh::setFixity(const size_t &i, const unsigned int &dof,
479 const bool &flag) {
480
481 // to set i^th bit as true of integer a,
482 // a |= 1UL << (i % 8)
483
484 // to set i^th bit as false of integer a,
485 // a &= ~(1UL << (i % 8))
486
487 flag ? (d_fix[i] |= 1UL << dof) : (d_fix[i] &= ~(1UL << dof));
488}
490 if (!d_enc.empty())
491 d_enc.shrink_to_fit();
492 d_numElems = 0;
493 if (!d_nec.empty())
494 d_nec.shrink_to_fit();
495}
496
497std::string Mesh::printStr(int nt, int lvl) const {
498
499 auto tabS = util::io::getTabS(nt);
500 std::ostringstream oss;
501 oss << tabS << "------- Mesh --------" << std::endl << std::endl;
502 oss << tabS << "Dimension = " << d_dim << std::endl;
503 oss << tabS << "Spatial discretization type = " << d_spatialDiscretization << std::endl;
504 oss << tabS << "Mesh size = " << d_h << std::endl;
505 oss << tabS << "Num nodes = " << d_numNodes << std::endl;
506 oss << tabS << "Num elements = " << d_numElems << std::endl;
507 oss << tabS << "Element type = " << d_eType << std::endl;
508 oss << tabS << "Num nodes per element = " << d_eNumVertex << std::endl;
509 oss << tabS << "Num nodal vol = " << d_vol.size() << std::endl;
510 oss << tabS << "Bounding box: " << std::endl;
511 oss << util::io::printBoxStr(d_bbox, nt + 1);
512 oss << tabS << std::endl;
513
514 return oss.str();
515}
516
517} // namespace mesh
std::vector< size_t > getElementConnectivity(const size_t &i) const
Get the connectivity of element.
Definition mesh.h:213
bool d_needEncData
Flag that indicates whether we need enc data (set by input mesh deck in constructor)
Definition mesh.h:512
void clearElementData()
Clear element-node connectivity data.
Definition mesh.cpp:489
std::string d_filename
Filename to read mesh data.
Definition mesh.h:509
std::string printStr(int nt=0, int lvl=0) const
Returns the string containing printable information about the object.
Definition mesh.cpp:497
std::vector< size_t > d_enc
Element-node connectivity data.
Definition mesh.h:443
Mesh(size_t dim=0)
Constructor.
Definition mesh.cpp:31
std::pair< std::vector< double >, std::vector< double > > d_bbox
Bounding box.
Definition mesh.h:541
std::vector< util::Point > d_nodes
Vector of initial (reference) coordinates of nodes.
Definition mesh.h:435
bool d_encDataPopulated
Flag that indicates whether element-node connectivity data is read from file.
Definition mesh.h:515
size_t d_numElems
Number of elements.
Definition mesh.h:406
bool readElementData(const std::string &filename)
Reads element-node connectivity data from file. This function is meant for cases when mesh was create...
Definition mesh.cpp:287
void computeMeshSize()
Compute the mesh size.
Definition mesh.cpp:446
size_t d_eType
Element type.
Definition mesh.h:417
size_t d_numNodes
Number of nodes.
Definition mesh.h:403
size_t d_dim
Dimension of the mesh.
Definition mesh.h:496
std::string d_spatialDiscretization
Tag for spatial discretization type.
Definition mesh.h:506
void finalizeMeshDerivedFieldsFromCurrentNodes(bool compute_vol_from_elements, const std::string &volume_error_note)
After nodes, enc, nec, and dof-related fields are set: 2D z clear, bbox, optional nodal volume,...
Definition mesh.cpp:252
void setZCoordinateZero()
For , set on all reference nodes (x–y plane). Call before computeBBox() when nodes may carry numeric...
Definition mesh.cpp:418
std::vector< uint8_t > d_fix
Vector of fixity mask of each node.
Definition mesh.h:459
size_t d_numDofs
Number of dofs = (dimension) times (number of nodes)
Definition mesh.h:518
void setFixity(const size_t &i, const unsigned int &dof, const bool &flag)
Set the fixity to free (0) or fixed (1)
Definition mesh.cpp:478
void computeVol()
Compute the nodal volume.
Definition mesh.cpp:340
std::vector< double > d_vol
Vector of volume of each node.
Definition mesh.h:467
void loadFromTetraElements3D(std::vector< util::Point > nodes, std::vector< size_t > enc, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
Populate mesh from 3D tetrahedron data (0-based node indices in enc) without reading a file.
Definition mesh.cpp:214
void loadFromTriangleElements2D(std::vector< util::Point > nodes, std::vector< size_t > enc, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
Populate mesh from 2D triangle data (0-based node indices in enc) without reading a file.
Definition mesh.cpp:176
void computeBBox()
Compute the bounding box from d_nodes (after setZCoordinateZero() for 2D if applicable).
Definition mesh.cpp:425
size_t d_eNumVertex
Number of vertex per element.
Definition mesh.h:432
void print(int nt=0, int lvl=0) const
Prints the information about the object.
Definition mesh.h:309
void createData(const std::string &filename, bool ref_config=false)
Reads mesh data from the file and populates other data.
Definition mesh.cpp:71
std::vector< std::vector< size_t > > d_nec
Node-element connectivity data.
Definition mesh.h:449
double d_h
Characteristic mesh spacing (minimum nodal distance); always from computeMeshSize() after nodes exist...
Definition mesh.h:544
Collects a message with stream syntax for use in an exception.
Definition io.h:52
static int vtk_map_element_to_num_nodes[16]
Map from element type to number of nodes (for vtk)
static const int vtk_type_triangle
Integer flag for triangle element.
static const int vtk_type_tetra
Integer flag for tetrahedron element.
std::unique_ptr< BaseElem > elem(size_t type, size_t order)
Collection of methods and data related to finite element and mesh.
Definition mesh.cpp:29
void readVtuFileCells(const std::string &filename, size_t dim, size_t &element_type, size_t &num_elem, std::vector< size_t > *enc, std::vector< std::vector< size_t > > *nec)
Reads cell data, i.e. element-node connectivity and node-element connectivity.
Definition reader.cpp:172
void readMshFileCells(const std::string &filename, size_t dim, size_t &element_type, size_t &num_elem, std::vector< size_t > *enc, std::vector< std::vector< size_t > > *nec)
Reads cell data, i.e. element-node connectivity and node-element connectivity.
Definition reader.cpp:407
bool readVtuFilePointData(const std::string &filename, const std::string &tag, std::vector< uint8_t > *data)
Reads data of specified tag from the vtu file.
Definition reader.cpp:213
void readVtuFileNodes(const std::string &filename, size_t dim, std::vector< util::Point > *nodes, bool ref_config=false)
Reads nodal coordinates.
Definition reader.cpp:139
void readCsvFile(const std::string &filename, size_t dim, std::vector< util::Point > *nodes, std::vector< double > *volumes)
Reads mesh data into node file and element file.
Definition reader.cpp:18
void readMshFile(const std::string &filename, size_t dim, std::vector< util::Point > *nodes, size_t &element_type, size_t &num_elem, 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 reader.cpp:356
std::string printBoxStr(const std::pair< util::Point, util::Point > &box, int nt=print_default_tab)
Returns formatted string for output.
Definition io.h:231
std::string getTabS(int nt)
Returns tab spaces of a given size.
Definition io.h:82
std::string printStr(const T &msg, int nt=print_default_tab)
Returns formatted string for output.
Definition io.h:96
std::string getExtensionFromFile(std::string const &filename)
Get extension from the filename.
Definition io.h:351
void log(std::ostringstream &oss, bool screen_out=false, int printMpiRank=print_default_mpi_rank)
Global method to log the message.
Definition io.cpp:41
unsigned int getNThreads()
Get number of threads to be used by taskflow.
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:22
Structure to read and store mesh related input data.
Definition meshDeck.h:28
std::string d_filename
Filename to read mesh data.
Definition meshDeck.h:31
Structure to read and store model related input data.
Definition modelDeck.h:27
bool d_populateElementNodeConnectivity
Flag to indicate if we should populate element-node connectivity data in meshes.
Definition modelDeck.h:62
size_t d_dim
Dimension.
Definition modelDeck.h:108
std::string d_spatialDiscretization
Tag for spatial discretization.
Definition modelDeck.h:49