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

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

Data Structures

class  BaseElem
 A base class which provides methods to map points to/from reference element and to compute quadrature data. More...
 
class  LineElem
 A class for mapping and quadrature related operations for linear 2-node line element. More...
 
class  Mesh
 A class for mesh data. More...
 
struct  QuadData
 A struct to store the quadrature data. List of data are. More...
 
class  QuadElem
 A class for mapping and quadrature related operations for bi-linear quadrangle element. More...
 
class  TetElem
 A class for mapping and quadrature related operations for linear tetrahedron element. More...
 
class  TriElem
 A class for mapping and quadrature related operations for linear triangle element. 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, fe::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 createUniformMesh (fe::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 getCurrentQuadPoints (const fe::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 fe::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 fe::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 fe::createUniformMesh ( fe::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 23 of file meshUtil.cpp.

23 {
24
25 mesh_p->d_dim = dim;
26 if (nGrid.size() < dim or box.first.size() < dim or box.second.size() < dim) {
27 std::cerr << "createUniformMesh(): check nGrid or box arguments.\n";
28 exit(1);
29 }
30
31 if (dim == 1) {
32 mesh_p->d_bbox.first = std::vector<double>{box.first[0], 0., 0.};
33 mesh_p->d_bbox.second = std::vector<double>{box.second[0], 0., 0.};
34 mesh_p->d_numNodes = (nGrid[0] + 1);
35 mesh_p->d_numElems = nGrid[0];
37 } else if (dim == 2) {
38 mesh_p->d_bbox.first = std::vector<double>{box.first[0], box.first[1], 0.};
39 mesh_p->d_bbox.second = std::vector<double>{box.second[0], box.second[1], 0.};
40 mesh_p->d_numNodes = (nGrid[0] + 1) * (nGrid[1] + 1);
41 mesh_p->d_numElems = nGrid[0] * nGrid[1];
43 } else if (dim == 3) {
44 mesh_p->d_bbox.first = std::vector<double>{box.first[0], box.first[1], box.first[2]};
45 mesh_p->d_bbox.second = std::vector<double>{box.second[0], box.second[1], box.second[2]};
46 mesh_p->d_numNodes = (nGrid[0] + 1) * (nGrid[1] + 1) * (nGrid[2] + 1);
47 mesh_p->d_numElems = nGrid[0] * nGrid[1] * nGrid[2];
49 } else {
50 std::cerr << "createUniformMesh(): invalid dim = " << dim << " argument.\n";
51 exit(1);
52 }
53
55 mesh_p->d_numDofs = mesh_p->d_numNodes * mesh_p->d_dim;
56
57 // local nodal data
58 mesh_p->d_nodes.resize(mesh_p->d_numNodes);
59 mesh_p->d_enc.resize(mesh_p->d_numElems * mesh_p->d_eNumVertex);
60 mesh_p->d_fix = std::vector<uint8_t>(mesh_p->d_nodes.size(), uint8_t(0));
61 mesh_p->d_vol.resize(mesh_p->d_numNodes);
62
63 // create mesh data
64 std::vector<double> h;
65 double h_small = 0.;
66 for (size_t i=0; i<dim; i++) {
67 h.push_back((box.second[i] - box.first[i])/nGrid[i]);
68 if (i == 0)
69 h_small = h[0];
70 else {
71 if (std::abs(h[i] - h_small) > 1.0e-14 and h_small > h[1] + 1.0e-14)
72 h_small = h[i];
73 }
74 }
75
76 // set smallest h as mesh size
77 mesh_p->d_h = h_small;
78
79 if (dim == 1) {
80 // compute node positions
81 for (size_t i = 0; i <= nGrid[0]; i++) {
82 mesh_p->d_nodes[i] = util::Point(box.first[0] + double(i) * h[0], 0., 0.);
83 mesh_p->d_vol[i] = h[0];
84 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[i] *= 0.5;
85 } // loop over i
86
87 // compute element-node connectivity
88 for (size_t i = 0; i < nGrid[0]; i++) {
89 // element node connectivity
90 // TODO Check if ordering is conforming to the standard
91 mesh_p->d_enc[2 * i + 0] = i;
92 mesh_p->d_enc[2 * i + 1] = i + 1;
93 } // loop over i
94 } else if (dim == 2) {
95 // compute node positions
96 for (size_t j = 0; j <= nGrid[1]; j++) {
97 for (size_t i = 0; i <= nGrid[0]; i++) {
98 // node number
99 size_t n = j * (nGrid[0] + 1) + i;
100 mesh_p->d_nodes[n] = util::Point(box.first[0] + double(i) * h[0],
101 box.first[1] + double(j) * h[1], 0.);
102
103 mesh_p->d_vol[n] = h[0] * h[1];
104 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[n] *= 0.5;
105 if (j == 0 || j == nGrid[1]) mesh_p->d_vol[n] *= 0.5;
106 } // loop over i
107 } // loop over j
108
109 // compute element-node connectivity
110 for (size_t j = 0; j < nGrid[1]; j++) {
111 for (size_t i = 0; i < nGrid[0]; i++) {
112
113 // element number
114 auto n = j * nGrid[0] + i;
115
116 // element node connectivity (put it in anti clockwise order)
117 mesh_p->d_enc[4 * n + 0] = j * (nGrid[0] + 1) + i;
118 mesh_p->d_enc[4 * n + 1] = j * (nGrid[0] + 1) + i + 1;
119 mesh_p->d_enc[4 * n + 2] = (j + 1) * (nGrid[0] + 1) + i + 1;
120 mesh_p->d_enc[4 * n + 3] = (j + 1) * (nGrid[0] + 1) + i;
121 } // loop over i
122 } // loop over j
123 } else if (dim == 3) {
124 // compute node positions
125 for (size_t k = 0; k <= nGrid[2]; k++) {
126 for (size_t j = 0; j <= nGrid[1]; j++) {
127 for (size_t i = 0; i <= nGrid[0]; i++) {
128 // node number
129 size_t n = k * (nGrid[1] + 1) * (nGrid[0] + 1) + j * (nGrid[0] + 1) + i;
130 mesh_p->d_nodes[n] = util::Point(box.first[0] + double(i) * h[0],
131 box.first[1] + double(j) * h[1],
132 box.first[2] + double(k) * h[2]);
133
134 mesh_p->d_vol[n] = h[0] * h[1] * h[2];
135 if (i == 0 || i == nGrid[0]) mesh_p->d_vol[n] *= 0.5;
136 if (j == 0 || j == nGrid[1]) mesh_p->d_vol[n] *= 0.5;
137 if (k == 0 || k == nGrid[2]) mesh_p->d_vol[n] *= 0.5;
138 } // loop over i
139 } // loop over j
140 } // loop over k
141
142 // compute element-node connectivity
143 for (size_t k = 0; k <= nGrid[2]; k++) {
144 for (size_t j = 0; j < nGrid[1]; j++) {
145 for (size_t i = 0; i < nGrid[0]; i++) {
146
147 // element number
148 auto n = k * nGrid[1] * nGrid[0] + j * nGrid[0] + i;
149
150 // element node connectivity
151 // TODO Check if ordering is conforming to the standard
152 mesh_p->d_enc[8 * n + 0] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
153 + j * (nGrid[0] + 1) + i;
154 mesh_p->d_enc[8 * n + 1] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
155 + j * (nGrid[0] + 1) + i + 1;
156 mesh_p->d_enc[8 * n + 2] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
157 + (j + 1) * (nGrid[0] + 1) + i + 1;
158 mesh_p->d_enc[8 * n + 3] = k * (nGrid[1] + 1) * (nGrid[0] + 1)
159 + (j + 1) * (nGrid[0] + 1) + i;
160
161 mesh_p->d_enc[8 * n + 4] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
162 + j * (nGrid[0] + 1) + i;
163 mesh_p->d_enc[8 * n + 5] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
164 + j * (nGrid[0] + 1) + i + 1;
165 mesh_p->d_enc[8 * n + 6] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
166 + (j + 1) * (nGrid[0] + 1) + i + 1;
167 mesh_p->d_enc[8 * n + 7] = (k + 1) * (nGrid[1] + 1) * (nGrid[0] + 1)
168 + (j + 1) * (nGrid[0] + 1) + i;
169 } // loop over i
170 } // loop over j
171 } // loop over k
172 }
173}
std::vector< util::Point > d_nodes
Vector of initial (reference) coordinates of nodes.
Definition mesh.h:407
std::vector< double > d_vol
Vector of volume of each node.
Definition mesh.h:439
double d_h
Mesh size.
Definition mesh.h:516
size_t d_dim
Dimension of the mesh.
Definition mesh.h:468
std::vector< uint8_t > d_fix
Vector of fixity mask of each node.
Definition mesh.h:431
size_t d_numElems
Number of elements.
Definition mesh.h:378
std::pair< std::vector< double >, std::vector< double > > d_bbox
Bounding box.
Definition mesh.h:513
size_t d_eType
Element type.
Definition mesh.h:389
std::vector< size_t > d_enc
Element-node connectivity data.
Definition mesh.h:415
size_t d_numNodes
Number of nodes.
Definition mesh.h:375
size_t d_eNumVertex
Number of vertex per element.
Definition mesh.h:404
size_t d_numDofs
Number of dofs = (dimension) times (number of nodes)
Definition mesh.h:490
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.
float h
mesh size (use smaller radius to decide)
A structure to represent 3d vectors.
Definition point.h:30

References fe::Mesh::d_bbox, fe::Mesh::d_dim, fe::Mesh::d_enc, fe::Mesh::d_eNumVertex, fe::Mesh::d_eType, fe::Mesh::d_fix, fe::Mesh::d_h, fe::Mesh::d_nodes, fe::Mesh::d_numDofs, fe::Mesh::d_numElems, fe::Mesh::d_numNodes, fe::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 model::DEMModel::createParticles(), test::testGraphPartitioning(), and test::testMPI().

Here is the caller graph for this function:

◆ getCurrentQuadPoints()

void fe::getCurrentQuadPoints ( const fe::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 176 of file meshUtil.cpp.

182 {
183
184 size_t num_elems = mesh_p->getNumElements();
185
186 // check data
187 assert((num_elems != 0) && "Number of elements in the mesh is zero "
188 "possibly due to missing element-node "
189 "connectivity data. Can not proceed with "
190 "computation.\n");
191
192 assert(( (xRef.size() >= mesh_p->getNumNodes() + iNodeStart) ||
193 (u.size() >= mesh_p->getNumNodes() + iNodeStart)
194 ) &&
195 "Number of elements i nnodal data can not be smaller than number of "
196 "nodes.\n");
197
198 // get Quadrature
199 fe::BaseElem *elem;
200 if (mesh_p->getElementType() == util::vtk_type_line)
201 elem = new fe::LineElem(quadOrder);
202 else if (mesh_p->getElementType() == util::vtk_type_triangle)
203 elem = new fe::TriElem(quadOrder);
204 else if (mesh_p->getElementType() == util::vtk_type_quad)
205 elem = new fe::QuadElem(quadOrder);
206 else if (mesh_p->getElementType() == util::vtk_type_tetra)
207 elem = new fe::TetElem(quadOrder);
208 else {
209 std::cerr << fmt::format("Error: Can not compute strain/stress as the element "
210 "type = {} is not yet supported in this routine.\n", mesh_p->getElementType());
211 exit(EXIT_FAILURE);
212 }
213
214 // get total number of quadrature points by getting the number of quad
215 // points in one element times the number of elements
216 size_t numQuadPointsTotal = mesh_p->getNumElements() *
217 elem->getNumQuadPoints();
218
219 assert((xQuadCur.size() >= numQuadPointsTotal + iQuadStart)
220 && "Number of elements in xQuad data can not be less than "
221 "total number of quadrature points.\n");
222
223 // std::cout << fmt::format("num_elems = {}, "
224 // "iNodeStart = {}, "
225 // "numQuadPointsTotal = {}, "
226 // "iQuadStart = {}, "
227 // "xQuadCur.size() = {}",
228 // num_elems,
229 // iNodeStart,
230 // numQuadPointsTotal,
231 // iQuadStart,
232 // xQuadCur.size())
233 // << std::endl;
234
235
236 // compute current position of quad points
237 tf::Executor executor(util::parallel::getNThreads());
238 tf::Taskflow taskflow;
239 taskflow.for_each_index(
240 (std::size_t) 0, num_elems, (std::size_t) 1,
241 [elem, mesh_p, xRef, u, iNodeStart, iQuadStart, &xQuadCur]
242 (std::size_t e) {
243
244 // get ids of nodes of element and reference coordinate of nodes
245 auto id_nds = mesh_p->getElementConnectivity(e);
246 auto e_nds_start = iNodeStart + mesh_p->d_eNumVertex * e;
247 auto e_nds_end = e_nds_start + mesh_p->d_eNumVertex;
248
249 //assert( (e_nds_end <= xRef.size()) && "e_nds_end bigger than size of xRef\n" );
250
251 //std::vector<util::Point> nds(xRef.begin() + e_nds_start,
252 // xRef.begin() + e_nds_end);
253 std::vector<util::Point> nds;
254 for (const auto &i : id_nds)
255 nds.push_back(xRef[i + iNodeStart]);
256
257 auto qds = elem->getQuadDatas(nds);
258
259 auto qd_point_current = util::Point();
260
261 for (size_t q=0; q<qds.size(); q++) {
262 qd_point_current = qds[q].d_p;
263 for (size_t i = 0; i < id_nds.size(); i++) {
264 auto i_global_id = iNodeStart + id_nds[i];
265 qd_point_current += u[i_global_id] * qds[q].d_shapes[i];
266 }
267
268 // location of this quad points current position in the vector
269 // is e * getNumQuadPoints() + q, where e is the index of
270 // current element we are processing
271 auto q_global_id = iQuadStart + e * elem->getNumQuadPoints() + q;
272 xQuadCur[q_global_id] = qd_point_current;
273 }
274 } // loop over elements
275 ); // for_each
276
277 executor.run(taskflow).get();
278}
A base class which provides methods to map points to/from reference element and to compute quadrature...
Definition baseElem.h:84
virtual std::vector< fe::QuadData > getQuadDatas(const std::vector< util::Point > &nodes)=0
Get vector of quadrature data.
size_t getNumQuadPoints()
Get number of quadrature points in the data.
Definition baseElem.h:111
A class for mapping and quadrature related operations for linear 2-node line element.
Definition lineElem.h:49
size_t getElementType() const
Get the type of element in mesh.
Definition mesh.h:106
std::vector< size_t > getElementConnectivity(const size_t &i) const
Get the connectivity of element.
Definition mesh.h:210
size_t getNumNodes() const
Get the number of nodes.
Definition mesh.h:88
size_t getNumElements() const
Get the number of elements.
Definition mesh.h:94
A class for mapping and quadrature related operations for bi-linear quadrangle element.
Definition quadElem.h:64
A class for mapping and quadrature related operations for linear tetrahedron element.
Definition tetElem.h:141
A class for mapping and quadrature related operations for linear triangle element.
Definition triElem.h:91
static const int vtk_type_triangle
Integer flag for triangle element.
static const int vtk_type_tetra
Integer flag for tetrahedron element.
unsigned int getNThreads()
Get number of threads to be used by taskflow.

References fe::Mesh::d_eNumVertex, fe::Mesh::getElementConnectivity(), fe::Mesh::getElementType(), util::parallel::getNThreads(), fe::Mesh::getNumElements(), fe::Mesh::getNumNodes(), fe::BaseElem::getNumQuadPoints(), fe::BaseElem::getQuadDatas(), util::vtk_type_line, util::vtk_type_quad, util::vtk_type_tetra, and util::vtk_type_triangle.

Referenced by model::DEMModel::output(), and twoparticle_demo::Model::twoParticleTestMaxShearStress().

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

◆ getMaxShearStressAndLoc()

void fe::getMaxShearStressAndLoc ( const fe::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 429 of file meshUtil.cpp.

438 {
439
440 assert((mesh_p->getDimension() == 2) && "In getMaxShearStressAndLoc(), only dimension = 2 is supported.\n");
441
442 size_t num_elems = mesh_p->getNumElements();
443
444 // check data
445 assert((num_elems != 0) && "Number of elements in the mesh is zero "
446 "possibly due to missing element-node "
447 "connectivity data. Can not proceed with "
448 "computation.\n");
449
450 assert(( (xRef.size() >= mesh_p->getNumNodes() + iNodeStart) ||
451 (u.size() >= mesh_p->getNumNodes() + iNodeStart)
452 ) &&
453 "Number of elements i nnodal data can not be smaller than number of "
454 "nodes.\n");
455
456 // get Quadrature
457 fe::BaseElem *elem;
458 if (mesh_p->getElementType() == util::vtk_type_line)
459 elem = new fe::LineElem(quadOrder);
460 else if (mesh_p->getElementType() == util::vtk_type_triangle)
461 elem = new fe::TriElem(quadOrder);
462 else if (mesh_p->getElementType() == util::vtk_type_quad)
463 elem = new fe::QuadElem(quadOrder);
464 else if (mesh_p->getElementType() == util::vtk_type_tetra)
465 elem = new fe::TetElem(quadOrder);
466 else {
467 std::cerr << "Error: Can not compute strain/stress as the element "
468 "type is not yet supported in this routine.\n";
469 exit(EXIT_FAILURE);
470 }
471
472 // get total number of quadrature points by getting the number of quad
473 // points in one element times the number of elements
474 size_t numQuadPointsTotal = mesh_p->getNumElements() *
475 elem->getNumQuadPoints();
476
477 assert((stress.size() >= numQuadPointsTotal + iStrainStart)
478 && "Number of elements in stress data can not be less than "
479 "total number of quadrature points.\n");
480
481 // compute principal shear stress
482 double max_stress = 0.;
483 size_t max_stress_e = 0;
484 size_t max_stress_q = 0;
485 for (size_t e = 0; e < num_elems; e++) {
486 for (size_t q=0; q<elem->getNumQuadPoints(); q++) {
487 auto q_global_id = iStrainStart + e * elem->getNumQuadPoints() + q;
488 const auto stress_e = stress[q_global_id];
489
490 const auto principle_shear_stress =
491 std::sqrt(0.25 * std::pow(stress_e.get(0) - stress_e.get(1), 2) +
492 std::pow(stress_e.get(5), 2));
493
494 if (util::isLess(max_stress, principle_shear_stress)) {
495 max_stress = principle_shear_stress;
496 max_stress_e = e;
497 max_stress_q = q;
498 }
499 }
500 }
501
502 // set data
503 maxShearStress = max_stress;
504
505 // now compute current and reference location of the quadrature point at which
506 // stress is maximum
507 {
508 // get ids of nodes of element and reference coordinate of nodes
509 auto id_nds = mesh_p->getElementConnectivity(max_stress_e);
510 auto e_nds_start = iNodeStart + mesh_p->d_eNumVertex * max_stress_e;
511 auto e_nds_end = e_nds_start + mesh_p->d_eNumVertex;
512 std::vector<util::Point> nds(xRef.begin() + e_nds_start, xRef.begin() + e_nds_end);
513
514 auto qds = elem->getQuadDatas(nds);
515 auto qd_point_current = qds[max_stress_q].d_p;
516 maxShearStressLocRef = qd_point_current;
517 for (size_t i = 0; i < id_nds.size(); i++) {
518 auto i_global_id = iNodeStart + id_nds[i];
519 qd_point_current += u[i_global_id] * qds[max_stress_q].d_shapes[i];
520 }
521
522 maxShearStressLocCur = qd_point_current;
523 }
524}
size_t getDimension() const
Get the dimension of the domain.
Definition mesh.h:82
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:20

References fe::Mesh::d_eNumVertex, fe::Mesh::getDimension(), fe::Mesh::getElementConnectivity(), fe::Mesh::getElementType(), fe::Mesh::getNumElements(), fe::Mesh::getNumNodes(), fe::BaseElem::getNumQuadPoints(), fe::BaseElem::getQuadDatas(), util::isLess(), util::vtk_type_line, util::vtk_type_quad, util::vtk_type_tetra, and util::vtk_type_triangle.

Referenced by twoparticle_demo::Model::twoParticleTestMaxShearStress().

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

◆ getStrainStress()

void fe::getStrainStress ( const fe::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 280 of file meshUtil.cpp.

292 {
293
294 assert((mesh_p->getDimension() > 1) && "In getStrainStress(), dimension = 2,3 is supported.\n");
295
296 size_t num_elems = mesh_p->getNumElements();
297
298 // check data
299 assert((num_elems != 0) && "Number of elements in the mesh is zero "
300 "possibly due to missing element-node "
301 "connectivity data. Can not proceed with "
302 "computation.\n");
303
304 assert(( (xRef.size() >= mesh_p->getNumNodes() + iNodeStart) ||
305 (u.size() >= mesh_p->getNumNodes() + iNodeStart)
306 ) &&
307 "Number of elements i nodal data can not be smaller than number of "
308 "nodes.\n");
309
310 // get Quadrature
311 fe::BaseElem *elem;
312 if (mesh_p->getElementType() == util::vtk_type_line)
313 elem = new fe::LineElem(quadOrder);
314 else if (mesh_p->getElementType() == util::vtk_type_triangle)
315 elem = new fe::TriElem(quadOrder);
316 else if (mesh_p->getElementType() == util::vtk_type_quad)
317 elem = new fe::QuadElem(quadOrder);
318 else if (mesh_p->getElementType() == util::vtk_type_tetra)
319 elem = new fe::TetElem(quadOrder);
320 else {
321 std::cerr << "Error: Can not compute strain/stress as the element "
322 "type is not yet supported in this routine.\n";
323 exit(EXIT_FAILURE);
324 }
325
326 // get total number of quadrature points by getting the number of quad
327 // points in one element times the number of elements
328 size_t numQuadPointsTotal = mesh_p->getNumElements() *
329 elem->getNumQuadPoints();
330
331 assert((strain.size() >= numQuadPointsTotal + iStrainStart)
332 && "Number of elements in strain data can not be less than "
333 "total number of quadrature points.\n");
334
335 // check if we can compute stress from given material data
336 computeStress = computeStress || util::isLess(mu, 1.e-16) || util::isLess(lambda, 1.e-16);
337
338 if (computeStress)
339 assert((stress.size() >= numQuadPointsTotal + iStrainStart)
340 && "Number of elements in stress data can not be less than "
341 "total number of quadrature points.\n");
342
343 // compute current position of quad points
344 tf::Executor executor(util::parallel::getNThreads());
345 tf::Taskflow taskflow;
346 taskflow.for_each_index(
347 (std::size_t) 0, num_elems, (std::size_t) 1,
348 [elem, mesh_p, xRef, u, iNodeStart, iStrainStart,
349 isPlaneStrain, nu, lambda, mu, computeStress,
350 &strain, &stress]
351 (std::size_t e) {
352
353 auto ssn = util::SymMatrix3();
354 auto sss = util::SymMatrix3();
355
356 // get ids of nodes of element and reference coordinate of nodes
357 auto id_nds = mesh_p->getElementConnectivity(e);
358 auto e_nds_start = iNodeStart + mesh_p->d_eNumVertex * e;
359 auto e_nds_end = e_nds_start + mesh_p->d_eNumVertex;
360 //std::vector<util::Point> nds(xRef.begin() + e_nds_start,
361 // xRef.begin() + e_nds_end);
362 std::vector<util::Point> nds;
363 for (const auto &i : id_nds)
364 nds.push_back(xRef[i + iNodeStart]);
365
366 auto qds = elem->getQuadDatas(nds);
367
368 for (size_t q=0; q<qds.size(); q++) {
369 ssn = util::SymMatrix3();
370 sss = util::SymMatrix3();
371
372 // compute strain
373 for (size_t i = 0; i < id_nds.size(); i++) {
374 auto i_global_id = iNodeStart + id_nds[i];
375 auto ui = u[i_global_id];
376
377 ssn(0, 0) += ui[0] + qds[q].d_derShapes[i][0];
378 if (mesh_p->getDimension() > 1) {
379 ssn(1, 1) += ui[1] + qds[q].d_derShapes[i][1];
380 // xy
381 ssn(0, 1) += 0.5 * ui[0] * qds[q].d_derShapes[i][1] +
382 0.5 * ui[1] * qds[q].d_derShapes[i][0];
383 }
384 if (mesh_p->getDimension() > 2) {
385 ssn(2, 2) += ui[2] + qds[q].d_derShapes[i][2];
386
387 // yz
388 ssn(1, 2) += 0.5 * ui[1] * qds[q].d_derShapes[i][2] +
389 0.5 * ui[2] * qds[q].d_derShapes[i][1];
390 // xz
391 ssn(0, 2) += 0.5 * ui[0] * qds[q].d_derShapes[i][2] +
392 0.5 * ui[2] * qds[q].d_derShapes[i][0];
393 }
394 }
395
396 if (mesh_p->getDimension() == 2 && isPlaneStrain)
397 ssn(2, 2) = -nu * (ssn(0, 0) + ssn(1, 1)) / (1. - nu);
398
399 // compute stress
400 if (computeStress) {
401 auto trace_ssn = ssn(0, 0) + ssn(1, 1) + ssn(2, 2);
402 sss(0, 0) = lambda * trace_ssn + 2 * mu * ssn(0, 0);
403 sss(0, 1) = 2 * mu * ssn(0, 1);
404 sss(0, 2) = 2 * mu * ssn(0, 2);
405
406 sss(1, 1) = lambda * trace_ssn + 2 * mu * ssn(1, 1);
407 sss(1, 2) = 2 * mu * ssn(1, 2);
408
409 sss(2, 2) = lambda * trace_ssn + 2 * mu * ssn(2, 2);
410
411 if (mesh_p->getDimension() == 2 && !isPlaneStrain)
412 sss(2, 2) = nu * (sss(0, 0) + sss(1, 1));
413 }
414
415 // location of this quad points in the vector
416 // is e * getNumQuadPoints() + q, where e is the index of
417 // current element we are processing
418 auto q_global_id = iStrainStart + e * elem->getNumQuadPoints() + q;
419 strain[q_global_id] = ssn;
420 if (computeStress)
421 stress[q_global_id] = sss;
422 }
423 } // loop over elements
424 ); // for_each
425
426 executor.run(taskflow).get();
427}
A structure to represent 3d matrices.
Definition matrix.h:258

References fe::Mesh::d_eNumVertex, fe::Mesh::getDimension(), fe::Mesh::getElementConnectivity(), fe::Mesh::getElementType(), util::parallel::getNThreads(), fe::Mesh::getNumElements(), fe::Mesh::getNumNodes(), fe::BaseElem::getNumQuadPoints(), fe::BaseElem::getQuadDatas(), util::isLess(), util::vtk_type_line, util::vtk_type_quad, util::vtk_type_tetra, and util::vtk_type_triangle.

Referenced by model::DEMModel::output(), and twoparticle_demo::Model::twoParticleTestMaxShearStress().

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

◆ metisGraphPartition() [1/2]

void fe::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 18 of file meshPartitioning.cpp.

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

References util::methods::timeDiff().

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

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

◆ metisGraphPartition() [2/2]

void fe::metisGraphPartition ( std::string  partitionMethod,
fe::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 81 of file meshPartitioning.cpp.

84 {
85 mesh_p->d_nPart = nPartitions;
86 mesh_p->d_partitionMethod = partitionMethod;
87 fe::metisGraphPartition(partitionMethod, nodeNeighs,
88 mesh_p->d_nodePartition, nPartitions);
89}
std::vector< size_t > d_nodePartition
Node partition information. For each node i, d_nodePartition[i] specifies the partition number,...
Definition mesh.h:463
size_t d_nPart
Number of partitions.
Definition mesh.h:449
std::string d_partitionMethod
Partitioning method. It could be either empty string or "metis_recursive" or "metis_kway".
Definition mesh.h:454
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 fe::Mesh::d_nodePartition, fe::Mesh::d_nPart, fe::Mesh::d_partitionMethod, and metisGraphPartition().

Here is the call graph for this function: