PeriDEM 0.3.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 - 2026 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 */
8
10#include "inp/deckIncludes.h"
12#include "periDEMModel.h"
13#include "util/function.h"
14#include "util/io.h"
15#include <algorithm>
16#include <cmath>
17#include <filesystem>
18#include <format>
19#include <fstream>
20#include <limits>
21#include <random>
22#include <stdexcept>
23#include <string>
24#include <thread>
25#include <vector>
26
27namespace {
28
29std::string directoryPathWithTrailingSep(const std::filesystem::path &dir) {
30 namespace fs = std::filesystem;
31 fs::path n = fs::absolute(dir).lexically_normal();
32 std::string s = n.string();
33 if (!s.empty() && s.back() != '/' && s.back() != '\\')
34 s += fs::path::preferred_separator;
35 return s;
36}
37
39 int zone{};
40 double x{}, y{}, z{}, r{}, theta{};
41};
42
43double maxElem(const std::vector<double> &v) {
44 double m = -std::numeric_limits<double>::infinity();
45 for (double x : v)
46 m = std::max(m, x);
47 return m;
48}
49
50bool doesParticleIntersect(const PackedParticle &p, const std::vector<PackedParticle> &existing,
51 const std::vector<double> &rect, double padding) {
52 const double p_rect_lox = p.x - p.r;
53 const double p_rect_loy = p.y - p.r;
54 const double p_rect_hix = p.x + p.r;
55 const double p_rect_hiy = p.y + p.r;
56 if (p_rect_lox < rect[0] + padding || p_rect_loy < rect[1] + padding || p_rect_hix > rect[3] - padding ||
57 p_rect_hiy > rect[4] - padding)
58 return true;
59
60 for (const auto &q : existing) {
61 const double dx = p.x - q.x;
62 const double dy = p.y - q.y;
63 const double dz = p.z - q.z;
64 const double dist = std::sqrt(dx * dx + dy * dy + dz * dz);
65 if (dist <= p.r + q.r + padding)
66 return true;
67 }
68 return false;
69}
70
75std::vector<PackedParticle> generateParticleLocations(const std::vector<double> &in_rect, double max_y,
76 double mesh_size, double R, int N_target,
77 double padding, std::mt19937 &gen) {
78 std::vector<PackedParticle> particles;
79 std::uniform_real_distribution<double> u_r(-0.1 * R, 0.1 * R);
80 /* Do not use uniform_int_distribution: libstdc++ vs libc++ map mt19937
81 * differently, so geom_id diverges while x,y,theta stay the same. */
82
83 const double check_r = R;
84 const int rows = static_cast<int>((max_y - in_rect[1]) / (2.0 * check_r));
85 const double rect_L = in_rect[3] - in_rect[0];
86 const int cols = static_cast<int>(rect_L / (2.0 * check_r));
87
88 int counter = 0;
89 double x_old = in_rect[0];
90 double x_old_right = in_rect[3];
91 double y_old = in_rect[1];
92 const double cz = 0.0;
93
94 std::vector<double> cy_accptd;
95 cy_accptd.push_back(y_old);
96
97 std::vector<double> row_rads_prev{R, R};
98 for (int i = 0; i < rows; ++i) {
99 if (i > 0)
100 y_old = maxElem(cy_accptd) + maxElem(row_rads_prev);
101
102 std::vector<double> row_rads{R};
103
104 if (y_old + padding + maxElem(row_rads) >= max_y)
105 break;
106
107 int num_p_cols = 0;
108 int j = 0;
109 while (true) {
110 if (num_p_cols > cols - 1 || j > 100 * N_target)
111 break;
112 if (counter >= N_target)
113 break;
114
115 if (j == 0) {
116 x_old = in_rect[0];
117 x_old_right = in_rect[3];
118 }
119
120 const int p_zone = static_cast<int>(gen() % 8);
121 const double r0 = R;
122 double r = r0 + u_r(gen);
123
124 double cx = 0., cy = 0.;
125 if (i % 2 == 0) {
126 std::uniform_real_distribution<double> rph(-0.1 * r0, 0.05 * r0);
127 std::uniform_real_distribution<double> rpv(-0.05 * r0, 0.05 * r0);
128 const double cx0 = x_old_right - padding - r;
129 cx = cx0 - rph(gen);
130 cy = y_old + padding + r + rpv(gen);
131 } else {
132 std::uniform_real_distribution<double> rph(-0.05 * r0, 0.1 * r0);
133 std::uniform_real_distribution<double> rpv(-0.05 * r0, 0.05 * r0);
134 const double cx0 = x_old + padding + r;
135 cx = cx0 + rph(gen);
136 cy = y_old + padding + r + rpv(gen);
137 }
138
139 PackedParticle trial{p_zone, cx, cy, cz, r, 0.0};
140 if (!doesParticleIntersect(trial, particles, in_rect, padding)) {
141 std::uniform_real_distribution<double> orient(0.0, 2.0 * M_PI);
142 trial.theta = orient(gen);
143 particles.push_back(trial);
144 row_rads.push_back(trial.r);
145 cy_accptd.push_back(cy);
146 if (i % 2 == 0)
147 x_old_right = cx - trial.r;
148 else
149 x_old = cx + trial.r;
150
151 ++counter;
152 num_p_cols++;
153 }
154 ++j;
155 }
156 row_rads_prev = std::move(row_rads);
157 }
158 return particles;
159}
160
163 double min_x{}, max_x{}, min_y{}, max_y{};
164};
165
166PackedBounds packedAxisBounds(const std::vector<PackedParticle> &packed) {
167 PackedBounds b;
168 b.min_x = std::numeric_limits<double>::infinity();
169 b.max_x = -std::numeric_limits<double>::infinity();
170 b.min_y = std::numeric_limits<double>::infinity();
171 b.max_y = -std::numeric_limits<double>::infinity();
172 for (const auto &p : packed) {
173 b.min_x = std::min(b.min_x, p.x - p.r);
174 b.max_x = std::max(b.max_x, p.x + p.r);
175 b.min_y = std::min(b.min_y, p.y - p.r);
176 b.max_y = std::max(b.max_y, p.y + p.r);
177 }
178 return b;
179}
180
181json contactPairJson(double R_contact_factor, bool damping_on, bool friction_on, double Kn, double beta_n_eps,
182 double friction_coeff, double Kn_factor, double beta_n_factor) {
183 json j;
184 j["Contact_Radius_Factor"] = R_contact_factor;
185 if (Kn < 1e-20) {
186 j["Kn"] = 0.0;
187 } else {
188 j["Kn"] = Kn;
189 }
190 j["Damping_On"] = damping_on;
191 j["Epsilon"] = beta_n_eps;
192 j["Friction_On"] = friction_on;
193 j["Friction_Coeff"] = friction_coeff;
194 j["Kn_Factor"] = Kn_factor;
195 j["Beta_n_Factor"] = damping_on ? beta_n_factor : 0.0;
196 return j;
197}
198
199double KnFromBulk(double Ka, double Kb, double horizon) {
200 return 18.0 * util::harmonicMean(Ka, Kb) / (M_PI * std::pow(horizon, 5));
201}
202
203json buildInputJson(const std::string &output_path_for_deck, const std::filesystem::path &inp_dir,
204 int argc, char *argv[]) {
205
206 util::io::InputParser input(argc, argv);
207
208 const std::vector<double> center = {0.0, 0.0, 0.0};
209 const double R = 0.001;
210 const double mesh_size = R / 5.0;
211 const double horizon = 2.0 * mesh_size;
212
213 const double Lin = 0.05;
214 const double Win = 0.04;
215
216 constexpr double wall_top_inset = 1e-7;
217 constexpr double annulus_inset = 1e-7;
218 /* Clearance between void floor / plate and particle circum-bounds (~1–2 mesh). */
219 constexpr double clearance_mesh = 1.5;
220 /* Meshed triangles/hex/drum can extend slightly beyond circumcircle r in VTU. */
221 const double geom_pad = 0.25 * mesh_size;
222 const double plate_thickness = std::max(3.0 * mesh_size, 2.0 * mesh_size);
223
224 const double w_drum2d = R * 0.2;
225
226 const double final_time = 0.001;
227 size_t num_steps = 400;
228 if (input.cmdOptionExists("-numSteps"))
229 num_steps = static_cast<size_t>(std::stoul(input.getCmdOption("-numSteps")));
230
231 const size_t num_outputs = 10;
232 const size_t dt_out_n = std::max<size_t>(1, num_steps / num_outputs);
233 const size_t test_dt_out_n = std::max<size_t>(1, dt_out_n / 10);
234
235 const double rho_wall = 600.;
236 const double poisson_wall = 0.25;
237 const double K_wall = 1.e+4;
238 const double E_wall = material::toE(K_wall, poisson_wall);
239 const double G_wall = material::toGE(E_wall, poisson_wall);
240 const double KIc_wall = 5e+6;
241 const double Gc_wall = material::toGc(KIc_wall, poisson_wall, E_wall);
242
243 const double rho_p = 600.;
244 const double poisson_p = poisson_wall;
245 const double K_p = 5.e+3;
246 const double E_p = material::toE(K_p, poisson_p);
247 const double G_p = material::toGE(E_p, poisson_p);
248 const double KIc_p = 5e+6;
249 const double Gc_p = material::toGc(KIc_p, poisson_p, E_p);
250
251 const double R_contact_factor = 0.95;
252 const double padding = 1.1 * R_contact_factor * mesh_size;
253 const int N_target = 500;
254
255 const std::vector<double> in_rect = {center[0] - 0.5 * Lin, center[1] - 0.5 * Win, center[2],
256 center[0] + 0.5 * Lin, center[1] + 0.5 * Win, center[2]};
257
258 std::mt19937 gen(30);
259 const double max_y = in_rect[4] - clearance_mesh * mesh_size;
260 std::vector<PackedParticle> packed =
261 generateParticleLocations(in_rect, max_y, mesh_size, R, N_target, padding, gen);
262 if (packed.empty())
263 throw std::runtime_error("compression_large_set_inbuilt_2mat2contact: particle pack is empty");
264 for (auto &p : packed)
265 p.z = 0.0;
266
267 const double m = clearance_mesh * mesh_size;
268 /* Seat bed: lowest circum-bottom = void_floor + m (void floor = seed inner bottom). */
269 {
270 const PackedBounds bb0 = packedAxisBounds(packed);
271 const double delta_y = (in_rect[1] + m) - bb0.min_y;
272 for (auto &p : packed)
273 p.y += delta_y;
274 }
275
276 const PackedBounds bb = packedAxisBounds(packed);
277
278 /* Inner void (Gmsh “remove” rectangle): circum-bounds ± m ± geom_pad in x; floor at seed; top = domain. */
279 const double void_lox = bb.min_x - m - geom_pad;
280 const double void_hix = bb.max_x + m + geom_pad;
281 const double void_loy = in_rect[1];
282 /* Moving plate: bottom = top of bed + clearance + pad so FE nodes stay under the plate. */
283 const double plate_bottom_y = bb.max_y + m + geom_pad;
284 double plate_top_y = plate_bottom_y + plate_thickness;
285
286 /* Outer solid: wrap void with wall thickness; extend upward just past the plate (no huge empty band). */
287 const double side = std::max(1.5 * horizon, 2.0 * mesh_size);
288 const double out_lox = void_lox - side;
289 const double out_hix = void_hix + side;
290 const double out_loy = void_loy - side;
291 const double out_hiy = plate_top_y + wall_top_inset + 2.5 * mesh_size;
292
293 std::vector<double> out_rect = {out_lox, out_loy, center[2], out_hix, out_hiy, center[2]};
294
295 /* Open-top void: inner cut runs to outer top (inset for Gmsh strict-inside). */
296 const double void_hi_y = out_rect[4] - annulus_inset;
297 std::vector<double> remove_rect = {void_lox, void_loy, center[2], void_hix, void_hi_y, center[2]};
298
299 util::io::print(std::format(
300 "[compression_large_set_inbuilt_2mat2contact] bbox(center±r) x∈[{:.6f},{:.6f}] y∈[{:.6f},{:.6f}]; "
301 "void x∈[{:.6f},{:.6f}] y_lo {:.6f}; plate y [{:.6f},{:.6f}]; void_hi {:.6f}; outer y∈[{:.6f},{:.6f}]\n",
302 bb.min_x, bb.max_x, bb.min_y, bb.max_y, void_lox, void_hix, void_loy, plate_bottom_y, plate_top_y,
303 void_hi_y, out_rect[1], out_rect[4]));
304
305 std::vector<double> moving_rect = {void_lox, plate_bottom_y, center[2], void_hix, plate_top_y, center[2]};
306
307 std::vector<double> fixed_container_params;
308 fixed_container_params.insert(fixed_container_params.end(), remove_rect.begin(), remove_rect.end());
309 fixed_container_params.insert(fixed_container_params.end(), out_rect.begin(), out_rect.end());
310
311 const size_t n_pack = packed.size();
312 const size_t n_wall_fixed = n_pack;
313 const size_t n_wall_moving = n_pack + 1;
314 const size_t n_total = n_pack + 2;
315
316 /* Reference geometries at origin; packing uses circum-radius ~ R for all zones. */
317 const double ell_a = 0.95 * R;
318 const double ell_b = 0.58 * R;
319 const double ell_theta = 0.35;
320 const double sq_half = R / std::sqrt(2.0);
321 /* Axis-aligned rectangle (~same circum extent as R). */
322 const double rx = 0.82 * R;
323 const double ry = 0.62 * R;
324
325 std::vector<geom::GeomData> pGeomVec(10);
326 pGeomVec[0].d_geomName = "circle";
327 pGeomVec[0].d_geomParams = {R, center[0], center[1], center[2]};
328 pGeomVec[1].d_geomName = "triangle";
329 pGeomVec[1].d_geomParams = {R, center[0], center[1], center[2]};
330 pGeomVec[2].d_geomName = "drum2d";
331 pGeomVec[2].d_geomParams = {R, w_drum2d, center[0], center[1], center[2]};
332 pGeomVec[3].d_geomName = "hexagon";
333 pGeomVec[3].d_geomParams = {R, center[0], center[1], center[2]};
334 pGeomVec[4].d_geomName = "ellipse";
335 pGeomVec[4].d_geomParams = {ell_a, ell_b, ell_theta, center[0], center[1], center[2]};
336 pGeomVec[5].d_geomName = "rectangle";
337 pGeomVec[5].d_geomParams = {-rx, -ry, center[2], rx, ry, center[2]};
338 pGeomVec[6].d_geomName = "square";
339 pGeomVec[6].d_geomParams = {-sq_half, -sq_half, center[2], sq_half, sq_half, center[2]};
340 pGeomVec[7].d_geomName = "circle_minus_circle";
341 pGeomVec[7].d_geomParams = {center[0], center[1], center[2], R, 0.35 * R};
342 pGeomVec[8].d_geomName = "rectangle_minus_rectangle";
343 pGeomVec[8].d_geomParams = fixed_container_params;
344 pGeomVec[9].d_geomName = "rectangle";
345 pGeomVec[9].d_geomParams = moving_rect;
346
347 for (auto &g : pGeomVec)
349
350 /* Annulus composite centroid can pick up tiny numerical z; 2D setup keeps all sites on z = 0. */
351 const util::Point cfix = pGeomVec[8].d_geom_p->center();
352 const util::Point cmov = pGeomVec[9].d_geom_p->center();
353 const util::Point site_wall_fixed(cfix.d_x, cfix.d_y, 0.0);
354 const util::Point site_wall_moving(cmov.d_x, cmov.d_y, 0.0);
355
356 auto modelDeckJson = inp::ModelDeck::getExampleJson(2, final_time, num_steps, "finite_difference",
357 "central_difference", true, 2, "Multi_Particle", 0);
358
359 std::vector<std::string> out_tags = {"Displacement", "Velocity", "Force", "Force_Density", "Damage_Z",
360 "Damage", "Nodal_Volume", "Zone_ID", "Particle_ID", "Fixity",
361 "Force_Fixity", "Contact_Nodes", "No_Fail_Node", "Boundary_Node_Flag"};
362 /* Perform_FE_Out must be true so VTU includes element connectivity (appendMesh). If false, only
363 * points are written (appendNodes) and ParaView’s default “Surface” view looks empty — use
364 * Representation → Points, or enable this flag. Large packs often leave FE out. */
365 auto outputDeckJson = inp::OutputDeck::getExampleJson("vtu", output_path_for_deck, out_tags, dt_out_n, 2,
366 true, "zlib", true, test_dt_out_n, "0", true);
367
368 auto bcDeckJson = inp::BCDeck::getExampleJson(0, 2, 0, true, util::Point(0, -10, 0));
369
370 bcDeckJson["Displacement_BC"]["Set_1"] = inp::BCBaseDeck::getExampleJson("Displacement_BC", false, geom::GeomData(),
371 {n_wall_fixed}, {}, "", {}, "", {},
372 {1, 2}, true, "", {});
373
374 json set2;
375 set2["Particle_List"] = std::vector<size_t>{n_wall_moving};
376 set2["Direction"] = std::vector<size_t>{2};
377 set2["Time_Function"] = json{{"Type", "linear"}, {"Parameters", std::vector<double>{-0.06}}};
378 set2["Spatial_Function"] = json{{"Type", "constant"}};
379 bcDeckJson["Displacement_BC"]["Set_2"] = set2;
380
381 json pDeckJson = json::object();
382
383 pDeckJson["Particle"] = inp::ParticleDeck::getParticleGeomExampleJson(pGeomVec);
384
385 json meshRoot = json{{"Sets", 10}};
386 const char *mesh_names[] = {"mesh_cir", "mesh_tri", "mesh_drum2d", "mesh_hex",
387 "mesh_ellipse", "mesh_rect", "mesh_square", "mesh_circirc",
388 "mesh_fixed_container", "mesh_moving_container"};
389 for (int zi = 0; zi < 10; ++zi) {
390 const std::string fname = (inp_dir / (std::string(mesh_names[zi]) + ".msh")).string();
391 meshRoot["Set_" + std::to_string(zi + 1)] =
392 json{{"File", fname},
393 {"CreateMesh",
394 json{{"Flag", true}, {"Info", "gmsh_builtin_mesh"}, {"Mesh_Size", mesh_size}, {"Write_Mesh_File", true}}}};
395 }
396 pDeckJson["Mesh"] = meshRoot;
397
398 /* Two material laws: 0 = particle, 1 = wall (fixed + moving). geom_id still selects mesh shape (10 meshes). */
399 json matRoot = json{{"Sets", 2}};
400 matRoot["Set_1"] = inp::MaterialDeck::getExampleJson("PDState", false, horizon, 0, rho_p, K_p, G_p, Gc_p, true, 1);
401 matRoot["Set_2"] =
402 inp::MaterialDeck::getExampleJson("PDState", false, horizon, 0, rho_wall, K_wall, G_wall, Gc_wall, true, 1);
403 pDeckJson["Material"] = matRoot;
404
405 const double Kn_pp = KnFromBulk(K_p, K_p, horizon);
406 const double Kn_pw = KnFromBulk(K_p, K_wall, horizon);
407 const double Kn_ww = 0.0;
408
409 const double beta_n_eps = 0.95;
410 const double friction_coeff = 0.5;
411 const bool damping_on = true;
412 const bool friction_on = false;
413 const double beta_n_factor = 100.;
414 const double Kn_factor = 1.;
415
416 /* Contact zones: 0 = granular, 1 = wall (fixed + moving). 2×2 matrix → three unique pairs (1-1, 1-2, 2-2). */
417 const json j_contact_pp =
418 contactPairJson(R_contact_factor, damping_on, friction_on, Kn_pp, beta_n_eps, friction_coeff, Kn_factor,
419 beta_n_factor);
420 const json j_contact_pw =
421 contactPairJson(R_contact_factor, damping_on, friction_on, Kn_pw, beta_n_eps, friction_coeff, Kn_factor,
422 beta_n_factor);
423 const json j_contact_ww =
424 contactPairJson(R_contact_factor, damping_on, friction_on, Kn_ww, beta_n_eps, friction_coeff, Kn_factor,
425 beta_n_factor);
426
427 json contactRoot = inp::ContactDeck::getExampleJson(2);
428 contactRoot["Set_1_1"] = j_contact_pp;
429 contactRoot["Set_1_2"] = j_contact_pw;
430 contactRoot["Set_2_2"] = j_contact_ww;
431 pDeckJson["Contact"] = contactRoot;
432
433 pDeckJson["Neighbor"] = inp::PNeighborDeck::getExampleJson("simple_all", 10.0, 100, 0.5);
434
435 auto pGenJson = inp::PGenDeck::getExampleJson("From_File");
436 pGenJson["Random_Rotation"] = false;
437 pGenJson["Data"]["N"] = n_total;
438
439 constexpr size_t k_mat_particle = 0;
440 constexpr size_t k_mat_wall = 1;
441 constexpr size_t k_contact_grains = 0;
442 constexpr size_t k_contact_wall = 1;
443
444 for (size_t pi = 0; pi < n_pack; ++pi) {
445 const auto &p = packed[pi];
446 pGenJson["Data"][std::to_string(pi)] = json{
447 {"x", p.x}, {"y", p.y}, {"z", 0.0}, {"theta", p.theta},
448 {"s", 1.0}, {"geom_id", static_cast<size_t>(p.zone)},
449 {"mat_id", k_mat_particle},
450 {"contact_id", k_contact_grains},
451 };
452 }
453
454 pGenJson["Data"][std::to_string(n_pack)] = json{{"x", site_wall_fixed.d_x},
455 {"y", site_wall_fixed.d_y},
456 {"z", 0.0},
457 {"theta", 0.0},
458 {"s", 1.0},
459 {"geom_id", size_t(8)},
460 {"mat_id", k_mat_wall},
461 {"contact_id", k_contact_wall}};
462
463 pGenJson["Data"][std::to_string(n_pack + 1)] = json{{"x", site_wall_moving.d_x},
464 {"y", site_wall_moving.d_y},
465 {"z", 0.0},
466 {"theta", 0.0},
467 {"s", 1.0},
468 {"geom_id", size_t(9)},
469 {"mat_id", k_mat_wall},
470 {"contact_id", k_contact_wall}};
471
472 pDeckJson["Particle_Generation"] = pGenJson;
473
474 /* Top-level comment only: ignored by inp::Input (only known sections are parsed). */
475 return json{{"Comment",
476 "compression_large_set_inbuilt"},
477 {"Model", modelDeckJson},
478 {"Output", outputDeckJson},
479 {"Force_BC", bcDeckJson["Force_BC"]},
480 {"Displacement_BC", bcDeckJson["Displacement_BC"]},
481 {"Particle", pDeckJson["Particle"]},
482 {"Mesh", pDeckJson["Mesh"]},
483 {"Material", pDeckJson["Material"]},
484 {"Contact", pDeckJson["Contact"]},
485 {"Neighbor", pDeckJson["Neighbor"]},
486 {"Particle_Generation", pDeckJson["Particle_Generation"]}};
487}
488
489} // namespace
490
491int main(int argc, char *argv[]) {
492
493 util::parallel::initMpi(argc, argv);
494 int mpiSize = util::parallel::mpiSize(), mpiRank = util::parallel::mpiRank();
495 util::io::print(std::format("Initialized MPI. MPI size = {}, MPI rank = {}\n", mpiSize, mpiRank));
497
498 util::io::InputParser input(argc, argv);
499
500 unsigned int nThreads;
501 if (input.cmdOptionExists("-nThreads"))
502 nThreads = std::stoi(input.getCmdOption("-nThreads"));
503 else {
504 nThreads = std::thread::hardware_concurrency();
505 util::io::print(std::format("Running test with default number of threads = {}\n", nThreads));
506 }
508 util::io::print(std::format("Number of threads = {}\n", util::parallel::getNThreads()));
509
510 namespace fs = std::filesystem;
511 const fs::path cwd = fs::current_path();
512
513 fs::path out_dir = cwd / "out";
514 fs::path inp_dir = cwd / "inp";
515
516 if (input.cmdOptionExists("-outputDir")) {
517 fs::path p = input.getCmdOption("-outputDir");
518 out_dir = p.is_absolute() ? std::move(p) : cwd / p;
519 }
520 if (input.cmdOptionExists("-inputDir")) {
521 fs::path p = input.getCmdOption("-inputDir");
522 inp_dir = p.is_absolute() ? std::move(p) : cwd / p;
523 } else if (input.cmdOptionExists("-outputDir")) {
524 inp_dir = out_dir.parent_path() / "inp";
525 }
526
527 fs::create_directories(out_dir);
528 fs::create_directories(inp_dir);
529
530 const std::string output_path_for_deck = directoryPathWithTrailingSep(out_dir);
531
532 util::io::print(std::format("Output directory (VTU, log.txt): {}\n", fs::absolute(out_dir).string()));
533 util::io::print(std::format("Input directory (input.json, meshes): {}\n", fs::absolute(inp_dir).string()));
534
535 auto inputJson = buildInputJson(output_path_for_deck, inp_dir, argc, argv);
536
537 const fs::path input_json_path = inp_dir / "input.json";
538 {
539 std::ofstream os(input_json_path);
540 if (!os)
541 throw std::runtime_error("Failed to open " + input_json_path.string() + " for writing.");
542 os << inputJson.dump(2);
543 }
544 util::io::print(std::format("Wrote deck to {}\n", fs::absolute(input_json_path).string()));
545
546 auto deck = std::make_shared<inp::Input>(inputJson);
547
548 PeriDEMModel dem(deck);
549 dem.run(deck);
550
551 return EXIT_SUCCESS;
552}
void run(std::shared_ptr< inp::Input > &deck)
Input command line argument parser.
Definition inputParser.h:28
bool cmdOptionExists(const std::string &option) const
Check if argument exists.
Definition inputParser.h:60
const std::string & getCmdOption(const std::string &option) const
Get value of argument specified by key.
Definition inputParser.h:45
nlohmann::ordered_json json
json buildInputJson(const std::string &output_path_for_deck, const std::filesystem::path &inp_dir, int argc, char *argv[])
Definition main.cpp:203
std::string directoryPathWithTrailingSep(const std::filesystem::path &dir)
Definition main.cpp:34
bool doesParticleIntersect(const PackedParticle &p, const std::vector< PackedParticle > &existing, const std::vector< double > &rect, double padding)
Definition main.cpp:50
std::vector< PackedParticle > generateParticleLocations(const std::vector< double > &in_rect, double max_y, double mesh_size, double R, int N_target, double padding, std::mt19937 &gen)
Definition main.cpp:75
PackedBounds packedAxisBounds(const std::vector< PackedParticle > &packed)
Definition main.cpp:166
double KnFromBulk(double Ka, double Kb, double horizon)
Definition main.cpp:199
double maxElem(const std::vector< double > &v)
Definition main.cpp:43
json contactPairJson(double R_contact_factor, bool damping_on, bool friction_on, double Kn, double beta_n_eps, double friction_coeff, double Kn_factor, double beta_n_factor)
Definition main.cpp:181
void createGeomObject(const std::string &geom_type, const std::vector< double > &params, const std::vector< std::string > &vec_type, const std::vector< std::string > &vec_flag, std::shared_ptr< geom::GeomObject > &obj, bool perform_check)
double toGc(double KIc, double nu, double E)
Compute critical energy release rate Gc from critical stress-intensity factor KIc,...
double toGE(double E, double nu)
Compute shear modulus from Young's modulus E and Poisson's ratio nu.
double toE(double K, double nu)
Compute Young's modulus E from Bulk modulus K and Poisson's ratio nu.
void print(const T &msg, int nt=print_default_tab, int printMpiRank=print_default_mpi_rank)
Prints formatted information.
Definition io.h:128
unsigned int getNThreads()
Get number of threads to be used by taskflow.
void initNThreads(unsigned int nThreads=std::thread::hardware_concurrency())
Initializes MpiStatus struct.
const MpiStatus * getMpiStatus()
Returns pointer to MpiStatus struct.
void initMpi(int argc=0, char *argv[]=nullptr)
Initializes MPI and also creates MpiStatus struct.
int mpiSize()
Get size (number) of processors.
int mpiRank()
get rank (id) of this processor
double harmonicMean(const double &m1, const double &m2)
Definition function.cpp:131
Input data for geometrical objects.
static json getExampleJson(std::string type="Foce_BC", bool isRegionActive=false, geom::GeomData regionGeomData=geom::GeomData(), std::vector< size_t > pList=std::vector< size_t >(), std::vector< size_t > pNotList=std::vector< size_t >(), std::string timeFnType="", std::vector< double > timeFnParams=std::vector< double >(), std::string spatialFnType="", std::vector< double > spatialFnParams=std::vector< double >(), std::vector< size_t > direction=std::vector< size_t >(), bool isDisplacementZero=false, std::string icType="", std::vector< double > icVec=std::vector< double >())
Returns example JSON object for ModelDeck configuration.
Definition bcBaseDeck.h:157
static json getExampleJson(size_t nForceSets=0, size_t nDispSets=0, size_t nICSets=0, bool gravityActive=false, util::Point gravity=util::Point())
Returns example JSON object for ModelDeck configuration.
Definition bcDeck.h:69
static json getExampleJson(size_t nSets=0)
Returns example JSON object for ModelDeck configuration.
Definition contactDeck.h:77
static json getExampleJson(std::string materialType="PDState", bool isPlainStrain=false, double horizon=-1., double horizonMeshRatio=-1., double density=1., double K=0., double G=0., double Gc=0., bool computeParamsFromElastic=true, size_t influenceFnType=0, double E=-1.)
Returns example JSON object for ModelDeck configuration.
static json getExampleJson(size_t dim=2, double tFinal=1.0, size_t Nt=10, std::string spatialDiscretization="finite_difference", std::string timeDiscretization="central_difference", bool populateElementNodeConnectivity=true, size_t quadOrder=2, std::string particleSimType="Multi_Particle", int seed=0)
Returns example JSON object for ModelDeck configuration.
Definition modelDeck.h:164
static json getExampleJson(std::string outFormat="vtu", std::string path="./", std::vector< std::string > outTags={"Displacement"}, size_t outputInterval=1, size_t debug=2, bool performFEOut=true, std::string compressType="zlib", bool performOut=true, size_t dtTestOut=1, std::string tagPPFile="", bool pvdCollection=false)
Returns example JSON object for ModelDeck configuration.
Definition outputDeck.h:144
static json getExampleJson(std::string genMethod="From_File")
Returns example JSON object for ModelDeck configuration.
Definition pGenDeck.h:65
static json getExampleJson(std::string updateCriteria="simple_all", double sFactor=1., size_t neighUpdateInterval=1, double nearBdNodesTol=0.5)
Returns example JSON object for ModelDeck configuration.
static json getParticleGeomExampleJson(std::vector< geom::GeomData > pGeomVec=std::vector< geom::GeomData >())
Returns example JSON object for ModelDeck configuration.
A structure to represent 3d vectors.
Definition point.h:30
double d_y
the y coordinate
Definition point.h:36
double d_x
the x coordinate
Definition point.h:33
int main()
Definition main.cpp:31