PeriDEM 0.2.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2024 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 <PeriDEMConfig.h>
12
13#include "model/dem/demModel.h"
16#include "util/function.h"
17#include "util/geomObjects.h"
18#include "util/matrix.h"
19#include "util/methods.h"
20#include "util/point.h"
22#include "rw/reader.h"
23#include "util/function.h"
24#include "util/geom.h"
25#include "util/methods.h"
26#include "util/randomDist.h"
27#include "util/parallelUtil.h"
29#include "inp/decks/modelDeck.h"
34#include "fe/elemIncludes.h"
35#include "fe/meshUtil.h"
36
37#include <fmt/format.h>
38#include <fstream>
39#include <iostream>
40#include <random>
41
42#include <taskflow/taskflow/taskflow.hpp>
43#include <taskflow/taskflow/algorithm/for_each.hpp>
44
49using util::io::log;
50
55class Model : public model::DEMModel {
56
57public:
58
64 explicit Model(inp::Input *deck) : model::DEMModel(deck, "twoparticle_demo::Model") {
65
66 if (d_ppFile.is_open())
67 d_ppFile.close();
68
69 std::string filename =
70 d_outputDeck_p->d_path + "pp_" + d_outputDeck_p->d_tagPPFile + ".csv";
71 d_ppFile = std::ofstream(filename, std::ios_base::out);
72 d_ppFile << "t, delta, cont_area_r, s_loc, s_val, max_dist, "
73 "cont_area_r_ideal, s_loc_ideal, s_val_ideal" << std::flush;
74 }
75
81 void run(inp::Input *deck) override {
82
83 log(d_name + ": Running TwoParticle_Demo app \n");
84
85 // initialize data
86 init();
87
88 // check if init() successfully created quadrature data which we need for postprocessing
89 {
90 size_t totalQuadPoints = 0;
91 for (auto &p: d_particlesListTypeAll) {
92 const auto &particle_mesh_p = p->d_rp_p->getMeshP();
93
94 // get Quadrature
95 fe::BaseElem *elem;
96 if (particle_mesh_p->getElementType() == util::vtk_type_line)
97 elem = new fe::LineElem(d_modelDeck_p->d_quadOrder);
98 else if (particle_mesh_p->getElementType() == util::vtk_type_triangle)
99 elem = new fe::TriElem(d_modelDeck_p->d_quadOrder);
100 else if (particle_mesh_p->getElementType() == util::vtk_type_quad)
101 elem = new fe::QuadElem(d_modelDeck_p->d_quadOrder);
102 else if (particle_mesh_p->getElementType() == util::vtk_type_tetra)
103 elem = new fe::TetElem(d_modelDeck_p->d_quadOrder);
104 else {
105 std::cerr << fmt::format("Error: Can not compute strain/stress as the element "
106 "type = {} is not yet supported in this routine.\n", particle_mesh_p->getElementType());
107 exit(EXIT_FAILURE);
108 }
109
110 totalQuadPoints += particle_mesh_p->getNumElements() *
111 elem->getNumQuadPoints();
112 }
113
114 if (d_xQuadCur.size() != totalQuadPoints
115 or d_strain.size() != totalQuadPoints
116 or d_stress.size() != totalQuadPoints) {
117 std::cerr << "Error: DEMModel::init() did not initialize quadrature data.\n";
118 exit(EXIT_FAILURE);
119 }
120 }
121
122 // integrate in time
123 integrate();
124
125 // close
126 close();
127 }
128
132 void integrate() override {
133 // perform output at the beginning
134 if (d_n == 0 && d_outputDeck_p->d_performOut) {
135 log(fmt::format("{}: Output step = {}, time = {:.6f} \n", d_name, d_n, d_time),
136 2);
137 output();
138 }
139
140 // apply initial condition
141 if (d_n == 0) applyInitialCondition();
142
143 // apply loading
146
147 for (size_t i = d_n; i < d_modelDeck_p->d_Nt; i++) {
148
149 log(fmt::format("{}: Time step: {}, time: {:8.6f}, steps completed = {}%\n",
150 d_name,
151 i,
152 d_time,
153 float(i) * 100. / d_modelDeck_p->d_Nt),
154 2, d_n % d_infoN == 0, 3);
155
156 // NOTE: If there is need for different time-stepping scheme, one can
157 // define another function similar to these two below
158 auto t1 = steady_clock::now();
160 double integrate_time =
161 util::methods::timeDiff(t1, steady_clock::now());
162
163 log(fmt::format(" Integration time (ms) = {}\n", integrate_time),
164 2, d_n % d_infoN == 0, 3);
165
166 if (d_pDeck_p->d_testName == "two_particle") {
167 // NOTE: The purpose of this app 'twop' is to show that if we have
168 // specific post-processing requirement from the outcome of
169 // simulation -- eg in two-particle test, we may be interested in the
170 // maximum of y-coordinate of top particle to measure the damping
171 // effect or the maximum shear stress -- we wrap the base DEMModel
172 // class as we did here and add a specific post-processing function
173 // like 'ppTwoParticleTest()'.
175 }
176
177 // handle general output
178 if ((d_n % d_outputDeck_p->d_dtOut == 0) &&
179 (d_n >= d_outputDeck_p->d_dtOut) && d_outputDeck_p->d_performOut) {
180 output();
181 }
182
183 // check for stop (we may want to terminate the simulation early if the
184 // results are garbage, or if some other criteria is met)
185 // NOTE: this too can be specific to particular application
186 checkStop();
187 } // loop over time steps
188 }
189
194
195 bool continue_dt = false;
196 auto check_dt = d_outputDeck_p->d_dtTestOut;
197 if ((d_n % check_dt == 0) && (d_n >= check_dt))
198 continue_dt = true;
199
200 if (!continue_dt)
201 return;
202
203 // compute QoIs
206
207 // log
208 d_ppFile << d_time << ", " << -d_penDist << ", " << d_contactAreaRadius
209 << ", " << d_maxStressLocRef << ", " << d_maxStress << ", "
210 << d_maxDist << ", " << d_contactAreaRadiusIdeal << ", "
212 << std::endl;
213 }
214
219
220 // get alias for particles
221 const auto &p0 = this->d_particlesListTypeAll[0];
222 const auto &p1 = this->d_particlesListTypeAll[1];
223
224 // get penetration distance
225 const auto &xc0 = p0->getXCenter();
226 const auto &xc1 = p1->getXCenter();
227 const double &r = p0->d_geom_p->boundingRadius();
228
229 const auto &contact = d_cDeck_p->getContact(p0->d_zoneId, p1->d_zoneId);
230 double r_e = r + contact.d_contactR;
231
232 d_penDist = xc1.dist(xc0) - r_e - r;
233 if (util::isLess(d_penDist, 0.))
235 std::sqrt(std::pow(r_e, 2.) - std::pow(r_e + d_penDist, 2.));
236 else if (util::isGreater(d_penDist, 0.)) {
237 d_penDist = 0.;
239 }
240
241 // get max distance of second particle (i.e. the y-coord of center + radius)
242 d_maxDist = xc1.d_y + p1->d_geom_p->boundingRadius();
243
244 // compute maximum y coordinate of particle 2
245 double max_y_loc = p1->getXLocal(0).d_y;
246 for (size_t i = 0; i < p1->getNumNodes(); i++)
247 if (util::isLess(max_y_loc, p1->getXLocal(i).d_y))
248 max_y_loc = p1->getXLocal(i).d_y;
249
250 if (util::isLess(d_maxY, max_y_loc))
251 d_maxY = max_y_loc;
252
253 log(fmt::format("max y: {} \n", d_maxY), 2, d_n % d_infoN == 0, 3);
254
255 // compute ideal values
256 static int contact_pp_ideal = -1;
257 if (contact_pp_ideal == -1) {
258 double mass = p1->getDensity() * M_PI * std::pow(r, 2.);
259
260 const auto &mat_data =
261 p1->getMaterial()->computeMaterialProperties(d_modelDeck_p->d_dim);
262
263 d_contactAreaRadiusIdeal = 3. * mass * std::abs(d_pDeck_p->d_gravity[1]) *
264 2. * r * (1. - std::pow(mat_data.d_nu, 2.)) /
265 (4. * mat_data.d_E);
267
269
271 0.93 * mass * std::abs(d_pDeck_p->d_gravity[1]) /
273
274 contact_pp_ideal = 0;
275 }
276 }
277
282
283 // compute maximum shear stress and where it occurs
284 double max_stress_t = 0.;
285 auto max_stress_loc_cur_t = util::Point();
286 auto max_stress_loc_ref_t = util::Point();
287
288 // if particle mat data is not computed, compute them
289 if (d_particlesMatDataList.empty()) {
290 for (auto &p: d_particlesListTypeAll) {
291 d_particlesMatDataList.push_back(p->getMaterial()->computeMaterialProperties(
292 p->getMeshP()->getDimension()));
293 }
294 }
295
296 // compute stress and strain
297 for (auto &p: d_particlesListTypeAll) {
298
299 const auto particle_mesh_p = p->getMeshP();
300
301 fe::getCurrentQuadPoints(particle_mesh_p.get(), d_xRef, d_u, d_xQuadCur,
302 p->d_globStart,
303 p->d_globQuadStart,
304 d_modelDeck_p->d_quadOrder);
305
306 auto p_z_id = p->d_zoneId;
307 auto isPlaneStrain = d_pDeck_p->d_particleZones[p_z_id].d_matDeck.d_isPlaneStrain;
308 fe::getStrainStress(particle_mesh_p.get(), d_xRef, d_u,
309 isPlaneStrain,
311 p->d_globStart,
312 p->d_globQuadStart,
313 d_particlesMatDataList[p->getId()].d_nu,
314 d_particlesMatDataList[p->getId()].d_lambda,
315 d_particlesMatDataList[p->getId()].d_mu,
316 true,
317 d_modelDeck_p->d_quadOrder);
318
319 double p_max_stress = 0.;
320 auto p_max_stress_loc_cur = util::Point();
321 auto p_max_stress_loc_ref = util::Point();
322 fe::getMaxShearStressAndLoc(p->getMeshP().get(), d_xRef, d_u, d_stress,
323 p_max_stress,
324 p_max_stress_loc_ref,
325 p_max_stress_loc_cur,
326 p->d_globStart, p->d_globQuadStart, d_modelDeck_p->d_quadOrder);
327
328 if (util::isGreater(p_max_stress, max_stress_t)) {
329 max_stress_t = p_max_stress;
330 auto p_center_node_id = p->d_globStart + p->d_rp_p->getCenterNodeId();
331 max_stress_loc_ref_t = p_max_stress_loc_ref - d_xRef[p_center_node_id];
332 max_stress_loc_cur_t = p_max_stress_loc_cur - d_x[p_center_node_id];
333 }
334 }
335
336 d_maxStress = max_stress_t;
337 d_maxStressLocRef = max_stress_loc_ref_t.length();
338 d_maxStressLocCur = max_stress_loc_cur_t.length();
339 }
340
341public:
342
344 double d_penDist = 0.;
345
348
350 double d_maxDist = 0.;
351
353 double d_maxStress = 0.;
354
356 double d_maxStressLocRef = 0.;
357
359 double d_maxStressLocCur = 0.;
360
362 double d_maxY = 0.;
363
366
368 double d_maxStressIdeal = 0.;
369
372};
373} // namespace twoparticle_demo
374
375int main(int argc, char *argv[]) {
376
377 // print program version
378 std::cout << "TwoParticle_Demo (PeriDEM)"
379 << " (Version " << MAJOR_VERSION << "." << MINOR_VERSION << "."
380 << UPDATE_VERSION << ")" << std::endl << std::flush;
381
382 util::io::InputParser input(argc, argv);
383
384 if (input.cmdOptionExists("-h")) {
385 // print help
386 std::cout << "Syntax to run the app: ./TwoParticle_Demo -i <input file> -nThreads <number of threads>";
387 std::cout << "Example: ./TwoParticle_Demo -i input.yaml -nThreads 2";
388 }
389
390 // read input arguments
391 unsigned int nThreads;
392 if (input.cmdOptionExists("-nThreads")) nThreads = std::stoi(input.getCmdOption("-nThreads"));
393 else {
394 nThreads = 2;
395 util::io::print(fmt::format("Running TwoParticle_Demo with number of threads = {}\n", nThreads));
396 }
397 // set number of threads
399 util::io::print(fmt::format("Number of threads = {}\n", util::parallel::getNThreads()));
400
401 std::string filename;
402 if (input.cmdOptionExists("-i"))
403 filename = input.getCmdOption("-i");
404 else {
405 filename = "./example/input_0.yaml";
406 util::io::print(fmt::format("Running TwoParticle_Demo with example input file = {}\n", filename));
407 }
408
409 // current time
410 auto begin = steady_clock::now();
411
412 // create deck
413 auto *deck = new inp::Input(filename);
414
415 // check which model to run
416 if (deck->isPeriDEM()) {
417 // ensure two variables in the deck are set
418 deck->getModelDeck()->d_populateElementNodeConnectivity = true;
419
420 // simulate model
421 twoparticle_demo::Model dem(deck);
422 dem.run(deck);
423 }
424
425 // get time elapsed
426 auto end = steady_clock::now();
427
428 std::cout << "Total simulation time (s) = "
429 << util::methods::timeDiff(begin, end, "seconds")
430 << std::endl;
431}
size_t const MINOR_VERSION
size_t const UPDATE_VERSION
size_t const MAJOR_VERSION
A base class which provides methods to map points to/from reference element and to compute quadrature...
Definition baseElem.h:84
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
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
A class to read input file.
Definition input.h:61
A class for discrete element particle simulation with peridynamic model
Definition demModel.h:32
virtual void computeExternalForces()
Computes external/boundary condition forces.
Definition demModel.cpp:791
DEMModel(inp::Input *deck, std::string modelName="DEMModel")
Constructor.
Definition demModel.cpp:44
virtual void output()
Output the snapshot of data at current time step.
virtual void applyInitialCondition()
Applies initial condition.
virtual void computeExternalDisplacementBC()
Applies displacement boundary conditions.
Definition demModel.cpp:814
virtual void integrateStep()
Performs one time step.
Definition demModel.cpp:342
virtual void close()
Closure operations.
Definition demModel.cpp:104
void log(std::ostringstream &oss, int priority=0, bool check_condition=true, int override_priority=-1, bool screen_out=false)
Prints message if any of these two conditions are true.
Definition demModel.cpp:53
virtual void init()
Initialize remaining data members.
Definition demModel.cpp:109
virtual void checkStop()
Checks if simulation should be stopped due to abnormal state of system.
std::string d_name
Name of the model for logging purposes (useful if other classes are built on top of this class)
Definition demModel.h:42
std::shared_ptr< inp::ContactDeck > d_cDeck_p
Contact deck.
Definition modelData.h:564
std::vector< particle::BaseParticle * > d_particlesListTypeAll
List of particles + walls.
Definition modelData.h:592
std::vector< util::Point > d_xRef
reference positions of the nodes
Definition modelData.h:630
size_t d_infoN
Print log step interval.
Definition modelData.h:540
std::vector< util::Point > d_u
Displacement of the nodes.
Definition modelData.h:636
std::shared_ptr< inp::ModelDeck > d_modelDeck_p
Model deck.
Definition modelData.h:552
std::vector< util::SymMatrix3 > d_stress
Stress in elements (values at quadrature points)
Definition modelData.h:737
size_t d_n
Current time step.
Definition modelData.h:531
std::vector< util::Point > d_x
Current positions of the nodes.
Definition modelData.h:633
std::ofstream d_ppFile
File stream to output information.
Definition modelData.h:546
std::vector< util::Point > d_xQuadCur
Current position of quadrature points.
Definition modelData.h:731
std::shared_ptr< inp::OutputDeck > d_outputDeck_p
Output deck.
Definition modelData.h:558
double d_time
Current time.
Definition modelData.h:534
std::shared_ptr< inp::ParticleDeck > d_pDeck_p
Particle deck.
Definition modelData.h:561
std::vector< util::SymMatrix3 > d_strain
Strain in elements (values at quadrature points)
Definition modelData.h:734
std::vector< inp::MatData > d_particlesMatDataList
List of particle material data. Only populated if needed for calculation of stress or other quantitie...
Definition modelData.h:604
Main model class to handle demo two-particle test implementation. Goal is to show that it is easy to ...
Definition main.cpp:55
double d_maxStressIdeal
Ideal maximum stress.
Definition main.cpp:368
double d_maxStressLocCur
Maximum stress location in current configuration.
Definition main.cpp:359
void twoParticleTest()
Handles postprocessing for two-particle test.
Definition main.cpp:193
void twoParticleTestPenetrationDist()
Computes penetration distance of top particle into bottom particle.
Definition main.cpp:218
double d_maxStressLocRefIdeal
Ideal maximum stress location location in reference configuration.
Definition main.cpp:371
void integrate() override
Perform time step integration.
Definition main.cpp:132
double d_contactAreaRadiusIdeal
Ideal contact area radius from Hertz theory.
Definition main.cpp:365
double d_maxStress
Maximum stress.
Definition main.cpp:353
double d_maxDist
Maximum vertical distance of top particle in initial configuration.
Definition main.cpp:350
double d_maxY
Current maximum vertical distance of top particle.
Definition main.cpp:362
double d_contactAreaRadius
Contact area radius.
Definition main.cpp:347
double d_penDist
Penetration distance of top particle into bottom particle.
Definition main.cpp:344
double d_maxStressLocRef
Maximum stress location in reference configuration.
Definition main.cpp:356
void twoParticleTestMaxShearStress()
Computes maximum shear stress and its location in particle.
Definition main.cpp:281
void run(inp::Input *deck) override
Runs simulation by executing steps such as init(), integrate(), and close().
Definition main.cpp:81
Model(inp::Input *deck)
Constructor.
Definition main.cpp:64
Input command line argument parser.
Definition io.h:355
bool cmdOptionExists(const std::string &option) const
Check if argument exists.
Definition io.h:387
const std::string & getCmdOption(const std::string &option) const
Get value of argument specified by key.
Definition io.h:372
static const int vtk_type_triangle
Integer flag for triangle element.
static const int vtk_type_quad
Integer flag for quad element.
static const int vtk_type_tetra
Integer flag for tetrahedron element.
static const int vtk_type_line
Integer flag for line element.
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.
Definition meshUtil.cpp:429
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.
Definition meshUtil.cpp:280
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 ele...
Definition meshUtil.cpp:176
Namespace to define demo app for two-particle tests.
Definition main.cpp:48
void print(const T &msg, int nt=print_default_tab, int printMpiRank=print_default_mpi_rank)
Prints formatted information.
Definition io.h:108
void log(std::ostringstream &oss, bool screen_out=false, int printMpiRank=print_default_mpi_rank)
Global method to log the message.
Definition io.cpp:38
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
unsigned int getNThreads()
Get number of threads to be used by taskflow.
void initNThreads(unsigned int nThreads=std::thread::hardware_concurrency())
Initializes MpiStatus struct.
bool isGreater(const double &a, const double &b)
Returns true if a > b.
Definition function.cpp:15
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:20
A structure to represent 3d vectors.
Definition point.h:30
int main()