33 #include "libmesh/mesh_communication.h" 34 #include "libmesh/partitioner.h" 39 _debug_output_level(1),
40 _min_weight_multiplier(0.0)
42 #ifndef LIBMESH_ENABLE_UNIQUE_ID 43 mooseError(
"MOOSE requires unique ids to be enabled in libmesh (configure with " 44 "--enable-unique-id) to use XFEM!");
51 for (std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
_cut_elem_map.begin();
69 std::vector<Point> & crack_front_points)
71 elem_id_crack_tip.clear();
72 crack_front_points.clear();
75 unsigned int crack_tip_index = 0;
78 std::map<unsigned int, const Elem *> elem_id_map;
81 for (std::map<
const Elem *, std::vector<Point>>::iterator mit1 =
86 unsigned int elem_id = mit1->first->id();
87 if (elem_id == std::numeric_limits<unsigned int>::max())
89 elem_id_map[m] = mit1->first;
93 elem_id_map[elem_id] = mit1->first;
96 for (std::map<unsigned int, const Elem *>::iterator mit1 = elem_id_map.begin();
97 mit1 != elem_id_map.end();
100 const Elem * elem = mit1->second;
101 std::map<const Elem *, std::vector<Point>>::iterator mit2 =
105 elem_id_crack_tip[crack_tip_index] = mit2->first;
106 crack_front_points[crack_tip_index] =
116 Elem * elem =
_mesh->elem_ptr(elem_id);
117 std::map<const Elem *, RealVectorValue>::iterator mit;
120 mooseError(
" ERROR: element ", elem->id(),
" already marked for crack growth.");
128 Elem * elem =
_mesh->elem_ptr(elem_id);
129 std::map<const Elem *, unsigned int>::iterator mit;
132 mooseError(
" ERROR: side of element ", elem->id(),
" already marked for crack initiation.");
141 Elem * elem =
_mesh->elem_ptr(elem_id);
142 std::set<const Elem *>::iterator mit;
146 " ERROR: element ", elem->id(),
" already marked for fragment-secondary crack initiation.");
162 const unsigned int interface_id)
164 Elem * elem =
_mesh->elem_ptr(elem_id);
172 const unsigned int interface_id)
174 Elem * elem =
_mesh->elem_ptr(elem_id);
191 std::set<EFAElement *>::iterator sit;
192 for (sit = CrackTipElements.begin(); sit != CrackTipElements.end(); ++sit)
194 if (
_mesh->mesh_dimension() == 2)
200 Point origin(0, 0, 0);
201 Point direction(0, 0, 0);
203 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
215 std::vector<Point> tip_data;
216 tip_data.push_back(origin);
217 tip_data.push_back(direction);
218 const Elem * elem =
_mesh->elem_ptr((*sit)->id());
220 std::pair<
const Elem *, std::vector<Point>>(elem, tip_data));
228 bool mesh_changed =
false;
237 _mesh->update_parallel_id_counts();
238 MeshCommunication().make_elems_parallel_consistent(*
_mesh);
239 MeshCommunication().make_nodes_parallel_consistent(*
_mesh);
242 _mesh->allow_renumbering(
false);
243 _mesh->skip_partitioning(
true);
244 _mesh->prepare_for_use();
264 const std::vector<std::shared_ptr<NonlinearSystemBase>> & nl,
268 mooseError(
"Use of XFEM with distributed mesh is not yet supported");
270 bool mesh_changed =
false;
289 _mesh->allow_renumbering(
false);
290 _mesh->skip_partitioning(
true);
291 _mesh->prepare_for_use();
312 mooseError(
"XFEM does not currently support multiple nonlinear systems");
314 nls[0]->serializeSolution();
327 current_solution.
close();
328 old_solution.
close();
329 older_solution.
close();
330 current_aux_solution.
close();
331 old_aux_solution.
close();
332 older_aux_solution.
close();
344 for (
auto & elem :
_mesh->element_ptr_range())
346 std::vector<unsigned int> quad;
347 for (
unsigned int i = 0; i < elem->n_nodes(); ++i)
348 quad.push_back(elem->node_id(i));
350 if (
_mesh->mesh_dimension() == 2)
352 else if (
_mesh->mesh_dimension() == 3)
359 for (
auto & elem :
_mesh->element_ptr_range())
361 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
_cut_elem_map.find(elem->unique_id());
380 bool marked_sides =
false;
381 if (
_mesh->mesh_dimension() == 2)
386 else if (
_mesh->mesh_dimension() == 3)
397 bool marked_edges =
false;
398 bool marked_nodes =
false;
402 for (
const auto & gmei : gme.second)
406 for (
unsigned int i = 0; i < gmei._elem_cut_edges.size(); ++i)
409 gmei._elem_cut_edges[i]._host_side_id))
412 gmei._elem_cut_edges[i]._host_side_id,
413 gmei._elem_cut_edges[i]._distance);
418 for (
unsigned int i = 0; i < gmei._elem_cut_nodes.size(); ++i)
424 for (
unsigned int i = 0; i < gmei._frag_cut_edges.size();
428 gmei._frag_cut_edges[i]._host_side_id))
431 gmei._frag_cut_edges[i]._host_side_id,
432 gmei._frag_cut_edges[i]._distance))
443 return marked_edges || marked_nodes;
451 Point crack_tip_origin,
452 Point crack_tip_direction,
453 Real & distance_keep,
454 unsigned int & edge_id_keep,
457 std::vector<Point> edge_ends(2, Point(0.0, 0.0, 0.0));
458 Point edge1(0.0, 0.0, 0.0);
459 Point edge2(0.0, 0.0, 0.0);
460 Point left_angle(0.0, 0.0, 0.0);
461 Point right_angle(0.0, 0.0, 0.0);
462 Point left_angle_normal(0.0, 0.0, 0.0);
463 Point right_angle_normal(0.0, 0.0, 0.0);
464 Point crack_direction_normal(0.0, 0.0, 0.0);
465 Point edge1_to_tip(0.0, 0.0, 0.0);
466 Point edge2_to_tip(0.0, 0.0, 0.0);
467 Point edge1_to_tip_normal(0.0, 0.0, 0.0);
468 Point edge2_to_tip_normal(0.0, 0.0, 0.0);
470 Real cos_45 = std::cos(45.0 / 180.0 * 3.14159);
471 Real sin_45 = std::sin(45.0 / 180.0 * 3.14159);
473 left_angle(0) = cos_45 * crack_tip_direction(0) - sin_45 * crack_tip_direction(1);
474 left_angle(1) = sin_45 * crack_tip_direction(0) + cos_45 * crack_tip_direction(1);
476 right_angle(0) = cos_45 * crack_tip_direction(0) + sin_45 * crack_tip_direction(1);
477 right_angle(1) = -sin_45 * crack_tip_direction(0) + cos_45 * crack_tip_direction(1);
479 left_angle_normal(0) = -left_angle(1);
480 left_angle_normal(1) = left_angle(0);
482 right_angle_normal(0) = -right_angle(1);
483 right_angle_normal(1) = right_angle(0);
485 crack_direction_normal(0) = -crack_tip_direction(1);
486 crack_direction_normal(1) = crack_tip_direction(0);
488 Real angle_min = 0.0;
492 for (
unsigned int i = 0; i <
nsides; ++i)
499 edge1_to_tip = (edge_ends[0] * 0.95 + edge_ends[1] * 0.05) - crack_tip_origin;
500 edge2_to_tip = (edge_ends[0] * 0.05 + edge_ends[1] * 0.95) - crack_tip_origin;
502 edge1_to_tip /=
pow(edge1_to_tip.norm_sq(), 0.5);
503 edge2_to_tip /=
pow(edge2_to_tip.norm_sq(), 0.5);
505 edge1_to_tip_normal(0) = -edge1_to_tip(1);
506 edge1_to_tip_normal(1) = edge1_to_tip(0);
508 edge2_to_tip_normal(0) = -edge2_to_tip(1);
509 edge2_to_tip_normal(1) = edge2_to_tip(0);
511 Real angle_edge1_normal = edge1_to_tip_normal * normal;
512 Real angle_edge2_normal = edge2_to_tip_normal * normal;
514 if (std::abs(angle_edge1_normal) > std::abs(angle_min) &&
515 (edge1_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
518 distance_keep = 0.05;
519 normal_keep = edge1_to_tip_normal;
520 angle_min = angle_edge1_normal;
522 else if (std::abs(angle_edge2_normal) > std::abs(angle_min) &&
523 (edge2_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
526 distance_keep = 0.95;
527 normal_keep = edge2_to_tip_normal;
528 angle_min = angle_edge2_normal;
532 crack_tip_origin, left_angle_normal, edge_ends[0], edge_ends[1],
distance) &&
535 if (std::abs(left_angle_normal * normal) > std::abs(angle_min) &&
536 (edge1_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
540 normal_keep = left_angle_normal;
541 angle_min = left_angle_normal * normal;
545 crack_tip_origin, right_angle_normal, edge_ends[0], edge_ends[1],
distance) &&
548 if (std::abs(right_angle_normal * normal) > std::abs(angle_min) &&
549 (edge2_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
553 normal_keep = right_angle_normal;
554 angle_min = right_angle_normal * normal;
558 crack_direction_normal,
564 if (std::abs(crack_direction_normal * normal) > std::abs(angle_min) &&
565 (crack_tip_direction * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
569 normal_keep = crack_direction_normal;
570 angle_min = crack_direction_normal * normal;
577 if ((distance_keep - 0.05) < 0.0)
579 distance_keep = 0.05;
581 else if ((distance_keep - 0.95) > 0.0)
583 distance_keep = 0.95;
590 bool marked_edges =
false;
591 for (std::map<const Elem *, RealVectorValue>::iterator pmeit =
_state_marked_elems.begin();
595 const Elem * elem = pmeit->first;
600 if (volfrac_elem < 0.25)
609 unsigned int orig_cut_side_id = std::numeric_limits<unsigned int>::max();
610 Real orig_cut_distance = -1.0;
615 Point crack_tip_origin(0, 0, 0);
616 Point crack_tip_direction(0, 0, 0);
621 if (orig_cut_side_id <
nsides)
623 orig_edge = CEMElem->
getEdge(orig_cut_side_id);
627 mooseError(
"element ", elem->id(),
" has no valid crack-tip edge");
630 std::map<const Elem *, std::vector<Point>>::iterator ecodm =
634 crack_tip_origin = (ecodm->second)[0];
635 crack_tip_direction = (ecodm->second)[1];
638 mooseError(
"element ", elem->id(),
" cannot find its crack tip origin and direction.");
642 std::map<const Elem *, unsigned int>::iterator mit1;
644 std::set<const Elem *>::iterator mit2;
649 orig_cut_side_id = mit1->second;
653 orig_cut_distance = 0.5;
655 orig_edge = CEMElem->
getEdge(orig_cut_side_id);
658 Point elem_center(0.0, 0.0, 0.0);
660 for (
unsigned int i = 0; i <
nsides; ++i)
665 elem_center /=
nsides * 2.0;
669 crack_tip_origin = edge_center;
670 crack_tip_direction = elem_center - edge_center;
671 crack_tip_direction /=
pow(crack_tip_direction.norm_sq(), 0.5);
681 " flagged for a secondary crack, but has ",
685 if (interior_edge_id.size() == 1)
686 orig_cut_side_id = interior_edge_id[0];
690 orig_cut_distance = 0.5;
694 Point elem_center(0.0, 0.0, 0.0);
697 for (
unsigned int i = 0; i < nsides_frag; ++i)
704 elem_center /= nsides_frag * 2.0;
708 crack_tip_origin = edge_center;
709 crack_tip_direction = elem_center - edge_center;
710 crack_tip_direction /=
pow(crack_tip_direction.norm_sq(), 0.5);
715 " flagged for state-based growth, but has no edge intersections");
718 Point cut_origin(0.0, 0.0, 0.0);
722 mooseError(
"element ", elem->id(),
" does not have valid orig_node");
725 std::vector<Point> edge_ends(2, Point(0.0, 0.0, 0.0));
726 Point edge1(0.0, 0.0, 0.0);
727 Point edge2(0.0, 0.0, 0.0);
728 Point cut_edge_point(0.0, 0.0, 0.0);
729 bool find_compatible_direction =
false;
730 unsigned int edge_id_keep = 0;
731 Real distance_keep = 0.0;
732 Point normal_keep(0.0, 0.0, 0.0);
734 bool edge_cut =
false;
736 for (
unsigned int i = 0; i <
nsides; ++i)
743 crack_tip_origin, normal, edge_ends[0], edge_ends[1],
distance) &&
749 normal_keep = normal;
756 Point between_two_cuts = (cut_edge_point - crack_tip_origin);
757 between_two_cuts /=
pow(between_two_cuts.norm_sq(), 0.5);
758 Real angle_between_two_cuts = between_two_cuts * crack_tip_direction;
760 if (angle_between_two_cuts > std::cos(45.0 / 180.0 * 3.14159))
761 find_compatible_direction =
true;
763 if (!find_compatible_direction && edge_cut)
780 Point growth_direction(0.0, 0.0, 0.0);
782 growth_direction(0) = -normal_keep(1);
783 growth_direction(1) = normal_keep(0);
785 if (growth_direction * crack_tip_direction < 1.0e-10)
786 growth_direction *= (-1.0);
788 Real x0 = crack_tip_origin(0);
789 Real y0 = crack_tip_origin(1);
795 for (
const auto & elem :
_mesh->element_ptr_range())
797 std::vector<CutEdgeForCrackGrowthIncr> elem_cut_edges;
807 for (
unsigned int i = 0; i < elem_cut_edges.size(); ++i)
810 elem_cut_edges[i]._host_side_id))
813 elem->id(), elem_cut_edges[i]._host_side_id, elem_cut_edges[i]._distance);
832 crack_tip_origin, normal, edge_ends[0], edge_ends[1],
distance) &&
854 bool marked_faces =
false;
858 for (
const auto & gmei : gme.second)
862 for (
unsigned int i = 0; i < gmei._elem_cut_faces.size(); ++i)
864 if (!EFAElem->
isFacePhantom(gmei._elem_cut_faces[i]._face_id))
867 gmei._elem_cut_faces[i]._face_id,
868 gmei._elem_cut_faces[i]._face_edge,
869 gmei._elem_cut_faces[i]._position);
874 for (
unsigned int i = 0; i < gmei._frag_cut_faces.size();
880 gmei._frag_cut_faces[i]._face_id,
881 gmei._frag_cut_faces[i]._face_edge,
882 gmei._frag_cut_faces[i]._position);
895 bool marked_faces =
false;
902 Point cut_origin,
RealVectorValue cut_normal, Point & edge_p1, Point & edge_p2, Real & dist)
905 bool does_intersect =
false;
906 Point origin2p1 = edge_p1 - cut_origin;
907 Real plane2p1 = cut_normal(0) * origin2p1(0) + cut_normal(1) * origin2p1(1);
908 Point origin2p2 = edge_p2 - cut_origin;
909 Real plane2p2 = cut_normal(0) * origin2p2(0) + cut_normal(1) * origin2p2(1);
911 if (plane2p1 * plane2p2 < 0.0)
913 dist = -plane2p1 / (plane2p2 - plane2p1);
914 does_intersect =
true;
916 return does_intersect;
922 bool mesh_changed =
false;
924 std::set<Node *> nodes_to_delete;
925 std::set<Node *> nodes_to_delete_displaced;
926 std::set<unsigned int> cutelems_to_delete;
927 unsigned int deleted_elem_count = 0;
928 std::vector<std::string> healed_geometric_cuts;
937 Elem * elem1 =
const_cast<Elem *
>(it.first);
938 Elem * elem2 =
const_cast<Elem *
>(it.second);
940 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
946 cutelems_to_delete.insert(elem1->unique_id());
948 for (
unsigned int in = 0; in < elem1->n_nodes(); ++in)
950 Node * e1node = elem1->node_ptr(in);
951 Node * e2node = elem2->node_ptr(in);
955 elem1->set_node(in, e2node);
956 nodes_to_delete.insert(e1node);
958 else if (e1node != e2node)
959 nodes_to_delete.insert(e2node);
963 mooseError(
"Could not find XFEMCutElem for element to be kept in healing");
968 std::vector<const Elem *> healed_elems = {elem1, elem2};
974 for (
auto e : healed_elems)
975 if (elem1->processor_id() ==
_mesh->processor_id() &&
976 e->processor_id() ==
_mesh->processor_id())
984 if (parent_gcsid == gcsid)
993 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
999 for (
unsigned int in = 0; in < elem1_displaced->n_nodes(); ++in)
1001 Node * e1node_displaced = elem1_displaced->node_ptr(in);
1002 Node * e2node_displaced = elem2_displaced->node_ptr(in);
1004 e1node_displaced != e2node_displaced)
1006 elem1_displaced->set_node(in, e2node_displaced);
1007 nodes_to_delete_displaced.insert(e1node_displaced);
1009 else if (e1node_displaced != e2node_displaced)
1010 nodes_to_delete_displaced.insert(e2node_displaced);
1014 mooseError(
"Could not find XFEMCutElem for element to be kept in healing");
1016 elem2_displaced->nullify_neighbors();
1025 cutelems_to_delete.insert(elem2->unique_id());
1026 elem2->nullify_neighbors();
1027 _mesh->get_boundary_info().remove(elem2);
1028 unsigned int deleted_elem_id = elem2->id();
1029 _mesh->delete_elem(elem2);
1032 if (deleted_elem_count == 0)
1034 _console <<
"XFEM healing deleted element: " << deleted_elem_id << std::endl;
1036 ++deleted_elem_count;
1037 mesh_changed =
true;
1042 for (
auto & sit : nodes_to_delete)
1044 Node * node_to_delete = sit;
1045 dof_id_type deleted_node_id = node_to_delete->id();
1046 _mesh->get_boundary_info().remove(node_to_delete);
1047 _mesh->delete_node(node_to_delete);
1049 _console <<
"XFEM healing deleted node: " << deleted_node_id << std::endl;
1054 for (
auto & sit : nodes_to_delete_displaced)
1056 Node * node_to_delete_displaced = sit;
1057 _displaced_mesh->get_boundary_info().remove(node_to_delete_displaced);
1062 for (
auto & ced : cutelems_to_delete)
1090 _console <<
"\nXFEM mesh healing complete\n";
1091 _console <<
"Names of healed geometric cut objects: ";
1092 for (
auto geomcut : healed_geometric_cuts)
1095 _console <<
"# deleted nodes: " << nodes_to_delete.size() <<
"\n";
1096 _console <<
"# deleted elements: " << deleted_elem_count <<
"\n";
1100 return mesh_changed;
1107 if (nls.size() != 1)
1108 mooseError(
"XFEM does not currently support multiple nonlinear systems");
1110 std::map<unsigned int, Node *> efa_id_to_new_node;
1111 std::map<unsigned int, Node *> efa_id_to_new_node2;
1112 std::map<unsigned int, Elem *> efa_id_to_new_elem;
1125 _console <<
"\nXFEM Element fragment algorithm mesh prior to cutting:\n";
1134 _console <<
"\nXFEM Element fragment algorithm mesh after cutting:\n";
1143 bool mesh_changed = (new_nodes.size() + new_elements.size() + delete_elements.size() > 0);
1148 nls[0]->serializeSolution();
1160 std::map<Node *, Node *> new_nodes_to_parents;
1163 for (
unsigned int i = 0; i < new_nodes.size(); ++i)
1165 unsigned int new_node_id = new_nodes[i]->id();
1166 unsigned int parent_id = new_nodes[i]->parent()->id();
1168 Node * parent_node =
_mesh->node_ptr(parent_id);
1169 Node * new_node = Node::build(*parent_node,
_mesh->max_node_id()).release();
1170 _mesh->add_node(new_node);
1172 new_nodes_to_parents[new_node] = parent_node;
1174 new_node->set_n_systems(parent_node->n_systems());
1175 efa_id_to_new_node.insert(std::make_pair(new_node_id, new_node));
1177 _console <<
"XFEM added new node: " << new_node->id() << std::endl;
1181 Node * new_node2 = Node::build(*parent_node2,
_displaced_mesh->max_node_id()).release();
1184 new_node2->set_n_systems(parent_node2->n_systems());
1185 efa_id_to_new_node2.insert(std::make_pair(new_node_id, new_node2));
1190 std::map<unsigned int, std::vector<const Elem *>> temporary_parent_children_map;
1192 std::vector<boundary_id_type> parent_boundary_ids;
1194 for (
unsigned int i = 0; i < new_elements.size(); ++i)
1196 unsigned int parent_id = new_elements[i]->getParent()->id();
1197 unsigned int efa_child_id = new_elements[i]->id();
1199 Elem * parent_elem =
_mesh->elem_ptr(parent_id);
1200 Elem * libmesh_elem = Elem::build(parent_elem->type()).release();
1206 if (parent_elem == it.first)
1207 it.first = libmesh_elem;
1208 else if (parent_elem == it.second)
1209 it.second = libmesh_elem;
1214 if (new_elements[i]->getParent()->numChildren() > 1)
1215 temporary_parent_children_map[parent_elem->id()].push_back(libmesh_elem);
1217 Elem * parent_elem2 =
nullptr;
1218 Elem * libmesh_elem2 =
nullptr;
1222 libmesh_elem2 = Elem::build(parent_elem2->type()).release();
1228 if (parent_elem2 == it.first)
1229 it.first = libmesh_elem2;
1230 else if (parent_elem2 == it.second)
1231 it.second = libmesh_elem2;
1236 for (
unsigned int j = 0;
j < new_elements[i]->numNodes(); ++
j)
1238 unsigned int node_id = new_elements[i]->getNode(
j)->id();
1239 Node * libmesh_node;
1241 std::map<unsigned int, Node *>::iterator nit = efa_id_to_new_node.find(node_id);
1242 if (nit != efa_id_to_new_node.end())
1243 libmesh_node = nit->second;
1245 libmesh_node =
_mesh->node_ptr(node_id);
1247 if (libmesh_node->processor_id() == DofObject::invalid_processor_id)
1248 libmesh_node->processor_id() = parent_elem->processor_id();
1250 libmesh_elem->set_node(
j, libmesh_node);
1253 if (parent_elem->is_semilocal(
_mesh->processor_id()))
1255 Node * solution_node = libmesh_node;
1256 if (new_nodes_to_parents.find(libmesh_node) != new_nodes_to_parents.end())
1257 solution_node = new_nodes_to_parents[libmesh_node];
1260 (libmesh_node->processor_id() ==
_mesh->processor_id()))
1273 current_aux_solution,
1275 older_aux_solution);
1279 Node * parent_node = parent_elem->node_ptr(
j);
1280 _mesh->get_boundary_info().boundary_ids(parent_node, parent_boundary_ids);
1281 _mesh->get_boundary_info().add_node(libmesh_node, parent_boundary_ids);
1285 std::map<unsigned int, Node *>::iterator nit2 = efa_id_to_new_node2.find(node_id);
1286 if (nit2 != efa_id_to_new_node2.end())
1287 libmesh_node = nit2->second;
1291 if (libmesh_node->processor_id() == DofObject::invalid_processor_id)
1292 libmesh_node->processor_id() = parent_elem2->processor_id();
1294 libmesh_elem2->set_node(
j, libmesh_node);
1296 parent_node = parent_elem2->node_ptr(
j);
1297 _displaced_mesh->get_boundary_info().boundary_ids(parent_node, parent_boundary_ids);
1298 _displaced_mesh->get_boundary_info().add_node(libmesh_node, parent_boundary_ids);
1302 libmesh_elem->set_p_level(parent_elem->p_level());
1303 libmesh_elem->set_p_refinement_flag(parent_elem->p_refinement_flag());
1304 _mesh->add_elem(libmesh_elem);
1305 libmesh_elem->set_n_systems(parent_elem->n_systems());
1306 libmesh_elem->subdomain_id() = parent_elem->subdomain_id();
1307 libmesh_elem->processor_id() = parent_elem->processor_id();
1311 std::map<const Elem *, std::vector<Point>>::iterator mit =
1321 _console <<
"XFEM added new element: " << libmesh_elem->id() << std::endl;
1324 if (
_mesh->mesh_dimension() == 2)
1327 if (!new_efa_elem2d)
1328 mooseError(
"EFAelem is not of EFAelement2D type");
1332 libmesh_elem->n_sides());
1334 else if (
_mesh->mesh_dimension() == 3)
1337 if (!new_efa_elem3d)
1338 mooseError(
"EFAelem is not of EFAelement3D type");
1342 libmesh_elem->n_sides());
1344 _cut_elem_map.insert(std::pair<unique_id_type, XFEMCutElem *>(libmesh_elem->unique_id(), xfce));
1345 efa_id_to_new_elem.insert(std::make_pair(efa_child_id, libmesh_elem));
1349 libmesh_elem2->set_p_level(parent_elem2->p_level());
1350 libmesh_elem2->set_p_refinement_flag(parent_elem2->p_refinement_flag());
1352 libmesh_elem2->set_n_systems(parent_elem2->n_systems());
1353 libmesh_elem2->subdomain_id() = parent_elem2->subdomain_id();
1354 libmesh_elem2->processor_id() = parent_elem2->processor_id();
1357 unsigned int n_sides = parent_elem->n_sides();
1358 for (
unsigned int side = 0; side < n_sides; ++side)
1360 _mesh->get_boundary_info().boundary_ids(parent_elem, side, parent_boundary_ids);
1361 _mesh->get_boundary_info().add_side(libmesh_elem, side, parent_boundary_ids);
1365 n_sides = parent_elem2->n_sides();
1366 for (
unsigned int side = 0; side < n_sides; ++side)
1368 _displaced_mesh->get_boundary_info().boundary_ids(parent_elem2, side, parent_boundary_ids);
1369 _displaced_mesh->get_boundary_info().add_side(libmesh_elem2, side, parent_boundary_ids);
1373 unsigned int n_edges = parent_elem->n_edges();
1376 _mesh->get_boundary_info().edge_boundary_ids(parent_elem,
edge, parent_boundary_ids);
1377 _mesh->get_boundary_info().add_edge(libmesh_elem,
edge, parent_boundary_ids);
1381 n_edges = parent_elem2->n_edges();
1385 parent_elem2,
edge, parent_boundary_ids);
1391 if (parent_elem->processor_id() ==
_mesh->processor_id())
1393 if (
_material_data[0]->getMaterialPropertyStorage().hasStatefulProperties())
1397 for (
unsigned int side = 0; side < parent_elem->n_sides(); ++side)
1399 _mesh->get_boundary_info().boundary_ids(parent_elem, side, parent_boundary_ids);
1400 std::vector<boundary_id_type>::iterator it_bd = parent_boundary_ids.begin();
1401 for (; it_bd != parent_boundary_ids.end(); ++it_bd)
1421 if (cei.
match(old_cei.second))
1425 _console <<
"XFEM set material properties for element: " << libmesh_elem->id()
1443 current_aux_solution,
1445 older_aux_solution);
1450 for (std::size_t i = 0; i < delete_elements.size(); ++i)
1452 Elem * elem_to_delete =
_mesh->elem_ptr(delete_elements[i]->
id());
1455 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
1459 delete cemit->second;
1467 elem_to_delete->nullify_neighbors();
1468 _mesh->get_boundary_info().remove(elem_to_delete);
1469 unsigned int deleted_elem_id = elem_to_delete->id();
1470 _mesh->delete_elem(elem_to_delete);
1472 _console <<
"XFEM deleted element: " << deleted_elem_id << std::endl;
1476 Elem * elem_to_delete2 =
_displaced_mesh->elem_ptr(delete_elements[i]->
id());
1477 elem_to_delete2->nullify_neighbors();
1483 for (std::map<
unsigned int, std::vector<const Elem *>>::iterator it =
1484 temporary_parent_children_map.begin();
1485 it != temporary_parent_children_map.end();
1488 std::vector<const Elem *> & sibling_elem_vec = it->second;
1495 if (it->first == elem_id)
1497 std::make_pair(sibling_elem_vec[0], sibling_elem_vec[1]));
1510 std::make_pair(elem, elem_pair));
1516 temporary_parent_children_map.clear();
1524 std::set<EFAElement *>::const_iterator sit;
1525 for (sit = CrackTipElements.begin(); sit != CrackTipElements.end(); ++sit)
1527 unsigned int eid = (*sit)->id();
1528 Elem * crack_tip_elem;
1529 std::map<unsigned int, Elem *>::iterator eit = efa_id_to_new_elem.find(eid);
1530 if (eit != efa_id_to_new_elem.end())
1531 crack_tip_elem = eit->second;
1533 crack_tip_elem =
_mesh->elem_ptr(eid);
1542 if ((*sit)->getParent() !=
nullptr)
1544 if (
_mesh->mesh_dimension() == 2)
1548 mooseError(
"EFAelem is not of EFAelement2D type");
1550 for (
unsigned int edge_id = 0; edge_id < efa_elem2d->
numEdges(); ++edge_id)
1552 for (
unsigned int en_iter = 0; en_iter < efa_elem2d->
numEdgeNeighbors(edge_id);
1556 if (edge_neighbor !=
nullptr && edge_neighbor->
id() == mie)
1561 else if (
_mesh->mesh_dimension() == 3)
1565 mooseError(
"EFAelem is not of EFAelement3D type");
1567 for (
unsigned int face_id = 0; face_id < efa_elem3d->
numFaces(); ++face_id)
1569 for (
unsigned int fn_iter = 0; fn_iter < efa_elem3d->
numFaceNeighbors(face_id);
1573 if (face_neighbor !=
nullptr && face_neighbor->
id() == mie)
1586 _console <<
"\nXFEM mesh cutting with element fragment algorithm complete\n";
1587 _console <<
"# new nodes: " << new_nodes.size() <<
"\n";
1588 _console <<
"# new elements: " << new_elements.size() <<
"\n";
1589 _console <<
"# deleted elements: " << delete_elements.size() <<
"\n";
1595 return mesh_changed;
1602 MeshBase * displaced_mesh)
const 1604 Point node_coor(0.0, 0.0, 0.0);
1605 std::vector<EFANode *> master_nodes;
1606 std::vector<Point> master_points;
1607 std::vector<double> master_weights;
1609 CEMElem->
getMasterInfo(CEMnode, master_nodes, master_weights);
1610 for (std::size_t i = 0; i < master_nodes.size(); ++i)
1615 const Node * node = elem->node_ptr(local_node_id);
1617 node = displaced_mesh->node_ptr(node->id());
1618 Point node_p((*node)(0), (*node)(1), (*node)(2));
1619 master_points.push_back(node_p);
1622 mooseError(
"master nodes must be permanent");
1624 for (std::size_t i = 0; i < master_nodes.size(); ++i)
1625 node_coor += master_weights[i] * master_points[i];
1633 Real phys_volfrac = 1.0;
1634 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1647 return phys_volfrac;
1653 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1671 unsigned int plane_id)
const 1674 Point planedata(0.0, 0.0, 0.0);
1675 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1683 if ((
unsigned int)quantity < 3)
1685 unsigned int index = (
unsigned int)quantity;
1687 comp = planedata(index);
1689 else if ((
unsigned int)quantity < 6)
1691 unsigned int index = (
unsigned int)quantity - 3;
1693 comp = planedata(index);
1696 mooseError(
"In get_cut_plane index out of range");
1733 std::vector<std::vector<Point>> & frag_faces,
1734 bool displaced_mesh)
const 1736 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1755 mooseError(
"EFAelem is not of EFAelement2D type");
1767 mooseError(
"EFAelem is not of EFAelement3D type");
1775 std::vector<std::vector<Point>> & frag_edges)
const 1782 mooseError(
"element ", elem->id(),
" has more than one fragment at this point");
1785 std::vector<Point> p_line(2, Point(0.0, 0.0, 0.0));
1788 frag_edges.push_back(p_line);
1796 std::vector<std::vector<Point>> & frag_faces)
const 1803 mooseError(
"element ", elem->id(),
" has more than one fragment at this point");
1807 std::vector<Point> p_line(num_face_nodes, Point(0.0, 0.0, 0.0));
1808 for (
unsigned int j = 0;
j < num_face_nodes; ++
j)
1810 frag_faces.push_back(p_line);
1824 if (xfem_qrule ==
"volfrac")
1826 else if (xfem_qrule ==
"moment_fitting")
1828 else if (xfem_qrule ==
"direct")
1857 bool have_weights =
false;
1861 mooseAssert(xfce !=
nullptr,
"Must have valid XFEMCutElem object here");
1863 have_weights =
true;
1865 Real ave_weight_multiplier = 0;
1866 for (
unsigned int i = 0; i < weights.
size(); ++i)
1867 ave_weight_multiplier += weights[i];
1868 ave_weight_multiplier /= weights.
size();
1873 for (
unsigned int i = 0; i < weights.
size(); ++i)
1874 weights[i] += amount_to_add;
1877 return have_weights;
1887 bool have_weights =
false;
1891 mooseAssert(xfce !=
nullptr,
"Must have valid XFEMCutElem object here");
1893 have_weights =
true;
1895 return have_weights;
1900 unsigned int plane_id,
1902 std::vector<Point> & intersectionPoints,
1903 bool displaced_mesh)
const 1905 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1919 std::vector<Point> & quad_pts,
1920 std::vector<Real> & quad_wts)
const 1922 Point p1 = intersection_points[0];
1923 Point p2 = intersection_points[1];
1926 std::size_t num_qpoints = 2;
1929 Real xi0 = -std::sqrt(1.0 / 3.0);
1930 Real xi1 = std::sqrt(1.0 / 3.0);
1932 quad_wts.resize(num_qpoints);
1933 quad_pts.resize(num_qpoints);
1937 quad_wts[0] = 1.0 * integ_jacobian;
1938 quad_wts[1] = 1.0 * integ_jacobian;
1940 quad_pts[0] = (1.0 - xi0) / 2.0 * p1 + (1.0 + xi0) / 2.0 * p2;
1941 quad_pts[1] = (1.0 - xi1) / 2.0 * p1 + (1.0 + xi1) / 2.0 * p2;
1946 std::vector<Point> & quad_pts,
1947 std::vector<Real> & quad_wts)
const 1949 std::size_t nnd_pe = intersection_points.size();
1950 Point xcrd(0.0, 0.0, 0.0);
1951 for (std::size_t i = 0; i < nnd_pe; ++i)
1952 xcrd += intersection_points[i];
1955 quad_pts.resize(nnd_pe);
1956 quad_wts.resize(nnd_pe);
1960 for (std::size_t
j = 0;
j < nnd_pe; ++
j)
1962 std::vector<std::vector<Real>> shape(3, std::vector<Real>(3, 0.0));
1963 std::vector<Point> subtrig_points(3, Point(0.0, 0.0, 0.0));
1965 int jplus1 =
j < nnd_pe - 1 ?
j + 1 : 0;
1966 subtrig_points[0] = xcrd;
1967 subtrig_points[1] = intersection_points[
j];
1968 subtrig_points[2] = intersection_points[jplus1];
1970 std::vector<std::vector<Real>> sg2;
1972 for (std::size_t l = 0; l < sg2.size(); ++l)
1975 std::vector<Real> tsg_line(3, 0.0);
1976 for (std::size_t
k = 0;
k < 3; ++
k)
1978 tsg_line[0] += shape[
k][2] * subtrig_points[
k](0);
1979 tsg_line[1] += shape[
k][2] * subtrig_points[
k](1);
1980 tsg_line[2] += shape[
k][2] * subtrig_points[
k](2);
1982 quad_pts[
j + l] = Point(tsg_line[0], tsg_line[1], tsg_line[2]);
1983 quad_wts[
j + l] = sg2[l][3] * jac;
1990 const Node * node_to_store_from,
1997 std::vector<dof_id_type> stored_solution_dofs =
getNodeSolutionDofs(node_to_store_from, sys);
1998 std::vector<Real> stored_solution_scratch;
2000 std::size_t stored_solution_size =
2002 stored_solution_scratch.reserve(stored_solution_size);
2006 for (
auto dof : stored_solution_dofs)
2007 stored_solution_scratch.push_back(current_solution(dof));
2011 for (
auto dof : stored_solution_dofs)
2012 stored_solution_scratch.push_back(old_solution(dof));
2014 for (
auto dof : stored_solution_dofs)
2015 stored_solution_scratch.push_back(older_solution(dof));
2018 if (stored_solution_scratch.size() > 0)
2019 stored_solution[node_to_store_to->unique_id()] = stored_solution_scratch;
2024 const Elem * elem_to_store_from,
2032 std::vector<Real> stored_solution_scratch;
2034 std::size_t stored_solution_size =
2036 stored_solution_scratch.reserve(stored_solution_size);
2040 for (
auto dof : stored_solution_dofs)
2041 stored_solution_scratch.push_back(current_solution(dof));
2045 for (
auto dof : stored_solution_dofs)
2046 stored_solution_scratch.push_back(old_solution(dof));
2048 for (
auto dof : stored_solution_dofs)
2049 stored_solution_scratch.push_back(older_solution(dof));
2052 if (stored_solution_scratch.size() > 0)
2053 stored_solution[elem_to_store_to->unique_id()] = stored_solution_scratch;
2058 const std::map<
unique_id_type, std::vector<Real>> & stored_solution,
2063 for (
auto & node :
_mesh->local_node_ptr_range())
2065 auto mit = stored_solution.find(node->unique_id());
2066 if (mit != stored_solution.end())
2068 const std::vector<Real> & stored_node_solution = mit->second;
2071 stored_solution_dofs,
2078 for (
auto & elem :
as_range(
_mesh->local_elements_begin(),
_mesh->local_elements_end()))
2080 auto mit = stored_solution.find(elem->unique_id());
2081 if (mit != stored_solution.end())
2083 const std::vector<Real> & stored_elem_solution = mit->second;
2086 stored_solution_dofs,
2096 const std::vector<dof_id_type> & stored_solution_dofs,
2103 const auto old_solution_offset = stored_solution_dofs.size();
2104 const auto older_solution_offset = old_solution_offset * 2;
2106 for (std::size_t i = 0; i < stored_solution_dofs.size(); ++i)
2108 current_solution.
set(stored_solution_dofs[i], stored_solution[i]);
2111 old_solution.
set(stored_solution_dofs[i], stored_solution[old_solution_offset + i]);
2112 older_solution.
set(stored_solution_dofs[i], stored_solution[older_solution_offset + i]);
2117 std::vector<dof_id_type>
2122 std::vector<dof_id_type> solution_dofs;
2123 solution_dofs.reserve(
vars.size());
2124 for (
auto var :
vars)
2126 if (!var->isNodal())
2129 if (var_subdomains.empty() || var_subdomains.find(sid) != var_subdomains.end())
2131 unsigned int n_comp = elem->n_comp(sys.
number(), var->number());
2132 for (
unsigned int icomp = 0; icomp < n_comp; ++icomp)
2135 solution_dofs.push_back(elem_dof);
2140 return solution_dofs;
2143 std::vector<dof_id_type>
2148 std::vector<dof_id_type> solution_dofs;
2149 solution_dofs.reserve(
vars.size());
2150 for (
auto var :
vars)
2155 std::set<SubdomainID> intersect;
2156 set_intersection(var_subdomains.begin(),
2157 var_subdomains.end(),
2160 std::inserter(intersect, intersect.begin()));
2161 if (var_subdomains.empty() || !intersect.empty())
2163 unsigned int n_comp = node->n_comp(sys.
number(), var->number());
2164 for (
unsigned int icomp = 0; icomp < n_comp; ++icomp)
2167 solution_dofs.push_back(node_dof);
2172 return solution_dofs;
2180 std::set<unsigned int> elems = gcmit.second;
2181 if (elems.find(elem->id()) != elems.end())
2192 const auto & elem_props = storage.
props(state).at(elem);
2193 auto & serialized_props =
_geom_cut_elems[elem]._elem_material_properties[state - 1];
2194 serialized_props.clear();
2195 for (
const auto & side_props_pair : elem_props)
2197 const auto side = side_props_pair.first;
2198 std::ostringstream oss;
2200 serialized_props[side].assign(oss.str());
2217 bool need_boundary_materials =
false;
2218 for (
unsigned int side = 0; side < child_elem->n_sides(); ++side)
2220 std::vector<boundary_id_type> elem_boundary_ids;
2221 _mesh->get_boundary_info().boundary_ids(child_elem, side, elem_boundary_ids);
2222 for (
auto bdid : elem_boundary_ids)
2224 need_boundary_materials =
true;
2228 if (need_boundary_materials)
2243 const auto & serialized_props = cached_props[state - 1];
2244 for (
const auto & [side, serialized_side_props] : serialized_props)
2246 std::istringstream iss;
2247 iss.str(serialized_side_props);
2260 const Elem * elem_from,
2261 std::unordered_map<const Elem *, Xfem::CutElemInfo> & cached_cei)
const 2264 mooseAssert(cached_cei.count(elem_from) > 0,
"XFEM: Unable to find cached material properties.");
2269 cei._elem_material_properties,
2273 bool need_boundary_materials =
false;
2274 for (
unsigned int side = 0; side < elem->n_sides(); ++side)
2276 std::vector<boundary_id_type> elem_boundary_ids;
2277 _mesh->get_boundary_info().boundary_ids(elem, side, elem_boundary_ids);
2278 for (
auto bdid : elem_boundary_ids)
2280 need_boundary_materials =
true;
2284 if (need_boundary_materials)
2287 cei._bnd_material_properties,
2293 const Elem * cut_elem,
2294 const Elem * parent_elem)
const 2297 parent_elem = cut_elem;
2307 for (
auto i : e0->node_index_range())
2309 return e0->node_ptr(i);
2310 mooseError(
"cannot find a physical node in the current element");
void getCrackTipOrigin(std::map< unsigned int, const Elem *> &elem_id_crack_tip, std::vector< Point > &crack_front_points)
EFAFragment3D * getFragment(unsigned int frag_id) const
void getFragmentFaces(const Elem *elem, std::vector< std::vector< Point >> &frag_faces, bool displaced_mesh=false) const
void correctCrackExtensionDirection(const Elem *elem, EFAElement2D *CEMElem, EFAEdge *orig_edge, Point normal, Point crack_tip_origin, Point crack_tip_direction, Real &distance_keep, unsigned int &edge_id_keep, Point &normal_keep)
bool _use_crack_growth_increment
unsigned int _debug_output_level
Controls amount of debugging output information 0: None 1: Summary 2: Details on modifications to mes...
void setSolutionForDOFs(const std::vector< Real > &stored_solution, const std::vector< dof_id_type > &stored_solution_dofs, NumericVector< Number > ¤t_solution, NumericVector< Number > &old_solution, NumericVector< Number > &older_solution)
Set the solution for a set of DOFs.
MaterialProperties & setProps(const Elem *elem, unsigned int side, const unsigned int state=0)
const GeometricCutUserObject * getGeometricCutForElem(const Elem *elem) const
Get the GeometricCutUserObject associated with an element.
const std::vector< MooseVariableFieldBase *> & getVariables(THREAD_ID tid)
unsigned int numEdgeNeighbors(unsigned int edge_id) const
bool markCutEdgesByState(Real time)
void addElemNodeIntersection(unsigned int elemid, unsigned int nodeid)
void storeMaterialPropertiesForElement(const Elem *parent_elem, const Elem *child_elem)
Helper function to store the material properties of a healed element.
std::map< const Elem *, std::vector< Xfem::GeomMarkedElemInfo3D > > _geom_marked_elems_3d
Data structure for storing information about all 3D elements to be cut by geometry.
EFAElement3D * getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
EFANode * getEmbeddedNode(unsigned int index) const
CutSubdomainID getCutSubdomainID(const GeometricCutUserObject *gcuo, const Elem *cut_elem, const Elem *parent_elem=nullptr) const
Determine which cut subdomain the element belongs to relative to the cut.
void shapeFunc2D(unsigned int nen, std::vector< Real > &ss, std::vector< Point > &xl, std::vector< std::vector< Real >> &shp, Real &xsj, bool natl_flg)
Data structure describing geometrically described cut through 3D element.
bool isFacePhantom(unsigned int face_id) const
void addElemEdgeIntersection(unsigned int elemid, unsigned int edgeid, double position)
std::vector< const GeometricCutUserObject * > _geometric_cuts
void setSolution(SystemBase &sys, const std::map< unique_id_type, std::vector< Real >> &stored_solution, NumericVector< Number > ¤t_solution, NumericVector< Number > &old_solution, NumericVector< Number > &older_solution)
Set the solution for all locally-owned nodes/elements that have stored values.
unsigned int getCrackTipSplitElementID() const
virtual bool update(Real time, const std::vector< std::shared_ptr< NonlinearSystemBase >> &nl, AuxiliarySystem &aux) override
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_elems
Real _crack_growth_increment
bool isSecondaryInteriorEdge(unsigned int edge_id) const
bool shouldHealMesh() const
Should the elements cut by this cutting object be healed in the current time step?
virtual bool getXFEMFaceWeights(MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points, unsigned int side) override
void mooseError(Args &&... args)
virtual void getFragmentFaces(std::vector< std::vector< Point >> &frag_faces, MeshBase *displaced_mesh=nullptr) const =0
bool isPartialOverlap(const EFAEdge &other) const
std::vector< dof_id_type > getNodeSolutionDofs(const Node *node, SystemBase &sys) const
Get a vector of the dof indices for all components of all variables associated with a node...
const ExecFlagType EXEC_XFEM_MARK
Exec flag used to execute MooseObjects while elements are being marked for cutting by XFEM...
bool isPointInsidePhysicalDomain(const Elem *elem, const Point &point) const
Return true if the point is inside the element physical domain Note: if this element is not cut...
bool isSemiLocal(Node *const node) const
void updateEdgeNeighbors()
void getFragmentEdges(const Elem *elem, EFAElement2D *CEMElem, std::vector< std::vector< Point >> &frag_edges) const
bool match(const CutElemInfo &rhs)
bool cutMeshWithEFA(const std::vector< std::shared_ptr< NonlinearSystemBase >> &nl, AuxiliarySystem &aux)
unsigned int getTipEdgeID() const
unsigned int numEdges() const
EFAEdge * getEdge(unsigned int edge_id) const
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_displaced_elems
Real getPhysicalVolumeFraction() const
Returns the volume fraction of the element fragment.
void clearGeomMarkedElems()
Clear out the list of elements to be marked for cutting.
std::map< unique_id_type, XFEMCutElem * > _cut_elem_map
EFAElement * add3DElement(const std::vector< unsigned int > &quad, unsigned int id)
bool needBoundaryMaterialOnSide(BoundaryID bnd_id, const THREAD_ID tid)
const std::vector< EFAElement * > & getChildElements()
std::set< const Elem * > _crack_tip_elems
bool healMesh()
Potentially heal the mesh by merging some of the pairs of partial elements cut by XFEM back into sing...
XFEM(const InputParameters ¶ms)
virtual bool isPartial() const =0
ElementFragmentAlgorithm _efa_mesh
const std::set< SubdomainID > & getNodeBlockIds(const Node &node) const
bool hasIntersection() const
virtual unsigned int numFragments() const
NumericVector< Number > & solutionOlder()
std::array< std::unordered_map< unsigned int, std::string >, 2 > CachedMaterialProperties
Convenient typedef for local storage of stateful material properties.
std::vector< unsigned int > getInteriorEdgeID() const
unsigned int numEdges() const
void getFaceWeightMultipliers(MooseArray< Real > &face_weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points, unsigned int side)
bool isEdgePhantom(unsigned int edge_id) const
virtual unsigned int numFragments() const
Real distance(const Point &p)
std::set< const Elem * > _crack_tip_elems_to_be_healed
void addGeometricCut(GeometricCutUserObject *geometric_cut)
std::map< unique_id_type, std::vector< Real > > _cached_aux_solution
Data structure to store the auxiliary solution for nodes/elements affected by XFEM For each node/elem...
unsigned int numFaces() const
bool markCutEdgesByGeometry()
unsigned int CutSubdomainID
FEProblemBase * _fe_problem
std::vector< MaterialData *> _bnd_material_data
EFANode * getNode(unsigned int node_id) const
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num) override
void setMinWeightMultiplier(Real min_weight_multiplier)
Controls the minimum average weight multiplier for each element.
void updateTopology(bool mergeUncutVirtualEdges=true)
const std::vector< EFAElement * > & getParentElements()
virtual const EFAElement * getEFAElement() const =0
void updatePhysicalLinksAndFragments()
bool initCutIntersectionEdge(Point cut_origin, RealVectorValue cut_normal, Point &edge_p1, Point &edge_p2, Real &dist)
void addGeomMarkedElem3D(const unsigned int elem_id, const Xfem::GeomMarkedElemInfo3D geom_info, const unsigned int interface_id)
Add information about a new cut to be performed on a specific 3d element.
virtual void execute(const ExecFlagType &exec_type)
void addElemFaceIntersection(unsigned int elemid, unsigned int faceid, const std::vector< unsigned int > &edgeid, const std::vector< double > &position)
void storeCrackTipOriginAndDirection()
const Node * pickFirstPhysicalNode(const Elem *e, const Elem *e0) const
Return the first node in the provided element that is found to be in the physical domain...
void loadMaterialPropertiesForElement(const Elem *elem, const Elem *elem_from, std::unordered_map< const Elem *, Xfem::CutElemInfo > &cached_cei) const
Helper function to store the material properties of a healed element.
void dataStore(std::ostream &stream, FaceCenteredMapFunctor< T, Map > &m, void *context)
unsigned int size() const
const std::vector< EFANode * > & getNewNodes()
EFAFragment2D * getFragment(unsigned int frag_id) const
Real getCutPlane(const Elem *elem, const Xfem::XFEM_CUTPLANE_QUANTITY quantity, unsigned int plane_id) const
Get specified component of normal or origin for cut plane for a given element.
unsigned int numNodes() const
std::map< const GeometricCutUserObject *, unsigned int > _geom_marker_id_map
Data structure for storing the GeommetricCutUserObjects and their corresponding id.
virtual void getIntersectionInfo(unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, MeshBase *displaced_mesh=nullptr) const =0
std::vector< MaterialData *> _material_data
void addGeomMarkedElem2D(const unsigned int elem_id, const Xfem::GeomMarkedElemInfo2D geom_info, const unsigned int interface_id)
Add information about a new cut to be performed on a specific 2d element.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
void storeSolutionForElement(const Elem *elem_to_store_to, const Elem *elem_to_store_from, SystemBase &sys, std::map< unique_id_type, std::vector< Real >> &stored_solution, const NumericVector< Number > ¤t_solution, const NumericVector< Number > &old_solution, const NumericVector< Number > &older_solution)
Store the solution in stored_solution for a given element.
virtual Point getCutPlaneOrigin(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const =0
bool addFragEdgeIntersection(unsigned int elemid, unsigned int frag_edge_id, double position)
virtual bool isFinalCut() const
Xfem::XFEM_QRULE _XFEM_qrule
unsigned int n_points() const
void storeSolutionForNode(const Node *node_to_store_to, const Node *node_to_store_from, SystemBase &sys, std::map< unique_id_type, std::vector< Real >> &stored_solution, const NumericVector< Number > ¤t_solution, const NumericVector< Number > &old_solution, const NumericVector< Number > &older_solution)
Store the solution in stored_solution for a given node.
bool isThirdInteriorFace(unsigned int face_id) const
unsigned int number() const
virtual void getXFEMqRuleOnLine(std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
Data structure describing geometrically described cut through 2D element.
void loadMaterialPropertiesForElementHelper(const Elem *elem, const Xfem::CachedMaterialProperties &cached_props, MaterialPropertyStorage &storage) const
Load the material properties.
void setDebugOutputLevel(unsigned int debug_output_level)
Controls amount of debugging information output.
std::map< const Elem *, std::vector< Point > > _elem_crack_origin_direction_map
virtual void getXFEMIntersectionInfo(const Elem *elem, unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, bool displaced_mesh=false) const
std::map< const Elem *, std::vector< Xfem::GeomMarkedElemInfo2D > > _geom_marked_elems_2d
Data structure for storing information about all 2D elements to be cut by geometry.
std::map< unsigned int, std::set< unsigned int > > _geom_marker_id_elems
Data structure for storing the elements cut by specific geometric cutters.
void addFragFaceIntersection(unsigned int ElemID, unsigned int FragFaceID, const std::vector< unsigned int > &FragFaceEdgeID, const std::vector< double > &position)
virtual CutSubdomainID getCutSubdomainID(const Node *) const
Get CutSubdomainID telling which side the node belongs to relative to the cut.
bool hasStatefulProperties() const
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
virtual void initSolution(const std::vector< std::shared_ptr< NonlinearSystemBase >> &nl, AuxiliarySystem &aux) override
std::set< const Elem * > _state_marked_frags
EFANode * getTipEmbeddedNode() const
void restoreFragmentInfo(EFAElement *const elem, const EFAElement *const from_elem)
void storeMaterialPropertiesForElementHelper(const Elem *elem, MaterialPropertyStorage &storage)
const PropsType & props(const unsigned int state=0) const
virtual void getMasterInfo(EFANode *node, std::vector< EFANode *> &master_nodes, std::vector< double > &master_weights) const =0
EFAElement3D * getEFAElem3D(const Elem *elem)
Get the EFAElement3D object for a specified libMesh element.
EFAElement2D * getEdgeNeighbor(unsigned int edge_id, unsigned int neighbor_id) const
virtual void computePhysicalVolumeFraction()=0
Computes the volume fraction of the element fragment.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool isElemAtCrackTip(const Elem *elem) const
void stdQuadr2D(unsigned int nen, unsigned int iord, std::vector< std::vector< Real >> &sg2)
std::vector< dof_id_type > getElementSolutionDofs(const Elem *elem, SystemBase &sys) const
Get a vector of the dof indices for all components of all variables associated with an element...
Xfem::XFEM_QRULE & getXFEMQRule()
Real getPhysicalVolumeFraction(const Elem *elem) const
Get the volume fraction of an element that is physical.
virtual bool getXFEMWeights(MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points) override
virtual void getXFEMqRuleOnSurface(std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
EFAElement * add2DElement(const std::vector< unsigned int > &quad, unsigned int id)
bool markCutFacesByGeometry()
unsigned int getLocalNodeIndex(EFANode *node) const
void setCrackGrowthMethod(bool use_crack_growth_increment, Real crack_growth_increment)
void addStateMarkedElem(unsigned int elem_id, RealVectorValue &normal)
EFAElement * getElemByID(unsigned int id)
MeshBase * _displaced_mesh
const libMesh::QBase *const & qRule() const
std::unique_ptr< NumericVector< Number > > current_local_solution
const std::set< SubdomainID > & getSubdomainsForVar(unsigned int var_number) const
std::map< unique_id_type, std::vector< Real > > _cached_solution
Data structure to store the nonlinear solution for nodes/elements affected by XFEM For each node/elem...
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
bool isElemCut(const Elem *elem, XFEMCutElem *&xfce) const
void dataLoad(std::istream &stream, FaceCenteredMapFunctor< T, Map > &m, void *context)
virtual void set(const numeric_index_type i, const Number value)=0
virtual bool updateHeal() override
const ConsoleStream _console
virtual void serializeSolution()
void clearStateMarkedElems()
void getWeightMultipliers(MooseArray< Real > &weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points)
virtual libMesh::System & system() override
virtual bool isTransient() const override
virtual bool cutElementByCrackGrowthIncrement(const Elem *elem, std::vector< CutEdgeForCrackGrowthIncr > &cut_edges, Real time)
void setXFEMQRule(std::string &xfem_qrule)
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
NumericVector< Number > & solutionOld()
std::map< const Elem *, unsigned int > _state_marked_elem_sides
virtual bool isDistributedMesh() const
Information about a cut element.
EFANode * getNode(unsigned int index) const
const std::set< EFAElement * > & getCrackTipElements()
static const std::string k
unsigned int numFaceNeighbors(unsigned int face_id) const
Point getEFANodeCoords(EFANode *CEMnode, EFAElement *CEMElem, const Elem *elem, MeshBase *displaced_mesh=nullptr) const
std::map< const Elem *, RealVectorValue > _state_marked_elems
EFAElement2D * getEFAElem2D(const Elem *elem)
Get the EFAElement2D object for a specified libMesh element.
virtual Point getCutPlaneNormal(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const =0
void ErrorVector unsigned int
EFAEdge * getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const
void initCrackTipTopology()
bool markCutFacesByState()
void setInterfaceID(unsigned int interface_id)
Set the interface ID for this cutting object.
Real _min_weight_multiplier
The minimum average multiplier applied by XFEM to the standard quadrature weights to integrate partia...
void addStateMarkedFrag(unsigned int elem_id, RealVectorValue &normal)
unsigned int numFaces() const
virtual void getCrackTipOriginAndDirection(unsigned tip_id, Point &origin, Point &direction) const =0
std::unordered_map< const Elem *, Xfem::CutElemInfo > _geom_cut_elems
All geometrically cut elements and their CutElemInfo during the current execution of XFEM_MARK...
libMesh::IntRange< unsigned int > statefulIndexRange() const
bool isPointPhysical(const Point &p) const
std::unordered_map< const Elem *, Xfem::CutElemInfo > _old_geom_cut_elems
All geometrically cut elements and their CutElemInfo before the current execution of XFEM_MARK...