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 64 of file meshUtil.cpp.

64 {
65
66 mesh_p->d_dim = dim;
67 if (nGrid.size() < dim or box.first.size() < dim or box.second.size() < dim) {
68 throw std::runtime_error(
70 << "createUniformMesh(): check nGrid or box arguments.\n");
71 }
72
73 if (dim == 1) {
74 mesh_p->d_bbox.first = std::vector<double>{box.first[0], 0., 0.};
75 mesh_p->d_bbox.second = std::vector<double>{box.second[0], 0., 0.};
76 mesh_p->d_numNodes = (nGrid[0] + 1);
77 mesh_p->d_numElems = nGrid[0];
79 } else if (dim == 2) {
80 mesh_p->d_bbox.first = std::vector<double>{box.first[0], box.first[1], 0.};
81 mesh_p->d_bbox.second = std::vector<double>{box.second[0], box.second[1], 0.};
82 mesh_p->d_numNodes = (nGrid[0] + 1) * (nGrid[1] + 1);
83 mesh_p->d_numElems = nGrid[0] * nGrid[1];
85 } else if (dim == 3) {
86 mesh_p->d_bbox.first = std::vector<double>{box.first[0], box.first[1], box.first[2]};
87 mesh_p->d_bbox.second = std::vector<double>{box.second[0], box.second[1], box.second[2]};
88 mesh_p->d_numNodes = (nGrid[0] + 1) * (nGrid[1] + 1) * (nGrid[2] + 1);
89 mesh_p->d_numElems = nGrid[0] * nGrid[1] * nGrid[2];
91 } else {
92 throw std::runtime_error(
94 << "createUniformMesh(): invalid dim = " << dim << " argument.\n");
95 }
96
98 mesh_p->d_numDofs = mesh_p->d_numNodes * mesh_p->d_dim;
99
100 // local nodal data
101 mesh_p->d_nodes.resize(mesh_p->d_numNodes);
102 mesh_p->d_enc.resize(mesh_p->d_numElems * mesh_p->d_eNumVertex);
103 mesh_p->d_fix = std::vector<uint8_t>(mesh_p->d_nodes.size(), uint8_t(0));
104 mesh_p->d_vol.resize(mesh_p->d_numNodes);
105
106 // create mesh data
107 std::vector<double> h;
108 double h_small = 0.;
109 for (size_t i=0; i<dim; i++) {
110 h.push_back((box.second[i] - box.first[i])/nGrid[i]);
111 if (i == 0)
112 h_small = h[0];
113 else
114 h_small = std::min(h_small, h[i]);
115 }
116
117 // set smallest h as mesh size
118 mesh_p->d_h = h_small;
119
120 if (dim == 1) {
121 // compute node positions
122 for (size_t i = 0; i <= nGrid[0]; i++) {
123 mesh_p->d_nodes[i] = util::Point(box.first[0] + double(i) * h[0], 0., 0.);
124 mesh_p->d_vol[i] = h[0];
125 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[i] *= 0.5;
126 } // loop over i
127
128 // compute element-node connectivity
129 for (size_t i = 0; i < nGrid[0]; i++) {
130 // element node connectivity, in the VTK line order
131 mesh_p->d_enc[2 * i + 0] = i;
132 mesh_p->d_enc[2 * i + 1] = i + 1;
133 } // loop over i
134 } else if (dim == 2) {
135 // compute node positions
136 for (size_t j = 0; j <= nGrid[1]; j++) {
137 for (size_t i = 0; i <= nGrid[0]; i++) {
138 // node number
139 size_t n = j * (nGrid[0] + 1) + i;
140 mesh_p->d_nodes[n] = util::Point(box.first[0] + double(i) * h[0],
141 box.first[1] + double(j) * h[1], 0.);
142
143 mesh_p->d_vol[n] = h[0] * h[1];
144 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[n] *= 0.5;
145 if (j == 0 || j == nGrid[1]) mesh_p->d_vol[n] *= 0.5;
146 } // loop over i
147 } // loop over j
148
149 // compute element-node connectivity
150 for (size_t j = 0; j < nGrid[1]; j++) {
151 for (size_t i = 0; i < nGrid[0]; i++) {
152
153 // element number
154 auto n = j * nGrid[0] + i;
155
156 // element node connectivity (put it in anti clockwise order)
157 mesh_p->d_enc[4 * n + 0] = j * (nGrid[0] + 1) + i;
158 mesh_p->d_enc[4 * n + 1] = j * (nGrid[0] + 1) + i + 1;
159 mesh_p->d_enc[4 * n + 2] = (j + 1) * (nGrid[0] + 1) + i + 1;
160 mesh_p->d_enc[4 * n + 3] = (j + 1) * (nGrid[0] + 1) + i;
161 } // loop over i
162 } // loop over j
163 } else if (dim == 3) {
164 // compute node positions
165 for (size_t k = 0; k <= nGrid[2]; k++) {
166 for (size_t j = 0; j <= nGrid[1]; j++) {
167 for (size_t i = 0; i <= nGrid[0]; i++) {
168 // node number
169 size_t n = k * (nGrid[1] + 1) * (nGrid[0] + 1) + j * (nGrid[0] + 1) + i;
170 mesh_p->d_nodes[n] = util::Point(box.first[0] + double(i) * h[0],
171 box.first[1] + double(j) * h[1],
172 box.first[2] + double(k) * h[2]);
173
174 mesh_p->d_vol[n] = h[0] * h[1] * h[2];
175 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[n] *= 0.5;
176 if (j == 0 || j == nGrid[1]) mesh_p->d_vol[n] *= 0.5;
177 if (k == 0 || k == nGrid[2]) mesh_p->d_vol[n] *= 0.5;
178 } // loop over i
179 } // loop over j
180 } // loop over k
181
182 // compute element-node connectivity
183 // (k < nGrid[2]: there are nGrid[2] cells through the thickness, not
184 // nGrid[2]+1. Using <= overran d_enc and corrupted the heap.)
185 for (size_t k = 0; k < nGrid[2]; k++) {
186 for (size_t j = 0; j < nGrid[1]; j++) {
187 for (size_t i = 0; i < nGrid[0]; i++) {
188
189 // element number
190 auto n = k * nGrid[1] * nGrid[0] + j * nGrid[0] + i;
191
192 // element node connectivity, in the VTK hexahedron order: the
193 // face at k counterclockwise, then the face at k+1 with node 4
194 // above node 0
195 mesh_p->d_enc[8 * n + 0] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
196 + j * (nGrid[0] + 1) + i;
197 mesh_p->d_enc[8 * n + 1] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
198 + j * (nGrid[0] + 1) + i + 1;
199 mesh_p->d_enc[8 * n + 2] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
200 + (j + 1) * (nGrid[0] + 1) + i + 1;
201 mesh_p->d_enc[8 * n + 3] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
202 + (j + 1) * (nGrid[0] + 1) + i;
203
204 mesh_p->d_enc[8 * n + 4] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
205 + j * (nGrid[0] + 1) + i;
206 mesh_p->d_enc[8 * n + 5] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
207 + j * (nGrid[0] + 1) + i + 1;
208 mesh_p->d_enc[8 * n + 6] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
209 + (j + 1) * (nGrid[0] + 1) + i + 1;
210 mesh_p->d_enc[8 * n + 7] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
211 + (j + 1) * (nGrid[0] + 1) + i;
212 } // loop over i
213 } // loop over j
214 } // loop over k
215 }
216}
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
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_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 305 of file meshUtil.cpp.

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

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

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 373 of file meshUtil.cpp.

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

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

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 86 of file meshPartitioning.cpp.

89 {
90 mesh_p->d_nPart = nPartitions;
91 mesh_p->d_partitionMethod = partitionMethod;
92 mesh::metisGraphPartition(partitionMethod, nodeNeighs,
93 mesh_p->d_nodePartition, nPartitions);
94}
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 218 of file meshUtil.cpp.

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

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: