PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
materialUtil.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2026 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE)
9 */
10
11#include "materialUtil.h"
12#include "util/io.h"
13#include <stdexcept>
15#include "util/function.h"
16#include "util/parallelUtil.h"
17#include <iostream>
18#include <taskflow/taskflow/taskflow.hpp>
19#include <taskflow/taskflow/algorithm/for_each.hpp>
20
21namespace {
22
23double computeStateMxI(size_t i, const std::vector<util::Point> &nodes,
24 const std::vector<double> &nodal_vol,
25 const std::vector<std::vector<size_t>> &neighbors,
26 const std::vector<std::vector<float>> &neighbors_sq_dist,
27 const double &mesh_size,
29
30 double horizon = material->getHorizon();
31 const auto &xi = nodes[i];
32 double m = 0.;
33
34 // upper and lower bound for volume correction
35 auto check_up = horizon + 0.5 * mesh_size;
36 auto check_low = horizon - 0.5 * mesh_size;
37
38 size_t k = 0;
39 for (size_t j : neighbors[i]) {
40
41 const auto &xj = nodes[j];
42 double rji = (xj - xi).length();
43 //double rji = std::sqrt(neighbors_sq_dist[i][k]);
44
45 if (util::isGreater(rji, horizon)) // or j == i) <-- check! For weighted volume, we don't want to skip the node itself
46 continue;
47
48 // get corrected volume of node j
49 auto volj = nodal_vol[j];
50
51 if (util::isGreater(rji, check_low))
52 volj *= (check_up - rji) / mesh_size;
53
54 m += std::pow(rji, 2) * material->getInfFn(rji) * volj;
55
56 k++;
57 }
58
59 if (util::isLess(m, 1.0E-18)) {
60 std::ostringstream oss;
61 oss << "Error: Weighted nodal volume = " << m
62 << " should not be too close to zero.\n";
63
64 oss << "Mesh size = " << mesh_size << "\n";
65 oss << "J = " << material->getInfFn(0.5 * horizon) << "\n";
66 oss << "weighted volume (times 1.0e10) = " << m*1.e+10 << "\n";
67 oss << "nodal coord = " << xi.printStr() << "\n";
68 oss << material->printStr(0, 0);
69
70 throw std::runtime_error(
72 << oss.str());
73 }
74 return m;
75}
76
77double computeStateThetaxI(size_t i, const std::vector<util::Point> &nodes,
78 const std::vector<util::Point> &nodes_disp,
79 const std::vector<double> &nodal_vol,
80 const std::vector<std::vector<size_t>> &neighbors,
81 const std::vector<std::vector<float>> &neighbors_sq_dist,
82 const double &mesh_size,
84 const geometry::Fracture *fracture,
85 const std::vector<double> &mx) {
86
87 double horizon = material->getHorizon();
88 const auto &xi = nodes[i];
89 const auto &ui = nodes_disp[i];
90 double m = mx[i];
91 double theta = 0.;
92
93 // upper and lower bound for volume correction
94 auto check_up = horizon + 0.5 * mesh_size;
95 auto check_low = horizon - 0.5 * mesh_size;
96
97 size_t k = 0;
98 for (size_t j : neighbors[i]) {
99
100 const auto &xj = nodes[j];
101 const auto &uj = nodes_disp[j];
102 double rji = (xj - xi).length();
103 //double rji = std::sqrt(neighbors_sq_dist[i][k]); // distance in
104 // reference configuration
105
106 if (util::isGreater(rji, horizon) or j == i)
107 continue;
108
109 // get corrected volume of node j
110 auto volj = nodal_vol[j];
111
112 if (util::isGreater(rji, check_low))
113 volj *= (check_up - rji) / mesh_size;
114
115 // get bond state
116 double bond_state = fracture->getBondState(i, k) ? 0. : 1.;
117
118 // get change in bond length
119 auto yi = xi + ui;
120 auto yj = xj + uj;
121 double change_length = (yj - yi).length() - rji;
122
123 theta += bond_state * rji * change_length *
124 material->getInfFn(rji) * volj;
125
126 k += 1;
127 }
128
129 // 3/m in 3D, 2/m in 2D (Yang et al. 2024, eqs. 8-9)
130 return double(material->getDimension()) * theta / m;
131}
132
133double computeHydrostaticStrainI(size_t i, const std::vector<util::Point> &nodes,
134 const std::vector<util::Point> &nodes_disp,
135 const std::vector<double> &nodal_vol,
136 const std::vector<std::vector<size_t>> &neighbors,
137 const std::vector<std::vector<float>> &neighbors_sq_dist,
138 const double &mesh_size,
140 const geometry::Fracture *fracture,
141 size_t dim) {
142
143 double horizon = material->getHorizon();
144 const auto &xi = nodes[i];
145 const auto &ui = nodes_disp[i];
146 double theta = 0.;
147
148 // upper and lower bound for volume correction
149 auto check_up = horizon + 0.5 * mesh_size;
150 auto check_low = horizon - 0.5 * mesh_size;
151
152 // get volume of ball
153 double vol_ball = std::pow(horizon, 2) * M_PI;
154 if (dim == 3)
155 vol_ball *= horizon * 4. / 3.;
156
157 size_t k = 0;
158 for (size_t j : neighbors[i]) {
159
160 const auto &xj = nodes[j];
161 const auto &uj = nodes_disp[j];
162 double rji = (xj - xi).length();
163 //double rji = std::sqrt(neighbors_sq_dist[i][k]);
164
165 if (util::isGreater(rji, horizon) or j == i)
166 continue;
167
168 // get corrected volume of node j
169 auto volj = nodal_vol[j];
170
171 if (util::isGreater(rji, check_low))
172 volj *= (check_up - rji) / mesh_size;
173
174 // get bond state
175 double bond_state = fracture->getBondState(i, k) ? 0. : 1.;
176
177 // get bond strain
178 double Sji = material->getS(xj - xi, uj - ui);
179
180 theta += bond_state * rji * Sji *
181 material->getInfFn(rji) * volj / vol_ball;
182
183 k += 1;
184 }
185
186 return theta;
187}
188
189void updateBondFractureDataI(size_t i, const std::vector<util::Point> &nodes,
190 const std::vector<std::vector<size_t>> &neighbors,
191 const std::vector<util::Point> &nodes_disp,
193 geometry::Fracture *fracture) {
194
195 size_t k = 0;
196 for (size_t j : neighbors[i]) {
197
198 double s = material->getS(nodes[j] - nodes[i], nodes_disp[j] -
199 nodes_disp[i]);
200 double sc = material->getSc((nodes[j] - nodes[i]).length());
201
202 // get fracture state, modify, and set
203 auto fs = fracture->getBondState(i, k);
204 if (!fs && util::isGreater(std::abs(s), sc + 1.0e-10))
205 fs = true;
206 fracture->setBondState(i, k, fs);
207
208 k += 1;
209 }
210}
211
212} // anonymous namespace
213
214void material::computeStateMx(data::ModelData *model, bool compute_in_parallel) {
215
216 model->d_mX.resize(model->d_x.size());
217 if (!compute_in_parallel) {
218 for (size_t i = 0; i < model->d_x.size(); i++) {
219 const auto &pti = model->getPtId(i);
220 const auto &particle = model->getParticleFromAllList(pti);
221 auto mx = computeStateMxI(i, model->d_xRef, model->d_vol,
222 model->d_neighPd, model->d_neighPdSqdDist,
223 particle->getMeshSize(),
224 particle->getMaterial());
225
226 model->setMx(i, mx);
227 }
228 } else {
229
230 tf::Executor executor(util::parallel::getNThreads());
231 tf::Taskflow taskflow;
232
233 taskflow.for_each_index(
234 (std::size_t) 0, model->d_x.size(), (std::size_t) 1, [model](std::size_t i) {
235 const auto &pti = model->getPtId(i);
236 const auto &particle = model->getParticleFromAllList(pti);
237 auto mx = computeStateMxI(i, model->d_xRef, model->d_vol,
238 model->d_neighPd, model->d_neighPdSqdDist,
239 particle->getMeshSize(),
240 particle->getMaterial());
241
242 model->setMx(i, mx);
243 }
244 ); // for_each
245
246 executor.run(taskflow).get();
247 }
248}
249
250void material::computeStateThetax(data::ModelData *model, bool compute_in_parallel) {
251
252 model->d_thetaX.resize(model->d_x.size());
253 if (!compute_in_parallel) {
254 for (size_t i = 0; i < model->d_x.size(); i++) {
255 const auto &pti = model->getPtId(i);
256 const auto &particle = model->getParticleFromAllList(pti);
257
258 auto thetax = computeStateThetaxI(i, model->d_xRef, model->d_u,
259 model->d_vol,
260 model->d_neighPd, model->d_neighPdSqdDist,
261 particle->getMeshSize(),
262 particle->getMaterial(),
263 model->d_fracture_p.get(),
264 model->d_mX);
265
266 model->setThetax(i, thetax);
267
268 }
269
270 } else {
271
272 tf::Executor executor(util::parallel::getNThreads());
273 tf::Taskflow taskflow;
274
275 taskflow.for_each_index(
276 (std::size_t) 0, model->d_x.size(), (std::size_t) 1, [model](std::size_t i) {
277 const auto &pti = model->getPtId(i);
278 const auto &particle = model->getParticleFromAllList(pti);
279
280 auto thetax = computeStateThetaxI(i, model->d_xRef, model->d_u,
281 model->d_vol,
282 model->d_neighPd, model->d_neighPdSqdDist,
283 particle->getMeshSize(),
284 particle->getMaterial(),
285 model->d_fracture_p.get(),
286 model->d_mX);
287
288 model->setThetax(i, thetax);
289 }
290 ); // for_each
291
292 executor.run(taskflow).get();
293 }
294}
295
296void material::computeHydrostaticStrain(data::ModelData *model, bool compute_in_parallel) {
297
298 model->d_thetaX.resize(model->d_x.size());
299 if (!compute_in_parallel) {
300 for (size_t i = 0; i < model->d_x.size(); i++) {
301 const auto &pti = model->getPtId(i);
302 const auto &particle = model->getParticleFromAllList(pti);
303
304 auto thetax = computeHydrostaticStrainI(i, model->d_xRef, model->d_u,
305 model->d_vol,
306 model->d_neighPd, model->d_neighPdSqdDist,
307 particle->getMeshSize(),
308 particle->getMaterial(),
309 model->d_fracture_p.get(),
310 particle->getDimension());
311
312 model->setThetax(i, thetax);
313 }
314 } else {
315
316 tf::Executor executor(util::parallel::getNThreads());
317 tf::Taskflow taskflow;
318
319 taskflow.for_each_index(
320 (std::size_t) 0, model->d_x.size(), (std::size_t) 1, [model](std::size_t i) {
321 const auto &pti = model->getPtId(i);
322 const auto &particle = model->getParticleFromAllList(pti);
323
324 auto thetax = computeHydrostaticStrainI(i,
325 model->d_xRef,
326 model->d_u,
327 model->d_vol,
328 model->d_neighPd, model->d_neighPdSqdDist,
329 particle->getMeshSize(),
330 particle->getMaterial(),
331 model->d_fracture_p.get(),
332 particle->getDimension());
333
334 model->setThetax(i, thetax);
335 }
336 ); // for_each
337
338 executor.run(taskflow).get();
339 }
340
341}
342
343void material::updateBondFractureData(data::ModelData *model, bool compute_in_parallel) {
344
345 if (!compute_in_parallel) {
346 for (size_t i = 0; i < model->d_x.size(); i++) {
347 const auto &pti = model->getPtId(i);
348 const auto &particle = model->getParticleFromAllList(pti);
349
350 updateBondFractureDataI(i, model->d_xRef, model->d_neighPd, model->d_u,
351 particle->getMaterial(),
352 model->d_fracture_p.get());
353 }
354 } else {
355
356 tf::Executor executor(util::parallel::getNThreads());
357 tf::Taskflow taskflow;
358
359 taskflow.for_each_index(
360 (std::size_t) 0, model->d_x.size(), (std::size_t) 1, [model](std::size_t i) {
361 const auto &pti = model->getPtId(i);
362 const auto &particle = model->getParticleFromAllList(pti);
363
364 updateBondFractureDataI(i,
365 model->d_xRef,
366 model->d_neighPd,
367 model->d_u,
368 particle->getMaterial(),
369 model->d_fracture_p.get());
370 }
371 ); // for_each
372
373 executor.run(taskflow).get();
374 }
375}
A class to store model data.
Definition modelData.h:50
std::vector< util::Point > d_x
Current positions of the nodes.
Definition modelData.h:745
std::vector< util::Point > d_xRef
reference positions of the nodes
Definition modelData.h:742
std::vector< util::Point > d_u
Displacement of the nodes.
Definition modelData.h:748
std::vector< double > d_mX
Weighted volume.
Definition modelData.h:808
size_t & getPtId(size_t i)
Get particle id given the location in particle list.
Definition modelData.h:187
std::vector< std::vector< float > > d_neighPdSqdDist
Square distance neighbor data for peridynamic forces.
Definition modelData.h:773
std::unique_ptr< geometry::Fracture > d_fracture_p
Fracture state of bonds.
Definition modelData.h:736
std::vector< double > d_thetaX
Dilation.
Definition modelData.h:802
std::vector< std::vector< size_t > > d_neighPd
Neighbor data for peridynamic forces.
Definition modelData.h:770
void setMx(size_t i, const double &mx)
Set weighted-volume (mx) of the node.
Definition modelData.h:548
void setThetax(size_t i, const double &thetax)
Set volumetric deformation (thetax) of the node.
Definition modelData.h:579
std::vector< double > d_vol
Nodal volumes.
Definition modelData.h:760
const particle::BaseParticle * getParticleFromAllList(size_t i) const
Get pointer to base particle.
Definition modelData.h:86
A class for fracture state of bonds.
Definition fracture.h:26
void setBondState(const std::size_t &i, const std::size_t &j, const bool &state)
Sets the bond state.
Definition fracture.cpp:51
bool getBondState(const std::size_t &i, const std::size_t &j) const
Read bond state.
Definition fracture.cpp:64
Collection of methods and database related to peridynamic material.
Definition material.h:98
Collects a message with stream syntax for use in an exception.
Definition io.h:52
std::string str() const
The message built so far.
Definition io.h:67
void updateBondFractureDataI(size_t i, const std::vector< util::Point > &nodes, const std::vector< std::vector< size_t > > &neighbors, const std::vector< util::Point > &nodes_disp, const material::Material *material, geometry::Fracture *fracture)
double computeHydrostaticStrainI(size_t i, const std::vector< util::Point > &nodes, const std::vector< util::Point > &nodes_disp, const std::vector< double > &nodal_vol, const std::vector< std::vector< size_t > > &neighbors, const std::vector< std::vector< float > > &neighbors_sq_dist, const double &mesh_size, const material::Material *material, const geometry::Fracture *fracture, size_t dim)
double computeStateThetaxI(size_t i, const std::vector< util::Point > &nodes, const std::vector< util::Point > &nodes_disp, const std::vector< double > &nodal_vol, const std::vector< std::vector< size_t > > &neighbors, const std::vector< std::vector< float > > &neighbors_sq_dist, const double &mesh_size, const material::Material *material, const geometry::Fracture *fracture, const std::vector< double > &mx)
double computeStateMxI(size_t i, const std::vector< util::Point > &nodes, const std::vector< double > &nodal_vol, const std::vector< std::vector< size_t > > &neighbors, const std::vector< std::vector< float > > &neighbors_sq_dist, const double &mesh_size, const material::Material *material)
void computeHydrostaticStrain(data::ModelData *model, bool compute_in_parallel=false)
void computeStateMx(data::ModelData *model, bool compute_in_parallel=false)
Computes the moment term in state-based peridynamic formulation.
void updateBondFractureData(data::ModelData *model, bool compute_in_parallel=false)
void computeStateThetax(data::ModelData *model, bool compute_in_parallel=false)
Collection of methods and data related to particle object.
Definition modelData.h:36
unsigned int getNThreads()
Get number of threads to be used by taskflow.
bool isGreater(const double &a, const double &b)
Returns true if a > b.
Definition function.cpp:17
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:22