PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
mesh Namespace Reference

Collection of methods and data related to finite element and mesh. More...

Data Structures

class  Mesh
 A class for mesh data. More...
 

Functions

void metisGraphPartition (std::string partitionMethod, const std::vector< std::vector< size_t > > &nodeNeighs, std::vector< size_t > &nodePartition, size_t nPartitions)
 Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes as vertices and edges given by node neighbors. Then the metis function is called to partition the graph into specified number of parts.
 
void metisGraphPartition (std::string partitionMethod, mesh::Mesh *mesh_p, const std::vector< std::vector< size_t > > &nodeNeighs, size_t nPartitions)
 Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes as vertices and edges given by node neighbors. Then the metis function is called to partition the graph into specified number of parts.
 
void metisGraphPartition (std::string partitionMethod, std::vector< std::vector< size_t > > &nodeNeighs, size_t nparts, std::vector< size_t > &epart, std::vector< size_t > &npart)
 
void metisGraphPartition (std::string partitionMethod, mesh::Mesh *mesh_p, size_t nparts)
 
void createUniformMesh (mesh::Mesh *mesh_p, size_t dim, std::pair< std::vector< double >, std::vector< double > > box, std::vector< size_t > nGrid)
 Creates uniform mesh for rectangle/cuboid domain.
 
void removeNodesInBoxes (mesh::Mesh *mesh_p, const std::vector< std::vector< double > > &boxes)
 Removes nodes lying inside any of the given axis-aligned boxes.
 
void getCurrentQuadPoints (const mesh::Mesh *mesh_p, const std::vector< util::Point > &xRef, const std::vector< util::Point > &u, std::vector< util::Point > &xQuadCur, size_t iNodeStart=0, size_t iQuadStart=0, size_t quadOrder=1)
 Get current location of quadrature points of elements in the mesh. This function expects mesh has element-node connectivity data.
 
void getStrainStress (const mesh::Mesh *mesh_p, const std::vector< util::Point > &xRef, const std::vector< util::Point > &u, bool isPlaneStrain, std::vector< util::SymMatrix3 > &strain, std::vector< util::SymMatrix3 > &stress, size_t iNodeStart=0, size_t iStrainStart=0, double nu=0., double lambda=0., double mu=0., bool computeStress=false, size_t quadOrder=1)
 Strain and stress at quadrature points in the mesh.
 
void getMaxShearStressAndLoc (const mesh::Mesh *mesh_p, const std::vector< util::Point > &xRef, const std::vector< util::Point > &u, const std::vector< util::SymMatrix3 > &stress, double &maxShearStress, util::Point &maxShearStressLocRef, util::Point &maxShearStressLocCur, size_t iNodeStart=0, size_t iStrainStart=0, size_t quadOrder=1)
 Get location where maximum of specified component of stress occurs in this particle.
 

Detailed Description

Collection of methods and data related to finite element and mesh.

This namespace groups the data and methods related to finite element methods such as quadrature points, finite elements, and also data and methods related to mesh such as nodal coordinates, element-node connectivity, etc.

Function Documentation

◆ createUniformMesh()

void mesh::createUniformMesh ( mesh::Mesh mesh_p,
size_t  dim,
std::pair< std::vector< double >, std::vector< double > >  box,
std::vector< size_t >  nGrid 
)

Creates uniform mesh for rectangle/cuboid domain.

Parameters
mesh_pPointer to already created possibly empty mesh object
dimDimension of the domain
boxSpecifies domain (e.g., rectangle/cuboid)
nGridGrid sizes in dim directions

Definition at line 62 of file meshUtil.cpp.

62 {
63
64 mesh_p->d_dim = dim;
65 if (nGrid.size() < dim or box.first.size() < dim or box.second.size() < dim) {
66 std::cerr << "createUniformMesh(): check nGrid or box arguments.\n";
67 exit(1);
68 }
69
70 if (dim == 1) {
71 mesh_p->d_bbox.first = std::vector<double>{box.first[0], 0., 0.};
72 mesh_p->d_bbox.second = std::vector<double>{box.second[0], 0., 0.};
73 mesh_p->d_numNodes = (nGrid[0] + 1);
74 mesh_p->d_numElems = nGrid[0];
76 } else if (dim == 2) {
77 mesh_p->d_bbox.first = std::vector<double>{box.first[0], box.first[1], 0.};
78 mesh_p->d_bbox.second = std::vector<double>{box.second[0], box.second[1], 0.};
79 mesh_p->d_numNodes = (nGrid[0] + 1) * (nGrid[1] + 1);
80 mesh_p->d_numElems = nGrid[0] * nGrid[1];
82 } else if (dim == 3) {
83 mesh_p->d_bbox.first = std::vector<double>{box.first[0], box.first[1], box.first[2]};
84 mesh_p->d_bbox.second = std::vector<double>{box.second[0], box.second[1], box.second[2]};
85 mesh_p->d_numNodes = (nGrid[0] + 1) * (nGrid[1] + 1) * (nGrid[2] + 1);
86 mesh_p->d_numElems = nGrid[0] * nGrid[1] * nGrid[2];
88 } else {
89 std::cerr << "createUniformMesh(): invalid dim = " << dim << " argument.\n";
90 exit(1);
91 }
92
94 mesh_p->d_numDofs = mesh_p->d_numNodes * mesh_p->d_dim;
95
96 // local nodal data
97 mesh_p->d_nodes.resize(mesh_p->d_numNodes);
98 mesh_p->d_enc.resize(mesh_p->d_numElems * mesh_p->d_eNumVertex);
99 mesh_p->d_fix = std::vector<uint8_t>(mesh_p->d_nodes.size(), uint8_t(0));
100 mesh_p->d_vol.resize(mesh_p->d_numNodes);
101
102 // create mesh data
103 std::vector<double> h;
104 double h_small = 0.;
105 for (size_t i=0; i<dim; i++) {
106 h.push_back((box.second[i] - box.first[i])/nGrid[i]);
107 if (i == 0)
108 h_small = h[0];
109 else
110 h_small = std::min(h_small, h[i]);
111 }
112
113 // set smallest h as mesh size
114 mesh_p->d_h = h_small;
115
116 if (dim == 1) {
117 // compute node positions
118 for (size_t i = 0; i <= nGrid[0]; i++) {
119 mesh_p->d_nodes[i] = util::Point(box.first[0] + double(i) * h[0], 0., 0.);
120 mesh_p->d_vol[i] = h[0];
121 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[i] *= 0.5;
122 } // loop over i
123
124 // compute element-node connectivity
125 for (size_t i = 0; i < nGrid[0]; i++) {
126 // element node connectivity
127 // TODO Check if ordering is conforming to the standard
128 mesh_p->d_enc[2 * i + 0] = i;
129 mesh_p->d_enc[2 * i + 1] = i + 1;
130 } // loop over i
131 } else if (dim == 2) {
132 // compute node positions
133 for (size_t j = 0; j <= nGrid[1]; j++) {
134 for (size_t i = 0; i <= nGrid[0]; i++) {
135 // node number
136 size_t n = j * (nGrid[0] + 1) + i;
137 mesh_p->d_nodes[n] = util::Point(box.first[0] + double(i) * h[0],
138 box.first[1] + double(j) * h[1], 0.);
139
140 mesh_p->d_vol[n] = h[0] * h[1];
141 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[n] *= 0.5;
142 if (j == 0 || j == nGrid[1]) mesh_p->d_vol[n] *= 0.5;
143 } // loop over i
144 } // loop over j
145
146 // compute element-node connectivity
147 for (size_t j = 0; j < nGrid[1]; j++) {
148 for (size_t i = 0; i < nGrid[0]; i++) {
149
150 // element number
151 auto n = j * nGrid[0] + i;
152
153 // element node connectivity (put it in anti clockwise order)
154 mesh_p->d_enc[4 * n + 0] = j * (nGrid[0] + 1) + i;
155 mesh_p->d_enc[4 * n + 1] = j * (nGrid[0] + 1) + i + 1;
156 mesh_p->d_enc[4 * n + 2] = (j + 1) * (nGrid[0] + 1) + i + 1;
157 mesh_p->d_enc[4 * n + 3] = (j + 1) * (nGrid[0] + 1) + i;
158 } // loop over i
159 } // loop over j
160 } else if (dim == 3) {
161 // compute node positions
162 for (size_t k = 0; k <= nGrid[2]; k++) {
163 for (size_t j = 0; j <= nGrid[1]; j++) {
164 for (size_t i = 0; i <= nGrid[0]; i++) {
165 // node number
166 size_t n = k * (nGrid[1] + 1) * (nGrid[0] + 1) + j * (nGrid[0] + 1) + i;
167 mesh_p->d_nodes[n] = util::Point(box.first[0] + double(i) * h[0],
168 box.first[1] + double(j) * h[1],
169 box.first[2] + double(k) * h[2]);
170
171 mesh_p->d_vol[n] = h[0] * h[1] * h[2];
172 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[n] *= 0.5;
173 if (j == 0 || j == nGrid[1]) mesh_p->d_vol[n] *= 0.5;
174 if (k == 0 || k == nGrid[2]) mesh_p->d_vol[n] *= 0.5;
175 } // loop over i
176 } // loop over j
177 } // loop over k
178
179 // compute element-node connectivity
180 // (k < nGrid[2]: there are nGrid[2] cells through the thickness, not
181 // nGrid[2]+1. Using <= overran d_enc and corrupted the heap.)
182 for (size_t k = 0; k < nGrid[2]; k++) {
183 for (size_t j = 0; j < nGrid[1]; j++) {
184 for (size_t i = 0; i < nGrid[0]; i++) {
185
186 // element number
187 auto n = k * nGrid[1] * nGrid[0] + j * nGrid[0] + i;
188
189 // element node connectivity
190 // TODO Check if ordering is conforming to the standard
191 mesh_p->d_enc[8 * n + 0] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
192 + j * (nGrid[0] + 1) + i;
193 mesh_p->d_enc[8 * n + 1] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
194 + j * (nGrid[0] + 1) + i + 1;
195 mesh_p->d_enc[8 * n + 2] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
196 + (j + 1) * (nGrid[0] + 1) + i + 1;
197 mesh_p->d_enc[8 * n + 3] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
198 + (j + 1) * (nGrid[0] + 1) + i;
199
200 mesh_p->d_enc[8 * n + 4] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
201 + j * (nGrid[0] + 1) + i;
202 mesh_p->d_enc[8 * n + 5] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
203 + j * (nGrid[0] + 1) + i + 1;
204 mesh_p->d_enc[8 * n + 6] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
205 + (j + 1) * (nGrid[0] + 1) + i + 1;
206 mesh_p->d_enc[8 * n + 7] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
207 + (j + 1) * (nGrid[0] + 1) + i;
208 } // loop over i
209 } // loop over j
210 } // loop over k
211 }
212}
std::vector< size_t > d_enc
Element-node connectivity data.
Definition mesh.h:443
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
size_t d_numElems
Number of elements.
Definition mesh.h:406
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::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
std::vector< double > d_vol
Vector of volume of each node.
Definition mesh.h:467
size_t d_eNumVertex
Number of vertex per element.
Definition mesh.h:432
double d_h
Characteristic mesh spacing (minimum nodal distance); always from computeMeshSize() after nodes exist...
Definition mesh.h:544
static int vtk_map_element_to_num_nodes[16]
Map from element type to number of nodes (for vtk)
static const int vtk_type_quad
Integer flag for quad element.
static const int vtk_type_hexahedron
Integer flag for hexahedron element.
static const int vtk_type_line
Integer flag for line element.
A structure to represent 3d vectors.
Definition point.h:30

References mesh::Mesh::d_bbox, mesh::Mesh::d_dim, mesh::Mesh::d_enc, mesh::Mesh::d_eNumVertex, mesh::Mesh::d_eType, mesh::Mesh::d_fix, mesh::Mesh::d_h, mesh::Mesh::d_nodes, mesh::Mesh::d_numDofs, mesh::Mesh::d_numElems, mesh::Mesh::d_numNodes, mesh::Mesh::d_vol, util::vtk_map_element_to_num_nodes, util::vtk_type_hexahedron, util::vtk_type_line, and util::vtk_type_quad.

Referenced by mesh_gen::createParticleMesh(), test::testGraphPartitioning(), and test::testMPI().

Here is the caller graph for this function:

◆ getCurrentQuadPoints()

void mesh::getCurrentQuadPoints ( const mesh::Mesh mesh_p,
const std::vector< util::Point > &  xRef,
const std::vector< util::Point > &  u,
std::vector< util::Point > &  xQuadCur,
size_t  iNodeStart = 0,
size_t  iQuadStart = 0,
size_t  quadOrder = 1 
)

Get current location of quadrature points of elements in the mesh. This function expects mesh has element-node connectivity data.

In case of multiple particles and meshes, xRef and u data will hold data for all meshes. If this is the case, iNodeStart integer can be used to specify from what index the data for a given mesh should be read. E.g., if we have two particles with their own mesh, and suppose particle 1 and 2 have n1 and n2 number nodes than

  1. xRef and u will be a vector of n1+n2 size
  2. For particle 1, node data in xRef and u starts from iNodeStart = 0
  3. For particle 2, node data in xRef and u starts from iNodeStart = n1

For the above example, suppose first particle has total nq1 number of quadrature points from all the elements in the mesh of particle 1 and second particle has total nq2 number of quadrature points. Then,

  1. xQuadCur will be of size nq1 + nq2
  2. For particle 1, quad data in xQuadCur starts from iQuadStart = 0
  3. For particle 2, quad data in xQuadCur starts from iQuadStart = nq2
Parameters
mesh_pPointer to already created possibly empty mesh object
xRefVector of reference coordinates of nodes
uVector of displacement of nodes
xQuadCurVector of current positions of quadrature points (this argument is modified)
iNodeStartAssume that nodal data in xRef and u starts from iNodeStart
iQuadStartAssume that quadrature data in xQuadCur starts from iNodeStart
quadOrderOrder of quadrature approximation (default is 1)

Definition at line 301 of file meshUtil.cpp.

