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 * Hollow ellipse dropped onto a short tip-up triangle (pointy tip only).
8 * Tip contact opens a crack; target is bipartition into two pieces.
9 *
10 * -outputDir / -inputDir / -finalTime / -numSteps / -nThreads
11 */
12
13#include "inp/deckIncludes.h"
15#include "periDEMModel.h"
16#include "util/function.h"
17#include "util/io.h"
18#include "util/parallelUtil.h"
19
20#include <cmath>
21#include <cstdlib>
22#include <filesystem>
23#include <format>
24#include <fstream>
25#include <iomanip>
26#include <memory>
27#include <stdexcept>
28#include <string>
29#include <thread>
30#include <vector>
31
32namespace {
33
34std::string directoryPathWithTrailingSep(const std::filesystem::path &dir) {
35 namespace fs = std::filesystem;
36 fs::path n = fs::absolute(dir).lexically_normal();
37 std::string s = n.string();
38 if (!s.empty() && s.back() != '/' && s.back() != '\\')
39 s += fs::path::preferred_separator;
40 return s;
41}
42
43json buildInputJson(const std::string &output_path, const std::filesystem::path &mesh_tri,
44 const std::filesystem::path &mesh_ell, double final_time, size_t num_steps,
45 double mesh_size, double horizon) {
46 // Short tip — point only, not a tall triangle. Narrower tip concentrates load.
47 const double W = 0.0008;
48 const double H = 0.0012;
49
50 // Hollow ellipse (visibly elliptical ring).
51 const double a_out = 0.0020;
52 const double b_out = 0.0014;
53 // Thin ring so a tip-seeded crack can bipartition.
54 const double a_in = 0.00180;
55 const double b_in = 0.00122;
56 const double ell_theta = 0.0;
57 const double tip_gap = 0.00008;
58 const double tip_y = H;
59 const double ell_cy = tip_y + tip_gap + b_out;
60
61 const double rho_t = 1200.0;
62 const double K_t = 2.16e7;
63 const double nu_t = 0.25;
64 const double E_t = material::toE(K_t, nu_t);
65 const double G_t = material::toGE(E_t, nu_t);
66 const double Gc_t = 200.0;
67
68 const double rho_e = 1200.0;
69 const double K_e = 2.16e7;
70 const double nu_e = 0.25;
71 const double E_e = material::toE(K_e, nu_e);
72 const double G_e = material::toGE(E_e, nu_e);
73 // Low Gc so tip damage runs into a diametral through-crack.
74 const double Gc_e = 1.0;
75
76 const double R_contact_factor = 0.95;
77 const double Kn_tt = 18.0 * util::harmonicMean(K_t, K_t) / (M_PI * std::pow(horizon, 5));
78 const double Kn_ee = 18.0 * util::harmonicMean(K_e, K_e) / (M_PI * std::pow(horizon, 5));
79 const double Kn_te = 18.0 * util::harmonicMean(K_t, K_e) / (M_PI * std::pow(horizon, 5));
80
81 const double g = 10.0;
82 const double ic_vy = -2.5;
83
84 const size_t dt_out_n = std::max<size_t>(1, num_steps / 40);
85
86 auto model = inp::ModelDeck::getExampleJson(2, final_time, num_steps, "finite_difference",
87 "central_difference", true, 2, "Multi_Particle", 0);
88 model["Bond_Break"] = "tension";
89 // No self-contact across broken bonds — otherwise the crack stays glued.
90 model["Self_Contact"] = "none";
91
93 "vtu", output_path,
94 std::vector<std::string>({"Displacement", "Velocity", "Force", "Damage_Z", "Damage",
95 "Particle_ID", "Fixity"}),
96 dt_out_n, 1, true, "zlib", true, 1, "", true);
97
98 auto bc = inp::BCDeck::getExampleJson(0, 1, 1, true, util::Point(0., -g, 0.));
99 bc["Displacement_BC"]["Set_1"] = inp::BCBaseDeck::getExampleJson(
100 "Displacement_BC", false, geom::GeomData(), {0}, {}, "", {}, "", {}, {1, 2}, true, "", {});
101
102 bc["IC"]["Set_1"] = {
103 {"Particle_List", std::vector<size_t>{1}},
104 {"Constant_Velocity", {{"Velocity_Vector", std::vector<double>{0., ic_vy, 0.}}}}};
105
106 std::vector<geom::GeomData> pGeom(2);
107 pGeom[0].d_geomName = "triangle";
108 pGeom[0].d_geomParams = {-0.5 * W, 0., 0., 0.5 * W, 0., 0., 0., H, 0.};
109
110 pGeom[1].d_geomName = "ellipse_minus_ellipse";
111 pGeom[1].d_geomParams = {a_out, b_out, a_in, b_in, ell_theta, 0., 0., 0.};
112
113 for (auto &g : pGeom)
115
116 const util::Point c_tri = pGeom[0].d_geom_p->center();
117
118 json pDeck = json::object();
119 pDeck["Particle"] = inp::ParticleDeck::getParticleGeomExampleJson(pGeom);
120
121 pDeck["Mesh"] = {
122 {"Sets", 2},
123 {"Set_1",
124 {{"File", mesh_tri.string()},
125 {"CreateMesh",
126 {{"Flag", true},
127 {"Info", "gmsh_builtin_mesh"},
128 {"Mesh_Size", mesh_size},
129 {"Write_Mesh_File", true}}}}},
130 {"Set_2",
131 {{"File", mesh_ell.string()},
132 {"CreateMesh",
133 {{"Flag", true},
134 {"Info", "gmsh_builtin_mesh"},
135 {"Mesh_Size", mesh_size},
136 {"Write_Mesh_File", true}}}}}};
137
139 mat["Set_1"] =
140 inp::MaterialDeck::getExampleJson("PDState", false, horizon, 0, rho_t, K_t, G_t, Gc_t, true, 1);
141 mat["Set_2"] =
142 inp::MaterialDeck::getExampleJson("PDState", false, horizon, 0, rho_e, K_e, G_e, Gc_e, true, 1);
143 pDeck["Material"] = mat;
144
146 json cpair_wall = inp::ContactPairDeck::getExampleJson(R_contact_factor, true, true, false, Kn_tt, 0.95,
147 0.0, 1.0, 100.0, 1.0, 0.0, K_t);
148 // Tip contact: enough Beta_n to drive a crack, damping on to limit spray.
149 json cpair_tip = inp::ContactPairDeck::getExampleJson(0.90, true, true, false, Kn_te, 0.4,
150 0.0, 1.0, 8.0, 1.0, 0.0,
151 util::harmonicMean(K_t, K_e));
152 json cpair_ell = inp::ContactPairDeck::getExampleJson(R_contact_factor, true, true, false, Kn_ee, 0.95,
153 0.0, 1.0, 100.0, 1.0, 0.0, K_e);
154 contact["Set_1_1"] = cpair_wall;
155 contact["Set_1_1"]["Kn"] = Kn_tt;
156 contact["Set_1_1"]["K"] = K_t;
157 contact["Set_1_2"] = cpair_tip;
158 contact["Set_1_2"]["Kn"] = Kn_te;
159 contact["Set_1_2"]["K"] = util::harmonicMean(K_t, K_e);
160 contact["Set_2_2"] = cpair_ell;
161 contact["Set_2_2"]["Kn"] = Kn_ee;
162 contact["Set_2_2"]["K"] = K_e;
163 contact["Damping_Law"] = "com_and_node";
164 contact["Friction_Law"] = "coulomb_simple";
165 pDeck["Contact"] = contact;
166
167 pDeck["Neighbor"] = inp::PNeighborDeck::getExampleJson("simple_all", 8.0, 5, 0.5);
168
169 auto gen = inp::PGenDeck::getExampleJson("From_File");
170 gen["Random_Rotation"] = false;
171 gen["Data"]["N"] = 2;
172 gen["Data"]["0"] = {{"x", c_tri.d_x}, {"y", c_tri.d_y}, {"z", 0.0},
173 {"theta", 0.0}, {"s", 1.0},
174 {"geom_id", 0}, {"mat_id", 0}, {"contact_id", 0},
175 {"is_wall", true}};
176 gen["Data"]["1"] = {{"x", 0.0}, {"y", ell_cy}, {"z", 0.0},
177 {"theta", 0.0}, {"s", 1.0},
178 {"geom_id", 1}, {"mat_id", 1}, {"contact_id", 1}};
179 pDeck["Particle_Generation"] = gen;
180
181 json j = json::object();
182 j["Model"] = model;
183 j["Output"] = output;
184 j["Force_BC"] = bc["Force_BC"];
185 j["Displacement_BC"] = bc["Displacement_BC"];
186 j["IC"] = bc["IC"];
187 j["Particle"] = pDeck["Particle"];
188 j["Mesh"] = pDeck["Mesh"];
189 j["Material"] = pDeck["Material"];
190 j["Contact"] = pDeck["Contact"];
191 j["Neighbor"] = pDeck["Neighbor"];
192 j["Particle_Generation"] = pDeck["Particle_Generation"];
193 return j;
194}
195
196} // namespace
197
198int main(int argc, char *argv[]) {
199 util::parallel::initMpi(argc, argv);
200 util::io::InputParser input(argc, argv);
201
202 unsigned int n_threads = std::thread::hardware_concurrency();
203 if (input.cmdOptionExists("-nThreads"))
204 n_threads = std::stoul(input.getCmdOption("-nThreads"));
206 util::io::print(std::format("Number of threads = {}\n", util::parallel::getNThreads()));
207
208 double final_time = 0.0030;
209 size_t num_steps = 30000;
210 if (input.cmdOptionExists("-finalTime"))
211 final_time = std::stod(input.getCmdOption("-finalTime"));
212 if (input.cmdOptionExists("-numSteps"))
213 num_steps = std::stoul(input.getCmdOption("-numSteps"));
214
215 const double mesh_size = 0.00010;
216 const double horizon = 3.0 * mesh_size;
217
218 namespace fs = std::filesystem;
219 const fs::path cwd = fs::current_path();
220 fs::path out_dir = cwd / "out";
221 fs::path inp_dir = cwd / "inp";
222 if (input.cmdOptionExists("-outputDir")) {
223 fs::path p = input.getCmdOption("-outputDir");
224 out_dir = p.is_absolute() ? std::move(p) : cwd / p;
225 }
226 if (input.cmdOptionExists("-inputDir")) {
227 fs::path p = input.getCmdOption("-inputDir");
228 inp_dir = p.is_absolute() ? std::move(p) : cwd / p;
229 } else if (input.cmdOptionExists("-outputDir")) {
230 inp_dir = out_dir.parent_path() / "inp";
231 }
232 fs::create_directories(out_dir);
233 fs::create_directories(inp_dir);
234
235 const std::string output_path = directoryPathWithTrailingSep(out_dir);
236 const fs::path mesh_tri = inp_dir / "mesh_triangle.msh";
237 const fs::path mesh_ell = inp_dir / "mesh_hollow_ellipse.msh";
238
239 auto j = buildInputJson(output_path, mesh_tri, mesh_ell, final_time, num_steps, mesh_size,
240 horizon);
241 {
242 std::ofstream ofs(inp_dir / "input.json");
243 ofs << std::setw(2) << j << std::endl;
244 }
245
246 // Hard check: deck must request a hollow ellipse, not a rectangle plate.
247 if (j["Particle"]["Set_2"]["Type"] != "ellipse_minus_ellipse")
248 throw std::runtime_error("ellipse_triangle: Particle Set_2 must be ellipse_minus_ellipse");
249
250 util::io::print(std::format(
251 "[ellipse_triangle] Type={}, T={}, Nt={}, mesh={:.4e}, out={}\n",
252 j["Particle"]["Set_2"]["Type"].get<std::string>(), final_time, num_steps, mesh_size,
253 out_dir.string()));
254
255 auto deck = std::make_shared<inp::Input>(j);
256 PeriDEMModel dem(deck);
257 dem.run(deck);
258
259 return 0;
260}
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
std::string directoryPathWithTrailingSep(const std::filesystem::path &dir)
Definition main.cpp:34
json buildInputJson(const std::string &output_path, const std::filesystem::path &mesh_tri, const std::filesystem::path &mesh_ell, double final_time, size_t num_steps, double mesh_size, double horizon)
Definition main.cpp:43
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 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.
void initMpi(int argc=0, char *argv[]=nullptr)
Initializes MPI and also creates MpiStatus struct.
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(double contactR=0., bool computeContactR=true, bool dampingOn=true, bool frictionOn=true, double Kn=0., double eps=1., double mu=0., double KnFactor=1., double betanFactor=1., double deltaMax=1., double vMax=0., double K=0.)
Returns example JSON object for ModelDeck configuration.
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 getParticleContactExampleJson(size_t nSets=0)
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.
static json getParticleMaterialExampleJson(size_t nSets=0)
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