36 namespace fs = std::filesystem;
37 fs::path n = fs::absolute(dir).lexically_normal();
38 std::string s = n.string();
39 if (!s.empty() && s.back() !=
'/' && s.back() !=
'\\')
40 s += fs::path::preferred_separator;
45 double L,
double mesh_size,
double horizon,
double final_time,
46 size_t num_steps,
const std::string &self_contact) {
48 "central_difference",
true, 2,
"Single_Particle",
50 model[
"Self_Contact"] = self_contact;
51 model[
"Bond_Break"] =
"tension";
54 const double rho = 1200.0;
55 const double K = 2.16e5;
56 const double G = 1.296e5;
57 const double Gc = 5.0e6;
61 std::vector<std::string>({
"Displacement",
"Force",
"Damage_Z",
"Particle_ID"}),
62 num_steps, 1,
false,
"zlib",
false, num_steps,
"",
false);
64 const double strip = 0.2 * L;
65 json bc = json::object();
66 bc[
"Displacement_BC"] = {
71 {{
"Type",
"rectangle"},
72 {
"Parameters", std::vector<double>{-0.05 * L, -0.05 * L, 0., strip, L + 0.05 * L, 0.}}}}}},
73 {
"Direction", std::vector<size_t>{1, 2}},
74 {
"Time_Function", {{
"Type",
"constant"}, {
"Parameters", std::vector<double>{0.}}}},
75 {
"Spatial_Function", {{
"Type",
"constant"}}},
76 {
"Zero_Displacement",
true}}},
80 {{
"Type",
"rectangle"},
82 std::vector<double>{L - strip, -0.05 * L, 0., L + 0.05 * L, L + 0.05 * L, 0.}}}}}},
83 {
"Direction", std::vector<size_t>{1}},
84 {
"Time_Function", {{
"Type",
"constant"}, {
"Parameters", std::vector<double>{0.}}}},
85 {
"Spatial_Function", {{
"Type",
"constant"}}},
86 {
"Zero_Displacement",
false}}}};
93 json mesh_set = {{
"File", mesh_file.string()},
96 {
"Info",
"gmsh_builtin_mesh"},
97 {
"Mesh_Size", mesh_size},
98 {
"Write_Mesh_File",
true}}}};
105 json root = {{
"Model", model},
110 root.merge_patch(bc);
116 for (
size_t i = 0; i < dem.
d_neighPd.size(); ++i) {
117 const auto &xi = dem.
d_xRef[i];
118 for (
size_t k = 0; k < dem.
d_neighPd[i].size(); ++k) {
120 const auto &xj = dem.
d_xRef[j];
121 if ((xi.d_x - x_crack) * (xj.d_x - x_crack) < 0.) {
131 for (
size_t i = 0; i < dem.
d_xRef.size(); ++i) {
132 const double ux = (dem.
d_xRef[i].d_x >= x_crack) ? u_right : 0.;
140 double min_gap = 1.0e300;
143 double force_x_left = 0.;
144 double force_x_right = 0.;
149 for (
size_t i = 0; i < dem.
d_neighPd.size(); ++i) {
150 const auto &xi = dem.
d_xRef[i];
151 for (
size_t k = 0; k < dem.
d_neighPd[i].size(); ++k) {
155 const auto &xj = dem.
d_xRef[j];
156 if ((xi.d_x - x_crack) * (xj.d_x - x_crack) >= 0.)
158 const double gap = (dem.
d_x[j] - dem.
d_x[i]).length();
167 for (
size_t i = 0; i < dem.
d_xRef.size(); ++i) {
168 const double x = dem.
d_xRef[i].d_x;
169 const double fx = dem.
d_f[i].d_x * dem.
d_vol[i];
170 if (x < x_crack && x > x_crack - band)
172 if (x >= x_crack && x < x_crack + band)
179 double open_min_gap = 0.;
180 double close_min_gap = 0.;
181 double close_force_amp = 0.;
184LawResult runLaw(
const std::string &self_contact,
const std::filesystem::path &run_dir,
double L,
185 double mesh_size,
double horizon,
unsigned n_threads) {
186 namespace fs = std::filesystem;
187 const fs::path out_dir = run_dir /
"out";
188 const fs::path inp_dir = run_dir /
"inp";
189 fs::create_directories(out_dir);
190 fs::create_directories(inp_dir);
192 const fs::path
mesh = inp_dir /
"mesh_rect.msh";
198 std::ofstream os(inp_dir /
"input.json");
199 os << input_json.dump(2);
202 auto deck = std::make_shared<inp::Input>(input_json);
206 const double x_crack = 0.5 * L;
209 throw std::runtime_error(self_contact +
": precrack broke no bonds");
212 const double h = dem.
d_hMax > 0. ? dem.
d_hMax : mesh_size;
213 util::io::print(std::format(
"{}: nodes={}, broken_bonds={}, h={}, Rc={}, horizon={}\n",
214 self_contact, dem.
d_x.size(), n_broken, h, Rc, horizon));
217 const double u_open = 2.0 * Rc;
220 const auto open_m =
measure(dem, x_crack, 2.0 * horizon);
221 if (!(open_m.min_gap > 1.5 * Rc))
222 throw std::runtime_error(std::format(
"{}: open did not separate (min_gap={})", self_contact,
228 const double u_close = -0.5 * (Rc + 0.5 * horizon);
231 const auto close_m =
measure(dem, x_crack, 2.0 * horizon);
232 const double force_amp =
233 0.5 * (std::abs(close_m.force_x_left) + std::abs(close_m.force_x_right));
235 util::io::print(std::format(
"{}: open min_gap={}, close min_gap={}, force_amp={}\n", self_contact,
236 open_m.min_gap, close_m.min_gap, force_amp));
249int main(
int argc,
char *argv[]) {
253 unsigned int n_threads = 2;
255 n_threads =
static_cast<unsigned>(std::stoi(input.
getCmdOption(
"-nThreads")));
258 namespace fs = std::filesystem;
259 fs::path base = fs::current_path() /
"self_contact_mode1_run";
263 const double L = 0.002;
264 const double mesh_size = L / 6.0;
265 const double horizon = 3.0 * mesh_size;
270 bb =
runLaw(
"broken_bond_kn", base /
"broken_bond_kn", L, mesh_size, horizon, n_threads);
271 rg =
runLaw(
"reference_gap", base /
"reference_gap", L, mesh_size, horizon, n_threads);
272 }
catch (
const std::exception &e) {
273 util::io::print(std::format(
"self-contact Mode-I failed: {}\n", e.what()));
277 if (!(bb.close_force_amp > 0.) || !(rg.close_force_amp > 0.)) {
279 "close did not activate self-contact: F_bb={}, F_rg={}\n", bb.close_force_amp,
280 rg.close_force_amp));
284 const double fmax = std::max(bb.close_force_amp, rg.close_force_amp);
285 const double rel = std::abs(bb.close_force_amp - rg.close_force_amp) / fmax;
288 "self-contact laws did not differ enough under close: F_bb={}, F_rg={}, rel={}\n",
289 bb.close_force_amp, rg.close_force_amp, rel));
294 "self-contact Mode-I OK: open gaps bb={}/rg={}, close forces bb={}/rg={}, rel_diff={}\n", bb.open_min_gap,
295 rg.open_min_gap, bb.close_force_amp, rg.close_force_amp, rel));
std::vector< util::Point > d_x
Current positions of the nodes.
std::vector< util::Point > d_xRef
reference positions of the nodes
std::vector< util::Point > d_u
Displacement of the nodes.
std::vector< util::Point > d_f
Total force on the nodes.
std::unique_ptr< geometry::Fracture > d_fracture_p
Fracture state of bonds.
std::vector< std::vector< size_t > > d_neighPd
Neighbor data for peridynamic forces.
double d_maxContactR
Maximum contact radius between over pairs of particles and walls.
double d_hMax
Minimum mesh over all particles and walls.
std::vector< double > d_vol
Nodal volumes.
std::vector< util::Point > d_v
Velocity of the nodes.
nlohmann::ordered_json json
LawResult runLaw(const std::string &self_contact, const std::filesystem::path &run_dir, double L, double mesh_size, double horizon, unsigned n_threads)
std::string directoryPathWithTrailingSep(const std::filesystem::path &dir)
json buildInputJson(const std::string &output_path, const std::filesystem::path &mesh_file, double L, double mesh_size, double horizon, double final_time, size_t num_steps, const std::string &self_contact)
CrackMetrics measure(PeriDEMModel &dem, double x_crack, double band)
void applyRigidOpenClose(PeriDEMModel &dem, double x_crack, double u_right)
size_t applyPrecrack(PeriDEMModel &dem, double x_crack)
Collection of methods and data related to finite element and mesh.
Collection of methods and data related to particle object.
void print(const T &msg, int nt=print_default_tab, int printMpiRank=print_default_mpi_rank)
Prints formatted information.
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.
Input data for geometrical objects.
std::vector< double > d_geomParams
Zone parameters.
std::string d_geomName
Zone type.
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.
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.
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.