307 {
308
309 size_t num_elems = mesh_p->getNumElements();
310
311 // check data
312 assert((num_elems != 0) && "Number of elements in the mesh is zero "
313 "possibly due to missing element-node "
314 "connectivity data. Can not proceed with "
315 "computation.\n");
316
317 assert(( (xRef.size() >= mesh_p->getNumNodes() + iNodeStart) ||
318 (u.size() >= mesh_p->getNumNodes() + iNodeStart)
319 ) &&
320 "Number of elements i nnodal data can not be smaller than number of "
321 "nodes.\n");
322
323 auto elem = fe::elem(mesh_p->getElementType(), quadOrder);
324
325 // get total number of quadrature points by getting the number of quad
326 // points in one element times the number of elements
327 size_t numQuadPointsTotal = mesh_p->getNumElements() *
328 elem->getNumQuadPoints();
329
330 assert((xQuadCur.size() >= numQuadPointsTotal + iQuadStart)
331 && "Number of elements in xQuad data can not be less than "
332 "total number of quadrature points.\n");
333
334
335 // compute current position of quad points
336 auto *elem_p = elem.get();
337 tf::Executor executor(util::parallel::getNThreads());
338 tf::Taskflow taskflow;
339 taskflow.for_each_index(
340 (std::size_t) 0, num_elems, (std::size_t) 1,
341 [elem_p, mesh_p, xRef, u, iNodeStart, iQuadStart, &xQuadCur]
342 (std::size_t e) {
343
344 auto id_nds = mesh_p->getElementConnectivity(e);
345 std::vector<util::Point> nds;
346 for (const auto &i : id_nds)
347 nds.push_back(xRef[i + iNodeStart]);
348
349 auto qds = elem_p->getQuadDatas(nds);
350
351 auto qd_point_current = util::Point();
352
353 for (size_t q=0; q<qds.size(); q++) {
354 qd_point_current = qds[q].d_p;
355 for (size_t i = 0; i < id_nds.size(); i++) {
356 auto i_global_id = iNodeStart + id_nds[i];
357 qd_point_current += u[i_global_id] * qds[q].d_shapes[i];
358 }
359
360 auto q_global_id = iQuadStart + e * elem_p->getNumQuadPoints() + q;
361 xQuadCur[q_global_id] = qd_point_current;
362 }
363 }
364 ); // for_each
365
366 executor.run(taskflow).get();
367}
std::vector< size_t > getElementConnectivity(const size_t &i) const
Get the connectivity of element.
Definition mesh.h:213
size_t getNumNodes() const
Get the number of nodes.
Definition mesh.h:91
size_t getElementType() const
Get the type of element in mesh.
Definition mesh.h:109
size_t getNumElements() const
Get the number of elements.
Definition mesh.h:97
std::unique_ptr< BaseElem > elem(size_t type, size_t order)
unsigned int getNThreads()
Get number of threads to be used by taskflow.

References fe::elem(), mesh::Mesh::getElementConnectivity(), mesh::Mesh::getElementType(), util::parallel::getNThreads(), mesh::Mesh::getNumElements(), and mesh::Mesh::getNumNodes().

Referenced by rw::writeOutput().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getMaxShearStressAndLoc()

void mesh::getMaxShearStressAndLoc ( const mesh::Mesh mesh_p,
const std::vector< util::Point > &  xRef,
const std::vector< util::Point > &  u,
const std::vector< util::SymMatrix3 > &  stress,
double &  maxShearStress,
util::Point maxShearStressLocRef,
util::Point maxShearStressLocCur,
size_t  iNodeStart = 0,
size_t  iStrainStart = 0,
size_t  quadOrder = 1 
)

Get location where maximum of specified component of stress occurs in this particle.

Parameters
mesh_pPointer to already created possibly empty mesh object
xRefVector of reference coordinates of nodes
uVector of displacement of nodes
stressVector of symmetric stress tensor
maxShearStressValue of maximum shear stress
maxShearStressLocRefLocation where this occurs (in reference configuration)
maxShearStressLocCurLocation where this occurs (in current configuration)
iNodeStartAssume that nodal data in xRef and u starts from iNodeStar
iStrainStartAssume that quadrature data in strain/stress starts from iNodeStart
quadOrderOrder of quadrature approximation (default is 1)

Definition at line 473 of file meshUtil.cpp.

