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 json{{
"Dimension", 2},
49 {
"Final_Time", final_time},
50 {
"Time_Steps", num_steps},
51 {
"Discretization_Type",
json{{
"Spatial",
"finite_difference"}, {
"Time",
"central_difference"}}},
52 {
"Populate_ElementNodeConnectivity",
true},
53 {
"Quad_Approximation_Order", 2},
54 {
"Particle_Sim_Type",
"Single_Particle"},
56 model[
"Self_Contact"] = self_contact;
57 model[
"Bond_Break"] =
"tension";
60 const double rho = 1200.0;
61 const double K = 2.16e5;
62 const double G = 1.296e5;
63 const double Gc = 5.0e6;
66 json{{
"File_Format",
"vtu"},
67 {
"Path", output_path},
68 {
"Tags", std::vector<std::string>({
"Displacement",
"Force",
"Damage_Z",
"Particle_ID"})},
69 {
"Output_Interval", num_steps},
71 {
"Perform_FE_Out",
false},
72 {
"Compress_Type",
"zlib"},
73 {
"Perform_Out",
false},
74 {
"Test_Output_Interval", num_steps},
76 {
"PVD_Collection",
false}});
78 const double strip = 0.2 * L;
79 json bc = json::object();
80 bc[
"Displacement_BC"] = {
85 {{
"Type",
"rectangle"},
86 {
"Parameters", std::vector<double>{-0.05 * L, -0.05 * L, 0., strip, L + 0.05 * L, 0.}}}}}},
87 {
"Direction", std::vector<size_t>{1, 2}},
88 {
"Time_Function", {{
"Type",
"constant"}, {
"Parameters", std::vector<double>{0.}}}},
89 {
"Spatial_Function", {{
"Type",
"constant"}}},
90 {
"Zero_Displacement",
true}}},
94 {{
"Type",
"rectangle"},
96 std::vector<double>{L - strip, -0.05 * L, 0., L + 0.05 * L, L + 0.05 * L, 0.}}}}}},
97 {
"Direction", std::vector<size_t>{1}},
98 {
"Time_Function", {{
"Type",
"constant"}, {
"Parameters", std::vector<double>{0.}}}},
99 {
"Spatial_Function", {{
"Type",
"constant"}}},
100 {
"Zero_Displacement",
false}}}};
107 json mesh_set = {{
"File", mesh_file.string()},
110 {
"Info",
"gmsh_builtin_mesh"},
111 {
"Mesh_Size", mesh_size},
112 {
"Write_Mesh_File",
true}}}};
118 json{{
"Type",
"PDState"},
119 {
"Is_Plane_Strain",
false},
120 {
"Horizon", horizon},
125 {
"Compute_From_Classical",
true},
126 {
"Influence_Function",
json{{
"Type", 0}}}});
128 json root = {{
"Model", model},
133 root.merge_patch(bc);
139 for (
size_t i = 0; i < dem.
d_neighPd.size(); ++i) {
140 const auto &xi = dem.
d_xRef[i];
141 for (
size_t k = 0; k < dem.
d_neighPd[i].size(); ++k) {
143 const auto &xj = dem.
d_xRef[j];
144 if ((xi.d_x - x_crack) * (xj.d_x - x_crack) < 0.) {
154 for (
size_t i = 0; i < dem.
d_xRef.size(); ++i) {
155 const double ux = (dem.
d_xRef[i].d_x >= x_crack) ? u_right : 0.;
163 double min_gap = 1.0e300;
166 double force_x_left = 0.;
167 double force_x_right = 0.;
172 for (
size_t i = 0; i < dem.
d_neighPd.size(); ++i) {
173 const auto &xi = dem.
d_xRef[i];
174 for (
size_t k = 0; k < dem.
d_neighPd[i].size(); ++k) {
178 const auto &xj = dem.
d_xRef[j];
179 if ((xi.d_x - x_crack) * (xj.d_x - x_crack) >= 0.)
181 const double gap = (dem.
d_x[j] - dem.
d_x[i]).length();
190 for (
size_t i = 0; i < dem.
d_xRef.size(); ++i) {
191 const double x = dem.
d_xRef[i].d_x;
192 const double fx = dem.
d_f[i].d_x * dem.
d_vol[i];
193 if (x < x_crack && x > x_crack - band)
195 if (x >= x_crack && x < x_crack + band)
202 double open_min_gap = 0.;
203 double close_min_gap = 0.;
204 double close_force_amp = 0.;
207LawResult runLaw(
const std::string &self_contact,
const std::filesystem::path &run_dir,
double L,
208 double mesh_size,
double horizon,
unsigned n_threads,
209 bool deck_only =
false) {
210 namespace fs = std::filesystem;
211 const fs::path out_dir = run_dir /
"out";
212 const fs::path inp_dir = run_dir /
"inp";
213 fs::create_directories(out_dir);
214 fs::create_directories(inp_dir);
216 const fs::path
mesh = inp_dir /
"mesh_rect.msh";
222 std::ofstream os(inp_dir /
"input.json");
223 os << input_json.dump(2);
233 auto deck = std::make_shared<inp::Input>(input_json);
237 const double x_crack = 0.5 * L;
240 throw std::runtime_error(self_contact +
": precrack broke no bonds");
243 const double h = dem.
d_hMax > 0. ? dem.
d_hMax : mesh_size;
244 util::io::print(std::format(
"{}: nodes={}, broken_bonds={}, h={}, Rc={}, horizon={}\n",
245 self_contact, dem.
d_x.size(), n_broken, h, Rc, horizon));
248 const double u_open = 2.0 * Rc;
251 const auto open_m =
measure(dem, x_crack, 2.0 * horizon);
252 if (!(open_m.min_gap > 1.5 * Rc))
253 throw std::runtime_error(std::format(
"{}: open did not separate (min_gap={})", self_contact,
259 const double u_close = -0.5 * (Rc + 0.5 * horizon);
262 const auto close_m =
measure(dem, x_crack, 2.0 * horizon);
263 const double force_amp =
264 0.5 * (std::abs(close_m.force_x_left) + std::abs(close_m.force_x_right));
266 util::io::print(std::format(
"{}: open min_gap={}, close min_gap={}, force_amp={}\n", self_contact,
267 open_m.min_gap, close_m.min_gap, force_amp));
280int main(
int argc,
char *argv[]) {
284 unsigned int n_threads = 2;
286 n_threads =
static_cast<unsigned>(std::stoi(input.
getCmdOption(
"-nThreads")));
289 namespace fs = std::filesystem;
290 fs::path base = fs::current_path() /
"self_contact_mode1_run";
294 const double L = 0.002;
295 const double mesh_size = L / 6.0;
296 const double horizon = 3.0 * mesh_size;
302 bb =
runLaw(
"broken_bond_kn", base /
"broken_bond_kn", L, mesh_size, horizon,
303 n_threads, deck_only);
304 rg =
runLaw(
"reference_gap", base /
"reference_gap", L, mesh_size, horizon,
305 n_threads, deck_only);
308 }
catch (
const std::exception &e) {
309 util::io::print(std::format(
"self-contact Mode-I failed: {}\n", e.what()));
313 if (!(bb.close_force_amp > 0.) || !(rg.close_force_amp > 0.)) {
315 "close did not activate self-contact: F_bb={}, F_rg={}\n", bb.close_force_amp,
316 rg.close_force_amp));
320 const double fmax = std::max(bb.close_force_amp, rg.close_force_amp);
321 const double rel = std::abs(bb.close_force_amp - rg.close_force_amp) / fmax;
324 "self-contact laws did not differ enough under close: F_bb={}, F_rg={}, rel={}\n",
325 bb.close_force_amp, rg.close_force_amp, rel));
330 "self-contact Mode-I OK: open gaps bb={}/rg={}, close forces bb={}/rg={}, rel_diff={}\n", bb.open_min_gap,
331 rg.open_min_gap, bb.close_force_amp, rg.close_force_amp, rel));
int main(int argc, char *argv[])
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, bool deck_only=false)
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(const json &given=json::object())
Returns example JSON object for ModelDeck configuration.
static json getExampleJson(const json &given=json::object())
Returns the block with the given fields set.
static json getExampleJson(const std::string &)=delete
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.