24#include <taskflow/taskflow/taskflow.hpp>
25#include <taskflow/taskflow/algorithm/for_each.hpp>
32 const std::vector<util::Point> &u) {
33 std::vector<double> uflat(B.
nDof());
34 const int dim = B.
dim();
35 for (
size_t a = 0; a < u.size(); a++) {
36 uflat[dim *
static_cast<int>(a)] = u[a][0];
38 uflat[dim *
static_cast<int>(a) + 1] = u[a][1];
40 uflat[dim *
static_cast<int>(a) + 2] = u[a][2];
42 std::vector<double> e(B.
nStrain(), 0.);
43 for (
int i = 0; i < B.
nStrain(); i++)
44 for (
int j = 0; j < B.
nDof(); j++)
45 e[i] += B(i, j) * uflat[j];
50 s(0, 1) = (dim == 2) ? e[2] : e[5];
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");
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.};
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);
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];
92 throw std::runtime_error(
94 <<
"createUniformMesh(): invalid dim = " << dim <<
" argument.\n");
103 mesh_p->
d_fix = std::vector<uint8_t>(mesh_p->
d_nodes.size(), uint8_t(0));
107 std::vector<double> h;
109 for (
size_t i=0; i<dim; i++) {
110 h.push_back((box.second[i] - box.first[i])/nGrid[i]);
114 h_small = std::min(h_small, h[i]);
118 mesh_p->
d_h = h_small;
122 for (
size_t i = 0; i <= nGrid[0]; i++) {
124 mesh_p->
d_vol[i] = h[0];
125 if (i == 0 || i == nGrid[0]) mesh_p->
d_vol[i] *= 0.5;
129 for (
size_t i = 0; i < nGrid[0]; i++) {
131 mesh_p->
d_enc[2 * i + 0] = i;
132 mesh_p->
d_enc[2 * i + 1] = i + 1;
134 }
else if (dim == 2) {
136 for (
size_t j = 0; j <= nGrid[1]; j++) {
137 for (
size_t i = 0; i <= nGrid[0]; i++) {
139 size_t n = j * (nGrid[0] + 1) + i;
141 box.first[1] +
double(j) * h[1], 0.);
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;
150 for (
size_t j = 0; j < nGrid[1]; j++) {
151 for (
size_t i = 0; i < nGrid[0]; i++) {
154 auto n = j * nGrid[0] + i;
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;
163 }
else if (dim == 3) {
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++) {
169 size_t n = k * (nGrid[1] + 1) * (nGrid[0] + 1) + j * (nGrid[0] + 1) + i;
171 box.first[1] +
double(j) * h[1],
172 box.first[2] +
double(k) * h[2]);
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;
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++) {
190 auto n = k * nGrid[1] * nGrid[0] + j * nGrid[0] + i;
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;
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;
219 const std::vector<std::vector<double>> &boxes) {
220 if (boxes.empty() || mesh_p->
d_nodes.empty())
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])
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);
238 for (
size_t i = 0; i < n_old; ++i) {
239 if (inAnyBox(mesh_p->
d_nodes[i]))
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]);
248 std::vector<size_t> enc;
251 enc.reserve(mesh_p->
d_enc.size());
252 for (
size_t e = 0; e + nv <= mesh_p->
d_enc.size(); e += nv) {
254 for (
size_t v = 0; v < nv; ++v) {
255 if (new_id[mesh_p->
d_enc[e + v]] < 0) {
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]]));
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] &&
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));
296 mesh_p->
d_nodes = std::move(nodes);
297 mesh_p->
d_vol = std::move(vol);
298 mesh_p->
d_enc = std::move(enc);
302 mesh_p->
d_fix = std::vector<uint8_t>(mesh_p->
d_nodes.size(), uint8_t(0));
306 const std::vector<util::Point> &xRef,
307 const std::vector<util::Point> &u,
308 std::vector<util::Point> &xQuadCur,
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 "
321 assert(( (xRef.size() >= mesh_p->
getNumNodes() + iNodeStart) ||
324 "Number of elements i nnodal data can not be smaller than number of "
332 elem->getNumQuadPoints();
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");
340 auto *elem_p = elem.get();
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]
349 std::vector<util::Point> nds;
350 for (
const auto &i : id_nds)
351 nds.push_back(xRef[i + iNodeStart]);
353 auto qds = elem_p->getQuadDatas(nds);
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];
364 auto q_global_id = iQuadStart + e * elem_p->getNumQuadPoints() + q;
365 xQuadCur[q_global_id] = qd_point_current;
370 executor.run(taskflow).get();
374 const std::vector<util::Point> & xRef,
375 const std::vector<util::Point> &u,
377 std::vector<util::SymMatrix3> &strain,
378 std::vector<util::SymMatrix3> &stress,
387 assert((mesh_p->
getDimension() > 1) &&
"In getStrainStress(), dimension = 2,3 is supported.\n");
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 "
397 assert(( (xRef.size() >= mesh_p->
getNumNodes() + iNodeStart) ||
400 "Number of elements i nodal data can not be smaller than number of "
408 elem->getNumQuadPoints();
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");
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");
423 auto *elem_p = elem.get();
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,
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]);
442 auto qds = elem_p->getQuadDatas(nds);
444 for (
size_t q=0; q<qds.size(); q++) {
445 auto ssn = strainFromB(
fe::B(qds[q].d_derShapes, dim), u_el);
448 if (dim == 2 && isPlaneStrain)
449 ssn(2, 2) = -nu * (ssn(0, 0) + ssn(1, 1)) / (1. - nu);
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);
457 sss(1, 1) = lambda * trace_ssn + 2 * mu * ssn(1, 1);
458 sss(1, 2) = 2 * mu * ssn(1, 2);
460 sss(2, 2) = lambda * trace_ssn + 2 * mu * ssn(2, 2);
462 if (dim == 2 && !isPlaneStrain)
463 sss(2, 2) = nu * (sss(0, 0) + sss(1, 1));
466 auto q_global_id = iStrainStart + e * elem_p->getNumQuadPoints() + q;
467 strain[q_global_id] = ssn;
469 stress[q_global_id] = sss;
474 executor.run(taskflow).get();
478 const std::vector<util::Point> & xRef,
479 const std::vector<util::Point> &u,
480 const std::vector<util::SymMatrix3> &stress,
481 double &maxShearStress,
488 assert((mesh_p->
getDimension() == 2) &&
"In getMaxShearStressAndLoc(), only dimension = 2 is supported.\n");
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 "
498 assert(( (xRef.size() >= mesh_p->
getNumNodes() + iNodeStart) ||
501 "Number of elements i nnodal data can not be smaller than number of "
509 elem->getNumQuadPoints();
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");
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];
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));
529 max_stress = principle_shear_stress;
537 maxShearStress = max_stress;
544 auto e_nds_start = iNodeStart + mesh_p->
d_eNumVertex * max_stress_e;
546 std::vector<util::Point> nds(xRef.begin() + e_nds_start, xRef.begin() + e_nds_end);
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];
556 maxShearStressLocCur = qd_point_current;
std::vector< size_t > getElementConnectivity(const size_t &i) const
Get the connectivity of element.
size_t getNumNodes() const
Get the number of nodes.
std::vector< size_t > d_enc
Element-node connectivity data.
std::pair< std::vector< double >, std::vector< double > > d_bbox
Bounding box.
std::vector< util::Point > d_nodes
Vector of initial (reference) coordinates of nodes.
size_t d_numElems
Number of elements.
size_t d_eType
Element type.
size_t d_numNodes
Number of nodes.
size_t d_dim
Dimension of the mesh.
size_t getDimension() const
Get the dimension of the domain.
std::vector< uint8_t > d_fix
Vector of fixity mask of each node.
size_t d_numDofs
Number of dofs = (dimension) times (number of nodes)
size_t getElementType() const
Get the type of element in mesh.
std::vector< double > d_vol
Vector of volume of each node.
size_t d_eNumVertex
Number of vertex per element.
size_t getNumElements() const
Get the number of elements.
double d_h
Characteristic mesh spacing (minimum nodal distance); always from computeMeshSize() after nodes exist...
Collects a message with stream syntax for use in an exception.
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.
util::SymMatrix3 strainFromB(const fe::B &B, const std::vector< util::Point > &u)
std::unique_ptr< BaseElem > elem(size_t type, size_t order)
Collection of methods and data related to finite element and mesh.
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, size_t iQuadStart, size_t quadOrder)
Get current location of quadrature points of elements in the mesh. This function expects mesh has ele...
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, size_t iStrainStart, size_t quadOrder)
Get location where maximum of specified component of stress occurs in this particle.
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 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, size_t iStrainStart, double nu, double lambda, double mu, bool computeStress, size_t quadOrder)
Strain and stress at quadrature points in the mesh.
void removeNodesInBoxes(mesh::Mesh *mesh_p, const std::vector< std::vector< double > > &boxes)
Removes nodes lying inside any of the given axis-aligned boxes.
unsigned int getNThreads()
Get number of threads to be used by taskflow.
bool isLess(const double &a, const double &b)
Returns true if a < b.
A structure to represent 3d vectors.
A structure to represent 3d matrices.