482 {
483
484 assert((mesh_p->getDimension() == 2) && "In getMaxShearStressAndLoc(), only dimension = 2 is supported.\n");
485
486 size_t num_elems = mesh_p->getNumElements();
487
488 // check data
489 assert((num_elems != 0) && "Number of elements in the mesh is zero "
490 "possibly due to missing element-node "
491 "connectivity data. Can not proceed with "
492 "computation.\n");
493
494 assert(( (xRef.size() >= mesh_p->getNumNodes() + iNodeStart) ||
495 (u.size() >= mesh_p->getNumNodes() + iNodeStart)
496 ) &&
497 "Number of elements i nnodal data can not be smaller than number of "
498 "nodes.\n");
499
500 auto elem = fe::elem(mesh_p->getElementType(), quadOrder);
501
502 // get total number of quadrature points by getting the number of quad
503 // points in one element times the number of elements
504 size_t numQuadPointsTotal = mesh_p->getNumElements() *
505 elem->getNumQuadPoints();
506
507 assert((stress.size() >= numQuadPointsTotal + iStrainStart)
508 && "Number of elements in stress data can not be less than "
509 "total number of quadrature points.\n");
510
511 // compute principal shear stress
512 double max_stress = 0.;
513 size_t max_stress_e = 0;
514 size_t max_stress_q = 0;
515 for (size_t e = 0; e < num_elems; e++) {
516 for (size_t q=0; q<elem->getNumQuadPoints(); q++) {
517 auto q_global_id = iStrainStart + e * elem->getNumQuadPoints() + q;
518 const auto stress_e = stress[q_global_id];
519
520 const auto principle_shear_stress =
521 std::sqrt(0.25 * std::pow(stress_e.get(0) - stress_e.get(1), 2) +
522 std::pow(stress_e.get(5), 2));
523
524 if (util::isLess(max_stress, principle_shear_stress)) {
525 max_stress = principle_shear_stress;
526 max_stress_e = e;
527 max_stress_q = q;
528 }
529 }
530 }
531
532 // set data
533 maxShearStress = max_stress;
534
535 // now compute current and reference location of the quadrature point at which
536 // stress is maximum
537 {
538 // get ids of nodes of element and reference coordinate of nodes
539 auto id_nds = mesh_p->getElementConnectivity(max_stress_e);
540 auto e_nds_start = iNodeStart + mesh_p->d_eNumVertex * max_stress_e;
541 auto e_nds_end = e_nds_start + mesh_p->d_eNumVertex;
542 std::vector<util::Point> nds(xRef.begin() + e_nds_start, xRef.begin() + e_nds_end);
543
544 auto qds = elem->getQuadDatas(nds);
545 auto qd_point_current = qds[max_stress_q].d_p;
546 maxShearStressLocRef = qd_point_current;
547 for (size_t i = 0; i < id_nds.size(); i++) {
548 auto i_global_id = iNodeStart + id_nds[i];
549 qd_point_current += u[i_global_id] * qds[max_stress_q].d_shapes[i];
550 }
551
552 maxShearStressLocCur = qd_point_current;
553 }
554}
size_t getDimension() const
Get the dimension of the domain.
Definition mesh.h:85
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:20

References mesh::Mesh::d_eNumVertex, fe::elem(), mesh::Mesh::getDimension(), mesh::Mesh::getElementConnectivity(), mesh::Mesh::getElementType(), mesh::Mesh::getNumElements(), mesh::Mesh::getNumNodes(), and util::isLess().

Here is the call graph for this function:

◆ getStrainStress()

void mesh::getStrainStress ( const mesh::Mesh mesh_p,
const std::vector< util::Point > &  xRef,
const std::vector< util::Point > &  u,
bool  isPlaneStrain,
std::vector< util::SymMatrix3 > &  strain,
std::vector< util::SymMatrix3 > &  stress,
size_t  iNodeStart = 0,
size_t  iStrainStart = 0,
double  nu = 0.,
double  lambda = 0.,
double  mu = 0.,
bool  computeStress = false,
size_t  quadOrder = 1 
)

Strain and stress at quadrature points in the mesh.

In case of multiple particles and meshes, xRef and u data will hold data for all meshes. If this is the case, iNodeStart integer can be used to specify from what index the data for a given mesh should be read. Similarly, iStrainStart can be used to specify from what index the data for strain and stress should be substituted in strain/stress vectors. See documentation of @getCurrentQuadPoints().

Parameters
mesh_pPointer to already created possibly empty mesh object
xRefVector of reference coordinates of nodes
uVector of displacement of nodes
isPlaneStrainBool that indicates whether to use plane stress/strain assumption (only in 2-d)
strainVector of symmetric matrix to store strain (this argument is modified)
stressVector of symmetric matrix to store stress (this argument is modified)
iNodeStartAssume that nodal data in xRef and u starts from iNodeStart
iStrainStartAssume that quadrature data in strain/stress starts from iNodeStart
nuPoisson ratio (default is zero)
lambdaLame's first parameter (default is zero and for this value, stress will not be computed)
muLame's second parameter, i.e., shear modulus (default is zero and for this value, stress will not be computed)
computeStressFalse will not compute stress
quadOrderOrder of quadrature approximation (default is 1)

Definition at line 369 of file meshUtil.cpp.

