PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
main.cpp File Reference
#include "inp/deckIncludes.h"
#include "periDEMModel.h"
#include "util/io.h"
#include "util/parallelUtil.h"
#include <cmath>
#include <filesystem>
#include <format>
#include <functional>
#include <memory>
#include <string>
Include dependency graph for main.cpp:

Go to the source code of this file.

Namespaces

namespace  anonymous_namespace{main.cpp}
 

Functions

json anonymous_namespace{main.cpp}::makeDeck (const std::string &model, size_t dim, bool plane_strain, int influence, double L, double h, double horizon, double E, double nu, double Gc, const std::string &out)
 
int main (int argc, char *argv[])
 

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 79 of file main.cpp.

79 {
80 util::parallel::initMpi(argc, argv);
81 util::io::InputParser input(argc, argv);
83 input.cmdOptionExists("-nThreads")
84 ? std::stoi(input.getCmdOption("-nThreads"))
85 : 4);
86 auto opt = [&input](const char *f, const std::string &fb) {
87 return input.cmdOptionExists(f) ? input.getCmdOption(f) : fb;
88 };
89
90 const std::string model = opt("-model", "PDState");
91 const size_t dim = std::stoul(opt("-dim", "2"));
92 const bool plane_strain = std::stoi(opt("-planeStrain", "0")) != 0;
93 const int influence = std::stoi(opt("-influence", "0"));
94 const double m_ratio = std::stod(opt("-m", "4"));
95 const double h = std::stod(opt("-h", dim == 2 ? "0.02" : "0.05"));
96 const double tol = std::stod(opt("-tol", "0.02"));
97 const double L = std::stod(opt("-L", "1.0")), horizon = m_ratio * h;
98 const double E = 1.0e5, Gc = 10.;
99 // bond-based models fix nu by the plane mode; PDState takes the table nu
100 double nu = std::stod(opt("-nu", "0.3"));
101 if (model != "PDState")
102 nu = (dim == 2 && !plane_strain) ? 1. / 3. : 0.25;
103
104 const double mu = E / (2. * (1. + nu));
105 const double lambda = (dim == 2 && !plane_strain)
106 ? E * nu / (1. - nu * nu)
107 : E * nu / ((1. + nu) * (1. - 2. * nu));
108
109 namespace fs = std::filesystem;
110 struct Check { std::string name; double got, want; };
111
112 // build the model, apply each field, and compare with linear elasticity
113 auto runChecks = [&](const std::string &mname) {
114 const fs::path out = fs::current_path() /
115 std::format("calib_{}_{}d_{}_J{}", mname, dim,
116 plane_strain ? "pstrain" : "pstress", influence);
117 fs::create_directories(out);
118 auto deck = std::make_shared<inp::Input>(
119 makeDeck(mname, dim, plane_strain, influence, L, h, horizon, E, nu, Gc,
120 out.string() + "/"));
121 PeriDEMModel dem(deck);
122 dem.init();
123
124 // energy at x needs a full horizon; the state-based force at x also uses
125 // the dilatation of neighbors, so it needs two
126 auto inside = [&](const util::Point &x, double margin) {
127 const double c = 0.5 * L - margin - 1.5 * h;
128 return std::abs(x.d_x) < c && std::abs(x.d_y) < c &&
129 (dim == 2 || std::abs(x.d_z) < c);
130 };
131
132 // apply a displacement field, compute forces, and return interior
133 // averages of energy density, f_x and f_y
134 auto evaluate =
135 [&](const std::function<util::Point(const util::Point &)> &u) {
136 for (size_t i = 0; i < dem.d_xRef.size(); i++) {
137 dem.d_u[i] = u(dem.d_xRef[i]);
138 dem.d_x[i] = dem.d_xRef[i] + dem.d_u[i];
139 }
140 dem.computeForces();
141 double e = 0., fx = 0., fy = 0.;
142 size_t ne = 0, nf = 0;
143 for (size_t i = 0; i < dem.d_xRef.size(); i++) {
144 if (inside(dem.d_xRef[i], horizon)) {
145 e += dem.d_e[i];
146 ne++;
147 }
148 if (inside(dem.d_xRef[i], 2. * horizon)) {
149 fx += dem.d_f[i].d_x;
150 fy += dem.d_f[i].d_y;
151 nf++;
152 }
153 }
154 return std::array<double, 3>{e / ne, fx / nf, fy / nf};
155 };
156
157 const double eps = 1.0e-5, a = 1.0e-5 / L;
158 std::vector<Check> checks;
159
160 // homogeneous strains: uniaxial, equibiaxial, shear
161 auto r = evaluate([&](const util::Point &x) {
162 return util::Point(eps * x.d_x, 0., 0.); });
163 checks.push_back({"energy uniaxial strain", r[0],
164 0.5 * (lambda + 2. * mu) * eps * eps});
165 r = evaluate([&](const util::Point &x) {
166 return util::Point(eps * x.d_x, eps * x.d_y, dim == 3 ? eps * x.d_z : 0.); });
167 checks.push_back({"energy equibiaxial", r[0],
168 (mu * dim + 0.5 * lambda * dim * dim) * eps * eps});
169 r = evaluate([&](const util::Point &x) {
170 return util::Point(eps * x.d_y, eps * x.d_x, 0.); });
171 checks.push_back({"energy shear", r[0], 2. * mu * eps * eps});
172
173 // quadratic fields: divergence of stress
174 r = evaluate([&](const util::Point &x) {
175 return util::Point(0.5 * a * x.d_x * x.d_x, 0., 0.); });
176 checks.push_back({"force (lambda+2mu)", r[1], (lambda + 2. * mu) * a});
177 r = evaluate([&](const util::Point &x) {
178 return util::Point(0., 0.5 * a * x.d_x * x.d_x, 0.); });
179 checks.push_back({"force mu", r[2], mu * a});
180
181 util::io::print(std::format(
182 "CALIB model={} dim={} {} J={} delta/h={} nodes={} E={} nu={:.4f}\n",
183 mname, dim, plane_strain ? "plane_strain" : "plane_stress", influence,
184 m_ratio, dem.d_xRef.size(), E, nu));
185 return checks;
186 };
187
188 // -compareModel: a second bond-based model must give the same small-strain
189 // response (e.g. RNP against PMB), which removes the quadrature error
190 std::vector<Check> checks;
191 try {
192 checks = runChecks(model);
193 if (input.cmdOptionExists("-compareModel")) {
194 const auto ref = runChecks(input.getCmdOption("-compareModel"));
195 for (size_t k = 0; k < checks.size(); k++)
196 checks[k].want = ref[k].got;
197 }
198 } catch (const std::exception &e) {
199 // input checks are tested by matching this message
200 util::io::print(std::format("CALIB_ERROR {}\n", e.what()));
202 return 1;
203 }
204
205 bool ok = true;
206 for (const auto &c : checks) {
207 const double rel = (c.got - c.want) / c.want;
208 const bool pass = std::abs(rel) <= tol;
209 ok = ok && pass;
210 util::io::print(std::format(" {:<24} got={:+.15e} want={:+.6e} rel={:+.4f} {}\n",
211 c.name, c.got, c.want, rel, pass ? "OK" : "FAIL"));
212 }
213 util::io::print(ok ? "CALIB_PASS\n" : "CALIB_FAIL\n");
215 return ok ? 0 : 1;
216}
Input command line argument parser.
Definition inputParser.h:28
json makeDeck(const std::string &model, size_t dim, bool plane_strain, int influence, double L, double h, double horizon, double E, double nu, double Gc, const std::string &out)
Definition main.cpp:32
float E
Definition problem.py:64
void print(const T &msg, int nt=print_default_tab, int printMpiRank=print_default_mpi_rank)
Prints formatted information.
Definition io.h:171
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.
void finalizeMpi()
Call MPI_Finalize if this process initialized MPI.
A structure to represent 3d vectors.
Definition point.h:30
double d_y
the y coordinate
Definition point.h:36
double d_z
the z coordinate
Definition point.h:39
double d_x
the x coordinate
Definition point.h:33

References util::io::InputParser::cmdOptionExists(), PeriDEMModel::computeForces(), data::ModelData::d_e, data::ModelData::d_f, data::ModelData::d_u, data::ModelData::d_x, util::Point::d_x, data::ModelData::d_xRef, util::Point::d_y, util::Point::d_z, util::parallel::finalizeMpi(), util::io::InputParser::getCmdOption(), PeriDEMModel::init(), util::parallel::initMpi(), util::parallel::initNThreads(), main(), anonymous_namespace{main.cpp}::makeDeck(), and util::io::print().

Here is the call graph for this function: