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 if (stretchHandling == NO_STREACH ||
105 materialModel == MaterialModel::Hencky) {
110 op_loop_domain_side->getOpPtrVector().push_back(
111 physicalEquations->returnOpCalculateStretchFromStress(
112 dataAtPts, physicalEquations));
119 op_loop_domain_side->getOpPtrVector().push_back(
120 new OpCalculateTensor2SymmetricFieldValues<SPACE_DIM>(
121 stretchTensor, dataAtPts->getLogStretchTensorAtPts(), MBTET));
124 op_loop_domain_side->getOpPtrVector().push_back(
130 auto integrate_face_material_force_fe = [&](
auto &&face_energy_fe) {
132 CHKERR DMoFEMLoopFiniteElementsUpAndLowRank(
133 dM, skeletonElement, face_energy_fe, 0, mField.get_comm_size());
135 auto face_exchange = CommInterface::createEntitiesPetscVector(
136 mField.get_comm(), mField.get_moab(), 2, 3, Sev::inform);
138 auto print_loc_size = [
this](
auto v,
auto str,
auto sev) {
141 CHKERR VecGetLocalSize(
v.second, &size);
143 CHKERR VecGetOwnershipRange(
v.second, &low, &high);
144 MOFEM_LOG(
"EPSYNC", sev) << str <<
" local size " << size <<
" ( "
145 << low <<
" " << high <<
" ) ";
149 CHKERR print_loc_size(face_exchange,
"material face_exchange",
152 CHKERR CommInterface::updateEntitiesPetscVector(
153 mField.get_moab(), face_exchange, tags[ExhangeTags::MATERIALFORCE]);
154 CHKERR CommInterface::updateEntitiesPetscVector(
155 mField.get_moab(), faceExchange, tags[ExhangeTags::FACEPRESSURE]);
160 "front_skin_faces_material_force_" +
161 std::to_string(mField.get_comm_rank()) +
".vtk",
169 CHKERR integrate_face_material_force_fe(get_face_material_force_fe());
174 auto get_conn = [&](
auto e) {
176 CHK_MOAB_THROW(mField.get_moab().get_connectivity(&e, 1, conn,
true),
181 auto get_conn_range = [&](
auto e) {
188 auto get_adj = [&](
auto e,
auto dim) {
190 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(&e, 1, dim,
true, adj),
195 auto get_adj_range = [&](
auto e,
auto dim) {
197 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(e, dim,
true, adj,
198 moab::Interface::UNION),
203 auto get_vector_tag_data = [&](
auto r,
auto th) {
204 MatrixDouble tag_data(r.size(), 3,
false);
206 mField.get_moab().tag_get_data(th, r, tag_data.data().data()),
207 "get vector tag data");
211 auto calculate_edge_direction = [&](
auto e) {
215 mField.get_moab().get_connectivity(e, conn, num_nodes,
true),
217 std::array<double, 6> coords;
218 CHK_MOAB_THROW(mField.get_moab().get_coords(conn, num_nodes, coords.data()),
221 &coords[0], &coords[1], &coords[2]};
223 &coords[3], &coords[4], &coords[5]};
226 t_dir(
i) = t_p1(
i) - t_p0(
i);
230 auto average_vector_tag_at_edge = [&](
auto th) {
235 for (
auto e : *frontEdges) {
236 auto conn = get_conn(e);
237 auto data = get_vector_tag_data(conn, th);
238 auto t_node = getFTensor1FromPtr<SPACE_DIM>(data.data().data());
240 for (
auto n : conn) {
242 t_edge_material_force(
I) += t_node(
I);
245 t_edge_material_force(
I) /= conn.size();
248 calculate_edge_direction(e);
254 t_edge_material_force(
J);
255 t_edge_material_force(K) =
258 CHKERR mField.get_moab().tag_set_data(th, &e, 1,
259 &t_edge_material_force(0));
265 auto average_material_force_at_edge = [&](
auto th) {
268 if (mField.get_comm_rank() == 0) {
269 CHKERR average_vector_tag_at_edge(th);
274 CHKERR TSGetStepNumber(ts, &ts_step);
276 "front_edges_material_force_" +
277 std::to_string(ts_step) +
".vtk",
286 auto calculate_force_through_node = [&](
auto nb_J_integral_contours) {
291 if (mField.get_comm_rank() == 0) {
292 auto front_nodes = get_conn_range(*frontEdges);
293 Range all_skin_faces;
295 for (
auto n : front_nodes) {
297 for (
int ll = 0; ll < nb_J_integral_contours; ++ll) {
298 auto conn = get_conn_range(adj_tets);
299 adj_tets = get_adj_range(conn,
SPACE_DIM);
302 auto skin_faces = get_skin(mField, adj_tets);
303 auto material_forces =
304 get_vector_tag_data(skin_faces, tags[ExhangeTags::MATERIALFORCE]);
308 all_skin_faces.merge(skin_faces);
313 getFTensor1FromPtr<SPACE_DIM>(material_forces.data().data());
315 for (
auto face : skin_faces) {
318 t_face_force_tmp(
I) = t_face_T(
I);
321 auto face_tets = intersect(get_adj(face,
SPACE_DIM), adj_tets);
323 if (face_tets.empty()) {
327 if (face_tets.size() != 1) {
329 "face_tets.size() != 1");
332 int side_number, sense, offset;
337 t_face_force_tmp(
I) *= sense;
338 t_node_force(
I) += t_face_force_tmp(
I);
341 t_node_force(
I) /= griffithEnergy;
343 mField.get_moab().tag_set_data(tags[ExhangeTags::MATERIALFORCE],
344 &
n, 1, &t_node_force(0)),
351 CHKERR TSGetStepNumber(ts, &ts_step);
353 "front_skin_faces_material_force_" +
354 std::to_string(ts_step) +
".vtk",
363 auto get_adj_tets_for_contour = [&](
auto n,
auto nb_J_integral_contours) {
365 for (
int ll = 0; ll < nb_J_integral_contours; ++ll) {
366 auto conn = get_conn_range(adj_tets);
367 adj_tets = get_adj_range(conn,
SPACE_DIM);
372 auto get_front_node_adj_crack_faces = [&](
auto n) {
373 return intersect(get_adj(
n,
SPACE_DIM - 1), *crackFaces);
376 auto calculate_crack_area_growth_face = [&](
auto nb_J_integral_contours) {
381 if (mField.get_comm_rank() == 0) {
382 auto front_nodes = get_conn_range(*frontEdges);
387 auto body_skin = get_skin(mField, body_ents);
388 auto body_skin_conn = get_conn_range(body_skin);
390 auto calculate_seed_area_growth = [&](
auto n,
auto &adj_faces) {
393 auto boundary_node = intersect(
Range(
n,
n), body_skin_conn);
394 if (boundary_node.size()) {
395 auto faces = intersect(get_adj(
n,
SPACE_DIM - 1), body_skin);
396 for (
auto f : faces) {
398 CHKERR mField.getInterface<Tools>()->getTriNormal(
399 f, &t_normal_face(0));
400 t_project(
I) += t_normal_face(
I);
402 t_project.normalize();
409 if (boundary_node.size()) {
410 t_Q(
I,
J) -= t_project(
I) * t_project(
J);
414 for (
auto f : adj_faces) {
417 CHKERR mField.get_moab().get_connectivity(f, conn, num_nodes,
true);
418 std::array<double, 9> coords;
419 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
422 CHKERR mField.getInterface<Tools>()->getTriNormal(
423 coords.data(), &t_face_normal(0), &t_d_normal(0, 0, 0));
424 auto n_it = std::find(conn, conn + num_nodes,
n);
425 auto n_index = std::distance(conn, n_it);
428 t_d_normal(0, n_index, 0), t_d_normal(0, n_index, 1),
429 t_d_normal(0, n_index, 2),
431 t_d_normal(1, n_index, 0), t_d_normal(1, n_index, 1),
432 t_d_normal(1, n_index, 2),
434 t_d_normal(2, n_index, 0), t_d_normal(2, n_index, 1),
435 t_d_normal(2, n_index, 2)};
438 t_projected_hessian(
I,
J) =
439 t_Q(
I, K) * (t_face_hessian(K, L) * t_Q(L,
J));
441 t_area_dir(K) += t_face_normal(
I) * t_projected_hessian(
I, K) / 2.;
447 auto get_crack_area_growth_seed_nodes = [&](
auto &adj_tets) {
452 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
453 unite(*frontEdges, body_edges));
458 auto seed_n = get_conn_range(adj_edges);
459 auto skin_adj_edges = get_skin(mField, adj_edges);
460 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
461 seed_n = subtract(seed_n, skin_adj_edges);
463 return std::make_pair(seed_n, skin_adj_edges);
466 auto calculate_front_node_area_growth = [&](
auto &adj_tets) {
467 auto [seed_n, skin_adj_edges] =
468 get_crack_area_growth_seed_nodes(adj_tets);
471 auto add_area_growth_direction = [&](
auto sn,
double weight) {
472 auto adj_faces = intersect(get_adj(sn,
SPACE_DIM - 1), *crackFaces);
473 if (adj_faces.empty()) {
477 auto t_area_dir_sn = calculate_seed_area_growth(sn, adj_faces);
478 t_area_dir(
I) += weight * t_area_dir_sn(
I);
481 for (
auto sn : seed_n) {
482 add_area_growth_direction(sn, 1.);
484 for (
auto sn : skin_adj_edges) {
485 add_area_growth_direction(sn, 0.5);
491 for (
auto n : front_nodes) {
492 auto front_node_adj_faces = get_front_node_adj_crack_faces(
n);
493 if (front_node_adj_faces.empty()) {
497 auto adj_tets = get_adj_tets_for_contour(
n, nb_J_integral_contours);
498 auto t_area_dir = calculate_front_node_area_growth(adj_tets);
501 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &
n, 1,
510 auto calculate_crack_area_growth_no_face = [&](
auto nb_J_integral_contours,
511 auto material_force_tag) {
516 if (mField.get_comm_rank() == 0) {
517 auto front_nodes = get_conn_range(*frontEdges);
522 auto body_skin = get_skin(mField, body_ents);
523 auto body_skin_conn = get_conn_range(body_skin);
525 auto calculate_seed_area_growth = [&](
auto n,
auto &t_node_force) {
527 intersect(get_adj(
n, 1), unite(*frontEdges, body_edges));
529 for (
auto e : adj_edges) {
530 auto t_dir = calculate_edge_direction(e);
537 t_node_force_tmp(
I) = t_node_force(
I);
539 t_area_dir(
I) = -t_node_force_tmp(
I);
540 t_area_dir(
I) *=
l / 2;
544 auto get_crack_area_growth_seed_nodes = [&](
auto &adj_tets) {
545 auto adj_edges = intersect(get_adj_range(adj_tets, 1),
546 unite(*frontEdges, body_edges));
547 auto seed_n = get_conn_range(adj_edges);
548 auto skin_adj_edges = get_skin(mField, adj_edges);
549 skin_adj_edges = subtract(skin_adj_edges, body_skin_conn);
550 seed_n = subtract(seed_n, skin_adj_edges);
552 return std::make_pair(seed_n, skin_adj_edges);
555 auto calculate_front_node_area_growth = [&](
auto &adj_tets,
556 auto &t_node_force) {
557 auto [seed_n, skin_adj_edges] =
558 get_crack_area_growth_seed_nodes(adj_tets);
561 auto add_area_growth_direction = [&](
auto sn,
double weight) {
562 auto t_area_dir_sn = calculate_seed_area_growth(sn, t_node_force);
563 t_area_dir(
I) += weight * t_area_dir_sn(
I);
566 for (
auto sn : seed_n) {
567 add_area_growth_direction(sn, 1.);
569 for (
auto sn : skin_adj_edges) {
570 add_area_growth_direction(sn, 0.5);
576 for (
auto n : front_nodes) {
577 auto front_node_adj_faces = get_front_node_adj_crack_faces(
n);
578 if (front_node_adj_faces.empty()) {
580 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &
n, 1,
583 auto adj_tets = get_adj_tets_for_contour(
n, nb_J_integral_contours);
585 calculate_front_node_area_growth(adj_tets, t_node_force);
588 mField.get_moab().tag_set_data(tags[ExhangeTags::AREAGROWTH], &
n,
598 auto update_crack_area_growth_edges = [&]() {
601 if (mField.get_comm_rank() == 0) {
602 CHKERR average_vector_tag_at_edge(tags[ExhangeTags::AREAGROWTH]);
605 auto area_growth_edge_exchange = CommInterface::createEntitiesPetscVector(
606 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
607 CHKERR CommInterface::updateEntitiesPetscVector(
608 mField.get_moab(), area_growth_edge_exchange,
609 tags[ExhangeTags::AREAGROWTH]);
614 auto calculate_griffith_force = [&](ExhangeTags material_force_tag,
615 ExhangeTags griffith_force_tag) {
620 if (mField.get_comm_rank() == 0) {
621 auto front_nodes = get_conn_range(*frontEdges);
622 Range all_front_faces;
624 for (
auto n : front_nodes) {
626 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &
n, 1,
629 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH], &
n,
633 -t_node_force(
I) * t_area_dir(
I) / (t_area_dir(K) * t_area_dir(K));
635 tags[griffith_force_tag], &
n, 1, &griffith),
639 for (
auto e : *frontEdges) {
641 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &e, 1,
644 CHKERR mField.get_moab().tag_get_data(tags[ExhangeTags::AREAGROWTH], &e,
645 1, &t_edge_area_dir(0));
646 double griffith_energy =
647 -t_edge_force(
I) * t_edge_area_dir(
I) /
648 (t_edge_area_dir(K) * t_edge_area_dir(K));
649 CHKERR mField.get_moab().tag_set_data(tags[griffith_force_tag], &e, 1,
653 for (
auto e : *frontEdges) {
654 auto adj_faces = get_adj(e,
SPACE_DIM - 1);
657 all_front_faces.merge(adj_faces);
661 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &e, 1,
664 calculate_edge_direction(e);
671 for (
auto f : adj_faces) {
673 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
675 int side_number, sense, offset;
676 CHKERR mField.get_moab().side_number(f, e, side_number, sense, offset);
677 auto dot = -sense * t_cross(
I) * t_normal(
I);
679 tags[griffith_force_tag], &f, 1, &dot),
687 CHKERR TSGetStepNumber(ts, &ts_step);
689 "front_faces_material_force_" +
690 std::to_string(ts_step) +
".vtk",
696 auto vector_edge_exchange = CommInterface::createEntitiesPetscVector(
697 mField.get_comm(), mField.get_moab(), 1, 3, Sev::inform);
698 CHKERR CommInterface::updateEntitiesPetscVector(
699 mField.get_moab(), vector_edge_exchange, tags[material_force_tag]);
700 auto &scalar_edge_exchange = edgeExchange;
701 CHKERR CommInterface::updateEntitiesPetscVector(
702 mField.get_moab(), scalar_edge_exchange, tags[griffith_force_tag]);
707 auto calculate_griffith_force_simplified = [&](
auto material_force_tag,
708 auto griffith_force_tag) {
711 if (mField.get_comm_rank() == 0) {
712 auto front_nodes = get_conn_range(*frontEdges);
714 for (
auto n : front_nodes) {
716 CHKERR mField.get_moab().tag_get_data(tags[material_force_tag], &
n, 1,
719 auto adj_edges = intersect(get_adj(
n, 1), *frontEdges);
720 double adj_edges_length = 0.;
721 for (
auto e : adj_edges) {
722 auto t_edge_dir = calculate_edge_direction(e);
723 adj_edges_length += t_edge_dir.l2();
726 const double nodal_front_length = adj_edges_length / 2.;
727 if (nodal_front_length <= 0.) {
729 "Front node has zero adjacent front edge length");
732 double griffith_energy = t_node_force.
l2() / nodal_front_length;
733 CHK_MOAB_THROW(mField.get_moab().tag_set_data(tags[griffith_force_tag],
734 &
n, 1, &griffith_energy),
742 auto calculate_adjoint_material_force = [&]() {
745 if (ts == PETSC_NULLPTR) {
747 "TS is required to calculate adjoint material force");
751 this, SetIntegrationAtFrontVolume(frontVertices, frontAdjEdges),
752 SetIntegrationAtFrontFace(frontVertices, frontAdjEdges),
753 SmartPetscObj<TS>(ts,
true));
756 double obj_value = 0;
760 auto set_vertex_exchange_from_gradient = [&]() {
763 CHKERR VecZeroEntries(vertexExchange.second);
764 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
766 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
769 auto *problem_ptr = getProblemPtr(dmMaterial);
771 problem_ptr->getNumeredRowDofsPtr()->get<Unique_mi_tag>();
772 const auto field_bit = mField.get_field_bit_number(materialH1Positions);
775 double *exchange_array;
776 CHKERR VecGetArray(
g, &g_array);
777 CHKERR VecGetArray(vertexExchange.second, &exchange_array);
779 auto ptr = exchange_array;
781 for (
auto v : vertexExchange.first.first) {
782 std::array<double, SPACE_DIM> values = {0., 0., 0.};
784 dofs.lower_bound(DofEntity::getLoFieldEntityUId(field_bit,
v));
786 dofs.upper_bound(DofEntity::getHiFieldEntityUId(field_bit,
v));
787 for (; lo != hi; ++lo) {
788 if (!(*lo)->getHasLocalIndex())
790 const auto coeff = (*lo)->getDofCoeffIdx();
792 values[coeff] = g_array[(*lo)->getPetscLocalDofIdx()];
794 for (
int d = 0; d !=
SPACE_DIM; ++d, ++ptr) {
799 CHKERR VecRestoreArray(vertexExchange.second, &exchange_array);
800 CHKERR VecRestoreArray(
g, &g_array);
802 if (adjoint_gradient_vector !=
nullptr) {
803 (*adjoint_gradient_vector) =
g;
809 CHKERR set_vertex_exchange_from_gradient();
811 CHKERR CommInterface::setTagFromVector(
812 mField.get_moab(), vertexExchange,
813 tags[ExhangeTags::ADJOINT_MATERIALFORCE]);
814 CHKERR CommInterface::updateEntitiesPetscVector(
815 mField.get_moab(), vertexExchange,
816 tags[ExhangeTags::ADJOINT_MATERIALFORCE]);
821 auto print_results = [&](
auto nb_J_integral_conturs,
bool print_material,
822 bool print_adjoint) {
825 if (!print_material && !print_adjoint) {
829 auto get_conn_range = [&](
auto e) {
836 auto get_tag_data = [&](
auto &ents,
auto tag,
auto dim) {
837 std::vector<double> data(ents.size() * dim);
838 CHK_MOAB_THROW(mField.get_moab().tag_get_data(tag, ents, data.data()),
843 if (mField.get_comm_rank() == 0) {
844 auto at_nodes = [&]() {
846 auto conn = get_conn_range(*frontEdges);
847 std::vector<double> material_force;
848 std::vector<double> adjoint_material_force;
849 auto area_growth = get_tag_data(conn, tags[ExhangeTags::AREAGROWTH], 3);
850 std::vector<double> griffith_force;
851 std::vector<double> adjoint_griffith_force;
852 if (print_material) {
854 get_tag_data(conn, tags[ExhangeTags::MATERIALFORCE], 3);
856 get_tag_data(conn, tags[ExhangeTags::GRIFFITHFORCE], 1);
859 adjoint_material_force =
860 get_tag_data(conn, tags[ExhangeTags::ADJOINT_MATERIALFORCE], 3);
861 adjoint_griffith_force =
862 get_tag_data(conn, tags[ExhangeTags::ADJOINT_GRIFFITHFORCE], 1);
864 std::vector<double> coords(conn.size() * 3);
867 MOFEM_LOG(
"EPSELF", Sev::inform) <<
"Force results at nodes";
869 << std::left << std::setw(10) <<
"kind" << std::right
870 << std::setw(9) <<
"node" << std::setw(18) <<
"coord_x"
871 << std::setw(18) <<
"coord_y" << std::setw(18) <<
"coord_z"
872 << std::setw(18) <<
"force_x" << std::setw(18) <<
"force_y"
873 << std::setw(18) <<
"force_z" << std::setw(18) <<
"area_x"
874 << std::setw(18) <<
"area_y" << std::setw(18) <<
"area_z"
875 << std::setw(18) <<
"griffith" << std::setw(10) <<
"contour";
877 auto print_row = [&](
const char *kind,
const auto &force,
878 const auto &griffith,
const size_t i) {
880 << std::left << std::setw(10) << kind << std::right
881 << std::setw(9) << conn[
i] << std::scientific
882 << std::setprecision(10) << std::setw(18) << coords[
i * 3 + 0]
883 << std::setw(18) << coords[
i * 3 + 1] << std::setw(18)
884 << coords[
i * 3 + 2] << std::setw(18) << force[
i * 3 + 0]
885 << std::setw(18) << force[
i * 3 + 1] << std::setw(18)
886 << force[
i * 3 + 2] << std::setw(18) << area_growth[
i * 3 + 0]
887 << std::setw(18) << area_growth[
i * 3 + 1] << std::setw(18)
888 << area_growth[
i * 3 + 2] << std::setw(18) << griffith[
i]
889 << std::defaultfloat << std::setprecision(6) << std::setw(10)
890 << nb_J_integral_conturs;
893 for (
size_t i = 0;
i < conn.size(); ++
i) {
894 if (print_material) {
895 print_row(
"material", material_force, griffith_force,
i);
898 print_row(
"adjoint", adjoint_material_force, adjoint_griffith_force,
911 CHKERR calculate_material_forces();
913 PetscBool all_contours = PETSC_FALSE;
914 CHKERR PetscOptionsGetBool(PETSC_NULLPTR,
"",
915 "-calculate_J_integral_all_levels", &all_contours,
917 CHKERR PetscOptionsGetBool(
918 PETSC_NULLPTR,
"",
"-calculate_J_integral_all_contours", &all_contours,
921 if (all_contours == PETSC_TRUE) {
922 for (
int l = 0;
l < nbJIntegralContours; ++
l) {
923 CHKERR calculate_force_through_node(
l);
924 CHKERR average_material_force_at_edge(tags[ExhangeTags::MATERIALFORCE]);
925 CHKERR calculate_crack_area_growth_face(
l);
926 CHKERR calculate_crack_area_growth_no_face(
l, ExhangeTags::MATERIALFORCE);
927 CHKERR update_crack_area_growth_edges();
928 CHKERR calculate_griffith_force(ExhangeTags::MATERIALFORCE,
929 ExhangeTags::GRIFFITHFORCE);
930 CHKERR print_results(
l,
true,
false);
934 PetscBool has_nonzero_ts_solution = PETSC_FALSE;
936 if (ts != PETSC_NULLPTR) {
937 Vec ts_solution = PETSC_NULLPTR;
938 CHKERR TSGetSolution(ts, &ts_solution);
939 if (ts_solution != PETSC_NULLPTR) {
940 PetscReal ts_solution_norm = 0.0;
941 CHKERR VecNorm(ts_solution, NORM_2, &ts_solution_norm);
942 has_nonzero_ts_solution =
943 (ts_solution_norm > PETSC_MACHINE_EPSILON) ? PETSC_TRUE : PETSC_FALSE;
946 if (has_nonzero_ts_solution == PETSC_TRUE) {
947 CHKERR calculate_adjoint_material_force();
951 CHKERR calculate_force_through_node(nbJIntegralContours);
952 CHKERR average_material_force_at_edge(tags[ExhangeTags::MATERIALFORCE]);
953 CHKERR calculate_crack_area_growth_face(nbJIntegralContours);
954 CHKERR calculate_crack_area_growth_no_face(nbJIntegralContours,
955 ExhangeTags::MATERIALFORCE);
956 CHKERR update_crack_area_growth_edges();
957 CHKERR calculate_griffith_force(ExhangeTags::MATERIALFORCE,
958 ExhangeTags::GRIFFITHFORCE);
959 if (has_nonzero_ts_solution == PETSC_TRUE) {
960 CHKERR calculate_griffith_force(ExhangeTags::ADJOINT_MATERIALFORCE,
961 ExhangeTags::ADJOINT_GRIFFITHFORCE);
962 CHKERR calculate_griffith_force_simplified(
963 ExhangeTags::ADJOINT_MATERIALFORCE, ExhangeTags::ADJOINT_GRIFFITHFORCE);
965 CHKERR print_results(nbJIntegralContours,
true,
true);
971 bool set_orientation) {
974 constexpr bool debug =
false;
976 constexpr auto sev = Sev::verbose;
979 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
980 auto body_skin = get_skin(mField, body_ents);
981 Range body_skin_edges;
982 CHKERR mField.get_moab().get_adjacencies(body_skin, 1,
false, body_skin_edges,
983 moab::Interface::UNION);
984 Range boundary_skin_verts;
985 CHKERR mField.get_moab().get_connectivity(body_skin_edges,
986 boundary_skin_verts,
true);
989 Range geometry_edges_verts;
990 CHKERR mField.get_moab().get_connectivity(geometry_edges,
991 geometry_edges_verts,
true);
992 Range crack_faces_verts;
993 CHKERR mField.get_moab().get_connectivity(*crackFaces, crack_faces_verts,
995 Range crack_faces_edges;
996 CHKERR mField.get_moab().get_adjacencies(
997 *crackFaces, 1,
true, crack_faces_edges, moab::Interface::UNION);
998 Range crack_faces_tets;
999 CHKERR mField.get_moab().get_adjacencies(
1000 *crackFaces, 3,
true, crack_faces_tets, moab::Interface::UNION);
1003 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_verts,
true);
1005 CHKERR mField.get_moab().get_adjacencies(*frontEdges, 2,
true, front_faces,
1006 moab::Interface::UNION);
1007 Range front_verts_edges;
1008 CHKERR mField.get_moab().get_adjacencies(
1009 front_verts, 1,
true, front_verts_edges, moab::Interface::UNION);
1011 auto get_tags_vec = [&](
auto tag_name,
int dim) {
1012 std::vector<Tag> tags(1);
1017 auto create_and_clean = [&]() {
1019 auto &moab = mField.get_moab();
1020 auto rval = moab.tag_get_handle(tag_name, tags[0]);
1021 if (rval == MB_SUCCESS) {
1022 moab.tag_delete(tags[0]);
1024 double def_val[] = {0., 0., 0.};
1025 CHKERR moab.tag_get_handle(tag_name, dim, MB_TYPE_DOUBLE, tags[0],
1026 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
1035 auto get_adj_front = [&](
bool subtract_crack) {
1037 CHKERR mField.get_moab().get_adjacencies(*frontEdges,
SPACE_DIM - 1,
true,
1038 adj_front, moab::Interface::UNION);
1040 adj_front = subtract(adj_front, *crackFaces);
1046 auto th_front_position = get_tags_vec(
"FrontPosition", 3);
1047 auto th_max_face_energy = get_tags_vec(
"MaxFaceEnergy", 1);
1049 if (mField.get_comm_rank() == 0) {
1051 auto get_crack_adj_tets = [&](
auto r) {
1052 Range crack_faces_conn;
1053 CHKERR mField.get_moab().get_connectivity(r, crack_faces_conn);
1054 Range crack_faces_conn_tets;
1056 true, crack_faces_conn_tets,
1057 moab::Interface::UNION);
1058 return crack_faces_conn_tets;
1061 auto get_layers_for_sides = [&](
auto &side) {
1062 std::vector<Range> layers;
1066 auto get_adj = [&](
auto &r,
int dim) {
1068 CHKERR mField.get_moab().get_adjacencies(r, dim,
true, adj,
1069 moab::Interface::UNION);
1073 auto get_tets = [&](
auto r) {
return get_adj(r,
SPACE_DIM); };
1076 CHKERR mField.get_moab().get_connectivity(*frontEdges, front_nodes,
1078 Range front_faces = get_adj(front_nodes, 2);
1079 front_faces = subtract(front_faces, *crackFaces);
1080 auto front_tets = get_tets(front_nodes);
1081 auto front_side = intersect(side, front_tets);
1082 layers.push_back(front_side);
1084 auto adj_faces = get_skin(mField, layers.back());
1085 adj_faces = intersect(adj_faces, front_faces);
1086 auto adj_faces_tets = get_tets(adj_faces);
1087 adj_faces_tets = intersect(adj_faces_tets, front_tets);
1088 layers.push_back(unite(layers.back(), adj_faces_tets));
1089 if (layers.back().size() == layers[layers.size() - 2].size()) {
1100 auto layers_top = get_layers_for_sides(sides_pair.first);
1101 auto layers_bottom = get_layers_for_sides(sides_pair.second);
1108 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
".vtk",
1109 get_crack_adj_tets(*crackFaces));
1113 MOFEM_LOG(
"EP", sev) <<
"Nb. layers " << layers_top.size();
1115 for (
auto &r : layers_top) {
1116 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " << r.size();
1119 "layers_top_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
1124 for (
auto &r : layers_bottom) {
1125 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " << r.size();
1128 "layers_bottom_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
1134 auto get_cross = [&](
auto t_dir,
auto f) {
1136 CHKERR mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
1146 auto get_sense = [&](
auto f,
auto e) {
1147 int side, sense, offset;
1148 CHK_MOAB_THROW(mField.get_moab().side_number(f, e, side, sense, offset),
1150 return std::make_tuple(side, sense, offset);
1153 auto calculate_edge_direction = [&](
auto e,
auto normalize =
true) {
1156 CHKERR mField.get_moab().get_connectivity(e, conn, num_nodes,
true);
1157 std::array<double, 6> coords;
1158 CHKERR mField.get_moab().get_coords(conn, num_nodes, coords.data());
1160 &coords[0], &coords[1], &coords[2]};
1162 &coords[3], &coords[4], &coords[5]};
1165 t_dir(
i) = t_p1(
i) - t_p0(
i);
1171 auto evaluate_face_energy_and_set_orientation = [&](
auto front_edges,
1178 Tag th_material_force;
1179 switch (energyReleaseSelector) {
1182 CHKERR mField.get_moab().tag_get_handle(
"GriffithForce",
1186 CHKERR mField.get_moab().tag_get_handle(
"MaterialForce",
1191 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
1192 "Unknown energy release selector");
1200 auto find_maximal_face_energy = [&](
auto front_edges,
auto front_faces,
1201 auto &edge_face_max_energy_map) {
1205 CHKERR mField.get_moab().get_entities_by_dimension(0, 3, body_ents);
1206 auto body_skin = get_skin(mField, body_ents);
1210 for (
auto e : front_edges) {
1212 double griffith_force;
1213 CHKERR mField.get_moab().tag_get_data(th_face_energy, &e, 1,
1217 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2,
false, faces);
1218 faces = subtract(intersect(faces, front_faces), body_skin);
1219 std::vector<double> face_energy(faces.size());
1220 CHKERR mField.get_moab().tag_get_data(th_face_energy, faces,
1221 face_energy.data());
1222 auto max_energy_it =
1223 std::max_element(face_energy.begin(), face_energy.end());
1225 max_energy_it != face_energy.end() ? *max_energy_it : 0;
1227 edge_face_max_energy_map[e] =
1228 std::make_tuple(faces[max_energy_it - face_energy.begin()],
1229 griffith_force,
static_cast<double>(0));
1231 <<
"Edge " << e <<
" griffith force " << griffith_force
1232 <<
" max face energy " << max_energy <<
" factor "
1233 << max_energy / griffith_force;
1235 max_faces.insert(faces[max_energy_it - face_energy.begin()]);
1243 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
1257 auto calculate_face_orientation = [&](
auto &edge_face_max_energy_map) {
1260 auto up_down_face = [&](
1262 auto &face_angle_map_up,
1263 auto &face_angle_map_down
1268 for (
auto &
m : edge_face_max_energy_map) {
1270 auto [max_face, energy, opt_angle] =
m.second;
1273 CHKERR mField.get_moab().get_adjacencies(&e, 1, 2,
false, faces);
1274 faces = intersect(faces, front_faces);
1278 moab::Interface::UNION);
1279 if (adj_tets.size()) {
1284 moab::Interface::UNION);
1285 if (adj_tets.size()) {
1287 Range adj_tets_faces;
1289 CHKERR mField.get_moab().get_adjacencies(
1290 adj_tets,
SPACE_DIM - 1,
false, adj_tets_faces,
1291 moab::Interface::UNION);
1292 adj_tets_faces = intersect(adj_tets_faces, faces);
1297 get_cross(calculate_edge_direction(e,
true), max_face);
1298 auto [side_max, sense_max, offset_max] = get_sense(max_face, e);
1299 t_cross_max(
i) *= sense_max;
1301 for (
auto t : adj_tets) {
1302 Range adj_tets_faces;
1303 CHKERR mField.get_moab().get_adjacencies(
1304 &
t, 1,
SPACE_DIM - 1,
false, adj_tets_faces);
1305 adj_tets_faces = intersect(adj_tets_faces, faces);
1307 subtract(adj_tets_faces,
Range(max_face, max_face));
1309 if (adj_tets_faces.size() == 1) {
1313 auto t_cross = get_cross(calculate_edge_direction(e,
true),
1315 auto [side, sense, offset] =
1316 get_sense(adj_tets_faces[0], e);
1317 t_cross(
i) *= sense;
1318 double dot = t_cross(
i) * t_cross_max(
i);
1319 auto angle = std::acos(dot);
1322 CHKERR mField.get_moab().tag_get_data(
1323 th_face_energy, adj_tets_faces, &face_energy);
1325 auto [side_face, sense_face, offset_face] =
1326 get_sense(
t, max_face);
1328 if (sense_face > 0) {
1329 face_angle_map_up[e] = std::make_tuple(face_energy, angle,
1333 face_angle_map_down[e] = std::make_tuple(
1334 face_energy, -angle, adj_tets_faces[0]);
1345 auto calc_optimal_angle = [&](
1347 auto &face_angle_map_up,
1348 auto &face_angle_map_down
1353 for (
auto &
m : edge_face_max_energy_map) {
1355 auto &[max_face, e0,
a0] =
m.second;
1357 if (std::abs(e0) > std::numeric_limits<double>::epsilon()) {
1359 if (face_angle_map_up.find(e) == face_angle_map_up.end() ||
1360 face_angle_map_down.find(e) == face_angle_map_down.end()) {
1364 switch (energyReleaseSelector) {
1368 Tag th_material_force;
1369 CHKERR mField.get_moab().tag_get_handle(
"MaterialForce",
1372 CHKERR mField.get_moab().tag_get_data(
1373 th_material_force, &e, 1, &t_material_force(0));
1374 auto material_force_magnitude = t_material_force.
l2();
1375 if (material_force_magnitude <
1376 std::numeric_limits<double>::epsilon()) {
1381 auto t_edge_dir = calculate_edge_direction(e,
true);
1382 auto t_cross_max = get_cross(t_edge_dir, max_face);
1383 auto [side, sense, offset] = get_sense(max_face, e);
1384 t_cross_max(sense) *= sense;
1391 t_cross_max.normalize();
1394 t_material_force(
J) * t_cross_max(K);
1395 a0 = -std::asin(t_cross(
I) * t_edge_dir(
I));
1398 <<
"Optimal angle " <<
a0 <<
" energy " << e0;
1404 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
1405 "Unknown energy release selector");
1415 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
1417 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
1418 face_angle_map_down;
1419 CHKERR up_down_face(face_angle_map_up, face_angle_map_down);
1420 CHKERR calc_optimal_angle(face_angle_map_up, face_angle_map_down);
1424 auto th_angle = get_tags_vec(
"Angle", 1);
1426 for (
auto &
m : face_angle_map_up) {
1427 auto [e,
a, face] =
m.second;
1429 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &
a);
1432 for (
auto &
m : face_angle_map_down) {
1433 auto [e,
a, face] =
m.second;
1435 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1, &
a);
1438 Range max_energy_faces;
1439 for (
auto &
m : edge_face_max_energy_map) {
1440 auto [face, e, angle] =
m.second;
1441 max_energy_faces.insert(face);
1442 CHKERR mField.get_moab().tag_set_data(th_angle[0], &face, 1,
1445 if (mField.get_comm_rank() == 0) {
1457 auto get_conn = [&](
auto e) {
1459 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, conn,
true),
1464 auto get_adj = [&](
auto e,
auto dim) {
1467 e, dim,
false, adj, moab::Interface::UNION),
1472 auto get_coords = [&](
auto v) {
1480 auto get_rotated_normal = [&](
auto e,
auto f,
auto angle) {
1483 auto t_edge_dir = calculate_edge_direction(e,
true);
1484 auto [side, sense, offset] = get_sense(f, e);
1485 t_edge_dir(
i) *= sense;
1486 t_edge_dir.normalize();
1487 t_edge_dir(
i) *= angle;
1490 mField.getInterface<Tools>()->getTriNormal(f, &t_normal(0));
1492 t_rotated_normal(
i) = t_R(
i,
j) * t_normal(
j);
1493 return std::make_tuple(t_normal, t_rotated_normal);
1496 auto set_coord = [&](
auto v,
auto &adj_vertex_tets_verts,
auto &coords,
1497 auto &t_move,
auto gamma) {
1498 auto index = adj_vertex_tets_verts.index(
v);
1500 for (
auto ii : {0, 1, 2}) {
1501 coords[3 * index + ii] += gamma * t_move(ii);
1508 auto tets_quality = [&](
auto quality,
auto &adj_vertex_tets_verts,
1509 auto &adj_vertex_tets,
auto &coords) {
1510 for (
auto t : adj_vertex_tets) {
1513 CHKERR mField.get_moab().get_connectivity(
t, conn, num_nodes,
true);
1514 std::array<double, 12> tet_coords;
1515 for (
auto n = 0;
n != 4; ++
n) {
1516 auto index = adj_vertex_tets_verts.index(conn[
n]);
1520 for (
auto ii = 0; ii != 3; ++ii) {
1521 tet_coords[3 *
n + ii] = coords[3 * index + ii];
1524 double q = Tools::volumeLengthQuality(tet_coords.data());
1525 if (!std::isnormal(q))
1527 quality = std::min(quality, q);
1533 auto calculate_free_face_node_displacement =
1534 [&](
auto &edge_face_max_energy_map) {
1536 auto get_vertex_edges = [&](
auto vertex) {
1541 CHKERR mField.get_moab().get_adjacencies(vertex, 1,
false,
1543 vertex_edges = subtract(vertex_edges, front_verts_edges);
1545 if (boundary_skin_verts.size() &&
1546 boundary_skin_verts.find(vertex[0]) !=
1547 boundary_skin_verts.end()) {
1548 MOFEM_LOG(
"EP", sev) <<
"Boundary vertex";
1549 vertex_edges = intersect(vertex_edges, body_skin_edges);
1551 if (geometry_edges_verts.size() &&
1552 geometry_edges_verts.find(vertex[0]) !=
1553 geometry_edges_verts.end()) {
1554 MOFEM_LOG(
"EP", sev) <<
"Geometry edge vertex";
1555 vertex_edges = intersect(vertex_edges, geometry_edges);
1557 if (crack_faces_verts.size() &&
1558 crack_faces_verts.find(vertex[0]) !=
1559 crack_faces_verts.end()) {
1560 MOFEM_LOG(
"EP", sev) <<
"Crack face vertex";
1561 vertex_edges = intersect(vertex_edges, crack_faces_edges);
1568 return vertex_edges;
1573 using Bundle = std::vector<
1579 std::map<EntityHandle, Bundle> edge_bundle_map;
1581 for (
auto &
m : edge_face_max_energy_map) {
1583 auto edge =
m.first;
1584 auto &[max_face, energy, opt_angle] =
m.second;
1587 auto [t_normal, t_rotated_normal] =
1588 get_rotated_normal(edge, max_face, opt_angle);
1590 auto front_vertex = get_conn(
Range(
m.first,
m.first));
1591 auto adj_tets = get_adj(
Range(max_face, max_face), 3);
1592 auto adj_tets_faces = get_adj(adj_tets, 2);
1593 auto adj_front_faces = subtract(
1594 intersect(get_adj(
Range(edge, edge), 2), adj_tets_faces),
1596 if (adj_front_faces.size() > 3)
1598 "adj_front_faces.size()>3");
1601 CHKERR mField.get_moab().tag_get_data(th_material_force, &edge, 1,
1602 &t_material_force(0));
1603 std::vector<double> griffith_energy(adj_front_faces.size());
1604 CHKERR mField.get_moab().tag_get_data(
1605 th_face_energy, adj_front_faces, griffith_energy.data());
1607 auto set_edge_bundle = [&](
auto min_gamma) {
1608 for (
auto rotated_f : adj_front_faces) {
1610 double rotated_face_energy =
1611 griffith_energy[adj_front_faces.index(rotated_f)];
1613 auto vertex = subtract(get_conn(
Range(rotated_f, rotated_f)),
1615 if (vertex.size() != 1) {
1617 "Wrong number of vertex to move");
1619 auto front_vertex_edges_vertex = get_conn(
1620 intersect(get_adj(front_vertex, 1), crack_faces_edges));
1622 vertex, front_vertex_edges_vertex);
1623 if (vertex.empty()) {
1627 auto face_cardinality = [&](
auto f,
auto &seen_front_edges) {
1630 subtract(body_skin_edges, crack_faces_edges));
1631 auto faces =
Range(f, f);
1633 for (;
c < 10; ++
c) {
1635 subtract(get_adj(faces, 1), seen_front_edges);
1636 if (front_edges.size() == 0) {
1639 auto front_connected_edges =
1640 intersect(front_edges, whole_front);
1641 if (front_connected_edges.size()) {
1642 seen_front_edges.merge(front_connected_edges);
1645 faces.merge(get_adj(front_edges, 2));
1652 double rotated_face_cardinality = face_cardinality(
1658 rotated_face_cardinality = std::max(rotated_face_cardinality,
1661 auto t_vertex_coords = get_coords(vertex);
1662 auto vertex_edges = get_vertex_edges(vertex);
1667 CHKERR mField.get_moab().get_coords(&f0, 1, &t_v_e0(0));
1668 CHKERR mField.get_moab().get_coords(&f1, 1, &t_v_e1(0));
1671 for (
auto e_used_to_move_detection : vertex_edges) {
1672 auto edge_conn = get_conn(
Range(e_used_to_move_detection,
1673 e_used_to_move_detection));
1674 edge_conn = subtract(edge_conn, vertex);
1684 t_v0(
i) = (t_v_e0(
i) + t_v_e1(
i)) / 2;
1686 CHKERR mField.get_moab().get_coords(edge_conn, &t_v3(0));
1688 (t_v0(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
1690 (t_v3(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
1693 constexpr double eps =
1694 std::numeric_limits<double>::epsilon();
1695 if (std::isnormal(gamma) && gamma < 1.0 -
eps &&
1698 t_move(
i) = gamma * (t_v3(
i) - t_vertex_coords(
i));
1700 auto check_rotated_face_directoon = [&]() {
1702 t_delta(
i) = t_vertex_coords(
i) + t_move(
i) - t_v0(
i);
1705 (t_material_force(
i) / t_material_force.
l2()) *
1707 return -dot > 0 ? true :
false;
1710 if (check_rotated_face_directoon()) {
1713 <<
"Crack edge " << edge <<
" moved face "
1715 <<
" edge: " << e_used_to_move_detection
1716 <<
" face direction/energy " << rotated_face_energy
1717 <<
" face cardinality " << rotated_face_cardinality
1718 <<
" gamma: " << gamma;
1720 auto &bundle = edge_bundle_map[edge];
1721 bundle.emplace_back(rotated_f, e_used_to_move_detection,
1722 vertex[0], t_move, 1,
1723 rotated_face_cardinality, gamma);
1730 set_edge_bundle(std::numeric_limits<double>::epsilon());
1731 if (edge_bundle_map[edge].empty()) {
1732 set_edge_bundle(-1.);
1736 return edge_bundle_map;
1739 auto get_sort_by_energy = [&](
auto &edge_face_max_energy_map) {
1740 std::map<double, std::tuple<EntityHandle, EntityHandle, double>>
1743 for (
auto &
m : edge_face_max_energy_map) {
1745 auto &[max_face, energy, opt_angle] =
m.second;
1746 auto abs_energy = std::abs(energy);
1747 sort_by_energy[abs_energy] = std::make_tuple(e, max_face, opt_angle);
1750 return sort_by_energy;
1753 auto set_tag = [&](
auto &&adj_edges_map,
auto &&sort_by_energy) {
1756 Tag th_face_pressure;
1758 mField.get_moab().tag_get_handle(
"FacePressure", th_face_pressure),
1760 auto get_face_pressure = [&](
auto face) {
1762 CHK_MOAB_THROW(mField.get_moab().tag_get_data(th_face_pressure, &face,
1769 <<
"Number of edges to check " << sort_by_energy.size();
1771 enum face_energy { POSITIVE, NEGATIVE };
1772 constexpr bool skip_negative =
true;
1774 for (
auto fe : {face_energy::POSITIVE, face_energy::NEGATIVE}) {
1776 std::vector<double> energies;
1777 double max_pressure = -1;
1780 for (
auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
1782 auto energy = it->first;
1783 auto [max_edge, max_face, opt_angle] = it->second;
1785 auto face_pressure = get_face_pressure(max_face);
1786 energies.push_back(energy);
1788 max_pressure = std::max(max_pressure, face_pressure);
1791 double average_energy = 0;
1792 if (!energies.empty()) {
1794 std::accumulate(energies.begin(), energies.end(), 0.) /
1799 <<
"Average energy Griffiths energy of crack front "
1804 for (
auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
1807 auto energy = it->first;
1808 auto [max_edge, max_face, opt_angle] = it->second;
1810 auto face_pressure = get_face_pressure(max_face);
1811 if (skip_negative) {
1812 if (fe == face_energy::POSITIVE) {
1814 -(crackingAtol + crackingRtol * std::abs(max_pressure))) {
1816 <<
"Skip negative face " << max_face <<
" with energy "
1817 << energy <<
" and pressure " << face_pressure;
1824 <<
"Check face " << max_face <<
" edge " << max_edge
1825 <<
" energy " << energy <<
" optimal angle " << opt_angle
1826 <<
" face pressure " << face_pressure;
1829 if (!average_energy) {
1831 <<
"Average energy is zero, setting max Griffiths energy to "
1834 average_energy = energy;
1836 avgGriffithsEnergy = average_energy;
1837 auto jt = adj_edges_map.find(max_edge);
1838 if (jt == adj_edges_map.end()) {
1840 <<
"Edge " << max_edge <<
" not found in adj_edges_map";
1843 auto &bundle = jt->second;
1845 auto find_max_in_bundle_impl = [&](
auto edge,
auto &bundle,
1852 double max_quality = -2;
1853 double max_quality_evaluated = -2;
1854 double min_cardinality = std::numeric_limits<double>::max();
1858 for (
auto &b : bundle) {
1859 auto &[face, move_edge, vertex, t_move, quality, cardinality,
1862 auto adj_vertex_tets = get_adj(
Range(vertex, vertex), 3);
1863 auto adj_vertex_tets_verts = get_conn(adj_vertex_tets);
1864 std::vector<double> coords(3 * adj_vertex_tets_verts.size());
1866 adj_vertex_tets_verts, coords.data()),
1869 set_coord(vertex, adj_vertex_tets_verts, coords, t_move, gamma);
1870 quality = tets_quality(quality, adj_vertex_tets_verts,
1871 adj_vertex_tets, coords);
1873 auto eval_quality = [](
auto q,
auto c,
auto edge_gamma) {
1877 return ((edge_gamma < 0) ? (q / 2) : q) / pow(
c, 2);
1881 if (eval_quality(quality, cardinality, edge_gamma) >=
1882 max_quality_evaluated) {
1883 max_quality = quality;
1884 min_cardinality = cardinality;
1885 vertex_max = vertex;
1887 move_edge_max = move_edge;
1888 t_move_last(
i) = t_move(
i);
1889 max_quality_evaluated =
1890 eval_quality(max_quality, min_cardinality, edge_gamma);
1894 return std::make_tuple(vertex_max, face_max, t_move_last,
1895 max_quality, min_cardinality);
1898 auto find_max_in_bundle = [&](
auto edge,
auto &bundle) {
1899 auto b_org_bundle = bundle;
1900 auto r = find_max_in_bundle_impl(edge, bundle, 1.);
1901 auto &[vertex_max, face_max, t_move_last, max_quality,
1903 if (max_quality < 0) {
1904 for (
double gamma = 0.95; gamma >= 0.45; gamma -= 0.05) {
1905 bundle = b_org_bundle;
1906 r = find_max_in_bundle_impl(edge, bundle, gamma);
1907 auto &[vertex_max, face_max, t_move_last, max_quality,
1910 <<
"Back tracking: gamma " << gamma <<
" edge " << edge
1911 <<
" quality " << max_quality <<
" cardinality "
1913 if (max_quality > 0.01) {
1915 t_move_last(
I) *= gamma;
1926 auto set_tag_to_vertex_and_face = [&](
auto &&r,
auto &quality) {
1928 auto &[
v, f, t_move, q, cardinality] = r;
1930 if ((q > 0 && std::isnormal(q)) && energy > 0) {
1933 <<
"Set tag: vertex " <<
v <<
" face " << f <<
" "
1934 << max_edge <<
" move " << t_move <<
" energy " << energy
1935 <<
" quality " << q <<
" cardinality " << cardinality;
1936 CHKERR mField.get_moab().tag_set_data(th_position[0], &
v, 1,
1938 CHKERR mField.get_moab().tag_set_data(th_max_face_energy[0], &f,
1946 double quality = -2;
1947 CHKERR set_tag_to_vertex_and_face(
1949 find_max_in_bundle(max_edge, bundle),
1955 if (quality > 0 && std::isnormal(quality) && energy > 0) {
1957 <<
"Crack face set with quality: " << quality;
1970 MOFEM_LOG(
"EP", sev) <<
"Calculate orientation";
1971 std::map<EntityHandle, std::tuple<EntityHandle, double, double>>
1972 edge_face_max_energy_map;
1973 CHKERR find_maximal_face_energy(front_edges, front_faces,
1974 edge_face_max_energy_map);
1975 CHKERR calculate_face_orientation(edge_face_max_energy_map);
1977 MOFEM_LOG(
"EP", sev) <<
"Calculate node positions";
1980 calculate_free_face_node_displacement(edge_face_max_energy_map),
1981 get_sort_by_energy(edge_face_max_energy_map)
1988 auto get_max_griffith_force = [&](
auto r) {
1989 auto &moab = mField.get_moab();
1990 std::vector<double> gc(r.size());
1992 CHKERR moab.tag_get_handle(
"GriffithForce", th_gc);
1993 CHKERR moab.tag_get_data(th_gc, r, gc.data());
1994 double max_griffith_force = 0;
1995 for (
size_t i = 0;
i < r.size(); ++
i) {
1996 max_griffith_force = std::max(max_griffith_force, std::abs(gc[
i]));
1998 return max_griffith_force;
2001 MOFEM_LOG(
"EP", sev) <<
"Front edges " << frontEdges->size();
2002 if (std::abs(get_max_griffith_force(get_adj_front(
true))) >
2003 std::numeric_limits<double>::epsilon()) {
2004 CHKERR evaluate_face_energy_and_set_orientation(
2005 *frontEdges, get_adj_front(
true), sides_pair, th_front_position);
2007 auto adj_front = get_adj_front(
true);
2008 double zero[] = {0., 0., 0.};
2009 CHKERR mField.get_moab().tag_clear_data(th_front_position[0], adj_front,
2015 CHKERR VecZeroEntries(vertexExchange.second);
2016 CHKERR VecGhostUpdateBegin(vertexExchange.second, INSERT_VALUES,
2018 CHKERR VecGhostUpdateEnd(vertexExchange.second, INSERT_VALUES,
2020 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
2021 mField.get_moab(), vertexExchange, th_front_position[0]);
2022 CHKERR VecZeroEntries(faceExchange.second);
2023 CHKERR VecGhostUpdateBegin(faceExchange.second, INSERT_VALUES,
2025 CHKERR VecGhostUpdateEnd(faceExchange.second, INSERT_VALUES, SCATTER_FORWARD);
2026 CHKERR mField.getInterface<CommInterface>()->updateEntitiesPetscVector(
2027 mField.get_moab(), faceExchange, th_max_face_energy[0]);
2029 auto get_max_moved_faces = [&]() {
2030 Range max_moved_faces;
2031 auto adj_front = get_adj_front(
false);
2032 std::vector<double> face_energy(adj_front.size());
2033 CHKERR mField.get_moab().tag_get_data(th_max_face_energy[0], adj_front,
2034 face_energy.data());
2035 for (
int i = 0;
i != adj_front.size(); ++
i) {
2036 if (face_energy[
i] > std::numeric_limits<double>::epsilon()) {
2037 max_moved_faces.insert(adj_front[
i]);
2041 return boost::make_shared<Range>(max_moved_faces);
2045 maxMovedFaces = get_max_moved_faces();
2046 MOFEM_LOG(
"EP", sev) <<
"Number of of moved faces: " << maxMovedFaces->size();
2052 "max_moved_faces_" +
2053 boost::lexical_cast<std::string>(mField.get_comm_rank()) +
".vtk",
2103 constexpr bool potential_crack_debug =
false;
2104 if constexpr (potential_crack_debug) {
2107 Range crack_front_verts;
2108 CHKERR mField.get_moab().get_connectivity(*frontEdges, crack_front_verts,
2110 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2112 Range crack_front_faces;
2113 CHKERR mField.get_moab().get_adjacencies(crack_front_verts,
SPACE_DIM - 1,
2114 true, crack_front_faces,
2115 moab::Interface::UNION);
2116 crack_front_faces = intersect(crack_front_faces, add_ents);
2117 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2119 CHKERR mField.getInterface<MeshsetsManager>()->addEntitiesToMeshset(
2120 BLOCKSET, addCrackMeshsetId, crack_front_faces);
2123 auto get_crack_faces = [&]() {
2124 if (maxMovedFaces) {
2125 return unite(*crackFaces, *maxMovedFaces);
2131 auto get_extended_crack_faces = [&]() {
2132 auto get_faces_of_crack_front_verts = [&](
auto crack_faces_org) {
2133 ParallelComm *pcomm =
2138 if (!pcomm->rank()) {
2140 auto get_nodes = [&](
auto &&e) {
2142 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes,
true),
2143 "get connectivity");
2147 auto get_adj = [&](
auto &&e,
auto dim,
2148 auto t = moab::Interface::UNION) {
2151 mField.get_moab().get_adjacencies(e, dim,
true, adj,
t),
2159 auto body_skin = get_skin(mField, body_ents);
2160 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
2163 auto front_block_nodes = get_nodes(front_block_edges);
2167 s = crack_faces.size();
2169 auto crack_face_nodes = get_nodes(crack_faces_org);
2170 auto crack_faces_edges =
2171 get_adj(crack_faces_org, 1, moab::Interface::UNION);
2173 auto crack_skin = get_skin(mField, crack_faces_org);
2174 front_block_edges = subtract(front_block_edges, crack_skin);
2175 auto crack_skin_nodes = get_nodes(crack_skin);
2176 crack_skin_nodes.merge(front_block_nodes);
2178 auto crack_skin_faces =
2179 get_adj(crack_skin, 2, moab::Interface::UNION);
2181 subtract(subtract(crack_skin_faces, crack_faces_org), body_skin);
2183 crack_faces = crack_faces_org;
2184 for (
auto f : crack_skin_faces) {
2185 auto edges = intersect(
2186 get_adj(
Range(f, f), 1, moab::Interface::UNION), crack_skin);
2190 if (edges.size() == 2) {
2192 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
2196 if (edges.size() == 2) {
2197 auto edge_conn = get_nodes(
Range(edges));
2198 auto faces = intersect(get_adj(edges, 2, moab::Interface::UNION),
2200 if (faces.size() == 2) {
2201 auto edge0_conn = get_nodes(
Range(edges[0], edges[0]));
2202 auto edge1_conn = get_nodes(
Range(edges[1], edges[1]));
2203 auto edges_conn = intersect(intersect(edge0_conn, edge1_conn),
2205 if (edges_conn.size() == 1) {
2208 subtract(intersect(get_adj(edges_conn, 1,
2209 moab::Interface::INTERSECT),
2214 if (node_edges.size()) {
2217 CHKERR mField.get_moab().get_coords(edges_conn, &t_v0(0));
2219 auto get_t_dir = [&](
auto e_conn) {
2220 auto other_node = subtract(e_conn, edges_conn);
2222 CHKERR mField.get_moab().get_coords(other_node,
2224 t_dir(
i) -= t_v0(
i);
2230 get_t_dir(edge0_conn)(
i) + get_t_dir(edge1_conn)(
i);
2233 t_crack_surface_ave_dir(
i) = 0;
2234 for (
auto e : node_edges) {
2235 auto e_conn = get_nodes(
Range(e, e));
2236 auto t_dir = get_t_dir(e_conn);
2237 t_crack_surface_ave_dir(
i) += t_dir(
i);
2240 auto dot = t_ave_dir(
i) * t_crack_surface_ave_dir(
i);
2243 if (dot < -std::numeric_limits<double>::epsilon()) {
2244 crack_faces.insert(f);
2247 crack_faces.insert(f);
2251 }
else if (edges.size() == 3) {
2252 crack_faces.insert(f);
2256 if (edges.size() == 1) {
2258 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
2261 intersect(get_adj(
Range(f, f), 1, moab::Interface::UNION),
2262 front_block_edges));
2263 if (edges.size() == 2) {
2264 crack_faces.insert(f);
2270 crack_faces_org = crack_faces;
2272 }
while (s != crack_faces.size());
2278 return get_faces_of_crack_front_verts(get_crack_faces());
2283 get_extended_crack_faces());
2286 auto reconstruct_crack_faces = [&](
auto crack_faces) {
2287 ParallelComm *pcomm =
2293 Range new_crack_faces;
2294 if (!pcomm->rank()) {
2296 auto get_nodes = [&](
auto &&e) {
2298 CHK_MOAB_THROW(mField.get_moab().get_connectivity(e, nodes,
true),
2299 "get connectivity");
2303 auto get_adj = [&](
auto &&e,
auto dim,
2304 auto t = moab::Interface::UNION) {
2307 mField.get_moab().get_adjacencies(e, dim,
true, adj,
t),
2312 auto get_test_on_crack_surface = [&]() {
2313 auto crack_faces_nodes =
2314 get_nodes(crack_faces);
2315 auto crack_faces_tets =
2316 get_adj(crack_faces_nodes, 3,
2317 moab::Interface::UNION);
2321 auto crack_faces_tets_nodes =
2322 get_nodes(crack_faces_tets);
2323 crack_faces_tets_nodes =
2324 subtract(crack_faces_tets_nodes, crack_faces_nodes);
2326 subtract(crack_faces_tets, get_adj(crack_faces_tets_nodes, 3,
2327 moab::Interface::UNION));
2329 get_adj(crack_faces_tets, 2,
2330 moab::Interface::UNION);
2332 new_crack_faces.merge(crack_faces);
2334 return std::make_tuple(new_crack_faces, crack_faces_tets);
2337 auto carck_faces_test_edges = [&](
auto faces,
auto tets) {
2338 auto adj_tets_faces = get_adj(tets, 2, moab::Interface::UNION);
2339 auto adj_faces_edges = get_adj(subtract(faces, adj_tets_faces), 1,
2340 moab::Interface::UNION);
2341 auto adj_tets_edges = get_adj(tets, 1, moab::Interface::UNION);
2344 adj_faces_edges.merge(geometry_edges);
2345 adj_faces_edges.merge(front_block_edges);
2347 auto boundary_tets_edges = intersect(adj_tets_edges, adj_faces_edges);
2348 auto boundary_test_nodes = get_nodes(boundary_tets_edges);
2349 auto boundary_test_nodes_edges =
2350 get_adj(boundary_test_nodes, 1, moab::Interface::UNION);
2351 auto boundary_test_nodes_edges_nodes = subtract(
2352 get_nodes(boundary_test_nodes_edges), boundary_test_nodes);
2354 boundary_tets_edges =
2355 subtract(boundary_test_nodes_edges,
2356 get_adj(boundary_test_nodes_edges_nodes, 1,
2357 moab::Interface::UNION));
2362 auto body_skin = get_skin(mField, body_ents);
2364 auto body_skin_edges = get_adj(body_skin, 1, moab::Interface::UNION);
2365 body_skin_edges = intersect(get_adj(tets, 1, moab::Interface::UNION),
2367 body_skin = intersect(body_skin, adj_tets_faces);
2368 body_skin_edges = subtract(
2369 body_skin_edges, get_adj(body_skin, 1, moab::Interface::UNION));
2371 save_range(mField.get_moab(),
"body_skin_edges.vtk", body_skin_edges);
2372 for (
auto e : body_skin_edges) {
2373 auto adj_tet = intersect(
2374 get_adj(
Range(e, e), 3, moab::Interface::INTERSECT), tets);
2375 if (adj_tet.size() == 1) {
2376 boundary_tets_edges.insert(e);
2380 return boundary_tets_edges;
2383 auto p = get_test_on_crack_surface();
2384 auto &[new_crack_faces, crack_faces_tets] = p;
2395 auto boundary_tets_edges =
2396 carck_faces_test_edges(new_crack_faces, crack_faces_tets);
2398 boundary_tets_edges);
2400 auto resolve_surface = [&](
auto boundary_tets_edges,
2401 auto crack_faces_tets) {
2402 auto boundary_tets_edges_nodes = get_nodes(boundary_tets_edges);
2403 auto crack_faces_tets_faces =
2404 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
2406 Range all_removed_faces;
2407 Range all_removed_tets;
2411 while (size != crack_faces_tets.size()) {
2413 get_adj(crack_faces_tets, 2, moab::Interface::UNION);
2414 auto skin_tets = get_skin(mField, crack_faces_tets);
2416 get_skin(mField, subtract(crack_faces_tets_faces, tets_faces));
2417 auto skin_skin_nodes = get_nodes(skin_skin);
2419 size = crack_faces_tets.size();
2421 <<
"Crack faces tets size " << crack_faces_tets.size()
2422 <<
" crack faces size " << crack_faces_tets_faces.size();
2423 auto skin_tets_nodes = subtract(
2424 get_nodes(skin_tets),
2425 boundary_tets_edges_nodes);
2427 skin_tets_nodes = subtract(skin_tets_nodes, skin_skin_nodes);
2429 Range removed_nodes;
2430 Range tets_to_remove;
2431 Range faces_to_remove;
2432 for (
auto n : skin_tets_nodes) {
2434 intersect(get_adj(
Range(
n,
n), 3, moab::Interface::INTERSECT),
2436 if (tets.size() == 0) {
2440 auto hole_detetction = [&]() {
2442 get_adj(
Range(
n,
n), 3, moab::Interface::INTERSECT);
2447 if (adj_tets.size() == 0) {
2448 return std::make_pair(
2450 get_adj(
Range(
n,
n), 2, moab::Interface::INTERSECT),
2455 std::vector<Range> tets_groups;
2456 auto test_adj_tets = adj_tets;
2457 while (test_adj_tets.size()) {
2459 Range seed =
Range(test_adj_tets[0], test_adj_tets[0]);
2460 while (seed.size() != seed_size) {
2462 subtract(get_adj(seed, 2, moab::Interface::UNION),
2465 seed_size = seed.size();
2467 intersect(get_adj(adj_faces, 3, moab::Interface::UNION),
2470 tets_groups.push_back(seed);
2471 test_adj_tets = subtract(test_adj_tets, seed);
2473 if (tets_groups.size() == 1) {
2475 return std::make_pair(
2477 get_adj(
Range(
n,
n), 2, moab::Interface::INTERSECT),
2482 Range tets_to_remove;
2483 Range faces_to_remove;
2484 for (
auto &r : tets_groups) {
2485 auto f = get_adj(r, 2, moab::Interface::UNION);
2486 auto t = intersect(get_adj(f, 3, moab::Interface::UNION),
2489 if (f.size() > faces_to_remove.size() ||
2490 faces_to_remove.size() == 0) {
2491 faces_to_remove = f;
2496 <<
"Hole detection: faces to remove "
2497 << faces_to_remove.size() <<
" tets to remove "
2498 << tets_to_remove.size();
2499 return std::make_pair(faces_to_remove, tets_to_remove);
2502 if (tets.size() < tets_to_remove.size() ||
2503 tets_to_remove.size() == 0) {
2505 auto [h_faces_to_remove, h_tets_to_remove] =
2507 faces_to_remove = h_faces_to_remove;
2508 tets_to_remove = h_tets_to_remove;
2516 all_removed_faces.merge(faces_to_remove);
2517 all_removed_tets.merge(tets_to_remove);
2520 crack_faces_tets = subtract(crack_faces_tets, tets_to_remove);
2521 crack_faces_tets_faces =
2522 subtract(crack_faces_tets_faces, faces_to_remove);
2527 boost::lexical_cast<std::string>(counter) +
".vtk",
2530 "faces_to_remove_" +
2531 boost::lexical_cast<std::string>(counter) +
".vtk",
2535 boost::lexical_cast<std::string>(counter) +
".vtk",
2538 "crack_faces_tets_faces_" +
2539 boost::lexical_cast<std::string>(counter) +
".vtk",
2540 crack_faces_tets_faces);
2542 "crack_faces_tets_" +
2543 boost::lexical_cast<std::string>(counter) +
".vtk",
2549 auto cese_internal_faces = [&]() {
2551 auto skin_tets = get_skin(mField, crack_faces_tets);
2552 auto adj_faces = get_adj(skin_tets, 2, moab::Interface::UNION);
2554 subtract(adj_faces, skin_tets);
2555 auto adj_tets = get_adj(adj_faces, 3,
2556 moab::Interface::UNION);
2559 subtract(crack_faces_tets,
2562 crack_faces_tets_faces =
2563 subtract(crack_faces_tets_faces, adj_faces);
2565 all_removed_faces.merge(adj_faces);
2566 all_removed_tets.merge(adj_tets);
2569 <<
"Remove internal faces size " << adj_faces.size()
2570 <<
" tets size " << adj_tets.size();
2574 auto case_only_one_free_edge = [&]() {
2577 for (
auto t :
Range(crack_faces_tets)) {
2579 auto adj_faces = get_adj(
2581 moab::Interface::UNION);
2582 auto crack_surface_edges =
2583 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
2586 moab::Interface::UNION);
2589 subtract(get_adj(
Range(
t,
t), 1, moab::Interface::INTERSECT),
2590 crack_surface_edges);
2591 adj_edges = subtract(
2593 boundary_tets_edges);
2595 if (adj_edges.size() == 1) {
2597 subtract(crack_faces_tets,
2601 auto faces_to_remove =
2602 get_adj(adj_edges, 2, moab::Interface::UNION);
2605 crack_faces_tets_faces =
2606 subtract(crack_faces_tets_faces, faces_to_remove);
2608 all_removed_faces.merge(faces_to_remove);
2609 all_removed_tets.merge(
Range(
t,
t));
2611 MOFEM_LOG(
"EPSELF", Sev::inform) <<
"Remove free one edges ";
2615 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
2616 crack_faces_tets_faces =
2617 subtract(crack_faces_tets_faces, all_removed_faces);
2622 auto cese_flat_tet = [&](
auto max_adj_edges) {
2628 auto body_skin = get_skin(mField, body_ents);
2629 auto body_skin_edges =
2630 get_adj(body_skin, 1, moab::Interface::UNION);
2632 for (
auto t :
Range(crack_faces_tets)) {
2634 auto adj_faces = get_adj(
2636 moab::Interface::UNION);
2637 auto crack_surface_edges =
2638 get_adj(subtract(unite(crack_faces_tets_faces, crack_faces),
2641 moab::Interface::UNION);
2644 subtract(get_adj(
Range(
t,
t), 1, moab::Interface::INTERSECT),
2645 crack_surface_edges);
2646 adj_edges = subtract(adj_edges, body_skin_edges);
2648 auto tet_edges = get_adj(
Range(
t,
t), 1,
2649 moab::Interface::UNION);
2651 tet_edges = subtract(tet_edges, adj_edges);
2653 for (
auto e : tet_edges) {
2654 constexpr int opposite_edge[] = {5, 3, 4, 1, 2, 0};
2655 auto get_side = [&](
auto e) {
2656 int side, sense, offset;
2658 mField.get_moab().side_number(
t, e, side, sense, offset),
2659 "get side number failed");
2662 auto get_side_ent = [&](
auto side) {
2665 mField.get_moab().side_element(
t, 1, side, side_edge),
2669 adj_edges.erase(get_side_ent(opposite_edge[get_side(e)]));
2672 if (adj_edges.size() <= max_adj_edges) {
2675 Range faces_to_remove;
2676 for (
auto e : adj_edges) {
2677 auto edge_adj_faces =
2678 get_adj(
Range(e, e), 2, moab::Interface::UNION);
2679 edge_adj_faces = intersect(edge_adj_faces, adj_faces);
2680 if (edge_adj_faces.size() != 2) {
2682 "Adj faces size is not 2 for edge " +
2683 boost::lexical_cast<std::string>(e));
2686 auto get_normal = [&](
auto f) {
2689 mField.getInterface<Tools>()->getTriNormal(f, &t_n(0)),
2690 "get tri normal failed");
2693 auto t_n0 = get_normal(edge_adj_faces[0]);
2694 auto t_n1 = get_normal(edge_adj_faces[1]);
2695 auto get_sense = [&](
auto f) {
2696 int side, sense, offset;
2699 "get side number failed");
2702 auto sense0 = get_sense(edge_adj_faces[0]);
2703 auto sense1 = get_sense(edge_adj_faces[1]);
2708 auto dot_e = (sense0 * sense1) * t_n0(
i) * t_n1(
i);
2709 if (dot_e < dot || e == adj_edges[0]) {
2711 faces_to_remove = edge_adj_faces;
2715 all_removed_faces.merge(faces_to_remove);
2716 all_removed_tets.merge(
Range(
t,
t));
2719 <<
"Remove free edges on flat tet, with considered nb. of "
2721 << adj_edges.size();
2725 crack_faces_tets = subtract(crack_faces_tets, all_removed_tets);
2726 crack_faces_tets_faces =
2727 subtract(crack_faces_tets_faces, all_removed_faces);
2733 "Case only one free edge failed");
2734 for (
auto max_adj_edges : {0, 1, 2, 3}) {
2736 "Case only one free edge failed");
2739 "Case internal faces failed");
2743 "crack_faces_tets_faces_" +
2744 boost::lexical_cast<std::string>(counter) +
".vtk",
2745 crack_faces_tets_faces);
2747 "crack_faces_tets_" +
2748 boost::lexical_cast<std::string>(counter) +
".vtk",
2752 return std::make_tuple(crack_faces_tets_faces, crack_faces_tets,
2753 all_removed_faces, all_removed_tets);
2756 auto [resolved_faces, resolved_tets, all_removed_faces,
2758 resolve_surface(boundary_tets_edges, crack_faces_tets);
2759 resolved_faces.merge(subtract(crack_faces, all_removed_faces));
2767 crack_faces = resolved_faces;
2778 auto resolve_consisten_crack_extension = [&]() {
2780 auto crack_meshset =
2781 mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2783 auto meshset = crack_meshset->getMeshset();
2785 if (!mField.get_comm_rank()) {
2786 Range old_crack_faces;
2787 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
2789 auto extendeded_crack_faces = get_extended_crack_faces();
2790 auto reconstructed_crack_faces =
2791 subtract(reconstruct_crack_faces(extendeded_crack_faces),
2792 subtract(*crackFaces, old_crack_faces));
2793 if (nbCrackFaces >= reconstructed_crack_faces.size()) {
2795 <<
"No new crack faces to add, skipping adding to meshset";
2796 extendeded_crack_faces = subtract(
2797 extendeded_crack_faces, subtract(*crackFaces, old_crack_faces));
2799 <<
"Number crack faces size (extended) "
2800 << extendeded_crack_faces.size();
2801 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2802 CHKERR mField.get_moab().add_entities(meshset, extendeded_crack_faces);
2804 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2805 CHKERR mField.get_moab().add_entities(meshset,
2806 reconstructed_crack_faces);
2808 <<
"Number crack faces size (reconstructed) "
2809 << reconstructed_crack_faces.size();
2810 nbCrackFaces = reconstructed_crack_faces.size();
2815 if (!mField.get_comm_rank()) {
2816 CHKERR mField.get_moab().get_entities_by_type(meshset, MBTRI,
2819 crack_faces =
send_type(mField, crack_faces, MBTRI);
2820 if (mField.get_comm_rank()) {
2821 CHKERR mField.get_moab().clear_meshset(&meshset, 1);
2822 CHKERR mField.get_moab().add_entities(meshset, crack_faces);
2828 CHKERR resolve_consisten_crack_extension();