381 {
382
383 assert((mesh_p->getDimension() > 1) && "In getStrainStress(), dimension = 2,3 is supported.\n");
384
385 size_t num_elems = mesh_p->getNumElements();
386
387 // check data
388 assert((num_elems != 0) && "Number of elements in the mesh is zero "
389 "possibly due to missing element-node "
390 "connectivity data. Can not proceed with "
391 "computation.\n");
392
393 assert(( (xRef.size() >= mesh_p->getNumNodes() + iNodeStart) ||
394 (u.size() >= mesh_p->getNumNodes() + iNodeStart)
395 ) &&
396 "Number of elements i nodal data can not be smaller than number of "
397 "nodes.\n");
398
399 auto elem = fe::elem(mesh_p->getElementType(), quadOrder);
400
401 // get total number of quadrature points by getting the number of quad
402 // points in one element times the number of elements
403 size_t numQuadPointsTotal = mesh_p->getNumElements() *
404 elem->getNumQuadPoints();
405
406 assert((strain.size() >= numQuadPointsTotal + iStrainStart)
407 && "Number of elements in strain data can not be less than "
408 "total number of quadrature points.\n");
409
410 // check if we can compute stress from given material data
411 computeStress = computeStress || util::isLess(mu, 1.e-16) || util::isLess(lambda, 1.e-16);
412
413 if (computeStress)
414 assert((stress.size() >= numQuadPointsTotal + iStrainStart)
415 && "Number of elements in stress data can not be less than "
416 "total number of quadrature points.\n");
417
418 // compute current position of quad points
419 auto *elem_p = elem.get();
420 const auto dim = mesh_p->getDimension();
421 tf::Executor executor(util::parallel::getNThreads());
422 tf::Taskflow taskflow;
423 taskflow.for_each_index(
424 (std::size_t) 0, num_elems, (std::size_t) 1,
425 [elem_p, mesh_p, xRef, u, iNodeStart, iStrainStart,
426 isPlaneStrain, nu, lambda, mu, computeStress, dim,
427 &strain, &stress]
428 (std::size_t e) {
429
430 auto id_nds = mesh_p->getElementConnectivity(e);
431 std::vector<util::Point> nds;
432 std::vector<util::Point> u_el;
433 for (const auto &i : id_nds) {
434 nds.push_back(xRef[i + iNodeStart]);
435 u_el.push_back(u[i + iNodeStart]);
436 }
437
438 auto qds = elem_p->getQuadDatas(nds);
439
440 for (size_t q=0; q<qds.size(); q++) {
441 auto ssn = strainFromB(fe::B(qds[q].d_derShapes, dim), u_el);
442 auto sss = util::SymMatrix3();
443
444 if (dim == 2 && isPlaneStrain)
445 ssn(2, 2) = -nu * (ssn(0, 0) + ssn(1, 1)) / (1. - nu);
446
447 if (computeStress) {
448 auto trace_ssn = ssn(0, 0) + ssn(1, 1) + ssn(2, 2);
449 sss(0, 0) = lambda * trace_ssn + 2 * mu * ssn(0, 0);
450 sss(0, 1) = 2 * mu * ssn(0, 1);
451 sss(0, 2) = 2 * mu * ssn(0, 2);
452
453 sss(1, 1) = lambda * trace_ssn + 2 * mu * ssn(1, 1);
454 sss(1, 2) = 2 * mu * ssn(1, 2);
455
456 sss(2, 2) = lambda * trace_ssn + 2 * mu * ssn(2, 2);
457
458 if (dim == 2 && !isPlaneStrain)
459 sss(2, 2) = nu * (sss(0, 0) + sss(1, 1));
460 }
461
462 auto q_global_id = iStrainStart + e * elem_p->getNumQuadPoints() + q;
463 strain[q_global_id] = ssn;
464 if (computeStress)
465 stress[q_global_id] = sss;
466 }
467 }
468 );
469
470 executor.run(taskflow).get();
471}
util::SymMatrix3 strainFromB(const fe::B &B, const std::vector< util::Point > &u)
Definition meshUtil.cpp:29
A structure to represent 3d matrices.
Definition matrix.h:258

References fe::elem(), mesh::Mesh::getDimension(), mesh::Mesh::getElementConnectivity(), mesh::Mesh::getElementType(), util::parallel::getNThreads(), mesh::Mesh::getNumElements(), mesh::Mesh::getNumNodes(), and util::isLess().

Referenced by rw::writeOutput().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metisGraphPartition() [1/4]

void mesh::metisGraphPartition ( std::string  partitionMethod,
const std::vector< std::vector< size_t > > &  nodeNeighs,
std::vector< size_t > &  nodePartition,
size_t  nPartitions 
)

Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes as vertices and edges given by node neighbors. Then the metis function is called to partition the graph into specified number of parts.

Parameters
partitionMethodMethod to partition ("metis_recursive" or "metis_kway")
nodeNeighsNeighborlist of nodes
nodePartitionVector that stores partition number of nodes
nPartitionsNumber of partitions

Definition at line 19 of file meshPartitioning.cpp.

