Iterate over front edges, get adjacent faces, find maximal face energy. Maximal face energy is stored in the edge. Maximal face energy is magnitude of edge Griffith force.
For each front edge, find maximal face energy and orientation. This is by finding angle between edge material force and maximal face normal
4930 {
4932
4933 constexpr bool debug =
false;
4934 constexpr auto sev = Sev::verbose;
4935
4939 Range body_skin_edges;
4941 moab::Interface::UNION);
4942 Range boundary_skin_verts;
4944 boundary_skin_verts, true);
4945
4947 Range geometry_edges_verts;
4949 geometry_edges_verts, true);
4950 Range crack_faces_verts;
4952 true);
4953 Range crack_faces_edges;
4955 *
crackFaces, 1,
true, crack_faces_edges, moab::Interface::UNION);
4956 Range crack_faces_tets;
4958 *
crackFaces, 3,
true, crack_faces_tets, moab::Interface::UNION);
4959
4964 moab::Interface::UNION);
4965 Range front_verts_edges;
4967 front_verts, 1, true, front_verts_edges, moab::Interface::UNION);
4968
4969 auto get_tags_vec = [&](auto tag_name, int dim) {
4970 std::vector<Tag> tags(1);
4971
4972 if (dim > 3)
4974
4975 auto create_and_clean = [&]() {
4978 auto rval = moab.tag_get_handle(tag_name, tags[0]);
4979 if (
rval == MB_SUCCESS) {
4980 moab.tag_delete(tags[0]);
4981 }
4982 double def_val[] = {0., 0., 0.};
4983 CHKERR moab.tag_get_handle(tag_name, dim, MB_TYPE_DOUBLE, tags[0],
4984 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
4986 };
4987
4989
4990 return tags;
4991 };
4992
4993 auto get_adj_front = [&](bool subtract_crack) {
4996 adj_front, moab::Interface::UNION);
4997 if (subtract_crack)
4998 adj_front = subtract(adj_front, *
crackFaces);
4999 return adj_front;
5000 };
5001
5003
5004 auto th_front_position = get_tags_vec("FrontPosition", 3);
5005 auto th_max_face_energy = get_tags_vec("MaxFaceEnergy", 1);
5006
5008
5009 auto get_crack_adj_tets = [&](
auto r) {
5010 Range crack_faces_conn;
5012 Range crack_faces_conn_tets;
5014 true, crack_faces_conn_tets,
5015 moab::Interface::UNION);
5016 return crack_faces_conn_tets;
5017 };
5018
5019 auto get_layers_for_sides = [&](auto &side) {
5020 std::vector<Range> layers;
5021 auto get = [&]() {
5023
5024 auto get_adj = [&](
auto &
r,
int dim) {
5027 moab::Interface::UNION);
5028 return adj;
5029 };
5030
5031 auto get_tets = [&](
auto r) {
return get_adj(r,
SPACE_DIM); };
5032
5035 true);
5036 Range front_faces = get_adj(front_nodes, 2);
5037 front_faces = subtract(front_faces, *
crackFaces);
5038 auto front_tets = get_tets(front_nodes);
5039 auto front_side = intersect(side, front_tets);
5040 layers.push_back(front_side);
5041 for (;;) {
5043 adj_faces = intersect(adj_faces, front_faces);
5044 auto adj_faces_tets = get_tets(adj_faces);
5045 adj_faces_tets = intersect(adj_faces_tets, front_tets);
5046 layers.push_back(unite(layers.back(), adj_faces_tets));
5047 if (layers.back().size() == layers[layers.size() - 2].size()) {
5048 break;
5049 }
5050 }
5052 };
5054 return layers;
5055 };
5056
5058 auto layers_top = get_layers_for_sides(sides_pair.first);
5059 auto layers_bottom = get_layers_for_sides(sides_pair.second);
5060
5061#ifndef NDEBUG
5065 "crack_tets_" +
5070 sides_pair.second);
5071 MOFEM_LOG(
"EP", sev) <<
"Nb. layers " << layers_top.size();
5073 for (auto &r : layers_top) {
5074 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " <<
r.size();
5077 "layers_top_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
5079 }
5080
5082 for (auto &r : layers_bottom) {
5083 MOFEM_LOG(
"EP", sev) <<
"Layer " <<
l <<
" size " <<
r.size();
5086 "layers_bottom_" + boost::lexical_cast<std::string>(
l) +
".vtk", r);
5088 }
5089 }
5090#endif
5091
5092 auto get_cross = [&](
auto t_dir,
auto f) {
5101 return t_cross;
5102 };
5103
5104 auto get_sense = [&](
auto f,
auto e) {
5105 int side, sense, offset;
5107 "get sense");
5108 return std::make_tuple(side, sense, offset);
5109 };
5110
5111 auto calculate_edge_direction = [&](auto e, auto normalize = true) {
5113 int num_nodes;
5115 std::array<double, 6> coords;
5118 &coords[0], &coords[1], &coords[2]};
5120 &coords[3], &coords[4], &coords[5]};
5123 t_dir(
i) = t_p1(
i) - t_p0(
i);
5124 if (normalize)
5126 return t_dir;
5127 };
5128
5129 auto evaluate_face_energy_and_set_orientation = [&](auto front_edges,
5130 auto front_faces,
5131 auto &sides_pair,
5132 auto th_position) {
5134
5136 Tag th_material_force;
5141 th_face_energy);
5143 th_material_force);
5144 break;
5145 default:
5146 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
5147 "Unknown energy release selector");
5148 };
5149
5150
5151
5152
5153
5154
5155 auto find_maximal_face_energy = [&](auto front_edges, auto front_faces,
5156 auto &edge_face_max_energy_map) {
5158
5162
5164
5165 for (auto e : front_edges) {
5166
5167 double griffith_force;
5169 &griffith_force);
5170
5173 faces = subtract(intersect(faces, front_faces), body_skin);
5174 std::vector<double> face_energy(faces.size());
5176 face_energy.data());
5177 auto max_energy_it =
5178 std::max_element(face_energy.begin(), face_energy.end());
5179 double max_energy =
5180 max_energy_it != face_energy.end() ? *max_energy_it : 0;
5181
5182 edge_face_max_energy_map[e] =
5183 std::make_tuple(faces[max_energy_it - face_energy.begin()],
5184 griffith_force, static_cast<double>(0));
5186 << "Edge " << e << " griffith force " << griffith_force
5187 << " max face energy " << max_energy << " factor "
5188 << max_energy / griffith_force;
5189
5190 max_faces.insert(faces[max_energy_it - face_energy.begin()]);
5191 }
5192
5193#ifndef NDEBUG
5197 "max_faces_" +
5199 ".vtk",
5200 max_faces);
5201 }
5202#endif
5203
5205 };
5206
5207
5208
5209
5210
5211
5212 auto calculate_face_orientation = [&](auto &edge_face_max_energy_map) {
5214
5215 auto up_down_face = [&](
5216
5217 auto &face_angle_map_up,
5218 auto &face_angle_map_down
5219
5220 ) {
5222
5223 for (
auto &
m : edge_face_max_energy_map) {
5225 auto [max_face, energy, opt_angle] =
m.second;
5226
5229 faces = intersect(faces, front_faces);
5232 false, adj_tets,
5233 moab::Interface::UNION);
5234 if (adj_tets.size()) {
5235
5238 false, adj_tets,
5239 moab::Interface::UNION);
5240 if (adj_tets.size()) {
5241
5242 Range adj_tets_faces;
5243
5245 adj_tets,
SPACE_DIM - 1,
false, adj_tets_faces,
5246 moab::Interface::UNION);
5247 adj_tets_faces = intersect(adj_tets_faces, faces);
5249
5250
5251 auto t_cross_max =
5252 get_cross(calculate_edge_direction(e, true), max_face);
5253 auto [side_max, sense_max, offset_max] = get_sense(max_face, e);
5254 t_cross_max(
i) *= sense_max;
5255
5256 for (
auto t : adj_tets) {
5257 Range adj_tets_faces;
5259 &
t, 1,
SPACE_DIM - 1,
false, adj_tets_faces);
5260 adj_tets_faces = intersect(adj_tets_faces, faces);
5261 adj_tets_faces =
5262 subtract(adj_tets_faces,
Range(max_face, max_face));
5263
5264 if (adj_tets_faces.size() == 1) {
5265
5266
5267
5268 auto t_cross = get_cross(calculate_edge_direction(e, true),
5269 adj_tets_faces[0]);
5270 auto [side, sense, offset] =
5271 get_sense(adj_tets_faces[0], e);
5272 t_cross(
i) *= sense;
5273 double dot = t_cross(
i) * t_cross_max(
i);
5274 auto angle = std::acos(dot);
5275
5276 double face_energy;
5278 th_face_energy, adj_tets_faces, &face_energy);
5279
5280 auto [side_face, sense_face, offset_face] =
5281 get_sense(
t, max_face);
5282
5283 if (sense_face > 0) {
5284 face_angle_map_up[e] = std::make_tuple(face_energy, angle,
5285 adj_tets_faces[0]);
5286
5287 } else {
5288 face_angle_map_down[e] = std::make_tuple(
5289 face_energy, -angle, adj_tets_faces[0]);
5290 }
5291 }
5292 }
5293 }
5294 }
5295 }
5296
5298 };
5299
5300 auto calc_optimal_angle = [&](
5301
5302 auto &face_angle_map_up,
5303 auto &face_angle_map_down
5304
5305 ) {
5307
5308 for (
auto &
m : edge_face_max_energy_map) {
5310 auto &[max_face, e0,
a0] =
m.second;
5311
5312 if (std::abs(e0) > std::numeric_limits<double>::epsilon()) {
5313
5314 if (face_angle_map_up.find(e) == face_angle_map_up.end() ||
5315 face_angle_map_down.find(e) == face_angle_map_down.end()) {
5316
5317 } else {
5318
5322
5323 Tag th_material_force;
5325 th_material_force);
5328 th_material_force, &e, 1, &t_material_force(0));
5329 auto material_force_magnitude = t_material_force.
l2();
5330 if (material_force_magnitude <
5331 std::numeric_limits<double>::epsilon()) {
5333
5334 } else {
5335
5336 auto t_edge_dir = calculate_edge_direction(e, true);
5337 auto t_cross_max = get_cross(t_edge_dir, max_face);
5338 auto [side, sense, offset] = get_sense(max_face, e);
5339 t_cross_max(sense) *= sense;
5340
5344
5346 t_cross_max.normalize();
5349 t_material_force(
J) * t_cross_max(
K);
5350 a0 = -std::asin(t_cross(
I) * t_edge_dir(
I));
5351
5353 <<
"Optimal angle " <<
a0 <<
" energy " << e0;
5354 }
5355 break;
5356 }
5357 default: {
5358
5359 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
5360 "Unknown energy release selector");
5361 }
5362 }
5363 }
5364 }
5365 }
5366
5368 };
5369
5370 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
5371 face_angle_map_up;
5372 std::map<EntityHandle, std::tuple<double, double, EntityHandle>>
5373 face_angle_map_down;
5374 CHKERR up_down_face(face_angle_map_up, face_angle_map_down);
5375 CHKERR calc_optimal_angle(face_angle_map_up, face_angle_map_down);
5376
5377#ifndef NDEBUG
5379 auto th_angle = get_tags_vec("Angle", 1);
5381 for (
auto &
m : face_angle_map_up) {
5382 auto [e,
a, face] =
m.second;
5383 up.insert(face);
5385 }
5387 for (
auto &
m : face_angle_map_down) {
5388 auto [e,
a, face] =
m.second;
5389 down.insert(face);
5391 }
5392
5393 Range max_energy_faces;
5394 for (
auto &
m : edge_face_max_energy_map) {
5395 auto [face, e, angle] =
m.second;
5396 max_energy_faces.insert(face);
5398 &angle);
5399 }
5404 max_energy_faces);
5405 }
5406 }
5407#endif
5408
5410 };
5411
5412 auto get_conn = [&](auto e) {
5415 "get conn");
5416 return conn;
5417 };
5418
5419 auto get_adj = [&](auto e, auto dim) {
5422 e, dim, false, adj, moab::Interface::UNION),
5423 "get adj");
5424 return adj;
5425 };
5426
5427 auto get_coords = [&](
auto v) {
5430 "get coords");
5431 return t_coords;
5432 };
5433
5434
5435 auto get_rotated_normal = [&](
auto e,
auto f,
auto angle) {
5438 auto t_edge_dir = calculate_edge_direction(e, true);
5439 auto [side, sense, offset] = get_sense(
f, e);
5440 t_edge_dir(
i) *= sense;
5441 t_edge_dir.normalize();
5442 t_edge_dir(
i) *= angle;
5447 t_rotated_normal(
i) = t_R(
i,
j) * t_normal(
j);
5448 return std::make_tuple(t_normal, t_rotated_normal);
5449 };
5450
5451 auto set_coord = [&](
auto v,
auto &adj_vertex_tets_verts,
auto &coords,
5452 auto &t_move, auto gamma) {
5453 auto index = adj_vertex_tets_verts.index(
v);
5454 if (index >= 0) {
5455 for (auto ii : {0, 1, 2}) {
5456 coords[3 * index + ii] += gamma * t_move(ii);
5457 }
5458 return true;
5459 }
5460 return false;
5461 };
5462
5463 auto tets_quality = [&](auto quality, auto &adj_vertex_tets_verts,
5464 auto &adj_vertex_tets, auto &coords) {
5465 for (
auto t : adj_vertex_tets) {
5467 int num_nodes;
5469 std::array<double, 12> tet_coords;
5470 for (
auto n = 0;
n != 4; ++
n) {
5471 auto index = adj_vertex_tets_verts.index(conn[
n]);
5472 if (index < 0) {
5474 }
5475 for (auto ii = 0; ii != 3; ++ii) {
5476 tet_coords[3 *
n + ii] = coords[3 * index + ii];
5477 }
5478 }
5480 if (!std::isnormal(q))
5481 q = -2;
5482 quality = std::min(quality, q);
5483 };
5484
5485 return quality;
5486 };
5487
5488 auto calculate_free_face_node_displacement =
5489 [&](auto &edge_face_max_energy_map) {
5490
5491 auto get_vertex_edges = [&](auto vertex) {
5493
5494 auto impl = [&]() {
5497 vertex_edges);
5498 vertex_edges = subtract(vertex_edges, front_verts_edges);
5499
5500 if (boundary_skin_verts.size() &&
5501 boundary_skin_verts.find(vertex[0]) !=
5502 boundary_skin_verts.end()) {
5503 MOFEM_LOG(
"EP", sev) <<
"Boundary vertex";
5504 vertex_edges = intersect(vertex_edges, body_skin_edges);
5505 }
5506 if (geometry_edges_verts.size() &&
5507 geometry_edges_verts.find(vertex[0]) !=
5508 geometry_edges_verts.end()) {
5509 MOFEM_LOG(
"EP", sev) <<
"Geometry edge vertex";
5510 vertex_edges = intersect(vertex_edges, geometry_edges);
5511 }
5512 if (crack_faces_verts.size() &&
5513 crack_faces_verts.find(vertex[0]) !=
5514 crack_faces_verts.end()) {
5515 MOFEM_LOG(
"EP", sev) <<
"Crack face vertex";
5516 vertex_edges = intersect(vertex_edges, crack_faces_edges);
5517 }
5519 };
5520
5522
5523 return vertex_edges;
5524 };
5525
5526
5527
5528 using Bundle = std::vector<
5529
5532
5533 >;
5534 std::map<EntityHandle, Bundle> edge_bundle_map;
5535
5536 for (
auto &
m : edge_face_max_energy_map) {
5537
5538 auto edge =
m.first;
5539 auto &[max_face, energy, opt_angle] =
m.second;
5540
5541
5542 auto [t_normal, t_rotated_normal] =
5543 get_rotated_normal(edge, max_face, opt_angle);
5544
5545 auto front_vertex = get_conn(
Range(
m.first,
m.first));
5546 auto adj_tets = get_adj(
Range(max_face, max_face), 3);
5547 auto adj_tets_faces = get_adj(adj_tets, 2);
5548 auto adj_front_faces = subtract(
5549 intersect(get_adj(
Range(edge, edge), 2), adj_tets_faces),
5551 if (adj_front_faces.size() > 3)
5553 "adj_front_faces.size()>3");
5554
5557 &t_material_force(0));
5558 std::vector<double> griffith_energy(adj_front_faces.size());
5560 th_face_energy, adj_front_faces, griffith_energy.data());
5561
5562
5563 auto set_edge_bundle = [&](auto min_gamma) {
5564 for (auto rotated_f : adj_front_faces) {
5565
5566 double rotated_face_energy =
5567 griffith_energy[adj_front_faces.index(rotated_f)];
5568
5569 auto vertex = subtract(get_conn(
Range(rotated_f, rotated_f)),
5570 front_vertex);
5571 if (vertex.size() != 1) {
5573 "Wrong number of vertex to move");
5574 }
5575 auto front_vertex_edges_vertex = get_conn(
5576 intersect(get_adj(front_vertex, 1), crack_faces_edges));
5577 vertex = subtract(
5578 vertex, front_vertex_edges_vertex);
5579 if (vertex.empty()) {
5580 continue;
5581 }
5582
5583 auto face_cardinality = [&](
auto f,
auto &seen_front_edges) {
5584 auto whole_front =
5586 subtract(body_skin_edges, crack_faces_edges));
5589 for (;
c < 10; ++
c) {
5590 auto front_edges =
5591 subtract(get_adj(faces, 1), seen_front_edges);
5592 if (front_edges.size() == 0) {
5593 return 0;
5594 }
5595 auto front_connected_edges =
5596 intersect(front_edges, whole_front);
5597 if (front_connected_edges.size()) {
5598 seen_front_edges.merge(front_connected_edges);
5600 }
5601 faces.merge(get_adj(front_edges, 2));
5603 }
5605 };
5606
5608 double rotated_face_cardinality = face_cardinality(
5609 rotated_f,
5610 seen_edges);
5611
5612
5613
5614 rotated_face_cardinality = std::max(rotated_face_cardinality,
5615 1.);
5616
5617 auto t_vertex_coords = get_coords(vertex);
5618 auto vertex_edges = get_vertex_edges(vertex);
5619
5625
5627 for (auto e_used_to_move_detection : vertex_edges) {
5628 auto edge_conn = get_conn(
Range(e_used_to_move_detection,
5629 e_used_to_move_detection));
5630 edge_conn = subtract(edge_conn, vertex);
5631
5632
5633
5634
5635
5636
5637
5638
5640 t_v0(
i) = (t_v_e0(
i) + t_v_e1(
i)) / 2;
5644 (t_v0(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
5645 auto b =
5646 (t_v3(
i) - t_vertex_coords(
i)) * t_rotated_normal(
i);
5648
5649 constexpr double eps =
5650 std::numeric_limits<double>::epsilon();
5651 if (std::isnormal(gamma) && gamma < 1.0 -
eps &&
5652 gamma > -0.1) {
5654 t_move(
i) = gamma * (t_v3(
i) - t_vertex_coords(
i));
5655
5656 auto check_rotated_face_directoon = [&]() {
5658 t_delta(
i) = t_vertex_coords(
i) + t_move(
i) - t_v0(
i);
5660 auto dot =
5661 (t_material_force(
i) / t_material_force.
l2()) *
5663 return -dot > 0 ? true : false;
5664 };
5665
5666 if (check_rotated_face_directoon()) {
5667
5669 << "Crack edge " << edge << " moved face "
5670 << rotated_f
5671 << " edge: " << e_used_to_move_detection
5672 << " face direction/energy " << rotated_face_energy
5673 << " face cardinality " << rotated_face_cardinality
5674 << " gamma: " << gamma;
5675
5676 auto &bundle = edge_bundle_map[edge];
5677 bundle.emplace_back(rotated_f, e_used_to_move_detection,
5678 vertex[0], t_move, 1,
5679 rotated_face_cardinality, gamma);
5680 }
5681 }
5682 }
5683 }
5684 };
5685
5686 set_edge_bundle(std::numeric_limits<double>::epsilon());
5687 if (edge_bundle_map[edge].empty()) {
5688 set_edge_bundle(-1.);
5689 }
5690 }
5691
5692 return edge_bundle_map;
5693 };
5694
5695 auto get_sort_by_energy = [&](auto &edge_face_max_energy_map) {
5696 std::map<double, std::tuple<EntityHandle, EntityHandle, double>>
5697 sort_by_energy;
5698
5699 for (
auto &
m : edge_face_max_energy_map) {
5701 auto &[max_face, energy, opt_angle] =
m.second;
5702 sort_by_energy[energy] = std::make_tuple(e, max_face, opt_angle);
5703 }
5704
5705 return sort_by_energy;
5706 };
5707
5708 auto set_tag = [&](auto &&adj_edges_map, auto &&sort_by_energy) {
5710
5711 Tag th_face_pressure;
5713 mField.
get_moab().tag_get_handle(
"FacePressure", th_face_pressure),
5714 "get tag");
5715 auto get_face_pressure = [&](auto face) {
5716 double pressure;
5718 1, &pressure),
5719 "get rag data");
5720 return pressure;
5721 };
5722
5724 << "Number of edges to check " << sort_by_energy.size();
5725
5726 enum face_energy { POSITIVE, NEGATIVE };
5727 constexpr bool skip_negative = true;
5728
5729 for (auto fe : {face_energy::POSITIVE, face_energy::NEGATIVE}) {
5730
5731
5732
5733 for (auto it = sort_by_energy.rbegin(); it != sort_by_energy.rend();
5734 ++it) {
5735
5736 auto energy = it->first;
5737 auto [max_edge, max_face, opt_angle] = it->second;
5738
5739 auto face_pressure = get_face_pressure(max_face);
5740 if (skip_negative) {
5741 if (fe == face_energy::POSITIVE) {
5742 if (face_pressure < 0) {
5744 << "Skip negative face " << max_face << " with energy "
5745 << energy << " and pressure " << face_pressure;
5746 continue;
5747 }
5748 }
5749 }
5750
5752 << "Check face " << max_face << " edge " << max_edge
5753 << " energy " << energy << " optimal angle " << opt_angle
5754 << " face pressure " << face_pressure;
5755
5756 auto jt = adj_edges_map.find(max_edge);
5757 if (jt == adj_edges_map.end()) {
5759 << "Edge " << max_edge << " not found in adj_edges_map";
5760 continue;
5761 }
5762 auto &bundle = jt->second;
5763
5764 auto find_max_in_bundle_impl = [&](auto edge, auto &bundle,
5765 auto gamma) {
5767
5771 double max_quality = -2;
5772 double max_quality_evaluated = -2;
5773 double min_cardinality = std::numeric_limits<double>::max();
5774
5776
5777 for (auto &b : bundle) {
5778 auto &[face, move_edge, vertex, t_move, quality, cardinality,
5779 edge_gamma] = b;
5780
5781 auto adj_vertex_tets = get_adj(
Range(vertex, vertex), 3);
5782 auto adj_vertex_tets_verts = get_conn(adj_vertex_tets);
5783 std::vector<double> coords(3 * adj_vertex_tets_verts.size());
5785 adj_vertex_tets_verts, coords.data()),
5786 "get coords");
5787
5788 set_coord(vertex, adj_vertex_tets_verts, coords, t_move, gamma);
5789 quality = tets_quality(quality, adj_vertex_tets_verts,
5790 adj_vertex_tets, coords);
5791
5792 auto eval_quality = [](
auto q,
auto c,
auto edge_gamma) {
5793 if (q < 0) {
5794 return q;
5795 } else {
5796 return ((edge_gamma < 0) ? (q / 2) : q) / pow(
c, 2);
5797 }
5798 };
5799
5800 if (eval_quality(quality, cardinality, edge_gamma) >=
5801 max_quality_evaluated) {
5802 max_quality = quality;
5803 min_cardinality = cardinality;
5804 vertex_max = vertex;
5805 face_max = face;
5806 move_edge_max = move_edge;
5807 t_move_last(
i) = t_move(
i);
5808 max_quality_evaluated =
5809 eval_quality(max_quality, min_cardinality, edge_gamma);
5810 }
5811 }
5812
5813 return std::make_tuple(vertex_max, face_max, t_move_last,
5814 max_quality, min_cardinality);
5815 };
5816
5817 auto find_max_in_bundle = [&](auto edge, auto &bundle) {
5818 auto b_org_bundle = bundle;
5819 auto r = find_max_in_bundle_impl(edge, bundle, 1.);
5820 auto &[vertex_max, face_max, t_move_last, max_quality,
5822 if (max_quality < 0) {
5823 for (double gamma = 0.95; gamma >= 0.45; gamma -= 0.05) {
5824 bundle = b_org_bundle;
5825 r = find_max_in_bundle_impl(edge, bundle, gamma);
5826 auto &[vertex_max, face_max, t_move_last, max_quality,
5829 << "Back tracking: gamma " << gamma << " edge " << edge
5830 << " quality " << max_quality << " cardinality "
5831 << cardinality;
5832 if (max_quality > 0.01) {
5834 t_move_last(
I) *= gamma;
5836 }
5837 }
5840 }
5842 };
5843
5844
5845 auto set_tag_to_vertex_and_face = [&](
auto &&
r,
auto &quality) {
5847 auto &[
v,
f, t_move, q, cardinality] =
r;
5848
5849 if ((q > 0 && std::isnormal(q)) && energy > 0) {
5850
5852 <<
"Set tag: vertex " <<
v <<
" face " <<
f <<
" "
5853 << max_edge << " move " << t_move << " energy " << energy
5854 << " quality " << q << " cardinality " << cardinality;
5856 &t_move(0));
5858 1, &energy);
5859 }
5860
5861 quality = q;
5863 };
5864
5865 double quality = -2;
5866 CHKERR set_tag_to_vertex_and_face(
5867
5868 find_max_in_bundle(max_edge, bundle),
5869
5870 quality
5871
5872 );
5873
5874 if (quality > 0 && std::isnormal(quality) && energy > 0) {
5876 << "Crack face set with quality: " << quality;
5878 }
5879 }
5880
5881 if (!skip_negative)
5882 break;
5883 }
5884
5886 };
5887
5888
5889 MOFEM_LOG(
"EP", sev) <<
"Calculate orientation";
5890 std::map<EntityHandle, std::tuple<EntityHandle, double, double>>
5891 edge_face_max_energy_map;
5892 CHKERR find_maximal_face_energy(front_edges, front_faces,
5893 edge_face_max_energy_map);
5894 CHKERR calculate_face_orientation(edge_face_max_energy_map);
5895
5896 MOFEM_LOG(
"EP", sev) <<
"Calculate node positions";
5898
5899 calculate_free_face_node_displacement(edge_face_max_energy_map),
5900 get_sort_by_energy(edge_face_max_energy_map)
5901
5902 );
5903
5905 };
5906
5908 CHKERR evaluate_face_energy_and_set_orientation(
5909 *
frontEdges, get_adj_front(
false), sides_pair, th_front_position);
5910 }
5911
5912
5915 SCATTER_FORWARD);
5917 SCATTER_FORWARD);
5922 SCATTER_FORWARD);
5926
5927 auto get_max_moved_faces = [&]() {
5928 Range max_moved_faces;
5929 auto adj_front = get_adj_front(false);
5930 std::vector<double> face_energy(adj_front.size());
5932 face_energy.data());
5933 for (
int i = 0;
i != adj_front.size(); ++
i) {
5934 if (face_energy[
i] > std::numeric_limits<double>::epsilon()) {
5935 max_moved_faces.insert(adj_front[
i]);
5936 }
5937 }
5938
5939 return boost::make_shared<Range>(max_moved_faces);
5940 };
5941
5942
5945
5946#ifndef NDEBUG
5950 "max_moved_faces_" +
5953 }
5954#endif
5955
5957}
static auto get_two_sides_of_crack_surface(MoFEM::Interface &m_field, Range crack_faces)
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ MOFEM_ATOM_TEST_INVALID
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
const double c
speed of light (cm/ns)
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
FTensor::Index< 'm', 3 > m
CommInterface::EntitiesPetscVector vertexExchange
static enum EnergyReleaseSelector energyReleaseSelector
static auto exp(A &&t_w_vee, B &&theta)