15 const int tag, TS ts, SmartPetscObj<Vec> *adjoint_gradient_vector) {
18 constexpr bool debug =
false;
20 auto get_tags_vec = [&](std::vector<std::pair<std::string, int>> names) {
21 std::vector<Tag> tags;
22 tags.reserve(names.size());
23 auto create_and_clean = [&]() {
25 for (
auto n : names) {
26 tags.push_back(
Tag());
27 auto &tag = tags.back();
28 auto &moab = mField.get_moab();
29 auto rval = moab.tag_get_handle(
n.first.c_str(), tag);
30 if (rval == MB_SUCCESS) {
33 double def_val[] = {0., 0., 0.};
34 CHKERR moab.tag_get_handle(
n.first.c_str(),
n.second, MB_TYPE_DOUBLE,
35 tag, MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
45 ADJOINT_MATERIALFORCE,
48 ADJOINT_GRIFFITHFORCE,
52 auto tags = get_tags_vec({{
"MaterialForce", 3},
53 {
"AdjointMaterialForce", 3},
56 {
"AdjointGriffithForce", 1},
57 {
"FacePressure", 1}});
59 auto calculate_material_forces = [&]() {
65 auto get_face_material_force_fe = [&]() {
67 auto fe_ptr = boost::make_shared<FaceEle>(mField);
68 fe_ptr->getRuleHook = [](int, int, int) {
return -1; };
70 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges);
71 if (ts != PETSC_NULLPTR) {
72 fe_ptr->data_ctx |= PetscData::CTX_SET_TIME;
73 CHKERR TSGetTime(ts, &(fe_ptr->ts_t));
74 CHKERR TSGetTimeStep(ts, &(fe_ptr->ts_dt));
77 EshelbianPlasticity::AddHOOps<2, 2, 3>::add(
78 fe_ptr->getOpPtrVector(), {L2}, materialH1Positions, frontAdjEdges);
79 fe_ptr->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<3>(
80 hybridSpatialDisp,
dataAtPts->getHybridDispAtPts()));
81 fe_ptr->getOpPtrVector().push_back(
82 new OpCalculateVectorFieldGradient<SPACE_DIM, SPACE_DIM>(
83 hybridSpatialDisp,
dataAtPts->getGradHybridDispAtPts()));
84 auto op_loop_domain_side =
85 new OpLoopSide<VolumeElementForcesAndSourcesCoreOnSide>(
86 mField, elementVolumeName,
SPACE_DIM, Sev::noisy);
87 fe_ptr->getOpPtrVector().push_back(op_loop_domain_side);
91 op_loop_domain_side->getSideFEPtr()->getUserPolynomialBase() =
92 boost::make_shared<CGGUserPolynomialBase>(
nullptr,
true);
94 EshelbianPlasticity::AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
95 op_loop_domain_side->getOpPtrVector(), {HDIV, H1, L2},
96 materialH1Positions, frontAdjEdges,
nullptr,
nullptr,
nullptr);
97 op_loop_domain_side->getOpPtrVector().push_back(
98 new OpCalculateHVecTensorField<SPACE_DIM, SPACE_DIM>(
99 piolaStress,
dataAtPts->getApproxPAtPts()));
101 op_loop_domain_side->getOpPtrVector().push_back(
102 new OpCalculateVectorFieldValues<SPACE_DIM>(
103 rotAxis,
dataAtPts->getRotAxisAtPts(), MBTET));
104 CHKERR physicalEquations->pushMaterialForceFields(
105 *
this, op_loop_domain_side->getOpPtrVector(),
dataAtPts);
107 op_loop_domain_side->getOpPtrVector().push_back(
113 auto integrate_face_material_force_fe = [&](
auto &&face_energy_fe) {
115 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(
116 dM, skeletonElement, face_energy_fe, 0, mField.get_comm_size());
118 auto face_exchange = CommInterface::createEntitiesPetscVector(
119 mField.get_comm(), mField.get_moab(), 2, 3, Sev::inform);
121 auto print_loc_size = [
this](
auto v,
auto str,
auto sev) {
124 CHKERR VecGetLocalSize(
v.second, &size);
126 CHKERR VecGetOwnershipRange(
v.second, &low, &high);
127 MOFEM_LOG(
"EPSYNC", sev) << str <<
" local size " << size <<
" ( "
128 << low <<
" " << high <<
" ) ";
132 CHKERR print_loc_size(face_exchange,
"material face_exchange",
135 CHKERR CommInterface::updateEntitiesPetscVector(
136 mField.get_moab(), face_exchange, tags[ExhangeTags::MATERIALFORCE]);
137 CHKERR CommInterface::updateEntitiesPetscVector(
138 mField.get_moab(), faceExchange, tags[ExhangeTags::FACEPRESSURE]);
143 "front_skin_faces_material_force_" +
144 std::to_string(mField.get_comm_rank()) +
".vtk",
152 CHKERR integrate_face_material_force_fe(get_face_material_force_fe());
157 auto get_conn = [&](
auto e) {
159 CHK_MOAB_THROW(mField.get_moab().get_connectivity(&e, 1, conn,
true),
164 auto get_conn_range = [&](
auto e) {
171 auto get_adj = [&](
auto e,
auto dim) {
173 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(&e, 1, dim,
true, adj),
178 auto get_adj_range = [&](
auto e,
auto dim) {
180 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(e, dim,
true, adj,
181 moab::Interface::UNION),
186 auto get_vector_tag_data = [&](
auto r,
auto th) {
187 MatrixDouble tag_data(r.size(), 3,
false);
189 mField.get_moab().tag_get_data(th, r, tag_data.data().data()),
190 "get vector tag data");
194 auto calculate_edge_direction = [&](
auto e) {
195 const EntityHandle *conn;
198 mField.get_moab().get_connectivity(e, conn, num_nodes,
true),
200 std::array<double, 6> coords;
201 CHK_MOAB_THROW(mField.get_moab().get_coords(conn, num_nodes, coords.data()),
204 &coords[0], &coords[1], &coords[2]};
206 &coords[3], &coords[4], &coords[5]};
209 t_dir(
i) = t_p1(
i) - t_p0(
i);
213 auto average_vector_tag_at_edge = [&](
auto th) {
218 for (
auto e : *frontEdges) {
219 auto conn = get_conn(e);
220 auto data = get_vector_tag_data(conn, th);
221 auto t_node = getFTensor1FromPtr<SPACE_DIM>(data.data().data());
223 for (
auto n : conn) {
225 t_edge_material_force(
I) += t_node(
I);
228 t_edge_material_force(
I) /= conn.size();
231 calculate_edge_direction(e);
237 t_edge_material_force(
J);
238 t_edge_material_force(K) =
241 CHKERR mField.get_moab().tag_set_data(th, &e, 1,
242 &t_edge_material_force(0));
248 auto average_material_force_at_edge = [&](
auto th) {
251 if (mField.get_comm_rank() == 0) {
252 CHKERR average_vector_tag_at_edge(th);
257 CHKERR TSGetStepNumber(ts, &ts_step);
259 "front_edges_material_force_" +
260 std::to_string(ts_step) +
".vtk",
269 auto calculate_force_through_node = [&](
auto nb_J_integral_contours) {
274 if (mField.get_comm_rank() == 0) {
275 auto front_nodes = get_conn_range(*frontEdges);
276 Range all_skin_faces;
278 for (
auto n : front_nodes) {
280 for (
int ll = 0; ll < nb_J_integral_contours; ++ll) {
281 auto conn = get_conn_range(adj_tets);
282 adj_tets = get_adj_range(conn,
SPACE_DIM);
285 auto skin_faces = get_skin(mField, adj_tets);
286 auto material_forces =
287 get_vector_tag_data(skin_faces, tags[ExhangeTags::MATERIALFORCE]);
291 all_skin_faces.merge(skin_faces);
296 getFTensor1FromPtr<SPACE_DIM>(material_forces.data().data());
298 for (
auto face : skin_faces) {
301 t_face_force_tmp(
I) = t_face_T(
I);
304 auto face_tets = intersect(get_adj(face,
SPACE_DIM), adj_tets);
306 if (face_tets.empty()) {
310 if (face_tets.size() != 1) {
312 "face_tets.size() != 1");
315 int side_number, sense, offset;
320 t_face_force_tmp(
I) *= sense;
321 t_node_force(
I) += t_face_force_tmp(
I);
324 t_node_force(
I) /= griffithEnergy;
326 mField.get_moab().tag_set_data(tags[ExhangeTags::MATERIALFORCE],
327 &
n, 1, &t_node_force(0)),
334 CHKERR TSGetStepNumber(ts, &ts_step);
336 "front_skin_faces_material_force_" +
337 std::to_string(ts_step) +
".vtk",
346 auto get_adj_tets_for_contour = [&](
auto n,
auto nb_J_integral_contours) {
348 for (
int ll = 0; ll < nb_J_integral_contours; ++ll) {
349 auto conn = get_conn_range(adj_tets);
350 adj_tets = get_adj_range(conn,
SPACE_DIM);
355 auto get_front_node_adj_crack_faces = [&](
auto n) {
356 return intersect(get_adj(
n,
SPACE_DIM - 1), *crackFaces);
359 auto calculate_crack_area_growth_face = [&](
auto nb_J_integral_contours) {
364 if (mField.get_comm_rank() == 0) {
365 auto front_nodes = get_conn_range(*frontEdges);
370 auto body_skin = get_skin(mField, body_ents);
371 auto body_skin_conn = get_conn_range(body_skin);
373 auto calculate_seed_area_growth = [&](
auto n,
auto &adj_faces) {
376 auto boundary_node = intersect(
Range(
n,
n), body_skin_conn);
377 if (boundary_node.size()) {
378 auto faces = intersect(get_adj(
n,
SPACE_DIM - 1), body_skin);
379 for (
auto f : faces) {
381 CHKERR mField.getInterface<Tools>()->getTriNormal(
382 f, &t_normal_face(0));
383 t_project(
I) += t_normal_face(
I);
385 t_project.normalize();
392 if (boundary_node.size()) {
393 t_Q(
I,
J) -= t_project(
I) * t_project(
J);
397 for (
auto f : adj_faces) {
399 const EntityHandle *conn;
400 CHKERR mField.get_moab().get_connectivity(f, conn, num_nodes,
true);
401 std::array<double, 9> coords;
402 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
405 CHKERR mField.getInterface<Tools>()->getTriNormal(
406 coords.data(), &t_face_normal(0), &t_d_normal(0, 0, 0));
407 auto n_it = std::find(conn, conn + num_nodes,
n);
408 auto n_index = std::distance(conn, n_it);
411 t_d_normal(0, n_index, 0), t_d_normal(0, n_index, 1),
412 t_d_normal(0, n_index, 2),
414 t_d_normal(1, n_index, 0), t_d_normal(1, n_index, 1),
415 t_d_normal(1, n_index, 2),
417 t_d_normal(2, n_index, 0), t_d_normal(2, n_index, 1),
418 t_d_normal(2, n_index, 2)};
421 t_projected_hessian(
I,
J) =
422 t_Q(
I, K) * (t_face_hessian(K, L) * t_Q(L,
J));
424 t_area_dir(K) += t_face_normal(
I) * t_projected_hessian(
I, K) / 2.;
430 auto get_crack_area_growth_seed_nodes = [&](
auto &adj_tets) {
435 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
436 unite(*frontEdges, body_edges));
441 auto seed_n = get_conn_range(adj_edges);
442 auto skin_adj_edges = get_skin(mField, adj_edges);
443 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
444 seed_n = subtract(seed_n, skin_adj_edges);
446 return std::make_pair(seed_n, skin_adj_edges);
449 auto calculate_front_node_area_growth = [&](
auto &adj_tets) {
450 auto [seed_n, skin_adj_edges] =
451 get_crack_area_growth_seed_nodes(adj_tets);
454 auto add_area_growth_direction = [&](
auto sn,
double weight) {
455 auto adj_faces = intersect(get_adj(sn,
SPACE_DIM - 1), *crackFaces);
456 if (adj_faces.empty()) {
460 auto t_area_dir_sn = calculate_seed_area_growth(sn, adj_faces);
461 t_area_dir(
I) += weight * t_area_dir_sn(
I);
464 for (
auto sn : seed_n) {
465 add_area_growth_direction(sn, 1.);
467 for (
auto sn : skin_adj_edges) {
468 add_area_growth_direction(sn, 0.5);
474 for (
auto n : front_nodes) {
475 auto front_node_adj_faces = get_front_node_adj_crack_faces(
n);
476 if (front_node_adj_faces.empty()) {
480 auto adj_tets = get_adj_tets_for_contour(
n, nb_J_integral_contours);
481 auto t_area_dir = calculate_front_node_area_growth(adj_tets);
484 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &
n, 1,
493 auto calculate_crack_area_growth_no_face = [&](
auto nb_J_integral_contours,
494 auto material_force_tag) {
499 if (mField.get_comm_rank() == 0) {
500 auto front_nodes = get_conn_range(*frontEdges);
505 auto body_skin = get_skin(mField, body_ents);
506 auto body_skin_conn = get_conn_range(body_skin);
508 auto calculate_seed_area_growth = [&](
auto n,
auto &t_node_force) {
510 intersect(get_adj(
n, 1), unite(*frontEdges, body_edges));
512 for (
auto e : adj_edges) {
513 auto t_dir = calculate_edge_direction(e);
520 t_node_force_tmp(
I) = t_node_force(
I);
522 t_area_dir(
I) = -t_node_force_tmp(
I);
523 t_area_dir(
I) *=
l / 2;
527 auto get_crack_area_growth_seed_nodes = [&](
auto &adj_tets) {
528 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
529 unite(*frontEdges, body_edges));
530 auto seed_n = get_conn_range(adj_edges);
531 auto skin_adj_edges = get_skin(mField, adj_edges);
532 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
533 seed_n = subtract(seed_n, skin_adj_edges);
535 return std::make_pair(seed_n, skin_adj_edges);
538 auto calculate_front_node_area_growth = [&](
auto &adj_tets,
539 auto &t_node_force) {
540 auto [seed_n, skin_adj_edges] =
541 get_crack_area_growth_seed_nodes(adj_tets);
544 auto add_area_growth_direction = [&](
auto sn,
double weight) {
545 auto t_area_dir_sn = calculate_seed_area_growth(sn, t_node_force);
546 t_area_dir(
I) += weight * t_area_dir_sn(
I);
549 for (
auto sn : seed_n) {
550 add_area_growth_direction(sn, 1.);
552 for (
auto sn : skin_adj_edges) {
553 add_area_growth_direction(sn, 0.5);
559 for (
auto n : front_nodes) {
560 auto front_node_adj_faces = get_front_node_adj_crack_faces(
n);
561 if (front_node_adj_faces.empty()) {
563 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &
n, 1,
566 auto adj_tets = get_adj_tets_for_contour(
n, nb_J_integral_contours);
568 calculate_front_node_area_growth(adj_tets, t_node_force);
571 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &
n,
581 auto update_crack_area_growth_edges = [&]() {
584 if (mField.get_comm_rank() == 0) {
585 CHKERR average_vector_tag_at_edge(tags[ExhangeTags::AREAGROWTH]);
588 auto area_growth_edge_exchange = CommInterface::createEntitiesPetscVector(
589 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
590 CHKERR CommInterface::updateEntitiesPetscVector(
591 mField.get_moab(), area_growth_edge_exchange,
592 tags[ExhangeTags::AREAGROWTH]);
597 auto calculate_griffith_force = [&](ExhangeTags material_force_tag,
598 ExhangeTags griffith_force_tag) {
603 if (mField.get_comm_rank() == 0) {
604 auto front_nodes = get_conn_range(*frontEdges);
605 Range all_front_faces;
607 for (
auto n : front_nodes) {
609 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &
n, 1,
612 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH], &
n,
616 -t_node_force(
I) * t_area_dir(
I) / (t_area_dir(K) * t_area_dir(K));
618 tags[griffith_force_tag], &
n, 1, &griffith),
622 for (
auto e : *frontEdges) {
624 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &e, 1,
627 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH], &e,
628 1, &t_edge_area_dir(0));
629 double griffith_energy =
630 -t_edge_force(
I) * t_edge_area_dir(
I) /
631 (t_edge_area_dir(K) * t_edge_area_dir(K));
632 CHKERR mField.get_moab().tag_set_data(tags[griffith_force_tag], &e, 1,
636 for (
auto e : *frontEdges) {
637 auto adj_faces = get_adj(e,
SPACE_DIM - 1);
640 all_front_faces.merge(adj_faces);
644 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &e, 1,
647 calculate_edge_direction(e);
654 for (
auto f : adj_faces) {
656 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
658 int side_number, sense, offset;
659 CHKERR mField.get_moab().side_number(f, e, side_number, sense, offset);
660 auto dot = -sense * t_cross(
I) * t_normal(
I);
662 tags[griffith_force_tag], &f, 1, &dot),
670 CHKERR TSGetStepNumber(ts, &ts_step);
672 "front_faces_material_force_" +
673 std::to_string(ts_step) +
".vtk",
679 auto vector_edge_exchange = CommInterface::createEntitiesPetscVector(
680 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
681 CHKERR CommInterface::updateEntitiesPetscVector(
682 mField.get_moab(), vector_edge_exchange, tags[material_force_tag]);
683 auto &scalar_edge_exchange = edgeExchange;
684 CHKERR CommInterface::updateEntitiesPetscVector(
685 mField.get_moab(), scalar_edge_exchange, tags[griffith_force_tag]);
690 auto calculate_griffith_force_simplified = [&](
auto material_force_tag,
691 auto griffith_force_tag) {
694 if (mField.get_comm_rank() == 0) {
695 auto front_nodes = get_conn_range(*frontEdges);
697 for (
auto n : front_nodes) {
699 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &
n, 1,
702 auto adj_edges = intersect(get_adj(
n, 1), *frontEdges);
703 double adj_edges_length = 0.;
704 for (
auto e : adj_edges) {
705 auto t_edge_dir = calculate_edge_direction(e);
706 adj_edges_length += t_edge_dir.l2();
709 const double nodal_front_length = adj_edges_length / 2.;
710 if (nodal_front_length <= 0.) {
712 "Front node has zero adjacent front edge length");
715 double griffith_energy = t_node_force.
l2() / nodal_front_length;
716 CHK_MOAB_THROW(mField.get_moab().tag_set_data(tags[griffith_force_tag],
717 &
n, 1, &griffith_energy),
725 auto calculate_adjoint_material_force = [&]() {
728 if (ts == PETSC_NULLPTR) {
730 "TS is required to calculate adjoint material force");
747 auto set_vertex_exchange_from_gradient = [&]() {
750 CHKERR VecZeroEntries(vertexExchange.second);
751 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
753 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
756 auto *problem_ptr = getProblemPtr(dmMaterial);
758 problem_ptr->getNumeredRowDofsPtr()->get<Unique_mi_tag>();
759 const auto field_bit = mField.get_field_bit_number(materialH1Positions);
762 double *exchange_array;
763 CHKERR VecGetArray(
g, &g_array);
764 CHKERR VecGetArray(vertexExchange.second, &exchange_array);
766 auto ptr = exchange_array;
768 for (
auto v : vertexExchange.first.first) {
769 std::array<double, SPACE_DIM> values = {0., 0., 0.};
771 dofs.lower_bound(DofEntity::getLoFieldEntityUId(field_bit,
v));
773 dofs.upper_bound(DofEntity::getHiFieldEntityUId(field_bit,
v));
774 for (; lo != hi; ++lo) {
775 if (!(*lo)->getHasLocalIndex())
777 const auto coeff = (*lo)->getDofCoeffIdx();
779 values[coeff] = g_array[(*lo)->getPetscLocalDofIdx()];
781 for (
int d = 0; d !=
SPACE_DIM; ++d, ++ptr) {
786 CHKERR VecRestoreArray(vertexExchange.second, &exchange_array);
787 CHKERR VecRestoreArray(
g, &g_array);
789 if (adjoint_gradient_vector !=
nullptr) {
790 (*adjoint_gradient_vector) =
g;
796 CHKERR set_vertex_exchange_from_gradient();
798 CHKERR CommInterface::setTagFromVector(
799 mField.get_moab(), vertexExchange,
800 tags[ExhangeTags::ADJOINT_MATERIALFORCE]);
801 CHKERR CommInterface::updateEntitiesPetscVector(
802 mField.get_moab(), vertexExchange,
803 tags[ExhangeTags::ADJOINT_MATERIALFORCE]);
808 auto print_results = [&](
auto nb_J_integral_conturs,
bool print_material,
809 bool print_adjoint) {
812 if (!print_material && !print_adjoint) {
816 auto get_conn_range = [&](
auto e) {
823 auto get_tag_data = [&](
auto &ents,
auto tag,
auto dim) {
824 std::vector<double> data(ents.size() * dim);
825 CHK_MOAB_THROW(mField.get_moab().tag_get_data(tag, ents, data.data()),
830 if (mField.get_comm_rank() == 0) {
831 auto at_nodes = [&]() {
833 auto conn = get_conn_range(*frontEdges);
834 std::vector<double> material_force;
835 std::vector<double> adjoint_material_force;
836 auto area_growth = get_tag_data(conn, tags[ExhangeTags::AREAGROWTH], 3);
837 std::vector<double> griffith_force;
838 std::vector<double> adjoint_griffith_force;
839 if (print_material) {
841 get_tag_data(conn, tags[ExhangeTags::MATERIALFORCE], 3);
843 get_tag_data(conn, tags[ExhangeTags::GRIFFITHFORCE], 1);
846 adjoint_material_force =
847 get_tag_data(conn, tags[ExhangeTags::ADJOINT_MATERIALFORCE], 3);
848 adjoint_griffith_force =
849 get_tag_data(conn, tags[ExhangeTags::ADJOINT_GRIFFITHFORCE], 1);
851 std::vector<double> coords(conn.size() * 3);
854 MOFEM_LOG(
"EPSELF", Sev::inform) <<
"Force results at nodes";
856 << std::left << std::setw(10) <<
"kind" << std::right
857 << std::setw(9) <<
"node" << std::setw(18) <<
"coord_x"
858 << std::setw(18) <<
"coord_y" << std::setw(18) <<
"coord_z"
859 << std::setw(18) <<
"force_x" << std::setw(18) <<
"force_y"
860 << std::setw(18) <<
"force_z" << std::setw(18) <<
"area_x"
861 << std::setw(18) <<
"area_y" << std::setw(18) <<
"area_z"
862 << std::setw(18) <<
"griffith" << std::setw(10) <<
"contour";
864 auto print_row = [&](
const char *kind,
const auto &force,
865 const auto &griffith,
const size_t i) {
867 << std::left << std::setw(10) << kind << std::right
868 << std::setw(9) << conn[
i] << std::scientific
869 << std::setprecision(10) << std::setw(18) << coords[
i * 3 + 0]
870 << std::setw(18) << coords[
i * 3 + 1] << std::setw(18)
871 << coords[
i * 3 + 2] << std::setw(18) << force[
i * 3 + 0]
872 << std::setw(18) << force[
i * 3 + 1] << std::setw(18)
873 << force[
i * 3 + 2] << std::setw(18) << area_growth[
i * 3 + 0]
874 << std::setw(18) << area_growth[
i * 3 + 1] << std::setw(18)
875 << area_growth[
i * 3 + 2] << std::setw(18) << griffith[
i]
876 << std::defaultfloat << std::setprecision(6) << std::setw(10)
877 << nb_J_integral_conturs;
880 for (
size_t i = 0;
i < conn.size(); ++
i) {
881 if (print_material) {
882 print_row(
"material", material_force, griffith_force,
i);
885 print_row(
"adjoint", adjoint_material_force, adjoint_griffith_force,
898 CHKERR calculate_material_forces();
900 PetscBool all_contours = PETSC_FALSE;
901 CHKERR PetscOptionsGetBool(PETSC_NULLPTR,
"",
902 "-calculate_J_integral_all_levels", &all_contours,
904 CHKERR PetscOptionsGetBool(
905 PETSC_NULLPTR,
"",
"-calculate_J_integral_all_contours", &all_contours,
908 if (all_contours == PETSC_TRUE) {
909 for (
int l = 0;
l < nbJIntegralContours; ++
l) {
910 CHKERR calculate_force_through_node(
l);
911 CHKERR average_material_force_at_edge(tags[ExhangeTags::MATERIALFORCE]);
912 CHKERR calculate_crack_area_growth_face(
l);
913 CHKERR calculate_crack_area_growth_no_face(
l, ExhangeTags::MATERIALFORCE);
914 CHKERR update_crack_area_growth_edges();
915 CHKERR calculate_griffith_force(ExhangeTags::MATERIALFORCE,
916 ExhangeTags::GRIFFITHFORCE);
917 CHKERR print_results(
l,
true,
false);
921 PetscBool has_nonzero_ts_solution = PETSC_FALSE;
923 if (ts != PETSC_NULLPTR) {
924 Vec ts_solution = PETSC_NULLPTR;
925 CHKERR TSGetSolution(ts, &ts_solution);
926 if (ts_solution != PETSC_NULLPTR) {
927 PetscReal ts_solution_norm = 0.0;
928 CHKERR VecNorm(ts_solution, NORM_2, &ts_solution_norm);
929 has_nonzero_ts_solution =
930 (ts_solution_norm > PETSC_MACHINE_EPSILON) ? PETSC_TRUE : PETSC_FALSE;
933 if (has_nonzero_ts_solution == PETSC_TRUE) {
934 CHKERR calculate_adjoint_material_force();
938 CHKERR calculate_force_through_node(nbJIntegralContours);
939 CHKERR average_material_force_at_edge(tags[ExhangeTags::MATERIALFORCE]);
940 CHKERR calculate_crack_area_growth_face(nbJIntegralContours);
941 CHKERR calculate_crack_area_growth_no_face(nbJIntegralContours,
942 ExhangeTags::MATERIALFORCE);
943 CHKERR update_crack_area_growth_edges();
944 CHKERR calculate_griffith_force(ExhangeTags::MATERIALFORCE,
945 ExhangeTags::GRIFFITHFORCE);
946 if (has_nonzero_ts_solution == PETSC_TRUE) {
947 CHKERR calculate_griffith_force(ExhangeTags::ADJOINT_MATERIALFORCE,
948 ExhangeTags::ADJOINT_GRIFFITHFORCE);
949 CHKERR calculate_griffith_force_simplified(
950 ExhangeTags::ADJOINT_MATERIALFORCE, ExhangeTags::ADJOINT_GRIFFITHFORCE);
952 CHKERR print_results(nbJIntegralContours,
true,
true);
958 bool set_orientation) {
961 constexpr bool debug =
false;
963 constexpr auto sev = Sev::verbose;
966 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
967 auto body_skin = get_skin(mField, body_ents);
968 Range body_skin_edges;
969 CHKERR mField.get_moab().get_adjacencies(body_skin, 1,
false, body_skin_edges,
970 moab::Interface::UNION);
971 Range boundary_skin_verts;
972 CHKERR mField.get_moab().get_connectivity(body_skin_edges,
973 boundary_skin_verts,
true);
976 Range geometry_edges_verts;
977 CHKERR mField.get_moab().get_connectivity(geometry_edges,
978 geometry_edges_verts,
true);
979 Range crack_faces_verts;
980 CHKERR mField.get_moab().get_connectivity(*crackFaces, crack_faces_verts,
982 Range crack_faces_edges;
983 CHKERR mField.get_moab().get_adjacencies(
984 *crackFaces, 1,
true, crack_faces_edges, moab::Interface::UNION);
985 Range crack_faces_tets;
986 CHKERR mField.get_moab().get_adjacencies(
987 *crackFaces, 3,
true, crack_faces_tets, moab::Interface::UNION);
990 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_verts,
true);
992 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2,
true, front_faces,
993 moab::Interface::UNION);
994 Range front_verts_edges;
995 CHKERR mField.get_moab().get_adjacencies(
996 front_verts, 1,
true, front_verts_edges, moab::Interface::UNION);
998 auto get_tags_vec = [&](
auto tag_name,
int dim) {
999 std::vector<Tag> tags(1);
1004 auto create_and_clean = [&]() {
1006 auto &moab = mField.get_moab();
1007 auto rval = moab.tag_get_handle(tag_name, tags[0]);
1008 if (rval == MB_SUCCESS) {
1009 moab.tag_delete(tags[0]);
1011 double def_val[] = {0., 0., 0.};
1012 CHKERR moab.tag_get_handle(tag_name, dim, MB_TYPE_DOUBLE, tags[0],
1013 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
1022 auto get_adj_front = [&](
bool subtract_crack) {
1024 CHKERR mField.get_moab().get_adjacencies(*frontEdges,
SPACE_DIM - 1,
true,
1025 adj_front, moab::Interface::UNION);
1027 adj_front = subtract(adj_front, *crackFaces);
1033 auto th_front_position = get_tags_vec(
"FrontPosition", 3);
1034 auto th_max_face_energy = get_tags_vec(
"MaxFaceEnergy", 1);
1036 if (mField.get_comm_rank() == 0) {
1038 auto get_layers_for_sides = [&](
auto &side) {
1039 std::vector<Range> layers;
1043 auto get_adj = [&](
auto &r,
int dim) {
1045 CHKERR mField.get_moab().get_adjacencies(r, dim,
true, adj,
1046 moab::Interface::UNION);
1050 auto get_tets = [&](
auto r) {
return get_adj(r,
SPACE_DIM); };
1053 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_nodes,
1055 Range front_faces = get_adj(front_nodes, 2);
1056 front_faces = subtract(front_faces, *crackFaces);
1057 auto front_tets = get_tets(front_nodes);
1058 auto front_side = intersect(side, front_tets);
1059 layers.push_back(front_side);
1061 auto adj_faces = get_skin(mField, layers.back());
1062 adj_faces = intersect(adj_faces, front_faces);
1063 auto adj_faces_tets = get_tets(adj_faces);
1064 adj_faces_tets = intersect(adj_faces_tets, front_tets);
1065 layers.push_back(unite(layers.back(), adj_faces_tets));
1066 if (layers.back().size() == layers[layers.size() - 2].size()) {
1077 auto layers_top = get_layers_for_sides(sides_pair.first);
1078 auto layers_bottom = get_layers_for_sides(sides_pair.second);
1082 auto get_crack_adj_tets = [&](
auto r) {
1083 Range crack_faces_conn;
1084 CHKERR mField.get_moab().get_connectivity(r, crack_faces_conn);
1085 Range crack_faces_conn_tets;
1086 CHKERR mField.get_moab().get_adjacencies(
1087 crack_faces_conn,
SPACE_DIM,
true, crack_faces_conn_tets,
1088 moab::Interface::UNION);
1089 return crack_faces_conn_tets;
1094 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
".vtk",
1095 get_crack_adj_tets(*crackFaces));
1099 MOFEM_LOG(
"EP", sev) <<
"Nb. layers " << layers_top.size();
1101 for (
auto &r : layers_top) {
1102 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " << r.size();
1105 "layers_top_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
1110 for (
auto &r : layers_bottom) {
1111 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " << r.size();
1114 "layers_bottom_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
1120 auto get_cross = [&](
auto t_dir,
auto f) {
1122 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
1132 auto get_sense = [&](
auto f,
auto e) {
1133 int side, sense, offset;
1134 CHK_MOAB_THROW(mField.get_moab().side_number(f, e, side, sense, offset),
1136 return std::make_tuple(side, sense, offset);
1139 auto calculate_edge_direction = [&](
auto e,
auto normalize =
true) {
1140 const EntityHandle *conn;
1142 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes,
true);
1143 std::array<double, 6> coords;
1144 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
1146 &coords[0], &coords[1], &coords[2]};
1148 &coords[3], &coords[4], &coords[5]};
1151 t_dir(
i) = t_p1(
i) - t_p0(
i);
1157 auto evaluate_face_energy_and_set_orientation = [&](
auto front_edges,
1164 Tag th_material_force;
1165 switch (energyReleaseSelector) {
1168 CHKERR mField.get_moab().tag_get_handle(
"GriffithForce",
1172 CHKERR mField.get_moab().tag_get_handle(
"MaterialForce",
1177 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
1178 "Unknown energy release selector");
1186 auto find_maximal_face_energy = [&](
auto front_edges,
auto front_faces,
1187 auto &edge_face_max_energy_map) {
1191 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
1192 auto body_skin = get_skin(mField, body_ents);
1196 for (
auto e : front_edges) {
1198 double griffith_force;
1199 CHKERR mField.get_moab().tag_get_data(th_face_energy, &e, 1,
1203 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2,
false, faces);
1204 faces = subtract(intersect(faces, front_faces), body_skin);
1205 std::vector<double> face_energy(faces.size());
1206 CHKERR mField.get_moab().tag_get_data(th_face_energy, faces,
1207 face_energy.data());
1208 auto max_energy_it =
1209 std::max_element(face_energy.begin(), face_energy.end());
1211 max_energy_it != face_energy.end() ? *max_energy_it : 0;
1213 edge_face_max_energy_map[e] =
1214 std::make_tuple(faces[max_energy_it - face_energy.begin()],
1215 griffith_force,
static_cast<double>(0));
1217 <<
"Edge " << e <<
" griffith force " << griffith_force
1218 <<
" max face energy " << max_energy <<
" factor "
1219 << max_energy / griffith_force;
1221 max_faces.insert(faces[max_energy_it - face_energy.begin()]);
1229 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
1243 auto calculate_face_orientation = [&](
auto &edge_face_max_energy_map) {
1246 auto up_down_face = [&](
1248 auto &face_angle_map_up,
1249 auto &face_angle_map_down
1254 for (
auto &
m : edge_face_max_energy_map) {
1256 auto [max_face, energy, opt_angle] =
m.second;
1259 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2,
false, faces);
1260 faces = intersect(faces, front_faces);
1264 moab::Interface::UNION);
1265 if (adj_tets.size()) {
1270 moab::Interface::UNION);
1271 if (adj_tets.size()) {
1273 Range adj_tets_faces;
1275 CHKERR mField.get_moab().get_adjacencies(
1276 adj_tets,
SPACE_DIM - 1,
false, adj_tets_faces,
1277 moab::Interface::UNION);
1278 adj_tets_faces = intersect(adj_tets_faces, faces);
1283 get_cross(calculate_edge_direction(e,
true), max_face);
1284 auto [side_max, sense_max, offset_max] = get_sense(max_face, e);
1285 t_cross_max(
i) *= sense_max;
1287 for (
auto t : adj_tets) {
1288 Range adj_tets_faces;
1289 CHKERR mField.get_moab().get_adjacencies(
1290 &
t, 1,
SPACE_DIM - 1,
false, adj_tets_faces);
1291 adj_tets_faces = intersect(adj_tets_faces, faces);
1293 subtract(adj_tets_faces,
Range(max_face, max_face));
1295 if (adj_tets_faces.size() == 1) {
1299 auto t_cross = get_cross(calculate_edge_direction(e,
true),
1301 auto [side, sense, offset] =
1302 get_sense(adj_tets_faces[0], e);
1303 t_cross(
i) *= sense;
1304 double dot = t_cross(
i) * t_cross_max(
i);
1305 auto angle = std::acos(dot);
1308 CHKERR mField.get_moab().tag_get_data(
1309 th_face_energy, adj_tets_faces, &face_energy);
1311 auto [side_face, sense_face, offset_face] =
1312 get_sense(
t, max_face);
1314 if (sense_face > 0) {
1315 face_angle_map_up[e] = std::make_tuple(face_energy, angle,
1319 face_angle_map_down[e] = std::make_tuple(
1320 face_energy, -angle, adj_tets_faces[0]);
1331 auto calc_optimal_angle = [&](
1333 auto &face_angle_map_up,
1334 auto &face_angle_map_down
1339 for (
auto &
m : edge_face_max_energy_map) {
1341 auto &[max_face, e0,
a0] =
m.second;
1343 if (std::abs(e0) > std::numeric_limits<double>::epsilon()) {
1345 if (face_angle_map_up.find(e) == face_angle_map_up.end() ||
1346 face_angle_map_down.find(e) == face_angle_map_down.end()) {
1350 switch (energyReleaseSelector) {
1354 Tag th_material_force;
1355 CHKERR mField.get_moab().tag_get_handle(
"MaterialForce",
1358 CHKERR mField.get_moab().tag_get_data(
1359 th_material_force, &e, 1, &t_material_force(0));
1360 auto material_force_magnitude = t_material_force.
l2();
1361 if (material_force_magnitude <
1362 std::numeric_limits<double>::epsilon()) {
1367 auto t_edge_dir = calculate_edge_direction(e,
true);
1368 auto t_cross_max = get_cross(t_edge_dir, max_face);
1369 auto [side, sense, offset] = get_sense(max_face, e);
1370 t_cross_max(sense) *= sense;
1377 t_cross_max.normalize();
1380 t_material_force(
J) * t_cross_max(K);
1381 a0 = -std::asin(t_cross(
I) * t_edge_dir(
I));
1384 <<
"Optimal angle " <<
a0 <<
" energy " << e0;
1390 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
1391 "Unknown energy release selector");
1401 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
1403 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
1404 face_angle_map_down;
1405 CHKERR up_down_face(face_angle_map_up, face_angle_map_down);
1406 CHKERR calc_optimal_angle(face_angle_map_up, face_angle_map_down);
1410 auto th_angle = get_tags_vec(
"Angle", 1);
1412 for (
auto &
m : face_angle_map_up) {
1413 auto [e,
a, face] =
m.second;
1415 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &
a);
1418 for (
auto &
m : face_angle_map_down) {
1419 auto [e,
a, face] =
m.second;
1421 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &
a);
1424 Range max_energy_faces;
1425 for (
auto &
m : edge_face_max_energy_map) {
1426 auto [face, e, angle] =
m.second;
1427 max_energy_faces.insert(face);
1428 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1,
1431 if (mField.get_comm_rank() == 0) {
1443 auto get_conn = [&](
auto e) {
1445 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn,
true),
1450 auto get_adj = [&](
auto e,
auto dim) {
1453 e, dim,
false, adj, moab::Interface::UNION),
1458 auto get_coords = [&](
auto v) {
1466 auto get_rotated_normal = [&](
auto e,
auto f,
auto angle) {
1469 auto t_edge_dir = calculate_edge_direction(e,
true);
1470 auto [side, sense, offset] = get_sense(f, e);
1471 t_edge_dir(
i) *= sense;
1472 t_edge_dir.normalize();
1473 t_edge_dir(
i) *= angle;
1476 mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
1478 t_rotated_normal(
i) = t_R(
i,
j) * t_normal(
j);
1479 return std::make_tuple(t_normal, t_rotated_normal);
1482 auto set_coord = [&](
auto v,
auto &adj_vertex_tets_verts,
auto &coords,
1483 auto &t_move,
auto gamma) {
1484 auto index = adj_vertex_tets_verts.index(
v);
1486 for (
auto ii : {0, 1, 2}) {
1487 coords[3 * index + ii] += gamma * t_move(ii);
1494 auto tets_quality = [&](
auto quality,
auto &adj_vertex_tets_verts,
1495 auto &adj_vertex_tets,
auto &coords) {
1496 for (
auto t : adj_vertex_tets) {
1497 const EntityHandle *conn;
1499 CHKERR mField.get_moab().get_connectivity(
t, conn, num_nodes,
true);
1500 std::array<double, 12> tet_coords;
1501 for (
auto n = 0;
n != 4; ++
n) {
1502 auto index = adj_vertex_tets_verts.index(conn[
n]);
1506 for (
auto ii = 0; ii != 3; ++ii) {
1507 tet_coords[3 *
n + ii] = coords[3 * index + ii];
1510 double q = Tools::volumeLengthQuality(tet_coords.data());
1511 if (!std::isnormal(
q))
1513 quality = std::min(quality,
q);
1519 auto calculate_free_face_node_displacement =
1520 [&](
auto &edge_face_max_energy_map) {
1522 auto get_vertex_edges = [&](
auto vertex) {
1527 CHKERR mField.get_moab().get_adjacencies(vertex, 1,
false,
1529 vertex_edges = subtract(vertex_edges, front_verts_edges);
1531 if (boundary_skin_verts.size() &&
1532 boundary_skin_verts.find(vertex[0]) !=
1533 boundary_skin_verts.end()) {
1534 MOFEM_LOG(
"EP", sev) <<
"Boundary vertex";
1535 vertex_edges = intersect(vertex_edges, body_skin_edges);
1537 if (geometry_edges_verts.size() &&
1538 geometry_edges_verts.find(vertex[0]) !=
1539 geometry_edges_verts.end()) {
1540 MOFEM_LOG(
"EP", sev) <<
"Geometry edge vertex";
1541 vertex_edges = intersect(vertex_edges, geometry_edges);
1543 if (crack_faces_verts.size() &&
1544 crack_faces_verts.find(vertex[0]) !=
1545 crack_faces_verts.end()) {
1546 MOFEM_LOG(
"EP", sev) <<
"Crack face vertex";
1547 vertex_edges = intersect(vertex_edges, crack_faces_edges);
1554 return vertex_edges;
1559 using Bundle = std::vector<
1561 std::tuple<EntityHandle, EntityHandle, EntityHandle,
1565 std::map<EntityHandle, Bundle> edge_bundle_map;
1567 for (
auto &
m : edge_face_max_energy_map) {
1569 auto edge =
m.first;
1570 auto &[max_face, energy, opt_angle] =
m.second;
1573 auto [t_normal, t_rotated_normal] =
1574 get_rotated_normal(edge, max_face, opt_angle);
1576 auto front_vertex = get_conn(
Range(
m.first,
m.first));
1577 auto adj_tets = get_adj(
Range(max_face, max_face), 3);
1578 auto adj_tets_faces = get_adj(adj_tets, 2);
1579 auto adj_front_faces = subtract(
1580 intersect(get_adj(
Range(edge, edge), 2), adj_tets_faces),
1582 if (adj_front_faces.size() > 3)
1584 "adj_front_faces.size()>3");
1587 CHKERR mField.get_moab().tag_get_data(th_material_force, &edge, 1,
1588 &t_material_force(0));
1589 std::vector<double> griffith_energy(adj_front_faces.size());
1590 CHKERR mField.get_moab().tag_get_data(
1591 th_face_energy, adj_front_faces, griffith_energy.data());
1593 auto set_edge_bundle = [&](
auto min_gamma) {
1594 for (
auto rotated_f : adj_front_faces) {
1596 double rotated_face_energy =
1597 griffith_energy[adj_front_faces.index(rotated_f)];
1599 auto vertex = subtract(get_conn(
Range(rotated_f, rotated_f)),
1601 if (vertex.size() != 1) {
1603 "Wrong number of vertex to move");
1605 auto front_vertex_edges_vertex = get_conn(
1606 intersect(get_adj(front_vertex, 1), crack_faces_edges));
1608 vertex, front_vertex_edges_vertex);
1609 if (vertex.empty()) {
1613 auto face_cardinality = [&](
auto f,
auto &seen_front_edges) {
1616 subtract(body_skin_edges, crack_faces_edges));
1617 auto faces =
Range(f, f);
1619 for (;
c < 10; ++
c) {
1621 subtract(get_adj(faces, 1), seen_front_edges);
1622 if (front_edges.size() == 0) {
1625 auto front_connected_edges =
1626 intersect(front_edges, whole_front);
1627 if (front_connected_edges.size()) {
1628 seen_front_edges.merge(front_connected_edges);
1631 faces.merge(get_adj(front_edges, 2));
1638 double rotated_face_cardinality = face_cardinality(
1644 rotated_face_cardinality = std::max(rotated_face_cardinality,
1647 auto t_vertex_coords = get_coords(vertex);
1648 auto vertex_edges = get_vertex_edges(vertex);
1650 EntityHandle f0 = front_vertex[0];
1651 EntityHandle f1 = front_vertex[1];
1653 CHKERR mField.get_moab().get_coords(&f0, 1, &t_v_e0(0));
1654 CHKERR mField.get_moab().get_coords(&f1, 1, &t_v_e1(0));
1657 for (
auto e_used_to_move_detection : vertex_edges) {
1658 auto edge_conn = get_conn(
Range(e_used_to_move_detection,
1659 e_used_to_move_detection));
1660 edge_conn = subtract(edge_conn, vertex);
1670 t_v0(
i) = (t_v_e0(
i) + t_v_e1(
i)) / 2;
1672 CHKERR mField.get_moab().get_coords(edge_conn, &t_v3(0));
1674 (t_v0(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
1676 (t_v3(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
1679 constexpr double eps =
1680 std::numeric_limits<double>::epsilon();
1681 if (std::isnormal(gamma) && gamma < 1.0 -
eps &&
1684 t_move(
i) = gamma * (t_v3(
i) - t_vertex_coords(
i));
1686 auto check_rotated_face_directoon = [&]() {
1688 t_delta(
i) = t_vertex_coords(
i) + t_move(
i) - t_v0(
i);
1691 (t_material_force(
i) / t_material_force.
l2()) *
1693 return -dot > 0 ? true :
false;
1696 if (check_rotated_face_directoon()) {
1699 <<
"Crack edge " << edge <<
" moved face "
1701 <<
" edge: " << e_used_to_move_detection
1702 <<
" face direction/energy " << rotated_face_energy
1703 <<
" face cardinality " << rotated_face_cardinality
1704 <<
" gamma: " << gamma;
1706 auto &bundle = edge_bundle_map[edge];
1707 bundle.emplace_back(rotated_f, e_used_to_move_detection,
1708 vertex[0], t_move, 1,
1709 rotated_face_cardinality, gamma);
1716 set_edge_bundle(std::numeric_limits<double>::epsilon());
1717 if (edge_bundle_map[edge].empty()) {
1718 set_edge_bundle(-1.);
1722 return edge_bundle_map;
1725 auto get_sort_by_energy = [&](
auto &edge_face_max_energy_map) {
1726 std::map<double, std::tuple<EntityHandle, EntityHandle, double>>
1729 for (
auto &
m : edge_face_max_energy_map) {
1731 auto &[max_face, energy, opt_angle] =
m.second;
1732 auto abs_energy = std::abs(energy);
1733 sort_by_energy[abs_energy] = std::make_tuple(e, max_face, opt_angle);
1736 return sort_by_energy;
1739 auto set_tag = [&](
auto &&adj_edges_map,
auto &&sort_by_energy) {
1742 Tag th_face_pressure;
1744 mField.get_moab().tag_get_handle(
"FacePressure", th_face_pressure),
1746 auto get_face_pressure = [&](
auto face) {
1748 CHK_MOAB_THROW(mField.get_moab().tag_get_data(th_face_pressure, &face,
1755 <<
"Number of edges to check " << sort_by_energy.size();
1757 enum face_energy { POSITIVE, NEGATIVE };
1758 constexpr bool skip_negative =
true;
1760 for (
auto fe : {face_energy::POSITIVE, face_energy::NEGATIVE}) {
1762 std::vector<double> energies;
1763 double max_pressure = -1;
1766 for (
auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
1768 auto energy = it->first;
1769 auto [max_edge, max_face, opt_angle] = it->second;
1771 auto face_pressure = get_face_pressure(max_face);
1773 <<
"Faces to check: " << max_face <<
" energy " << energy
1774 <<
" face pressure " << face_pressure;
1776 const bool pressure_check =
1777 propagateUnderCompression || face_pressure > crackingAtol;
1778 if (energy > 0 && pressure_check) {
1779 energies.push_back(energy);
1781 max_pressure = std::max(max_pressure, face_pressure);
1784 double average_energy = 0;
1785 if (!energies.empty()) {
1787 std::accumulate(energies.begin(), energies.end(), 0.) /
1792 <<
"Average energy Griffiths energy of crack front "
1795 bool positive_pressure_face_found =
false;
1799 for (
auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
1802 auto energy = it->first;
1803 auto [max_edge, max_face, opt_angle] = it->second;
1805 auto face_pressure = get_face_pressure(max_face);
1806 if (skip_negative) {
1807 if (fe == face_energy::POSITIVE) {
1809 -(crackingAtol + crackingRtol * std::abs(max_pressure))) {
1811 <<
"Skip negative face " << max_face <<
" with energy "
1812 << energy <<
" and pressure " << face_pressure;
1818 if (fe == face_energy::POSITIVE)
1819 positive_pressure_face_found =
true;
1822 <<
"Check face " << max_face <<
" edge " << max_edge
1823 <<
" energy " << energy <<
" optimal angle " << opt_angle
1824 <<
" face pressure " << face_pressure;
1827 if (!average_energy) {
1829 <<
"Average energy is zero, setting max Griffiths energy to "
1832 average_energy = energy;
1834 avgGriffithsEnergy = average_energy;
1835 auto jt = adj_edges_map.find(max_edge);
1836 if (jt == adj_edges_map.end()) {
1838 <<
"Edge " << max_edge <<
" not found in adj_edges_map";
1841 auto &bundle = jt->second;
1843 auto find_max_in_bundle_impl = [&](
auto edge,
auto &bundle,
1847 EntityHandle vertex_max = 0;
1848 EntityHandle face_max = 0;
1849 EntityHandle move_edge_max = 0;
1850 double max_quality = -2;
1851 double max_quality_evaluated = -2;
1852 double min_cardinality = std::numeric_limits<double>::max();
1856 for (
auto &b : bundle) {
1857 auto &[face, move_edge, vertex, t_move, quality, cardinality,
1860 auto adj_vertex_tets = get_adj(
Range(vertex, vertex), 3);
1861 auto adj_vertex_tets_verts = get_conn(adj_vertex_tets);
1862 std::vector<double> coords(3 * adj_vertex_tets_verts.size());
1864 adj_vertex_tets_verts, coords.data()),
1867 set_coord(vertex, adj_vertex_tets_verts, coords, t_move, gamma);
1868 quality = tets_quality(quality, adj_vertex_tets_verts,
1869 adj_vertex_tets, coords);
1871 auto eval_quality = [](
auto q,
auto c,
auto edge_gamma) {
1875 return ((edge_gamma < 0) ? (
q / 2) :
q) / pow(
c, 2);
1879 if (eval_quality(quality, cardinality, edge_gamma) >=
1880 max_quality_evaluated) {
1881 max_quality = quality;
1882 min_cardinality = cardinality;
1883 vertex_max = vertex;
1885 move_edge_max = move_edge;
1886 t_move_last(
i) = t_move(
i);
1887 max_quality_evaluated =
1888 eval_quality(max_quality, min_cardinality, edge_gamma);
1892 return std::make_tuple(vertex_max, face_max, t_move_last,
1893 max_quality, min_cardinality);
1896 auto find_max_in_bundle = [&](
auto edge,
auto &bundle) {
1897 auto b_org_bundle = bundle;
1898 auto r = find_max_in_bundle_impl(edge, bundle, 1.);
1899 auto &[vertex_max, face_max, t_move_last, max_quality,
1901 if (max_quality < 0) {
1902 for (
double gamma = 0.95; gamma >= 0.45; gamma -= 0.05) {
1903 bundle = b_org_bundle;
1904 r = find_max_in_bundle_impl(edge, bundle, gamma);
1905 auto &[vertex_max, face_max, t_move_last, max_quality,
1908 <<
"Back tracking: gamma " << gamma <<
" edge " << edge
1909 <<
" quality " << max_quality <<
" cardinality "
1911 if (max_quality > 0.01) {
1913 t_move_last(
I) *= gamma;
1924 auto set_tag_to_vertex_and_face = [&](
auto &&r,
auto &quality) {
1926 auto &[
v, f, t_move,
q, cardinality] = r;
1928 if ((
q > 0 && std::isnormal(
q)) && energy > 0) {
1931 <<
"Set tag: vertex " <<
v <<
" face " << f <<
" "
1932 << max_edge <<
" move " << t_move <<
" energy " << energy
1933 <<
" quality " <<
q <<
" cardinality " << cardinality;
1934 CHKERR mField.get_moab().tag_set_data(th_position[0], &
v, 1,
1936 CHKERR mField.get_moab().tag_set_data(th_max_face_energy[0], &f,
1944 double quality = -2;
1945 CHKERR set_tag_to_vertex_and_face(
1947 find_max_in_bundle(max_edge, bundle),
1953 if (quality > 0 && std::isnormal(quality) && energy > 0) {
1955 <<
"Crack face set with quality: " << quality;
1960 if (fe == face_energy::POSITIVE && !positive_pressure_face_found) {
1961 if (!propagateUnderCompression) {
1962 potentialCrackArrest =
true;
1964 <<
"POTENTIAL ARREST: No suitable face found with positive "
1965 "face pressure to propagate crack";
1968 <<
"POTENTIAL ARREST: No suitable face found with positive "
1969 "face pressure to propagate crack; continuing because "
1970 "propagation under compression is enabled";
1982 MOFEM_LOG(
"EP", sev) <<
"Calculate orientation";
1983 std::map<EntityHandle, std::tuple<EntityHandle, double, double>>
1984 edge_face_max_energy_map;
1985 CHKERR find_maximal_face_energy(front_edges, front_faces,
1986 edge_face_max_energy_map);
1987 CHKERR calculate_face_orientation(edge_face_max_energy_map);
1989 MOFEM_LOG(
"EP", sev) <<
"Calculate node positions";
1992 calculate_free_face_node_displacement(edge_face_max_energy_map),
1993 get_sort_by_energy(edge_face_max_energy_map)
2000 auto get_max_griffith_force = [&](
auto r) {
2001 auto &moab = mField.get_moab();
2002 std::vector<double> gc(r.size());
2004 CHKERR moab.tag_get_handle(
"GriffithForce", th_gc);
2005 CHKERR moab.tag_get_data(th_gc, r, gc.data());
2006 double max_griffith_force = 0;
2007 for (
size_t i = 0;
i < r.size(); ++
i) {
2008 max_griffith_force = std::max(max_griffith_force, std::abs(gc[
i]));
2010 return max_griffith_force;
2013 MOFEM_LOG(
"EP", sev) <<
"Front edges " << frontEdges->size();
2014 if (std::abs(get_max_griffith_force(get_adj_front(
true))) >
2015 std::numeric_limits<double>::epsilon()) {
2016 CHKERR evaluate_face_energy_and_set_orientation(
2017 *frontEdges, get_adj_front(
true), sides_pair, th_front_position);
2019 auto adj_front = get_adj_front(
true);
2020 double zero[] = {0., 0., 0.};
2021 CHKERR mField.get_moab().tag_clear_data(th_front_position[0], adj_front,
2027 CHKERR VecZeroEntries(vertexExchange.second);
2028 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
2030 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
2032 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
2033 mField.get_moab(), vertexExchange, th_front_position[0]);
2034 CHKERR VecZeroEntries(faceExchange.second);
2035 CHKERR VecGhostUpdateBegin(faceExchange.second, INSERT_VALUES,
2037 CHKERR VecGhostUpdateEnd(faceExchange.second, INSERT_VALUES, SCATTER_FORWARD);
2038 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
2039 mField.get_moab(), faceExchange, th_max_face_energy[0]);
2041 auto get_max_moved_faces = [&]() {
2042 Range max_moved_faces;
2043 auto adj_front = get_adj_front(
false);
2044 std::vector<double> face_energy(adj_front.size());
2045 CHKERR mField.get_moab().tag_get_data(th_max_face_energy[0], adj_front,
2046 face_energy.data());
2047 for (
int i = 0;
i != adj_front.size(); ++
i) {
2048 if (face_energy[
i] > std::numeric_limits<double>::epsilon()) {
2049 max_moved_faces.insert(adj_front[
i]);
2053 return boost::make_shared<Range>(max_moved_faces);
2057 maxMovedFaces = get_max_moved_faces();
2058 MOFEM_LOG(
"EP", sev) <<
"Number of of moved faces: " << maxMovedFaces->size();
2064 "max_moved_faces_" +
2065 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
".vtk",
2115 constexpr bool potential_crack_debug =
false;
2116 if constexpr (potential_crack_debug) {
2119 Range crack_front_verts;
2120 CHKERR mField.get_moab().get_connectivity(*frontEdges, crack_front_verts,
2122 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2124 Range crack_front_faces;
2125 CHKERR mField.get_moab().get_adjacencies(crack_front_verts,
SPACE_DIM - 1,
2126 true, crack_front_faces,
2127 moab::Interface::UNION);
2128 crack_front_faces = intersect(crack_front_faces, add_ents);
2129 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2131 CHKERR mField.getInterface<MeshsetsManager>()->addEntitiesToMeshset(
2132 BLOCKSET, addCrackMeshsetId, crack_front_faces);
2135 auto get_crack_faces = [&]() {
2136 if (maxMovedFaces) {
2137 return unite(*crackFaces, *maxMovedFaces);
2143 auto get_extended_crack_faces = [&]() {
2144 auto get_faces_of_crack_front_verts = [&](
auto crack_faces_org) {
2145 ParallelComm *pcomm =
2150 if (!pcomm->rank()) {
2152 auto get_nodes = [&](
auto &&e) {
2154 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes,
true),
2155 "get connectivity");
2159 auto get_adj = [&](
auto &&e,
auto dim,
2160 auto t = moab::Interface::UNION) {
2163 mField.get_moab().get_adjacencies(e, dim,
true, adj,
t),
2171 auto body_skin = get_skin(mField, body_ents);
2172 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
2175 auto front_block_nodes = get_nodes(front_block_edges);
2179 s = crack_faces.size();
2181 auto crack_face_nodes = get_nodes(crack_faces_org);
2182 auto crack_faces_edges =
2183 get_adj(crack_faces_org, 1, moab::Interface::UNION);
2185 auto crack_skin = get_skin(mField, crack_faces_org);
2186 front_block_edges = subtract(front_block_edges, crack_skin);
2187 auto crack_skin_nodes = get_nodes(crack_skin);
2188 crack_skin_nodes.merge(front_block_nodes);
2190 auto crack_skin_faces =
2191 get_adj(crack_skin, 2, moab::Interface::UNION);
2193 subtract(subtract(crack_skin_faces, crack_faces_org), body_skin);
2195 crack_faces = crack_faces_org;
2196 for (
auto f : crack_skin_faces) {
2197 auto edges = intersect(
2198 get_adj(
Range(f, f), 1, moab::Interface::UNION), crack_skin);
2202 if (edges.size() == 2) {
2204 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
2208 if (edges.size() == 2) {
2209 auto edge_conn = get_nodes(
Range(edges));
2210 auto faces = intersect(get_adj(edges, 2, moab::Interface::UNION),
2212 if (faces.size() == 2) {
2213 auto edge0_conn = get_nodes(
Range(edges[0], edges[0]));
2214 auto edge1_conn = get_nodes(
Range(edges[1], edges[1]));
2215 auto edges_conn = intersect(intersect(edge0_conn, edge1_conn),
2217 if (edges_conn.size() == 1) {
2220 subtract(intersect(get_adj(edges_conn, 1,
2221 moab::Interface::INTERSECT),
2226 if (node_edges.size()) {
2229 CHKERR mField.get_moab().get_coords(edges_conn, &t_v0(0));
2231 auto get_t_dir = [&](
auto e_conn) {
2232 auto other_node = subtract(e_conn, edges_conn);
2234 CHKERR mField.get_moab().get_coords(other_node,
2236 t_dir(
i) -= t_v0(
i);
2242 get_t_dir(edge0_conn)(
i) + get_t_dir(edge1_conn)(
i);
2245 t_crack_surface_ave_dir(
i) = 0;
2246 for (
auto e : node_edges) {
2247 auto e_conn = get_nodes(
Range(e, e));
2248 auto t_dir = get_t_dir(e_conn);
2249 t_crack_surface_ave_dir(
i) += t_dir(
i);
2252 auto dot = t_ave_dir(
i) * t_crack_surface_ave_dir(
i);
2255 if (dot < -std::numeric_limits<double>::epsilon()) {
2256 crack_faces.insert(f);
2259 crack_faces.insert(f);
2263 }
else if (edges.size() == 3) {
2264 crack_faces.insert(f);
2268 if (edges.size() == 1) {
2270 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
2273 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
2274 front_block_edges));
2275 if (edges.size() == 2) {
2276 crack_faces.insert(f);
2282 crack_faces_org = crack_faces;
2284 }
while (s != crack_faces.size());
2290 return get_faces_of_crack_front_verts(get_crack_faces());
2295 get_extended_crack_faces());
2298 auto reconstruct_crack_faces = [&](
auto crack_faces) {
2299 ParallelComm *pcomm =
2305 Range new_crack_faces;
2306 if (!pcomm->rank()) {
2308 auto get_nodes = [&](
auto &&e) {
2310 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes,
true),
2311 "get connectivity");
2315 auto get_adj = [&](
auto &&e,
auto dim,
2316 auto t = moab::Interface::UNION) {
2319 mField.get_moab().get_adjacencies(e, dim,
true, adj,
t),
2324 auto get_test_on_crack_surface = [&]() {
2325 auto crack_faces_nodes =
2326 get_nodes(crack_faces);
2327 auto crack_faces_tets =
2328 get_adj(crack_faces_nodes, 3,
2329 moab::Interface::UNION);
2333 auto crack_faces_tets_nodes =
2334 get_nodes(crack_faces_tets);
2335 crack_faces_tets_nodes =
2336 subtract(crack_faces_tets_nodes, crack_faces_nodes);
2338 subtract(crack_faces_tets, get_adj(crack_faces_tets_nodes, 3,
2339 moab::Interface::UNION));
2341 get_adj(crack_faces_tets, 2,
2342 moab::Interface::UNION);
2344 new_crack_faces.merge(crack_faces);
2346 return std::make_tuple(new_crack_faces, crack_faces_tets);
2349 auto carck_faces_test_edges = [&](
auto faces,
auto tets) {
2350 auto adj_tets_faces = get_adj(tets, 2, moab::Interface::UNION);
2351 auto adj_faces_edges = get_adj(subtract(faces, adj_tets_faces), 1,
2352 moab::Interface::UNION);
2353 auto adj_tets_edges = get_adj(tets, 1, moab::Interface::UNION);
2356 adj_faces_edges.merge(geometry_edges);
2357 adj_faces_edges.merge(front_block_edges);
2359 auto boundary_tets_edges = intersect(adj_tets_edges, adj_faces_edges);
2360 auto boundary_test_nodes = get_nodes(boundary_tets_edges);
2361 auto boundary_test_nodes_edges =
2362 get_adj(boundary_test_nodes, 1, moab::Interface::UNION);
2363 auto boundary_test_nodes_edges_nodes = subtract(
2364 get_nodes(boundary_test_nodes_edges), boundary_test_nodes);
2366 boundary_tets_edges =
2367 subtract(boundary_test_nodes_edges,
2368 get_adj(boundary_test_nodes_edges_nodes, 1,
2369 moab::Interface::UNION));
2374 auto body_skin = get_skin(mField, body_ents);
2376 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
2377 body_skin_edges = intersect(get_adj(tets, 1, moab::Interface::UNION),
2379 body_skin = intersect(body_skin, adj_tets_faces);
2380 body_skin_edges = subtract(
2381 body_skin_edges, get_adj(body_skin, 1, moab::Interface::UNION));
2383 save_range(mField.get_moab(),
"body_skin_edges.vtk", body_skin_edges);
2384 for (
auto e : body_skin_edges) {
2385 auto adj_tet = intersect(
2386 get_adj(
Range(e, e), 3, moab::Interface::INTERSECT), tets);
2387 if (adj_tet.size() == 1) {
2388 boundary_tets_edges.insert(e);
2392 return boundary_tets_edges;
2395 auto p = get_test_on_crack_surface();
2396 auto &[new_crack_faces, crack_faces_tets] = p;
2407 auto boundary_tets_edges =
2408 carck_faces_test_edges(new_crack_faces, crack_faces_tets);
2410 boundary_tets_edges);
2412 auto resolve_surface = [&](
auto boundary_tets_edges,
2413 auto crack_faces_tets) {
2414 auto boundary_tets_edges_nodes = get_nodes(boundary_tets_edges);
2415 auto crack_faces_tets_faces =
2416 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
2418 Range all_removed_faces;
2419 Range all_removed_tets;
2423 while (size != crack_faces_tets.size()) {
2425 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
2426 auto skin_tets = get_skin(mField, crack_faces_tets);
2428 get_skin(mField, subtract(crack_faces_tets_faces, tets_faces));
2429 auto skin_skin_nodes = get_nodes(skin_skin);
2431 size = crack_faces_tets.size();
2433 <<
"Crack faces tets size " << crack_faces_tets.size()
2434 <<
" crack faces size " << crack_faces_tets_faces.size();
2435 auto skin_tets_nodes = subtract(
2436 get_nodes(skin_tets),
2437 boundary_tets_edges_nodes);
2439 skin_tets_nodes = subtract(skin_tets_nodes, skin_skin_nodes);
2441 Range removed_nodes;
2442 Range tets_to_remove;
2443 Range faces_to_remove;
2444 for (
auto n : skin_tets_nodes) {
2446 intersect(get_adj(
Range(
n,
n), 3, moab::Interface::INTERSECT),
2448 if (tets.size() == 0) {
2452 auto hole_detetction = [&]() {
2454 get_adj(
Range(
n,
n), 3, moab::Interface::INTERSECT);
2459 if (adj_tets.size() == 0) {
2460 return std::make_pair(
2462 get_adj(
Range(
n,
n), 2, moab::Interface::INTERSECT),
2467 std::vector<Range> tets_groups;
2468 auto test_adj_tets = adj_tets;
2469 while (test_adj_tets.size()) {
2471 Range seed =
Range(test_adj_tets[0], test_adj_tets[0]);
2472 while (seed.size() != seed_size) {
2474 subtract(get_adj(seed, 2, moab::Interface::UNION),
2477 seed_size = seed.size();
2479 intersect(get_adj(adj_faces, 3, moab::Interface::UNION),
2482 tets_groups.push_back(seed);
2483 test_adj_tets = subtract(test_adj_tets, seed);
2485 if (tets_groups.size() == 1) {
2487 return std::make_pair(
2489 get_adj(
Range(
n,
n), 2, moab::Interface::INTERSECT),
2494 Range tets_to_remove;
2495 Range faces_to_remove;
2496 for (
auto &r : tets_groups) {
2497 auto f = get_adj(r, 2, moab::Interface::UNION);
2498 auto t = intersect(get_adj(f, 3, moab::Interface::UNION),
2501 if (f.size() > faces_to_remove.size() ||
2502 faces_to_remove.size() == 0) {
2503 faces_to_remove = f;
2508 <<
"Hole detection: faces to remove "
2509 << faces_to_remove.size() <<
" tets to remove "
2510 << tets_to_remove.size();
2511 return std::make_pair(faces_to_remove, tets_to_remove);
2514 if (tets.size() < tets_to_remove.size() ||
2515 tets_to_remove.size() == 0) {
2517 auto [h_faces_to_remove, h_tets_to_remove] =
2519 faces_to_remove = h_faces_to_remove;
2520 tets_to_remove = h_tets_to_remove;
2528 all_removed_faces.merge(faces_to_remove);
2529 all_removed_tets.merge(tets_to_remove);
2532 crack_faces_tets = subtract(crack_faces_tets, tets_to_remove);
2533 crack_faces_tets_faces =
2534 subtract(crack_faces_tets_faces, faces_to_remove);
2539 boost::lexical_cast<std::string>(counter) +
".vtk",
2542 "faces_to_remove_" +
2543 boost::lexical_cast<std::string>(counter) +
".vtk",
2547 boost::lexical_cast<std::string>(counter) +
".vtk",
2550 "crack_faces_tets_faces_" +
2551 boost::lexical_cast<std::string>(counter) +
".vtk",
2552 crack_faces_tets_faces);
2554 "crack_faces_tets_" +
2555 boost::lexical_cast<std::string>(counter) +
".vtk",
2561 auto cese_internal_faces = [&]() {
2563 auto skin_tets = get_skin(mField, crack_faces_tets);
2564 auto adj_faces = get_adj(skin_tets, 2, moab::Interface::UNION);
2566 subtract(adj_faces, skin_tets);
2567 auto adj_tets = get_adj(adj_faces, 3,
2568 moab::Interface::UNION);
2571 subtract(crack_faces_tets,
2574 crack_faces_tets_faces =
2575 subtract(crack_faces_tets_faces, adj_faces);
2577 all_removed_faces.merge(adj_faces);
2578 all_removed_tets.merge(adj_tets);
2581 <<
"Remove internal faces size " << adj_faces.size()
2582 <<
" tets size " << adj_tets.size();
2586 auto case_only_one_free_edge = [&]() {
2589 for (
auto t :
Range(crack_faces_tets)) {
2591 auto adj_faces = get_adj(
2593 moab::Interface::UNION);
2594 auto crack_surface_edges =
2595 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
2598 moab::Interface::UNION);
2601 subtract(get_adj(
Range(
t,
t), 1, moab::Interface::INTERSECT),
2602 crack_surface_edges);
2603 adj_edges = subtract(
2605 boundary_tets_edges);
2607 if (adj_edges.size() == 1) {
2609 subtract(crack_faces_tets,
2613 auto faces_to_remove =
2614 get_adj(adj_edges, 2, moab::Interface::UNION);
2617 crack_faces_tets_faces =
2618 subtract(crack_faces_tets_faces, faces_to_remove);
2620 all_removed_faces.merge(faces_to_remove);
2621 all_removed_tets.merge(
Range(
t,
t));
2623 MOFEM_LOG(
"EPSELF", Sev::inform) <<
"Remove free one edges ";
2627 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
2628 crack_faces_tets_faces =
2629 subtract(crack_faces_tets_faces, all_removed_faces);
2634 auto cese_flat_tet = [&](
auto max_adj_edges) {
2640 auto body_skin = get_skin(mField, body_ents);
2641 auto body_skin_edges =
2642 get_adj(body_skin, 1, moab::Interface::UNION);
2644 for (
auto t :
Range(crack_faces_tets)) {
2646 auto adj_faces = get_adj(
2648 moab::Interface::UNION);
2649 auto crack_surface_edges =
2650 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
2653 moab::Interface::UNION);
2656 subtract(get_adj(
Range(
t,
t), 1, moab::Interface::INTERSECT),
2657 crack_surface_edges);
2658 adj_edges = subtract(adj_edges, body_skin_edges);
2660 auto tet_edges = get_adj(
Range(
t,
t), 1,
2661 moab::Interface::UNION);
2663 tet_edges = subtract(tet_edges, adj_edges);
2665 for (
auto e : tet_edges) {
2666 constexpr int opposite_edge[] = {5, 3, 4, 1, 2, 0};
2667 auto get_side = [&](
auto e) {
2668 int side, sense, offset;
2670 mField.get_moab().side_number(
t, e, side, sense, offset),
2671 "get side number failed");
2674 auto get_side_ent = [&](
auto side) {
2675 EntityHandle side_edge;
2677 mField.get_moab().side_element(
t, 1, side, side_edge),
2681 adj_edges.erase(get_side_ent(opposite_edge[get_side(e)]));
2684 if (adj_edges.size() <= max_adj_edges) {
2687 Range faces_to_remove;
2688 for (
auto e : adj_edges) {
2689 auto edge_adj_faces =
2690 get_adj(
Range(e, e), 2, moab::Interface::UNION);
2691 edge_adj_faces = intersect(edge_adj_faces, adj_faces);
2692 if (edge_adj_faces.size() != 2) {
2694 "Adj faces size is not 2 for edge " +
2695 boost::lexical_cast<std::string>(e));
2698 auto get_normal = [&](
auto f) {
2701 mField.getInterface<Tools>()->getTriNormal(f, &t_n(0)),
2702 "get tri normal failed");
2705 auto t_n0 = get_normal(edge_adj_faces[0]);
2706 auto t_n1 = get_normal(edge_adj_faces[1]);
2707 auto get_sense = [&](
auto f) {
2708 int side, sense, offset;
2711 "get side number failed");
2714 auto sense0 = get_sense(edge_adj_faces[0]);
2715 auto sense1 = get_sense(edge_adj_faces[1]);
2720 auto dot_e = (sense0 * sense1) * t_n0(
i) * t_n1(
i);
2721 if (dot_e < dot || e == adj_edges[0]) {
2723 faces_to_remove = edge_adj_faces;
2727 all_removed_faces.merge(faces_to_remove);
2728 all_removed_tets.merge(
Range(
t,
t));
2731 <<
"Remove free edges on flat tet, with considered nb. of "
2733 << adj_edges.size();
2737 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
2738 crack_faces_tets_faces =
2739 subtract(crack_faces_tets_faces, all_removed_faces);
2745 "Case only one free edge failed");
2746 for (
auto max_adj_edges : {0, 1, 2, 3}) {
2748 "Case only one free edge failed");
2751 "Case internal faces failed");
2755 "crack_faces_tets_faces_" +
2756 boost::lexical_cast<std::string>(counter) +
".vtk",
2757 crack_faces_tets_faces);
2759 "crack_faces_tets_" +
2760 boost::lexical_cast<std::string>(counter) +
".vtk",
2764 return std::make_tuple(crack_faces_tets_faces, crack_faces_tets,
2765 all_removed_faces, all_removed_tets);
2768 auto [resolved_faces, resolved_tets, all_removed_faces,
2770 resolve_surface(boundary_tets_edges, crack_faces_tets);
2771 resolved_faces.merge(subtract(crack_faces, all_removed_faces));
2779 crack_faces = resolved_faces;
2790 auto resolve_consisten_crack_extension = [&]() {
2792 auto crack_meshset =
2793 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2795 auto meshset = crack_meshset->getMeshset();
2797 if (!mField.get_comm_rank() && !noCrackExtension) {
2798 Range old_crack_faces;
2799 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
2801 auto extendeded_crack_faces = get_extended_crack_faces();
2802 auto reconstructed_crack_faces =
2803 subtract(reconstruct_crack_faces(extendeded_crack_faces),
2804 subtract(*crackFaces, old_crack_faces));
2805 if (nbCrackFaces >= reconstructed_crack_faces.size()) {
2807 <<
"No new crack faces to add, skipping adding to meshset";
2808 extendeded_crack_faces = subtract(
2809 extendeded_crack_faces, subtract(*crackFaces, old_crack_faces));
2811 <<
"Number crack faces size (extended) "
2812 << extendeded_crack_faces.size();
2813 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2814 CHKERR mField.get_moab().add_entities(meshset, extendeded_crack_faces);
2816 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2817 CHKERR mField.get_moab().add_entities(meshset,
2818 reconstructed_crack_faces);
2820 <<
"Number crack faces size (reconstructed) "
2821 << reconstructed_crack_faces.size();
2822 nbCrackFaces = reconstructed_crack_faces.size();
2827 if (!mField.get_comm_rank()) {
2828 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
2831 crack_faces =
send_type(mField, crack_faces, MBTRI);
2832 if (mField.get_comm_rank()) {
2833 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2834 CHKERR mField.get_moab().add_entities(meshset, crack_faces);
2840 CHKERR resolve_consisten_crack_extension();