22 {
23 // record time
24 auto t1 = steady_clock::now();
25 idx_t nvtxs = nodeNeighs.size();
26 idx_t ncon = 1; // # of balancing constraints (at least 1)
27 idx_t objval;
28 int metis_return;
29 idx_t nWeights = 1;
30 std::vector<idx_t> part(nvtxs, 0);
31 std::vector<idx_t> vwgt(nvtxs * nWeights, 0);
32 auto nParts = idx_t(nPartitions);
33
34 // create adjacency data based on nodeNeighs
35 // METIS needs xadj of length nvtxs+1 (CSR row pointers).
36 std::vector<idx_t> xadj(static_cast<size_t>(nvtxs) + 1, 0);
37 std::vector<idx_t> adjncy;
38 for (size_t i=0; i<static_cast<size_t>(nvtxs); i++) {
39 adjncy.insert(adjncy.end(), nodeNeighs[i].begin(), nodeNeighs[i].end());
40 xadj[i+1] = xadj[i] + idx_t(nodeNeighs[i].size());
41 }
42 std::cout << std::format("adjcny size = {}, xadj[end] = {}\n",
43 adjncy.size(), xadj[nvtxs]);
44
45 std::cout << "\nmetisGraphPartition():\n";
46 if (partitionMethod == "metis_recursive") {
47 std::cout << " METIS_PartGraphRecursive partitions a graph into K parts\n";
48 std::cout << " using multilevel recursive bisection.\n";
49
50 metis_return = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj.data(),
51 adjncy.data(), NULL, NULL,
52 NULL, &nParts, NULL, NULL, NULL, &objval,
53 part.data());
54 } else if (partitionMethod == "metis_kway") {
55 std::cout << " METIS_PartGraphKway partitions a graph into K parts\n";
56 std::cout << " using multilevel K-way partition.\n";
57
58 metis_return = METIS_PartGraphKway(&nvtxs, &ncon, xadj.data(),
59 adjncy.data(), NULL, NULL,
60 NULL, &nParts, NULL, NULL, NULL, &objval,
61 part.data());
62 } else {
63 std::cerr << "Argument partitionMethod = "
64 << partitionMethod << " is invalid.\n"
65 << "Valid values are {'metis_recursive', 'metis_kway'}.\n";
66 exit(1);
67 }
68
69 // record time
70 auto t2 = steady_clock::now();
71
72 std::cout << std::format("\n Return code = {}\n"
73 " Edge cuts for partition = {}\n"
74 " Partition calculation time (ms) = {}\n",
75 metis_return, (int) objval,
76 util::methods::timeDiff(t1, t2, "microseconds"));
77
78 // cast the part vector into nodePartition vector
79 nodePartition.resize(0);
80 nodePartition.insert(nodePartition.end(), part.begin(), part.end());
81}
float timeDiff(std::chrono::steady_clock::time_point begin, std::chrono::steady_clock::time_point end, std::string unit="microseconds")
Returns difference between two times.
Definition vecMethods.h:304

References util::methods::timeDiff().

Referenced by metisGraphPartition(), pd::setupDofPartition(), test::testGraphPartitioning(), and test::testMPI().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metisGraphPartition() [2/4]

void mesh::metisGraphPartition ( std::string  partitionMethod,
mesh::Mesh mesh_p,
const std::vector< std::vector< size_t > > &  nodeNeighs,
size_t  nPartitions 
)

Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes as vertices and edges given by node neighbors. Then the metis function is called to partition the graph into specified number of parts.

Parameters
partitionMethodMethod to partition ("recursive" or "kway")
mesh_pPointer to mesh
nodeNeighsNeighborlist of nodes
nPartitionsNumber of partitions

Definition at line 83 of file meshPartitioning.cpp.

86 {
87 mesh_p->d_nPart = nPartitions;
88 mesh_p->d_partitionMethod = partitionMethod;
89 mesh::metisGraphPartition(partitionMethod, nodeNeighs,
90 mesh_p->d_nodePartition, nPartitions);
91}
std::vector< size_t > d_nodePartition
Node partition information. For each node i, d_nodePartition[i] specifies the partition number,...
Definition mesh.h:491
size_t d_nPart
Number of partitions.
Definition mesh.h:477
std::string d_partitionMethod
Partitioning method. It could be either empty string or "metis_recursive" or "metis_kway".
Definition mesh.h:482
void metisGraphPartition(std::string partitionMethod, const std::vector< std::vector< size_t > > &nodeNeighs, std::vector< size_t > &nodePartition, size_t nPartitions)
Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes a...

References mesh::Mesh::d_nodePartition, mesh::Mesh::d_nPart, mesh::Mesh::d_partitionMethod, and metisGraphPartition().

Here is the call graph for this function:

◆ metisGraphPartition() [3/4]

void mesh::metisGraphPartition ( std::string  partitionMethod,
mesh::Mesh mesh_p,
size_t  nparts 
)

◆ metisGraphPartition() [4/4]

void mesh::metisGraphPartition ( std::string  partitionMethod,
std::vector< std::vector< size_t > > &  nodeNeighs,
size_t  nparts,
std::vector< size_t > &  epart,
std::vector< size_t > &  npart 
)

◆ removeNodesInBoxes()

void mesh::removeNodesInBoxes ( mesh::Mesh mesh_p,
const std::vector< std::vector< double > > &  boxes 
)

Removes nodes lying inside any of the given axis-aligned boxes.

