17 constexpr bool debug =
false;
19 auto get_tags_vec = [&](std::vector<std::pair<std::string, int>> names) {
20 std::vector<Tag> tags;
21 tags.reserve(names.size());
22 auto create_and_clean = [&]() {
24 for (
auto n : names) {
25 tags.push_back(
Tag());
26 auto &tag = tags.back();
27 auto &moab = mField.get_moab();
28 auto rval = moab.tag_get_handle(
n.first.c_str(), tag);
29 if (rval == MB_SUCCESS) {
32 double def_val[] = {0., 0., 0.};
33 CHKERR moab.tag_get_handle(
n.first.c_str(),
n.second, MB_TYPE_DOUBLE,
34 tag, MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
42 enum ExhangeTags { MATERIALFORCE, AREAGROWTH, GRIFFITHFORCE, FACEPRESSURE };
44 auto tags = get_tags_vec({{
"MaterialForce", 3},
47 {
"FacePressure", 1}});
49 auto calculate_material_forces = [&]() {
55 auto get_face_material_force_fe = [&]() {
57 auto fe_ptr = boost::make_shared<FaceEle>(mField);
58 fe_ptr->getRuleHook = [](int, int, int) {
return -1; };
60 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
63 EshelbianPlasticity::AddHOOps<2, 2, 3>::add(
64 fe_ptr->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
65 fe_ptr->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<3>(
66 hybridSpatialDisp, dataAtPts->getHybridDispAtPts()));
67 fe_ptr->getOpPtrVector().push_back(
68 new OpCalculateVectorFieldGradient<SPACE_DIM, SPACE_DIM>(
69 hybridSpatialDisp, dataAtPts->getGradHybridDispAtPts()));
70 auto op_loop_domain_side =
71 new OpLoopSide<VolumeElementForcesAndSourcesCoreOnSide>(
72 mField, elementVolumeName,
SPACE_DIM, Sev::noisy);
73 fe_ptr->getOpPtrVector().push_back(op_loop_domain_side);
77 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
78 boost::make_shared<CGGUserPolynomialBase>();
80 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
81 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
82 materialH1Positions, frontAdjEdges,
nullptr,
nullptr,
nullptr);
83 op_loop_domain_side->getOpPtrVector().push_back(
84 new OpCalculateHVecTensorField<SPACE_DIM, SPACE_DIM>(
85 piolaStress, dataAtPts->getApproxPAtPts()));
86 op_loop_domain_side->getOpPtrVector().push_back(
87 new OpCalculateHTensorTensorField<SPACE_DIM, SPACE_DIM>(
88 bubbleField, dataAtPts->getApproxPAtPts(), MBMAXTYPE));
90 op_loop_domain_side->getOpPtrVector().push_back(
91 new OpCalculateVectorFieldValues<SPACE_DIM>(
92 rotAxis, dataAtPts->getRotAxisAtPts(), MBTET));
93 if (noStretch || materialModel == MaterialModel::Hencky) {
98 op_loop_domain_side->getOpPtrVector().push_back(
99 physicalEquations->returnOpCalculateStretchFromStress(
100 dataAtPts, physicalEquations));
107 op_loop_domain_side->getOpPtrVector().push_back(
108 new OpCalculateTensor2SymmetricFieldValues<SPACE_DIM>(
109 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
112 op_loop_domain_side->getOpPtrVector().push_back(
118 auto integrate_face_material_force_fe = [&](
auto &&face_energy_fe) {
120 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(
121 dM, skeletonElement, face_energy_fe, 0, mField.get_comm_size());
123 auto face_exchange = CommInterface::createEntitiesPetscVector(
124 mField.get_comm(), mField.get_moab(), 2, 3, Sev::inform);
126 auto print_loc_size = [
this](
auto v,
auto str,
auto sev) {
129 CHKERR VecGetLocalSize(
v.second, &size);
131 CHKERR VecGetOwnershipRange(
v.second, &low, &high);
132 MOFEM_LOG(
"EPSYNC", sev) << str <<
" local size " << size <<
" ( "
133 << low <<
" " << high <<
" ) ";
137 CHKERR print_loc_size(face_exchange,
"material face_exchange",
140 CHKERR CommInterface::updateEntitiesPetscVector(
141 mField.get_moab(), face_exchange, tags[ExhangeTags::MATERIALFORCE]);
142 CHKERR CommInterface::updateEntitiesPetscVector(
143 mField.get_moab(), faceExchange, tags[ExhangeTags::FACEPRESSURE]);
148 "front_skin_faces_material_force_" +
149 std::to_string(mField.get_comm_rank()) +
".vtk",
157 CHKERR integrate_face_material_force_fe(get_face_material_force_fe());
162 auto calculate_front_material_force = [&](
auto nb_J_integral_contours) {
166 auto get_conn = [&](
auto e) {
168 CHK_MOAB_THROW(mField.get_moab().get_connectivity(&e, 1, conn,
true),
173 auto get_conn_range = [&](
auto e) {
180 auto get_adj = [&](
auto e,
auto dim) {
182 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(&e, 1, dim,
true, adj),
187 auto get_adj_range = [&](
auto e,
auto dim) {
189 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(e, dim,
true, adj,
190 moab::Interface::UNION),
195 auto get_material_force = [&](
auto r,
auto th) {
196 MatrixDouble material_forces(r.size(), 3,
false);
198 mField.get_moab().tag_get_data(th, r, material_forces.data().data()),
200 return material_forces;
203 if (mField.get_comm_rank() == 0) {
205 auto crack_edges = get_adj_range(*crackFaces, 1);
206 auto front_nodes = get_conn_range(*frontEdges);
213 Range all_skin_faces;
214 Range all_front_faces;
217 auto calculate_edge_direction = [&](
auto e) {
221 mField.get_moab().get_connectivity(e, conn, num_nodes,
true),
223 std::array<double, 6> coords;
225 mField.get_moab().get_coords(conn, num_nodes, coords.data()),
228 &coords[0], &coords[1], &coords[2]};
230 &coords[3], &coords[4], &coords[5]};
233 t_dir(
i) = t_p1(
i) - t_p0(
i);
238 auto calculate_force_through_node = [&]() {
249 auto body_skin = get_skin(mField, body_ents);
250 auto body_skin_conn = get_conn_range(body_skin);
253 for (
auto n : front_nodes) {
254 auto adj_tets = get_adj(
n, 3);
255 for (
int ll = 0; ll < nb_J_integral_contours; ++ll) {
256 auto conn = get_conn_range(adj_tets);
257 adj_tets = get_adj_range(conn, 3);
259 auto skin_faces = get_skin(mField, adj_tets);
260 auto material_forces = get_material_force(skin_faces, tags[0]);
264 all_skin_faces.merge(skin_faces);
268 auto calculate_node_material_force = [&]() {
270 getFTensor1FromPtr<SPACE_DIM>(material_forces.data().data());
272 for (
auto face : skin_faces) {
275 t_face_force_tmp(
I) = t_face_T(
I);
278 auto face_tets = intersect(get_adj(face, 3), adj_tets);
280 if (face_tets.empty()) {
284 if (face_tets.size() != 1) {
286 "face_tets.size() != 1");
289 int side_number, sense, offset;
294 t_face_force_tmp(
I) *= sense;
295 t_node_force(
I) += t_face_force_tmp(
I);
301 auto calculate_crack_area_growth_direction = [&](
auto n,
302 auto &t_node_force) {
305 auto boundary_node = intersect(
Range(
n,
n), body_skin_conn);
306 if (boundary_node.size()) {
307 auto faces = intersect(get_adj(
n, 2), body_skin);
308 for (
auto f : faces) {
310 CHKERR mField.getInterface<Tools>()->getTriNormal(
311 f, &t_normal_face(0));
312 t_project(
I) += t_normal_face(
I);
314 t_project.normalize();
321 if (boundary_node.size()) {
322 t_Q(
I,
J) -= t_project(
I) * t_project(
J);
325 auto adj_faces = intersect(get_adj(
n, 2), *crackFaces);
326 if (adj_faces.empty()) {
328 intersect(get_adj(
n, 1), unite(*frontEdges, body_edges));
330 for (
auto e : adj_edges) {
331 auto t_dir = calculate_edge_direction(e);
337 t_node_force_tmp(
I) = t_node_force(
I);
339 t_area_dir(
I) = -t_node_force_tmp(
I);
340 t_area_dir(
I) *=
l / 2;
345 auto front_edges = get_adj(
n, 1);
347 for (
auto f : adj_faces) {
350 CHKERR mField.get_moab().get_connectivity(f, conn, num_nodes,
352 std::array<double, 9> coords;
353 CHKERR mField.get_moab().get_coords(conn, num_nodes,
357 CHKERR mField.getInterface<Tools>()->getTriNormal(
358 coords.data(), &t_face_normal(0), &t_d_normal(0, 0, 0));
359 auto n_it = std::find(conn, conn + num_nodes,
n);
360 auto n_index = std::distance(conn, n_it);
363 t_d_normal(0, n_index, 0), t_d_normal(0, n_index, 1),
364 t_d_normal(0, n_index, 2),
366 t_d_normal(1, n_index, 0), t_d_normal(1, n_index, 1),
367 t_d_normal(1, n_index, 2),
369 t_d_normal(2, n_index, 0), t_d_normal(2, n_index, 1),
370 t_d_normal(2, n_index, 2)};
373 t_projected_hessian(
I,
J) =
374 t_Q(
I, K) * (t_face_hessian(K, L) * t_Q(L,
J));
377 t_face_normal(
I) * t_projected_hessian(
I, K) / 2.;
383 auto t_node_force = calculate_node_material_force();
384 t_node_force(
I) /= griffithEnergy;
386 mField.get_moab().tag_set_data(tags[ExhangeTags::MATERIALFORCE],
387 &
n, 1, &t_node_force(0)),
390 auto get_area_dir = [&]() {
392 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
393 unite(*frontEdges, body_edges));
394 auto seed_n = get_conn_range(adj_edges);
395 auto skin_adj_edges = get_skin(mField, adj_edges);
396 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
397 seed_n = subtract(seed_n, skin_adj_edges);
399 for (
auto sn : seed_n) {
401 calculate_crack_area_growth_direction(sn, t_node_force);
402 t_area_dir(
I) += t_area_dir_sn(
I);
404 for (
auto sn : skin_adj_edges) {
406 calculate_crack_area_growth_direction(sn, t_node_force);
407 t_area_dir(
I) += t_area_dir_sn(
I) / 2;
412 auto t_area_dir = get_area_dir();
415 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &
n,
418 auto griffith = -t_node_force(
I) * t_area_dir(
I) /
419 (t_area_dir(K) * t_area_dir(K));
421 mField.get_moab().tag_set_data(tags[ExhangeTags::GRIFFITHFORCE],
427 auto ave_node_force = [&](
auto th) {
430 for (
auto e : *frontEdges) {
432 auto conn = get_conn(e);
433 auto data = get_material_force(conn, th);
434 auto t_node = getFTensor1FromPtr<SPACE_DIM>(data.data().data());
436 for (
auto n : conn) {
438 t_edge(
I) += t_node(
I);
441 t_edge(
I) /= conn.size();
444 calculate_edge_direction(e);
456 CHKERR mField.get_moab().tag_set_data(th, &e, 1, &t_edge(0));
462 auto ave_node_griffith_energy = [&](
auto th) {
464 for (
auto e : *frontEdges) {
466 CHKERR mField.get_moab().tag_get_data(
467 tags[ExhangeTags::MATERIALFORCE], &e, 1, &t_edge_force(0));
469 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH],
470 &e, 1, &t_edge_area_dir(0));
471 double griffith_energy = -t_edge_force(
I) * t_edge_area_dir(
I) /
472 (t_edge_area_dir(K) * t_edge_area_dir(K));
473 CHKERR mField.get_moab().tag_set_data(th, &e, 1, &griffith_energy);
478 CHKERR ave_node_force(tags[ExhangeTags::MATERIALFORCE]);
479 CHKERR ave_node_force(tags[ExhangeTags::AREAGROWTH]);
480 CHKERR ave_node_griffith_energy(tags[ExhangeTags::GRIFFITHFORCE]);
485 CHKERR calculate_force_through_node();
488 for (
auto e : *frontEdges) {
489 auto adj_faces = get_adj(e, 2);
490 auto crack_face = intersect(get_adj(e, 2), *crackFaces);
494 all_front_faces.merge(adj_faces);
499 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::MATERIALFORCE],
500 &e, 1, &t_edge_force(0));
502 calculate_edge_direction(e);
511 for (
auto f : adj_faces) {
513 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
515 int side_number, sense, offset;
516 CHKERR mField.get_moab().side_number(f, e, side_number, sense,
518 auto dot = -sense * t_cross(
I) * t_normal(
I);
520 tags[ExhangeTags::GRIFFITHFORCE], &f, 1, &dot),
528 CHKERR TSGetStepNumber(ts, &ts_step);
530 "front_edges_material_force_" +
531 std::to_string(ts_step) +
".vtk",
534 "front_skin_faces_material_force_" +
535 std::to_string(ts_step) +
".vtk",
538 "front_faces_material_force_" +
539 std::to_string(ts_step) +
".vtk",
545 auto edge_exchange = CommInterface::createEntitiesPetscVector(
546 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
547 CHKERR CommInterface::updateEntitiesPetscVector(
548 mField.get_moab(), edge_exchange, tags[ExhangeTags::MATERIALFORCE]);
549 CHKERR CommInterface::updateEntitiesPetscVector(
550 mField.get_moab(), edge_exchange, tags[ExhangeTags::AREAGROWTH]);
551 CHKERR CommInterface::updateEntitiesPetscVector(
552 mField.get_moab(), edgeExchange, tags[ExhangeTags::GRIFFITHFORCE]);
557 auto print_results = [&](
auto nb_J_integral_conturs) {
560 auto get_conn_range = [&](
auto e) {
567 auto get_tag_data = [&](
auto &ents,
auto tag,
auto dim) {
568 std::vector<double> data(ents.size() * dim);
569 CHK_MOAB_THROW(mField.get_moab().tag_get_data(tag, ents, data.data()),
574 if (mField.get_comm_rank() == 0) {
575 auto at_nodes = [&]() {
577 auto conn = get_conn_range(*frontEdges);
578 auto material_force =
579 get_tag_data(conn, tags[ExhangeTags::MATERIALFORCE], 3);
580 auto area_growth = get_tag_data(conn, tags[ExhangeTags::AREAGROWTH], 3);
581 auto griffith_force =
582 get_tag_data(conn, tags[ExhangeTags::GRIFFITHFORCE], 1);
583 std::vector<double> coords(conn.size() * 3);
587 MOFEM_LOG(
"EPSELF", Sev::inform) <<
"Material force at nodes";
588 for (
size_t i = 0;
i < conn.size(); ++
i) {
590 <<
"Node " << conn[
i] <<
" coords " << coords[
i * 3 + 0] <<
" "
591 << coords[
i * 3 + 1] <<
" " << coords[
i * 3 + 2]
592 <<
" material force " << material_force[
i * 3 + 0] <<
" "
593 << material_force[
i * 3 + 1] <<
" " << material_force[
i * 3 + 2]
594 <<
" area growth " << area_growth[
i * 3 + 0] <<
" "
595 << area_growth[
i * 3 + 1] <<
" " << area_growth[
i * 3 + 2]
596 <<
" griffith force " << std::setprecision(12)
597 << griffith_force[
i] <<
" contour " << nb_J_integral_conturs;
607 CHKERR calculate_material_forces();
609 PetscBool all_contours = PETSC_FALSE;
610 CHKERR PetscOptionsGetBool(PETSC_NULLPTR,
"",
611 "-calculate_J_integral_all_levels", &all_contours,
613 CHKERR PetscOptionsGetBool(
614 PETSC_NULLPTR,
"",
"-calculate_J_integral_all_contours", &all_contours,
617 if (all_contours == PETSC_TRUE) {
618 for (
int l = 0;
l < nbJIntegralContours; ++
l) {
619 CHKERR calculate_front_material_force(
l);
624 CHKERR calculate_front_material_force(nbJIntegralContours);
625 CHKERR print_results(nbJIntegralContours);
631 bool set_orientation) {
634 constexpr bool debug =
false;
635 constexpr auto sev = Sev::verbose;
638 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
639 auto body_skin = get_skin(mField, body_ents);
640 Range body_skin_edges;
641 CHKERR mField.get_moab().get_adjacencies(body_skin, 1,
false, body_skin_edges,
642 moab::Interface::UNION);
643 Range boundary_skin_verts;
644 CHKERR mField.get_moab().get_connectivity(body_skin_edges,
645 boundary_skin_verts,
true);
648 Range geometry_edges_verts;
649 CHKERR mField.get_moab().get_connectivity(geometry_edges,
650 geometry_edges_verts,
true);
651 Range crack_faces_verts;
652 CHKERR mField.get_moab().get_connectivity(*crackFaces, crack_faces_verts,
654 Range crack_faces_edges;
655 CHKERR mField.get_moab().get_adjacencies(
656 *crackFaces, 1,
true, crack_faces_edges, moab::Interface::UNION);
657 Range crack_faces_tets;
658 CHKERR mField.get_moab().get_adjacencies(
659 *crackFaces, 3,
true, crack_faces_tets, moab::Interface::UNION);
662 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_verts,
true);
664 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2,
true, front_faces,
665 moab::Interface::UNION);
666 Range front_verts_edges;
667 CHKERR mField.get_moab().get_adjacencies(
668 front_verts, 1,
true, front_verts_edges, moab::Interface::UNION);
670 auto get_tags_vec = [&](
auto tag_name,
int dim) {
671 std::vector<Tag> tags(1);
676 auto create_and_clean = [&]() {
678 auto &moab = mField.get_moab();
679 auto rval = moab.tag_get_handle(tag_name, tags[0]);
680 if (rval == MB_SUCCESS) {
681 moab.tag_delete(tags[0]);
683 double def_val[] = {0., 0., 0.};
684 CHKERR moab.tag_get_handle(tag_name, dim, MB_TYPE_DOUBLE, tags[0],
685 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
694 auto get_adj_front = [&](
bool subtract_crack) {
696 CHKERR mField.get_moab().get_adjacencies(*frontEdges,
SPACE_DIM - 1,
true,
697 adj_front, moab::Interface::UNION);
699 adj_front = subtract(adj_front, *crackFaces);
705 auto th_front_position = get_tags_vec(
"FrontPosition", 3);
706 auto th_max_face_energy = get_tags_vec(
"MaxFaceEnergy", 1);
708 if (mField.get_comm_rank() == 0) {
710 auto get_crack_adj_tets = [&](
auto r) {
711 Range crack_faces_conn;
712 CHKERR mField.get_moab().get_connectivity(r, crack_faces_conn);
713 Range crack_faces_conn_tets;
715 true, crack_faces_conn_tets,
716 moab::Interface::UNION);
717 return crack_faces_conn_tets;
720 auto get_layers_for_sides = [&](
auto &side) {
721 std::vector<Range> layers;
725 auto get_adj = [&](
auto &r,
int dim) {
727 CHKERR mField.get_moab().get_adjacencies(r, dim,
true, adj,
728 moab::Interface::UNION);
732 auto get_tets = [&](
auto r) {
return get_adj(r,
SPACE_DIM); };
735 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_nodes,
737 Range front_faces = get_adj(front_nodes, 2);
738 front_faces = subtract(front_faces, *crackFaces);
739 auto front_tets = get_tets(front_nodes);
740 auto front_side = intersect(side, front_tets);
741 layers.push_back(front_side);
743 auto adj_faces = get_skin(mField, layers.back());
744 adj_faces = intersect(adj_faces, front_faces);
745 auto adj_faces_tets = get_tets(adj_faces);
746 adj_faces_tets = intersect(adj_faces_tets, front_tets);
747 layers.push_back(unite(layers.back(), adj_faces_tets));
748 if (layers.back().size() == layers[layers.size() - 2].size()) {
759 auto layers_top = get_layers_for_sides(sides_pair.first);
760 auto layers_bottom = get_layers_for_sides(sides_pair.second);
767 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
".vtk",
768 get_crack_adj_tets(*crackFaces));
772 MOFEM_LOG(
"EP", sev) <<
"Nb. layers " << layers_top.size();
774 for (
auto &r : layers_top) {
775 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " << r.size();
778 "layers_top_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
783 for (
auto &r : layers_bottom) {
784 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " << r.size();
787 "layers_bottom_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
793 auto get_cross = [&](
auto t_dir,
auto f) {
795 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
805 auto get_sense = [&](
auto f,
auto e) {
806 int side, sense, offset;
807 CHK_MOAB_THROW(mField.get_moab().side_number(f, e, side, sense, offset),
809 return std::make_tuple(side, sense, offset);
812 auto calculate_edge_direction = [&](
auto e,
auto normalize =
true) {
815 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes,
true);
816 std::array<double, 6> coords;
817 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
819 &coords[0], &coords[1], &coords[2]};
821 &coords[3], &coords[4], &coords[5]};
824 t_dir(
i) = t_p1(
i) - t_p0(
i);
830 auto evaluate_face_energy_and_set_orientation = [&](
auto front_edges,
837 Tag th_material_force;
838 switch (energyReleaseSelector) {
841 CHKERR mField.get_moab().tag_get_handle(
"GriffithForce",
843 CHKERR mField.get_moab().tag_get_handle(
"MaterialForce",
847 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
848 "Unknown energy release selector");
856 auto find_maximal_face_energy = [&](
auto front_edges,
auto front_faces,
857 auto &edge_face_max_energy_map) {
861 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
862 auto body_skin = get_skin(mField, body_ents);
866 for (
auto e : front_edges) {
868 double griffith_force;
869 CHKERR mField.get_moab().tag_get_data(th_face_energy, &e, 1,
873 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2,
false, faces);
874 faces = subtract(intersect(faces, front_faces), body_skin);
875 std::vector<double> face_energy(faces.size());
876 CHKERR mField.get_moab().tag_get_data(th_face_energy, faces,
879 std::max_element(face_energy.begin(), face_energy.end());
881 max_energy_it != face_energy.end() ? *max_energy_it : 0;
883 edge_face_max_energy_map[e] =
884 std::make_tuple(faces[max_energy_it - face_energy.begin()],
885 griffith_force,
static_cast<double>(0));
887 <<
"Edge " << e <<
" griffith force " << griffith_force
888 <<
" max face energy " << max_energy <<
" factor "
889 << max_energy / griffith_force;
891 max_faces.insert(faces[max_energy_it - face_energy.begin()]);
899 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
913 auto calculate_face_orientation = [&](
auto &edge_face_max_energy_map) {
916 auto up_down_face = [&](
918 auto &face_angle_map_up,
919 auto &face_angle_map_down
924 for (
auto &
m : edge_face_max_energy_map) {
926 auto [max_face, energy, opt_angle] =
m.second;
929 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2,
false, faces);
930 faces = intersect(faces, front_faces);
934 moab::Interface::UNION);
935 if (adj_tets.size()) {
940 moab::Interface::UNION);
941 if (adj_tets.size()) {
943 Range adj_tets_faces;
945 CHKERR mField.get_moab().get_adjacencies(
946 adj_tets,
SPACE_DIM - 1,
false, adj_tets_faces,
947 moab::Interface::UNION);
948 adj_tets_faces = intersect(adj_tets_faces, faces);
953 get_cross(calculate_edge_direction(e,
true), max_face);
954 auto [side_max, sense_max, offset_max] = get_sense(max_face, e);
955 t_cross_max(
i) *= sense_max;
957 for (
auto t : adj_tets) {
958 Range adj_tets_faces;
959 CHKERR mField.get_moab().get_adjacencies(
961 adj_tets_faces = intersect(adj_tets_faces, faces);
963 subtract(adj_tets_faces,
Range(max_face, max_face));
965 if (adj_tets_faces.size() == 1) {
969 auto t_cross = get_cross(calculate_edge_direction(e,
true),
971 auto [side, sense, offset] =
972 get_sense(adj_tets_faces[0], e);
974 double dot = t_cross(
i) * t_cross_max(
i);
975 auto angle = std::acos(dot);
978 CHKERR mField.get_moab().tag_get_data(
979 th_face_energy, adj_tets_faces, &face_energy);
981 auto [side_face, sense_face, offset_face] =
982 get_sense(
t, max_face);
984 if (sense_face > 0) {
985 face_angle_map_up[e] = std::make_tuple(face_energy, angle,
989 face_angle_map_down[e] = std::make_tuple(
990 face_energy, -angle, adj_tets_faces[0]);
1001 auto calc_optimal_angle = [&](
1003 auto &face_angle_map_up,
1004 auto &face_angle_map_down
1009 for (
auto &
m : edge_face_max_energy_map) {
1011 auto &[max_face, e0,
a0] =
m.second;
1013 if (std::abs(e0) > std::numeric_limits<double>::epsilon()) {
1015 if (face_angle_map_up.find(e) == face_angle_map_up.end() ||
1016 face_angle_map_down.find(e) == face_angle_map_down.end()) {
1020 switch (energyReleaseSelector) {
1024 Tag th_material_force;
1025 CHKERR mField.get_moab().tag_get_handle(
"MaterialForce",
1028 CHKERR mField.get_moab().tag_get_data(
1029 th_material_force, &e, 1, &t_material_force(0));
1030 auto material_force_magnitude = t_material_force.
l2();
1031 if (material_force_magnitude <
1032 std::numeric_limits<double>::epsilon()) {
1037 auto t_edge_dir = calculate_edge_direction(e,
true);
1038 auto t_cross_max = get_cross(t_edge_dir, max_face);
1039 auto [side, sense, offset] = get_sense(max_face, e);
1040 t_cross_max(sense) *= sense;
1047 t_cross_max.normalize();
1050 t_material_force(
J) * t_cross_max(K);
1051 a0 = -std::asin(t_cross(
I) * t_edge_dir(
I));
1054 <<
"Optimal angle " <<
a0 <<
" energy " << e0;
1060 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
1061 "Unknown energy release selector");
1071 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
1073 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
1074 face_angle_map_down;
1075 CHKERR up_down_face(face_angle_map_up, face_angle_map_down);
1076 CHKERR calc_optimal_angle(face_angle_map_up, face_angle_map_down);
1080 auto th_angle = get_tags_vec(
"Angle", 1);
1082 for (
auto &
m : face_angle_map_up) {
1083 auto [e,
a, face] =
m.second;
1085 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &
a);
1088 for (
auto &
m : face_angle_map_down) {
1089 auto [e,
a, face] =
m.second;
1091 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &
a);
1094 Range max_energy_faces;
1095 for (
auto &
m : edge_face_max_energy_map) {
1096 auto [face, e, angle] =
m.second;
1097 max_energy_faces.insert(face);
1098 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1,
1101 if (mField.get_comm_rank() == 0) {
1113 auto get_conn = [&](
auto e) {
1115 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn,
true),
1120 auto get_adj = [&](
auto e,
auto dim) {
1123 e, dim,
false, adj, moab::Interface::UNION),
1128 auto get_coords = [&](
auto v) {
1136 auto get_rotated_normal = [&](
auto e,
auto f,
auto angle) {
1139 auto t_edge_dir = calculate_edge_direction(e,
true);
1140 auto [side, sense, offset] = get_sense(f, e);
1141 t_edge_dir(
i) *= sense;
1142 t_edge_dir.normalize();
1143 t_edge_dir(
i) *= angle;
1146 mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
1148 t_rotated_normal(
i) = t_R(
i,
j) * t_normal(
j);
1149 return std::make_tuple(t_normal, t_rotated_normal);
1152 auto set_coord = [&](
auto v,
auto &adj_vertex_tets_verts,
auto &coords,
1153 auto &t_move,
auto gamma) {
1154 auto index = adj_vertex_tets_verts.index(
v);
1156 for (
auto ii : {0, 1, 2}) {
1157 coords[3 * index + ii] += gamma * t_move(ii);
1164 auto tets_quality = [&](
auto quality,
auto &adj_vertex_tets_verts,
1165 auto &adj_vertex_tets,
auto &coords) {
1166 for (
auto t : adj_vertex_tets) {
1169 CHKERR mField.get_moab().get_connectivity(
t, conn, num_nodes,
true);
1170 std::array<double, 12> tet_coords;
1171 for (
auto n = 0;
n != 4; ++
n) {
1172 auto index = adj_vertex_tets_verts.index(conn[
n]);
1176 for (
auto ii = 0; ii != 3; ++ii) {
1177 tet_coords[3 *
n + ii] = coords[3 * index + ii];
1180 double q = Tools::volumeLengthQuality(tet_coords.data());
1181 if (!std::isnormal(q))
1183 quality = std::min(quality, q);
1189 auto calculate_free_face_node_displacement =
1190 [&](
auto &edge_face_max_energy_map) {
1192 auto get_vertex_edges = [&](
auto vertex) {
1197 CHKERR mField.get_moab().get_adjacencies(vertex, 1,
false,
1199 vertex_edges = subtract(vertex_edges, front_verts_edges);
1201 if (boundary_skin_verts.size() &&
1202 boundary_skin_verts.find(vertex[0]) !=
1203 boundary_skin_verts.end()) {
1204 MOFEM_LOG(
"EP", sev) <<
"Boundary vertex";
1205 vertex_edges = intersect(vertex_edges, body_skin_edges);
1207 if (geometry_edges_verts.size() &&
1208 geometry_edges_verts.find(vertex[0]) !=
1209 geometry_edges_verts.end()) {
1210 MOFEM_LOG(
"EP", sev) <<
"Geometry edge vertex";
1211 vertex_edges = intersect(vertex_edges, geometry_edges);
1213 if (crack_faces_verts.size() &&
1214 crack_faces_verts.find(vertex[0]) !=
1215 crack_faces_verts.end()) {
1216 MOFEM_LOG(
"EP", sev) <<
"Crack face vertex";
1217 vertex_edges = intersect(vertex_edges, crack_faces_edges);
1224 return vertex_edges;
1229 using Bundle = std::vector<
1235 std::map<EntityHandle, Bundle> edge_bundle_map;
1237 for (
auto &
m : edge_face_max_energy_map) {
1239 auto edge =
m.first;
1240 auto &[max_face, energy, opt_angle] =
m.second;
1243 auto [t_normal, t_rotated_normal] =
1244 get_rotated_normal(edge, max_face, opt_angle);
1246 auto front_vertex = get_conn(
Range(
m.first,
m.first));
1247 auto adj_tets = get_adj(
Range(max_face, max_face), 3);
1248 auto adj_tets_faces = get_adj(adj_tets, 2);
1249 auto adj_front_faces = subtract(
1250 intersect(get_adj(
Range(edge, edge), 2), adj_tets_faces),
1252 if (adj_front_faces.size() > 3)
1254 "adj_front_faces.size()>3");
1257 CHKERR mField.get_moab().tag_get_data(th_material_force, &edge, 1,
1258 &t_material_force(0));
1259 std::vector<double> griffith_energy(adj_front_faces.size());
1260 CHKERR mField.get_moab().tag_get_data(
1261 th_face_energy, adj_front_faces, griffith_energy.data());
1263 auto set_edge_bundle = [&](
auto min_gamma) {
1264 for (
auto rotated_f : adj_front_faces) {
1266 double rotated_face_energy =
1267 griffith_energy[adj_front_faces.index(rotated_f)];
1269 auto vertex = subtract(get_conn(
Range(rotated_f, rotated_f)),
1271 if (vertex.size() != 1) {
1273 "Wrong number of vertex to move");
1275 auto front_vertex_edges_vertex = get_conn(
1276 intersect(get_adj(front_vertex, 1), crack_faces_edges));
1278 vertex, front_vertex_edges_vertex);
1279 if (vertex.empty()) {
1283 auto face_cardinality = [&](
auto f,
auto &seen_front_edges) {
1286 subtract(body_skin_edges, crack_faces_edges));
1287 auto faces =
Range(f, f);
1289 for (;
c < 10; ++
c) {
1291 subtract(get_adj(faces, 1), seen_front_edges);
1292 if (front_edges.size() == 0) {
1295 auto front_connected_edges =
1296 intersect(front_edges, whole_front);
1297 if (front_connected_edges.size()) {
1298 seen_front_edges.merge(front_connected_edges);
1301 faces.merge(get_adj(front_edges, 2));
1308 double rotated_face_cardinality = face_cardinality(
1314 rotated_face_cardinality = std::max(rotated_face_cardinality,
1317 auto t_vertex_coords = get_coords(vertex);
1318 auto vertex_edges = get_vertex_edges(vertex);
1323 CHKERR mField.get_moab().get_coords(&f0, 1, &t_v_e0(0));
1324 CHKERR mField.get_moab().get_coords(&f1, 1, &t_v_e1(0));
1327 for (
auto e_used_to_move_detection : vertex_edges) {
1328 auto edge_conn = get_conn(
Range(e_used_to_move_detection,
1329 e_used_to_move_detection));
1330 edge_conn = subtract(edge_conn, vertex);
1340 t_v0(
i) = (t_v_e0(
i) + t_v_e1(
i)) / 2;
1342 CHKERR mField.get_moab().get_coords(edge_conn, &t_v3(0));
1344 (t_v0(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
1346 (t_v3(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
1349 constexpr double eps =
1350 std::numeric_limits<double>::epsilon();
1351 if (std::isnormal(gamma) && gamma < 1.0 -
eps &&
1354 t_move(
i) = gamma * (t_v3(
i) - t_vertex_coords(
i));
1356 auto check_rotated_face_directoon = [&]() {
1358 t_delta(
i) = t_vertex_coords(
i) + t_move(
i) - t_v0(
i);
1361 (t_material_force(
i) / t_material_force.
l2()) *
1363 return -dot > 0 ? true :
false;
1366 if (check_rotated_face_directoon()) {
1369 <<
"Crack edge " << edge <<
" moved face "
1371 <<
" edge: " << e_used_to_move_detection
1372 <<
" face direction/energy " << rotated_face_energy
1373 <<
" face cardinality " << rotated_face_cardinality
1374 <<
" gamma: " << gamma;
1376 auto &bundle = edge_bundle_map[edge];
1377 bundle.emplace_back(rotated_f, e_used_to_move_detection,
1378 vertex[0], t_move, 1,
1379 rotated_face_cardinality, gamma);
1386 set_edge_bundle(std::numeric_limits<double>::epsilon());
1387 if (edge_bundle_map[edge].empty()) {
1388 set_edge_bundle(-1.);
1392 return edge_bundle_map;
1395 auto get_sort_by_energy = [&](
auto &edge_face_max_energy_map) {
1396 std::map<double, std::tuple<EntityHandle, EntityHandle, double>>
1399 for (
auto &
m : edge_face_max_energy_map) {
1401 auto &[max_face, energy, opt_angle] =
m.second;
1402 sort_by_energy[energy] = std::make_tuple(e, max_face, opt_angle);
1405 return sort_by_energy;
1408 auto set_tag = [&](
auto &&adj_edges_map,
auto &&sort_by_energy) {
1411 Tag th_face_pressure;
1413 mField.get_moab().tag_get_handle(
"FacePressure", th_face_pressure),
1415 auto get_face_pressure = [&](
auto face) {
1417 CHK_MOAB_THROW(mField.get_moab().tag_get_data(th_face_pressure, &face,
1424 <<
"Number of edges to check " << sort_by_energy.size();
1426 enum face_energy { POSITIVE, NEGATIVE };
1427 constexpr bool skip_negative =
true;
1429 for (
auto fe : {face_energy::POSITIVE, face_energy::NEGATIVE}) {
1433 for (
auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
1436 auto energy = it->first;
1437 auto [max_edge, max_face, opt_angle] = it->second;
1439 auto face_pressure = get_face_pressure(max_face);
1440 if (skip_negative) {
1441 if (fe == face_energy::POSITIVE) {
1442 if (face_pressure < 0) {
1444 <<
"Skip negative face " << max_face <<
" with energy "
1445 << energy <<
" and pressure " << face_pressure;
1452 <<
"Check face " << max_face <<
" edge " << max_edge
1453 <<
" energy " << energy <<
" optimal angle " << opt_angle
1454 <<
" face pressure " << face_pressure;
1456 auto jt = adj_edges_map.find(max_edge);
1457 if (jt == adj_edges_map.end()) {
1459 <<
"Edge " << max_edge <<
" not found in adj_edges_map";
1462 auto &bundle = jt->second;
1464 auto find_max_in_bundle_impl = [&](
auto edge,
auto &bundle,
1471 double max_quality = -2;
1472 double max_quality_evaluated = -2;
1473 double min_cardinality = std::numeric_limits<double>::max();
1477 for (
auto &b : bundle) {
1478 auto &[face, move_edge, vertex, t_move, quality, cardinality,
1481 auto adj_vertex_tets = get_adj(
Range(vertex, vertex), 3);
1482 auto adj_vertex_tets_verts = get_conn(adj_vertex_tets);
1483 std::vector<double> coords(3 * adj_vertex_tets_verts.size());
1485 adj_vertex_tets_verts, coords.data()),
1488 set_coord(vertex, adj_vertex_tets_verts, coords, t_move, gamma);
1489 quality = tets_quality(quality, adj_vertex_tets_verts,
1490 adj_vertex_tets, coords);
1492 auto eval_quality = [](
auto q,
auto c,
auto edge_gamma) {
1496 return ((edge_gamma < 0) ? (q / 2) : q) / pow(
c, 2);
1500 if (eval_quality(quality, cardinality, edge_gamma) >=
1501 max_quality_evaluated) {
1502 max_quality = quality;
1503 min_cardinality = cardinality;
1504 vertex_max = vertex;
1506 move_edge_max = move_edge;
1507 t_move_last(
i) = t_move(
i);
1508 max_quality_evaluated =
1509 eval_quality(max_quality, min_cardinality, edge_gamma);
1513 return std::make_tuple(vertex_max, face_max, t_move_last,
1514 max_quality, min_cardinality);
1517 auto find_max_in_bundle = [&](
auto edge,
auto &bundle) {
1518 auto b_org_bundle = bundle;
1519 auto r = find_max_in_bundle_impl(edge, bundle, 1.);
1520 auto &[vertex_max, face_max, t_move_last, max_quality,
1522 if (max_quality < 0) {
1523 for (
double gamma = 0.95; gamma >= 0.45; gamma -= 0.05) {
1524 bundle = b_org_bundle;
1525 r = find_max_in_bundle_impl(edge, bundle, gamma);
1526 auto &[vertex_max, face_max, t_move_last, max_quality,
1529 <<
"Back tracking: gamma " << gamma <<
" edge " << edge
1530 <<
" quality " << max_quality <<
" cardinality "
1532 if (max_quality > 0.01) {
1534 t_move_last(
I) *= gamma;
1545 auto set_tag_to_vertex_and_face = [&](
auto &&r,
auto &quality) {
1547 auto &[
v, f, t_move, q, cardinality] = r;
1549 if ((q > 0 && std::isnormal(q)) && energy > 0) {
1552 <<
"Set tag: vertex " <<
v <<
" face " << f <<
" "
1553 << max_edge <<
" move " << t_move <<
" energy " << energy
1554 <<
" quality " << q <<
" cardinality " << cardinality;
1555 CHKERR mField.get_moab().tag_set_data(th_position[0], &
v, 1,
1557 CHKERR mField.get_moab().tag_set_data(th_max_face_energy[0], &f,
1565 double quality = -2;
1566 CHKERR set_tag_to_vertex_and_face(
1568 find_max_in_bundle(max_edge, bundle),
1574 if (quality > 0 && std::isnormal(quality) && energy > 0) {
1576 <<
"Crack face set with quality: " << quality;
1589 MOFEM_LOG(
"EP", sev) <<
"Calculate orientation";
1590 std::map<EntityHandle, std::tuple<EntityHandle, double, double>>
1591 edge_face_max_energy_map;
1592 CHKERR find_maximal_face_energy(front_edges, front_faces,
1593 edge_face_max_energy_map);
1594 CHKERR calculate_face_orientation(edge_face_max_energy_map);
1596 MOFEM_LOG(
"EP", sev) <<
"Calculate node positions";
1599 calculate_free_face_node_displacement(edge_face_max_energy_map),
1600 get_sort_by_energy(edge_face_max_energy_map)
1607 MOFEM_LOG(
"EP", sev) <<
"Front edges " << frontEdges->size();
1608 CHKERR evaluate_face_energy_and_set_orientation(
1609 *frontEdges, get_adj_front(
false), sides_pair, th_front_position);
1613 CHKERR VecZeroEntries(vertexExchange.second);
1614 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
1616 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
1618 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
1619 mField.get_moab(), vertexExchange, th_front_position[0]);
1620 CHKERR VecZeroEntries(faceExchange.second);
1621 CHKERR VecGhostUpdateBegin(faceExchange.second, INSERT_VALUES,
1623 CHKERR VecGhostUpdateEnd(faceExchange.second, INSERT_VALUES, SCATTER_FORWARD);
1624 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
1625 mField.get_moab(), faceExchange, th_max_face_energy[0]);
1627 auto get_max_moved_faces = [&]() {
1628 Range max_moved_faces;
1629 auto adj_front = get_adj_front(
false);
1630 std::vector<double> face_energy(adj_front.size());
1631 CHKERR mField.get_moab().tag_get_data(th_max_face_energy[0], adj_front,
1632 face_energy.data());
1633 for (
int i = 0;
i != adj_front.size(); ++
i) {
1634 if (face_energy[
i] > std::numeric_limits<double>::epsilon()) {
1635 max_moved_faces.insert(adj_front[
i]);
1639 return boost::make_shared<Range>(max_moved_faces);
1643 maxMovedFaces = get_max_moved_faces();
1644 MOFEM_LOG(
"EP", sev) <<
"Number of of moved faces: " << maxMovedFaces->size();
1650 "max_moved_faces_" +
1651 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
".vtk",
1701 constexpr bool potential_crack_debug =
false;
1702 if constexpr (potential_crack_debug) {
1705 Range crack_front_verts;
1706 CHKERR mField.get_moab().get_connectivity(*frontEdges, crack_front_verts,
1708 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
1710 Range crack_front_faces;
1711 CHKERR mField.get_moab().get_adjacencies(crack_front_verts,
SPACE_DIM - 1,
1712 true, crack_front_faces,
1713 moab::Interface::UNION);
1714 crack_front_faces = intersect(crack_front_faces, add_ents);
1715 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
1717 CHKERR mField.getInterface<MeshsetsManager>()->addEntitiesToMeshset(
1718 BLOCKSET, addCrackMeshsetId, crack_front_faces);
1721 auto get_crack_faces = [&]() {
1722 if (maxMovedFaces) {
1723 return unite(*crackFaces, *maxMovedFaces);
1729 auto get_extended_crack_faces = [&]() {
1730 auto get_faces_of_crack_front_verts = [&](
auto crack_faces_org) {
1731 ParallelComm *pcomm =
1736 if (!pcomm->rank()) {
1738 auto get_nodes = [&](
auto &&e) {
1740 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes,
true),
1741 "get connectivity");
1745 auto get_adj = [&](
auto &&e,
auto dim,
1746 auto t = moab::Interface::UNION) {
1749 mField.get_moab().get_adjacencies(e, dim,
true, adj,
t),
1757 auto body_skin = get_skin(mField, body_ents);
1758 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
1761 auto front_block_nodes = get_nodes(front_block_edges);
1765 s = crack_faces.size();
1767 auto crack_face_nodes = get_nodes(crack_faces_org);
1768 auto crack_faces_edges =
1769 get_adj(crack_faces_org, 1, moab::Interface::UNION);
1771 auto crack_skin = get_skin(mField, crack_faces_org);
1772 front_block_edges = subtract(front_block_edges, crack_skin);
1773 auto crack_skin_nodes = get_nodes(crack_skin);
1774 crack_skin_nodes.merge(front_block_nodes);
1776 auto crack_skin_faces =
1777 get_adj(crack_skin, 2, moab::Interface::UNION);
1779 subtract(subtract(crack_skin_faces, crack_faces_org), body_skin);
1781 crack_faces = crack_faces_org;
1782 for (
auto f : crack_skin_faces) {
1783 auto edges = intersect(
1784 get_adj(
Range(f, f), 1, moab::Interface::UNION), crack_skin);
1788 if (edges.size() == 2) {
1790 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
1794 if (edges.size() == 2) {
1795 auto edge_conn = get_nodes(
Range(edges));
1796 auto faces = intersect(get_adj(edges, 2, moab::Interface::UNION),
1798 if (faces.size() == 2) {
1799 auto edge0_conn = get_nodes(
Range(edges[0], edges[0]));
1800 auto edge1_conn = get_nodes(
Range(edges[1], edges[1]));
1801 auto edges_conn = intersect(intersect(edge0_conn, edge1_conn),
1803 if (edges_conn.size() == 1) {
1806 subtract(intersect(get_adj(edges_conn, 1,
1807 moab::Interface::INTERSECT),
1812 if (node_edges.size()) {
1815 CHKERR mField.get_moab().get_coords(edges_conn, &t_v0(0));
1817 auto get_t_dir = [&](
auto e_conn) {
1818 auto other_node = subtract(e_conn, edges_conn);
1820 CHKERR mField.get_moab().get_coords(other_node,
1822 t_dir(
i) -= t_v0(
i);
1828 get_t_dir(edge0_conn)(
i) + get_t_dir(edge1_conn)(
i);
1831 t_crack_surface_ave_dir(
i) = 0;
1832 for (
auto e : node_edges) {
1833 auto e_conn = get_nodes(
Range(e, e));
1834 auto t_dir = get_t_dir(e_conn);
1835 t_crack_surface_ave_dir(
i) += t_dir(
i);
1838 auto dot = t_ave_dir(
i) * t_crack_surface_ave_dir(
i);
1841 if (dot < -std::numeric_limits<double>::epsilon()) {
1842 crack_faces.insert(f);
1845 crack_faces.insert(f);
1849 }
else if (edges.size() == 3) {
1850 crack_faces.insert(f);
1854 if (edges.size() == 1) {
1856 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
1859 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
1860 front_block_edges));
1861 if (edges.size() == 2) {
1862 crack_faces.insert(f);
1868 crack_faces_org = crack_faces;
1870 }
while (s != crack_faces.size());
1876 return get_faces_of_crack_front_verts(get_crack_faces());
1881 get_extended_crack_faces());
1884 auto reconstruct_crack_faces = [&](
auto crack_faces) {
1885 ParallelComm *pcomm =
1891 Range new_crack_faces;
1892 if (!pcomm->rank()) {
1894 auto get_nodes = [&](
auto &&e) {
1896 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes,
true),
1897 "get connectivity");
1901 auto get_adj = [&](
auto &&e,
auto dim,
1902 auto t = moab::Interface::UNION) {
1905 mField.get_moab().get_adjacencies(e, dim,
true, adj,
t),
1910 auto get_test_on_crack_surface = [&]() {
1911 auto crack_faces_nodes =
1912 get_nodes(crack_faces);
1913 auto crack_faces_tets =
1914 get_adj(crack_faces_nodes, 3,
1915 moab::Interface::UNION);
1919 auto crack_faces_tets_nodes =
1920 get_nodes(crack_faces_tets);
1921 crack_faces_tets_nodes =
1922 subtract(crack_faces_tets_nodes, crack_faces_nodes);
1924 subtract(crack_faces_tets, get_adj(crack_faces_tets_nodes, 3,
1925 moab::Interface::UNION));
1927 get_adj(crack_faces_tets, 2,
1928 moab::Interface::UNION);
1930 new_crack_faces.merge(crack_faces);
1932 return std::make_tuple(new_crack_faces, crack_faces_tets);
1935 auto carck_faces_test_edges = [&](
auto faces,
auto tets) {
1936 auto adj_tets_faces = get_adj(tets, 2, moab::Interface::UNION);
1937 auto adj_faces_edges = get_adj(subtract(faces, adj_tets_faces), 1,
1938 moab::Interface::UNION);
1939 auto adj_tets_edges = get_adj(tets, 1, moab::Interface::UNION);
1942 adj_faces_edges.merge(geometry_edges);
1943 adj_faces_edges.merge(front_block_edges);
1945 auto boundary_tets_edges = intersect(adj_tets_edges, adj_faces_edges);
1946 auto boundary_test_nodes = get_nodes(boundary_tets_edges);
1947 auto boundary_test_nodes_edges =
1948 get_adj(boundary_test_nodes, 1, moab::Interface::UNION);
1949 auto boundary_test_nodes_edges_nodes = subtract(
1950 get_nodes(boundary_test_nodes_edges), boundary_test_nodes);
1952 boundary_tets_edges =
1953 subtract(boundary_test_nodes_edges,
1954 get_adj(boundary_test_nodes_edges_nodes, 1,
1955 moab::Interface::UNION));
1960 auto body_skin = get_skin(mField, body_ents);
1962 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
1963 body_skin_edges = intersect(get_adj(tets, 1, moab::Interface::UNION),
1965 body_skin = intersect(body_skin, adj_tets_faces);
1966 body_skin_edges = subtract(
1967 body_skin_edges, get_adj(body_skin, 1, moab::Interface::UNION));
1969 save_range(mField.get_moab(),
"body_skin_edges.vtk", body_skin_edges);
1970 for (
auto e : body_skin_edges) {
1971 auto adj_tet = intersect(
1972 get_adj(
Range(e, e), 3, moab::Interface::INTERSECT), tets);
1973 if (adj_tet.size() == 1) {
1974 boundary_tets_edges.insert(e);
1978 return boundary_tets_edges;
1981 auto p = get_test_on_crack_surface();
1982 auto &[new_crack_faces, crack_faces_tets] = p;
1993 auto boundary_tets_edges =
1994 carck_faces_test_edges(new_crack_faces, crack_faces_tets);
1996 boundary_tets_edges);
1998 auto resolve_surface = [&](
auto boundary_tets_edges,
1999 auto crack_faces_tets) {
2000 auto boundary_tets_edges_nodes = get_nodes(boundary_tets_edges);
2001 auto crack_faces_tets_faces =
2002 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
2004 Range all_removed_faces;
2005 Range all_removed_tets;
2009 while (size != crack_faces_tets.size()) {
2011 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
2012 auto skin_tets = get_skin(mField, crack_faces_tets);
2014 get_skin(mField, subtract(crack_faces_tets_faces, tets_faces));
2015 auto skin_skin_nodes = get_nodes(skin_skin);
2017 size = crack_faces_tets.size();
2019 <<
"Crack faces tets size " << crack_faces_tets.size()
2020 <<
" crack faces size " << crack_faces_tets_faces.size();
2021 auto skin_tets_nodes = subtract(
2022 get_nodes(skin_tets),
2023 boundary_tets_edges_nodes);
2025 skin_tets_nodes = subtract(skin_tets_nodes, skin_skin_nodes);
2027 Range removed_nodes;
2028 Range tets_to_remove;
2029 Range faces_to_remove;
2030 for (
auto n : skin_tets_nodes) {
2032 intersect(get_adj(
Range(
n,
n), 3, moab::Interface::INTERSECT),
2034 if (tets.size() == 0) {
2038 auto hole_detetction = [&]() {
2040 get_adj(
Range(
n,
n), 3, moab::Interface::INTERSECT);
2045 if (adj_tets.size() == 0) {
2046 return std::make_pair(
2048 get_adj(
Range(
n,
n), 2, moab::Interface::INTERSECT),
2053 std::vector<Range> tets_groups;
2054 auto test_adj_tets = adj_tets;
2055 while (test_adj_tets.size()) {
2057 Range seed =
Range(test_adj_tets[0], test_adj_tets[0]);
2058 while (seed.size() != seed_size) {
2060 subtract(get_adj(seed, 2, moab::Interface::UNION),
2063 seed_size = seed.size();
2065 intersect(get_adj(adj_faces, 3, moab::Interface::UNION),
2068 tets_groups.push_back(seed);
2069 test_adj_tets = subtract(test_adj_tets, seed);
2071 if (tets_groups.size() == 1) {
2073 return std::make_pair(
2075 get_adj(
Range(
n,
n), 2, moab::Interface::INTERSECT),
2080 Range tets_to_remove;
2081 Range faces_to_remove;
2082 for (
auto &r : tets_groups) {
2083 auto f = get_adj(r, 2, moab::Interface::UNION);
2084 auto t = intersect(get_adj(f, 3, moab::Interface::UNION),
2087 if (f.size() > faces_to_remove.size() ||
2088 faces_to_remove.size() == 0) {
2089 faces_to_remove = f;
2094 <<
"Hole detection: faces to remove "
2095 << faces_to_remove.size() <<
" tets to remove "
2096 << tets_to_remove.size();
2097 return std::make_pair(faces_to_remove, tets_to_remove);
2100 if (tets.size() < tets_to_remove.size() ||
2101 tets_to_remove.size() == 0) {
2103 auto [h_faces_to_remove, h_tets_to_remove] =
2105 faces_to_remove = h_faces_to_remove;
2106 tets_to_remove = h_tets_to_remove;
2114 all_removed_faces.merge(faces_to_remove);
2115 all_removed_tets.merge(tets_to_remove);
2118 crack_faces_tets = subtract(crack_faces_tets, tets_to_remove);
2119 crack_faces_tets_faces =
2120 subtract(crack_faces_tets_faces, faces_to_remove);
2125 boost::lexical_cast<std::string>(counter) +
".vtk",
2128 "faces_to_remove_" +
2129 boost::lexical_cast<std::string>(counter) +
".vtk",
2133 boost::lexical_cast<std::string>(counter) +
".vtk",
2136 "crack_faces_tets_faces_" +
2137 boost::lexical_cast<std::string>(counter) +
".vtk",
2138 crack_faces_tets_faces);
2140 "crack_faces_tets_" +
2141 boost::lexical_cast<std::string>(counter) +
".vtk",
2147 auto cese_internal_faces = [&]() {
2149 auto skin_tets = get_skin(mField, crack_faces_tets);
2150 auto adj_faces = get_adj(skin_tets, 2, moab::Interface::UNION);
2152 subtract(adj_faces, skin_tets);
2153 auto adj_tets = get_adj(adj_faces, 3,
2154 moab::Interface::UNION);
2157 subtract(crack_faces_tets,
2160 crack_faces_tets_faces =
2161 subtract(crack_faces_tets_faces, adj_faces);
2163 all_removed_faces.merge(adj_faces);
2164 all_removed_tets.merge(adj_tets);
2167 <<
"Remove internal faces size " << adj_faces.size()
2168 <<
" tets size " << adj_tets.size();
2172 auto case_only_one_free_edge = [&]() {
2175 for (
auto t :
Range(crack_faces_tets)) {
2177 auto adj_faces = get_adj(
2179 moab::Interface::UNION);
2180 auto crack_surface_edges =
2181 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
2184 moab::Interface::UNION);
2187 subtract(get_adj(
Range(
t,
t), 1, moab::Interface::INTERSECT),
2188 crack_surface_edges);
2189 adj_edges = subtract(
2191 boundary_tets_edges);
2193 if (adj_edges.size() == 1) {
2195 subtract(crack_faces_tets,
2199 auto faces_to_remove =
2200 get_adj(adj_edges, 2, moab::Interface::UNION);
2203 crack_faces_tets_faces =
2204 subtract(crack_faces_tets_faces, faces_to_remove);
2206 all_removed_faces.merge(faces_to_remove);
2207 all_removed_tets.merge(
Range(
t,
t));
2209 MOFEM_LOG(
"EPSELF", Sev::inform) <<
"Remove free one edges ";
2213 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
2214 crack_faces_tets_faces =
2215 subtract(crack_faces_tets_faces, all_removed_faces);
2220 auto cese_flat_tet = [&](
auto max_adj_edges) {
2226 auto body_skin = get_skin(mField, body_ents);
2227 auto body_skin_edges =
2228 get_adj(body_skin, 1, moab::Interface::UNION);
2230 for (
auto t :
Range(crack_faces_tets)) {
2232 auto adj_faces = get_adj(
2234 moab::Interface::UNION);
2235 auto crack_surface_edges =
2236 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
2239 moab::Interface::UNION);
2242 subtract(get_adj(
Range(
t,
t), 1, moab::Interface::INTERSECT),
2243 crack_surface_edges);
2244 adj_edges = subtract(adj_edges, body_skin_edges);
2246 auto tet_edges = get_adj(
Range(
t,
t), 1,
2247 moab::Interface::UNION);
2249 tet_edges = subtract(tet_edges, adj_edges);
2251 for (
auto e : tet_edges) {
2252 constexpr int opposite_edge[] = {5, 3, 4, 1, 2, 0};
2253 auto get_side = [&](
auto e) {
2254 int side, sense, offset;
2256 mField.get_moab().side_number(
t, e, side, sense, offset),
2257 "get side number failed");
2260 auto get_side_ent = [&](
auto side) {
2263 mField.get_moab().side_element(
t, 1, side, side_edge),
2267 adj_edges.erase(get_side_ent(opposite_edge[get_side(e)]));
2270 if (adj_edges.size() <= max_adj_edges) {
2273 Range faces_to_remove;
2274 for (
auto e : adj_edges) {
2275 auto edge_adj_faces =
2276 get_adj(
Range(e, e), 2, moab::Interface::UNION);
2277 edge_adj_faces = intersect(edge_adj_faces, adj_faces);
2278 if (edge_adj_faces.size() != 2) {
2280 "Adj faces size is not 2 for edge " +
2281 boost::lexical_cast<std::string>(e));
2284 auto get_normal = [&](
auto f) {
2287 mField.getInterface<Tools>()->getTriNormal(f, &t_n(0)),
2288 "get tri normal failed");
2291 auto t_n0 = get_normal(edge_adj_faces[0]);
2292 auto t_n1 = get_normal(edge_adj_faces[1]);
2293 auto get_sense = [&](
auto f) {
2294 int side, sense, offset;
2297 "get side number failed");
2300 auto sense0 = get_sense(edge_adj_faces[0]);
2301 auto sense1 = get_sense(edge_adj_faces[1]);
2306 auto dot_e = (sense0 * sense1) * t_n0(
i) * t_n1(
i);
2307 if (dot_e < dot || e == adj_edges[0]) {
2309 faces_to_remove = edge_adj_faces;
2313 all_removed_faces.merge(faces_to_remove);
2314 all_removed_tets.merge(
Range(
t,
t));
2317 <<
"Remove free edges on flat tet, with considered nb. of "
2319 << adj_edges.size();
2323 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
2324 crack_faces_tets_faces =
2325 subtract(crack_faces_tets_faces, all_removed_faces);
2331 "Case only one free edge failed");
2332 for (
auto max_adj_edges : {0, 1, 2, 3}) {
2334 "Case only one free edge failed");
2337 "Case internal faces failed");
2341 "crack_faces_tets_faces_" +
2342 boost::lexical_cast<std::string>(counter) +
".vtk",
2343 crack_faces_tets_faces);
2345 "crack_faces_tets_" +
2346 boost::lexical_cast<std::string>(counter) +
".vtk",
2350 return std::make_tuple(crack_faces_tets_faces, crack_faces_tets,
2351 all_removed_faces, all_removed_tets);
2354 auto [resolved_faces, resolved_tets, all_removed_faces,
2356 resolve_surface(boundary_tets_edges, crack_faces_tets);
2357 resolved_faces.merge(subtract(crack_faces, all_removed_faces));
2365 crack_faces = resolved_faces;
2376 auto resolve_consisten_crack_extension = [&]() {
2378 auto crack_meshset =
2379 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2381 auto meshset = crack_meshset->getMeshset();
2383 if (!mField.get_comm_rank()) {
2384 Range old_crack_faces;
2385 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
2387 auto extendeded_crack_faces = get_extended_crack_faces();
2388 auto reconstructed_crack_faces =
2389 subtract(reconstruct_crack_faces(extendeded_crack_faces),
2390 subtract(*crackFaces, old_crack_faces));
2391 if (nbCrackFaces >= reconstructed_crack_faces.size()) {
2393 <<
"No new crack faces to add, skipping adding to meshset";
2394 extendeded_crack_faces = subtract(
2395 extendeded_crack_faces, subtract(*crackFaces, old_crack_faces));
2397 <<
"Number crack faces size (extended) "
2398 << extendeded_crack_faces.size();
2399 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2400 CHKERR mField.get_moab().add_entities(meshset, extendeded_crack_faces);
2402 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2403 CHKERR mField.get_moab().add_entities(meshset,
2404 reconstructed_crack_faces);
2406 <<
"Number crack faces size (reconstructed) "
2407 << reconstructed_crack_faces.size();
2408 nbCrackFaces = reconstructed_crack_faces.size();
2413 if (!mField.get_comm_rank()) {
2414 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
2417 crack_faces =
send_type(mField, crack_faces, MBTRI);
2418 if (mField.get_comm_rank()) {
2419 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2420 CHKERR mField.get_moab().add_entities(meshset, crack_faces);
2426 CHKERR resolve_consisten_crack_extension();