Elements touching a removed node are dropped and the remaining connectivity is renumbered. This carves a real void (e.g. a notch slot) out of a structured grid, instead of keeping the material and breaking its bonds.

After carving, nodal volumes on the new free faces are halved per axis (same rule as outer faces in createUniformMesh): a node whose one-grid-step neighbour would lie inside a void box gets the ½ factor on that axis.

Parameters
mesh_pMesh to modify in place
boxesList of boxes, each [xlo, ylo, zlo, xhi, yhi, zhi]

Definition at line 214 of file meshUtil.cpp.

215 {
216 if (boxes.empty() || mesh_p->d_nodes.empty())
217 return;
218
219 auto inAnyBox = [&boxes](const util::Point &p) {
220 for (const auto &b : boxes) {
221 if (p.d_x >= b[0] && p.d_x <= b[3] && p.d_y >= b[1] && p.d_y <= b[4] &&
222 p.d_z >= b[2] && p.d_z <= b[5])
223 return true;
224 }
225 return false;
226 };
227
228 const size_t n_old = mesh_p->d_nodes.size();
229 std::vector<long> new_id(n_old, -1);
230 std::vector<util::Point> nodes;
231 std::vector<double> vol;
232 nodes.reserve(n_old);
233 vol.reserve(n_old);
234 for (size_t i = 0; i < n_old; ++i) {
235 if (inAnyBox(mesh_p->d_nodes[i]))
236 continue;
237 new_id[i] = static_cast<long>(nodes.size());
238 nodes.push_back(mesh_p->d_nodes[i]);
239 if (i < mesh_p->d_vol.size())
240 vol.push_back(mesh_p->d_vol[i]);
241 }
242
243 // Keep only elements all of whose nodes survived, renumbered.
244 std::vector<size_t> enc;
245 const size_t nv = mesh_p->d_eNumVertex;
246 if (nv > 0) {
247 enc.reserve(mesh_p->d_enc.size());
248 for (size_t e = 0; e + nv <= mesh_p->d_enc.size(); e += nv) {
249 bool keep = true;
250 for (size_t v = 0; v < nv; ++v) {
251 if (new_id[mesh_p->d_enc[e + v]] < 0) {
252 keep = false;
253 break;
254 }
255 }
256 if (!keep)
257 continue;
258 for (size_t v = 0; v < nv; ++v)
259 enc.push_back(static_cast<size_t>(new_id[mesh_p->d_enc[e + v]]));
260 }
261 }
262
263 // Nodes on faces newly opened by the void kept full cell volumes from
264 // createUniformMesh (only the outer box faces were halved). Mirror that
265 // rule: if a one-grid-step probe along ±e_i lands inside a carved box,
266 // apply the same ½ factor on that axis (corners get multiple halves).
267 const double h = mesh_p->d_h > 0. ? mesh_p->d_h : 1.0e-3;
268 auto probeInBox = [&boxes](double x, double y, double z) {
269 for (const auto &b : boxes) {
270 if (x >= b[0] && x <= b[3] && y >= b[1] && y <= b[4] && z >= b[2] &&
271 z <= b[5])
272 return true;
273 }
274 return false;
275 };
276 for (size_t i = 0; i < nodes.size(); ++i) {
277 const auto &p = nodes[i];
278 const bool hx = probeInBox(p.d_x - h, p.d_y, p.d_z) ||
279 probeInBox(p.d_x + h, p.d_y, p.d_z);
280 const bool hy = probeInBox(p.d_x, p.d_y - h, p.d_z) ||
281 probeInBox(p.d_x, p.d_y + h, p.d_z);
282 const bool hz = mesh_p->d_dim > 2 && (probeInBox(p.d_x, p.d_y, p.d_z - h) ||
283 probeInBox(p.d_x, p.d_y, p.d_z + h));
284 if (hx)
285 vol[i] *= 0.5;
286 if (hy)
287 vol[i] *= 0.5;
288 if (hz)
289 vol[i] *= 0.5;
290 }
291
292 mesh_p->d_nodes = std::move(nodes);
293 mesh_p->d_vol = std::move(vol);
294 mesh_p->d_enc = std::move(enc);
295 mesh_p->d_numNodes = mesh_p->d_nodes.size();
296 mesh_p->d_numElems = (nv > 0) ? mesh_p->d_enc.size() / nv : 0;
297 mesh_p->d_numDofs = mesh_p->d_numNodes * mesh_p->d_dim;
298 mesh_p->d_fix = std::vector<uint8_t>(mesh_p->d_nodes.size(), uint8_t(0));
299}

References mesh::Mesh::d_dim, mesh::Mesh::d_enc, mesh::Mesh::d_eNumVertex, mesh::Mesh::d_fix, mesh::Mesh::d_h, mesh::Mesh::d_nodes, mesh::Mesh::d_numDofs, mesh::Mesh::d_numElems, mesh::Mesh::d_numNodes, and mesh::Mesh::d_vol.

Referenced by mesh_gen::createParticleMesh().

Here is the caller graph for this function: