www.mooseframework.org
XFEM.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "XFEM.h"
11 
12 // XFEM includes
13 #include "XFEMAppTypes.h"
14 #include "XFEMCutElem2D.h"
15 #include "XFEMCutElem3D.h"
16 #include "XFEMFuncs.h"
17 #include "EFANode.h"
18 #include "EFAEdge.h"
19 #include "EFAFace.h"
20 #include "EFAFragment2D.h"
21 #include "EFAFragment3D.h"
22 #include "EFAFuncs.h"
23 
24 // MOOSE includes
25 #include "AuxiliarySystem.h"
26 #include "MooseVariable.h"
27 #include "NonlinearSystem.h"
28 #include "FEProblem.h"
29 #include "Assembly.h"
30 #include "MooseUtils.h"
31 
32 #include "libmesh/mesh_communication.h"
33 #include "libmesh/partitioner.h"
34 
35 XFEM::XFEM(const InputParameters & params)
36  : XFEMInterface(params), _efa_mesh(Moose::out), _debug_output_level(1)
37 {
38 #ifndef LIBMESH_ENABLE_UNIQUE_ID
39  mooseError("MOOSE requires unique ids to be enabled in libmesh (configure with "
40  "--enable-unique-id) to use XFEM!");
41 #endif
42  _has_secondary_cut = false;
43 }
44 
46 {
47  for (std::map<unique_id_type, XFEMCutElem *>::iterator cemit = _cut_elem_map.begin();
48  cemit != _cut_elem_map.end();
49  ++cemit)
50  delete cemit->second;
51 }
52 
53 void
55 {
56  _geometric_cuts.push_back(geometric_cut);
57 
58  geometric_cut->setInterfaceID(_geometric_cuts.size() - 1);
59 
60  _geom_marker_id_map[geometric_cut] = _geometric_cuts.size() - 1;
61 }
62 
63 void
64 XFEM::getCrackTipOrigin(std::map<unsigned int, const Elem *> & elem_id_crack_tip,
65  std::vector<Point> & crack_front_points)
66 {
67  elem_id_crack_tip.clear();
68  crack_front_points.clear();
69  crack_front_points.resize(_elem_crack_origin_direction_map.size());
70 
71  unsigned int crack_tip_index = 0;
72  // This map is used to sort the order in _elem_crack_origin_direction_map such that every process
73  // has same order
74  std::map<unsigned int, const Elem *> elem_id_map;
75 
76  int m = -1;
77  for (std::map<const Elem *, std::vector<Point>>::iterator mit1 =
80  ++mit1)
81  {
82  unsigned int elem_id = mit1->first->id();
83  if (elem_id > 999999)
84  {
85  elem_id_map[m] = mit1->first;
86  m--;
87  }
88  else
89  {
90  elem_id_map[elem_id] = mit1->first;
91  }
92  }
93 
94  for (std::map<unsigned int, const Elem *>::iterator mit1 = elem_id_map.begin();
95  mit1 != elem_id_map.end();
96  mit1++)
97  {
98  const Elem * elem = mit1->second;
99  std::map<const Elem *, std::vector<Point>>::iterator mit2 =
101  if (mit2 != _elem_crack_origin_direction_map.end())
102  {
103  elem_id_crack_tip[crack_tip_index] = mit2->first;
104  crack_front_points[crack_tip_index] =
105  (mit2->second)[0]; // [0] stores origin coordinates and [1] stores direction
106  crack_tip_index++;
107  }
108  }
109 }
110 
111 void
112 XFEM::addStateMarkedElem(unsigned int elem_id, RealVectorValue & normal)
113 {
114  Elem * elem = _mesh->elem_ptr(elem_id);
115  std::map<const Elem *, RealVectorValue>::iterator mit;
116  mit = _state_marked_elems.find(elem);
117  if (mit != _state_marked_elems.end())
118  mooseError(" ERROR: element ", elem->id(), " already marked for crack growth.");
119  _state_marked_elems[elem] = normal;
120 }
121 
122 void
123 XFEM::addStateMarkedElem(unsigned int elem_id, RealVectorValue & normal, unsigned int marked_side)
124 {
125  addStateMarkedElem(elem_id, normal);
126  Elem * elem = _mesh->elem_ptr(elem_id);
127  std::map<const Elem *, unsigned int>::iterator mit;
128  mit = _state_marked_elem_sides.find(elem);
129  if (mit != _state_marked_elem_sides.end())
130  {
131  mooseError(" ERROR: side of element ", elem->id(), " already marked for crack initiation.");
132  exit(1);
133  }
134  _state_marked_elem_sides[elem] = marked_side;
135 }
136 
137 void
138 XFEM::addStateMarkedFrag(unsigned int elem_id, RealVectorValue & normal)
139 {
140  addStateMarkedElem(elem_id, normal);
141  Elem * elem = _mesh->elem_ptr(elem_id);
142  std::set<const Elem *>::iterator mit;
143  mit = _state_marked_frags.find(elem);
144  if (mit != _state_marked_frags.end())
145  {
146  mooseError(
147  " ERROR: element ", elem->id(), " already marked for fragment-secondary crack initiation.");
148  exit(1);
149  }
150  _state_marked_frags.insert(elem);
151 }
152 
153 void
155 {
156  _state_marked_elems.clear();
157  _state_marked_frags.clear();
158  _state_marked_elem_sides.clear();
159 }
160 
161 void
162 XFEM::addGeomMarkedElem2D(const unsigned int elem_id,
163  const Xfem::GeomMarkedElemInfo2D geom_info,
164  const unsigned int interface_id)
165 {
166  Elem * elem = _mesh->elem_ptr(elem_id);
167  _geom_marked_elems_2d[elem].push_back(geom_info);
168  _geom_marker_id_elems[interface_id].insert(elem_id);
169 }
170 
171 void
172 XFEM::addGeomMarkedElem3D(const unsigned int elem_id,
173  const Xfem::GeomMarkedElemInfo3D geom_info,
174  const unsigned int interface_id)
175 {
176  Elem * elem = _mesh->elem_ptr(elem_id);
177  _geom_marked_elems_3d[elem].push_back(geom_info);
178  _geom_marker_id_elems[interface_id].insert(elem_id);
179 }
180 
181 void
183 {
184  _geom_marked_elems_2d.clear();
185  _geom_marked_elems_3d.clear();
186 }
187 
188 void
190 {
192  std::set<EFAElement *> CrackTipElements = _efa_mesh.getCrackTipElements();
193  std::set<EFAElement *>::iterator sit;
194  for (sit = CrackTipElements.begin(); sit != CrackTipElements.end(); ++sit)
195  {
196  if (_mesh->mesh_dimension() == 2)
197  {
198  EFAElement2D * CEMElem = dynamic_cast<EFAElement2D *>(*sit);
199  EFANode * tip_node = CEMElem->getTipEmbeddedNode();
200  unsigned int cts_id = CEMElem->getCrackTipSplitElementID();
201 
202  Point origin(0, 0, 0);
203  Point direction(0, 0, 0);
204 
205  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
206  it = _cut_elem_map.find(_mesh->elem_ptr(cts_id)->unique_id());
207  if (it != _cut_elem_map.end())
208  {
209  const XFEMCutElem * xfce = it->second;
210  const EFAElement * EFAelem = xfce->getEFAElement();
211  if (EFAelem->isPartial()) // exclude the full crack tip elements
212  {
213  xfce->getCrackTipOriginAndDirection(tip_node->id(), origin, direction);
214  }
215  }
216 
217  std::vector<Point> tip_data;
218  tip_data.push_back(origin);
219  tip_data.push_back(direction);
220  const Elem * elem = _mesh->elem_ptr((*sit)->id());
222  std::pair<const Elem *, std::vector<Point>>(elem, tip_data));
223  }
224  }
225 }
226 
227 bool
229 {
230  bool mesh_changed = false;
231 
232  mesh_changed = healMesh();
233 
234  if (mesh_changed)
235  {
236  _mesh->update_parallel_id_counts();
237  MeshCommunication().make_elems_parallel_consistent(*_mesh);
238  MeshCommunication().make_nodes_parallel_consistent(*_mesh);
239  // _mesh->find_neighbors();
240  // _mesh->contract();
241  _mesh->allow_renumbering(false);
242  _mesh->skip_partitioning(true);
243  _mesh->prepare_for_use();
244  // _mesh->prepare_for_use(true,true); //doing this preserves the numbering, but generates
245  // warning
246 
247  if (_displaced_mesh)
248  {
249  _displaced_mesh->update_parallel_id_counts();
250  MeshCommunication().make_elems_parallel_consistent(*_displaced_mesh);
251  MeshCommunication().make_nodes_parallel_consistent(*_displaced_mesh);
252  _displaced_mesh->allow_renumbering(false);
253  _displaced_mesh->skip_partitioning(true);
254  _displaced_mesh->prepare_for_use();
255  // _displaced_mesh->prepare_for_use(true,true);
256  }
257  }
258 
259  _geom_marker_id_elems.clear();
260 
261  return mesh_changed;
262 }
263 
264 bool
265 XFEM::update(Real time, NonlinearSystemBase & nl, AuxiliarySystem & aux)
266 {
267  if (_moose_mesh->isDistributedMesh())
268  mooseError("Use of XFEM with distributed mesh is not yet supported");
269 
270  bool mesh_changed = false;
271 
272  buildEFAMesh();
273 
274  _fe_problem->execute(EXEC_XFEM_MARK);
275 
277 
278  if (markCuts(time))
279  mesh_changed = cutMeshWithEFA(nl, aux);
280 
281  if (mesh_changed)
282  {
283  buildEFAMesh();
285  }
286 
287  if (mesh_changed)
288  {
289  // _mesh->find_neighbors();
290  // _mesh->contract();
291  _mesh->allow_renumbering(false);
292  _mesh->skip_partitioning(true);
293  _mesh->prepare_for_use();
294  // _mesh->prepare_for_use(true,true); //doing this preserves the numbering, but generates
295  // warning
296 
297  if (_displaced_mesh)
298  {
299  _displaced_mesh->allow_renumbering(false);
300  _displaced_mesh->skip_partitioning(true);
301  _displaced_mesh->prepare_for_use();
302  // _displaced_mesh->prepare_for_use(true,true);
303  }
304  }
305 
308 
309  return mesh_changed;
310 }
311 
312 void
313 XFEM::initSolution(NonlinearSystemBase & nl, AuxiliarySystem & aux)
314 {
315  nl.serializeSolution();
316  aux.serializeSolution();
317  NumericVector<Number> & current_solution = *nl.system().current_local_solution;
318  NumericVector<Number> & old_solution = nl.solutionOld();
319  NumericVector<Number> & older_solution = nl.solutionOlder();
320  NumericVector<Number> & current_aux_solution = *aux.system().current_local_solution;
321  NumericVector<Number> & old_aux_solution = aux.solutionOld();
322  NumericVector<Number> & older_aux_solution = aux.solutionOlder();
323 
324  setSolution(nl, _cached_solution, current_solution, old_solution, older_solution);
325  setSolution(
326  aux, _cached_aux_solution, current_aux_solution, old_aux_solution, older_aux_solution);
327 
328  current_solution.close();
329  old_solution.close();
330  older_solution.close();
331  current_aux_solution.close();
332  old_aux_solution.close();
333  older_aux_solution.close();
334 
335  _cached_solution.clear();
336  _cached_aux_solution.clear();
337 }
338 
339 void
341 {
342  _efa_mesh.reset();
343 
344  // Load all existing elements in to EFA mesh
345  for (auto & elem : _mesh->element_ptr_range())
346  {
347  std::vector<unsigned int> quad;
348  for (unsigned int i = 0; i < elem->n_nodes(); ++i)
349  quad.push_back(elem->node_id(i));
350  if (_mesh->mesh_dimension() == 2)
351  _efa_mesh.add2DElement(quad, elem->id());
352  else if (_mesh->mesh_dimension() == 3)
353  _efa_mesh.add3DElement(quad, elem->id());
354  else
355  mooseError("XFEM only works for 2D and 3D");
356  }
357 
358  // Restore fragment information for elements that have been previously cut
359  for (auto & elem : _mesh->element_ptr_range())
360  {
361  std::map<unique_id_type, XFEMCutElem *>::iterator cemit = _cut_elem_map.find(elem->unique_id());
362  if (cemit != _cut_elem_map.end())
363  {
364  XFEMCutElem * xfce = cemit->second;
365  EFAElement * CEMElem = _efa_mesh.getElemByID(elem->id());
366  _efa_mesh.restoreFragmentInfo(CEMElem, xfce->getEFAElement());
367  }
368  }
369 
370  // Must update edge neighbors before restore edge intersections. Otherwise, when we
371  // add edge intersections, we do not have neighbor information to use.
372  // Correction: no need to use neighbor info now
375 }
376 
377 bool
378 XFEM::markCuts(Real time)
379 {
380  bool marked_sides = false;
381  if (_mesh->mesh_dimension() == 2)
382  {
383  marked_sides = markCutEdgesByGeometry();
384  marked_sides |= markCutEdgesByState(time);
385  }
386  else if (_mesh->mesh_dimension() == 3)
387  {
388  marked_sides = markCutFacesByGeometry();
389  marked_sides |= markCutFacesByState();
390  }
391  return marked_sides;
392 }
393 
394 bool
396 {
397  bool marked_edges = false;
398  bool marked_nodes = false;
399 
400  for (const auto & gme : _geom_marked_elems_2d)
401  {
402  for (const auto & gmei : gme.second)
403  {
404  EFAElement2D * EFAElem = getEFAElem2D(gme.first);
405 
406  for (unsigned int i = 0; i < gmei._elem_cut_edges.size(); ++i) // mark element edges
407  {
408  if (!EFAElem->isEdgePhantom(
409  gmei._elem_cut_edges[i]._host_side_id)) // must not be phantom edge
410  {
411  _efa_mesh.addElemEdgeIntersection(gme.first->id(),
412  gmei._elem_cut_edges[i]._host_side_id,
413  gmei._elem_cut_edges[i]._distance);
414  marked_edges = true;
415  }
416  }
417 
418  for (unsigned int i = 0; i < gmei._elem_cut_nodes.size(); ++i) // mark element edges
419  {
420  _efa_mesh.addElemNodeIntersection(gme.first->id(), gmei._elem_cut_nodes[i]._host_id);
421  marked_nodes = true;
422  }
423 
424  for (unsigned int i = 0; i < gmei._frag_cut_edges.size();
425  ++i) // MUST DO THIS AFTER MARKING ELEMENT EDGES
426  {
427  if (!EFAElem->getFragment(0)->isSecondaryInteriorEdge(
428  gmei._frag_cut_edges[i]._host_side_id))
429  {
430  if (_efa_mesh.addFragEdgeIntersection(gme.first->id(),
431  gmei._frag_cut_edges[i]._host_side_id,
432  gmei._frag_cut_edges[i]._distance))
433  {
434  marked_edges = true;
435  if (!isElemAtCrackTip(gme.first))
436  _has_secondary_cut = true;
437  }
438  }
439  }
440  }
441  }
442 
443  return marked_edges || marked_nodes;
444 }
445 
446 void
448  EFAElement2D * CEMElem,
449  EFAEdge * orig_edge,
450  Point normal,
451  Point crack_tip_origin,
452  Point crack_tip_direction,
453  Real & distance_keep,
454  unsigned int & edge_id_keep,
455  Point & normal_keep)
456 {
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);
469 
470  Real cos_45 = std::cos(45.0 / 180.0 * 3.14159);
471  Real sin_45 = std::sin(45.0 / 180.0 * 3.14159);
472 
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);
475 
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);
478 
479  left_angle_normal(0) = -left_angle(1);
480  left_angle_normal(1) = left_angle(0);
481 
482  right_angle_normal(0) = -right_angle(1);
483  right_angle_normal(1) = right_angle(0);
484 
485  crack_direction_normal(0) = -crack_tip_direction(1);
486  crack_direction_normal(1) = crack_tip_direction(0);
487 
488  Real angle_min = 0.0;
489  Real distance = 0.0;
490  unsigned int nsides = CEMElem->numEdges();
491 
492  for (unsigned int i = 0; i < nsides; ++i)
493  {
494  if (!orig_edge->isPartialOverlap(*CEMElem->getEdge(i)))
495  {
496  edge_ends[0] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(0), CEMElem, elem);
497  edge_ends[1] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(1), CEMElem, elem);
498 
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;
501 
502  edge1_to_tip /= pow(edge1_to_tip.norm_sq(), 0.5);
503  edge2_to_tip /= pow(edge2_to_tip.norm_sq(), 0.5);
504 
505  edge1_to_tip_normal(0) = -edge1_to_tip(1);
506  edge1_to_tip_normal(1) = edge1_to_tip(0);
507 
508  edge2_to_tip_normal(0) = -edge2_to_tip(1);
509  edge2_to_tip_normal(1) = edge2_to_tip(0);
510 
511  Real angle_edge1_normal = edge1_to_tip_normal * normal;
512  Real angle_edge2_normal = edge2_to_tip_normal * normal;
513 
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))
516  {
517  edge_id_keep = i;
518  distance_keep = 0.05;
519  normal_keep = edge1_to_tip_normal;
520  angle_min = angle_edge1_normal;
521  }
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))
524  {
525  edge_id_keep = i;
526  distance_keep = 0.95;
527  normal_keep = edge2_to_tip_normal;
528  angle_min = angle_edge2_normal;
529  }
530 
532  crack_tip_origin, left_angle_normal, edge_ends[0], edge_ends[1], distance) &&
533  (!CEMElem->isEdgePhantom(i)))
534  {
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))
537  {
538  edge_id_keep = i;
539  distance_keep = distance;
540  normal_keep = left_angle_normal;
541  angle_min = left_angle_normal * normal;
542  }
543  }
544  else if (initCutIntersectionEdge(
545  crack_tip_origin, right_angle_normal, edge_ends[0], edge_ends[1], distance) &&
546  (!CEMElem->isEdgePhantom(i)))
547  {
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))
550  {
551  edge_id_keep = i;
552  distance_keep = distance;
553  normal_keep = right_angle_normal;
554  angle_min = right_angle_normal * normal;
555  }
556  }
557  else if (initCutIntersectionEdge(crack_tip_origin,
558  crack_direction_normal,
559  edge_ends[0],
560  edge_ends[1],
561  distance) &&
562  (!CEMElem->isEdgePhantom(i)))
563  {
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))
566  {
567  edge_id_keep = i;
568  distance_keep = distance;
569  normal_keep = crack_direction_normal;
570  angle_min = crack_direction_normal * normal;
571  }
572  }
573  }
574  }
575 
576  // avoid small volume fraction cut
577  if ((distance_keep - 0.05) < 0.0)
578  {
579  distance_keep = 0.05;
580  }
581  else if ((distance_keep - 0.95) > 0.0)
582  {
583  distance_keep = 0.95;
584  }
585 }
586 
587 bool
589 {
590  bool marked_edges = false;
591  for (std::map<const Elem *, RealVectorValue>::iterator pmeit = _state_marked_elems.begin();
592  pmeit != _state_marked_elems.end();
593  ++pmeit)
594  {
595  const Elem * elem = pmeit->first;
596  RealVectorValue normal = pmeit->second;
597  EFAElement2D * CEMElem = getEFAElem2D(elem);
598 
599  Real volfrac_elem = getPhysicalVolumeFraction(elem);
600  if (volfrac_elem < 0.25)
601  continue;
602 
603  // continue if elem is already cut twice - IMPORTANT
604  if (CEMElem->isFinalCut())
605  continue;
606 
607  // find the first cut edge
608  unsigned int nsides = CEMElem->numEdges();
609  unsigned int orig_cut_side_id = 999999;
610  Real orig_cut_distance = -1.0;
611  EFANode * orig_node = NULL;
612  EFAEdge * orig_edge = NULL;
613 
614  // crack tip origin coordinates and direction
615  Point crack_tip_origin(0, 0, 0);
616  Point crack_tip_direction(0, 0, 0);
617 
618  if (isElemAtCrackTip(elem)) // crack tip element's crack intiation
619  {
620  orig_cut_side_id = CEMElem->getTipEdgeID();
621  if (orig_cut_side_id < nsides) // valid crack-tip edge found
622  {
623  orig_edge = CEMElem->getEdge(orig_cut_side_id);
624  orig_node = CEMElem->getTipEmbeddedNode();
625  }
626  else
627  mooseError("element ", elem->id(), " has no valid crack-tip edge");
628 
629  // obtain the crack tip origin coordinates and direction.
630  std::map<const Elem *, std::vector<Point>>::iterator ecodm =
632  if (ecodm != _elem_crack_origin_direction_map.end())
633  {
634  crack_tip_origin = (ecodm->second)[0];
635  crack_tip_direction = (ecodm->second)[1];
636  }
637  else
638  mooseError("element ", elem->id(), " cannot find its crack tip origin and direction.");
639  }
640  else
641  {
642  std::map<const Elem *, unsigned int>::iterator mit1;
643  mit1 = _state_marked_elem_sides.find(elem);
644  std::set<const Elem *>::iterator mit2;
645  mit2 = _state_marked_frags.find(elem);
646 
647  if (mit1 != _state_marked_elem_sides.end()) // specified boundary crack initiation
648  {
649  orig_cut_side_id = mit1->second;
650  if (!CEMElem->isEdgePhantom(orig_cut_side_id) &&
651  !CEMElem->getEdge(orig_cut_side_id)->hasIntersection())
652  {
653  orig_cut_distance = 0.5;
654  _efa_mesh.addElemEdgeIntersection(elem->id(), orig_cut_side_id, orig_cut_distance);
655  orig_edge = CEMElem->getEdge(orig_cut_side_id);
656  orig_node = orig_edge->getEmbeddedNode(0);
657  // get a virtual crack tip direction
658  Point elem_center(0.0, 0.0, 0.0);
659  Point edge_center;
660  for (unsigned int i = 0; i < nsides; ++i)
661  {
662  elem_center += getEFANodeCoords(CEMElem->getEdge(i)->getNode(0), CEMElem, elem);
663  elem_center += getEFANodeCoords(CEMElem->getEdge(i)->getNode(1), CEMElem, elem);
664  }
665  elem_center /= nsides * 2.0;
666  edge_center = getEFANodeCoords(orig_edge->getNode(0), CEMElem, elem) +
667  getEFANodeCoords(orig_edge->getNode(1), CEMElem, elem);
668  edge_center /= 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);
672  }
673  else
674  continue; // skip this elem if specified boundary edge is phantom
675  }
676  else if (mit2 != _state_marked_frags.end()) // cut-surface secondary crack initiation
677  {
678  if (CEMElem->numFragments() != 1)
679  mooseError("element ",
680  elem->id(),
681  " flagged for a secondary crack, but has ",
682  CEMElem->numFragments(),
683  " fragments");
684  std::vector<unsigned int> interior_edge_id = CEMElem->getFragment(0)->getInteriorEdgeID();
685  if (interior_edge_id.size() == 1)
686  orig_cut_side_id = interior_edge_id[0];
687  else
688  continue; // skip this elem if more than one interior edges found (i.e. elem's been cut
689  // twice)
690  orig_cut_distance = 0.5;
691  _efa_mesh.addFragEdgeIntersection(elem->id(), orig_cut_side_id, orig_cut_distance);
692  orig_edge = CEMElem->getFragmentEdge(0, orig_cut_side_id);
693  orig_node = orig_edge->getEmbeddedNode(0); // must be an interior embedded node
694  Point elem_center(0.0, 0.0, 0.0);
695  Point edge_center;
696  unsigned int nsides_frag = CEMElem->getFragment(0)->numEdges();
697  for (unsigned int i = 0; i < nsides_frag; ++i)
698  {
699  elem_center +=
700  getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(0), CEMElem, elem);
701  elem_center +=
702  getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(1), CEMElem, elem);
703  }
704  elem_center /= nsides_frag * 2.0;
705  edge_center = getEFANodeCoords(orig_edge->getNode(0), CEMElem, elem) +
706  getEFANodeCoords(orig_edge->getNode(1), CEMElem, elem);
707  edge_center /= 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);
711  }
712  else
713  mooseError("element ",
714  elem->id(),
715  " flagged for state-based growth, but has no edge intersections");
716  }
717 
718  Point cut_origin(0.0, 0.0, 0.0);
719  if (orig_node)
720  cut_origin = getEFANodeCoords(orig_node, CEMElem, elem); // cutting plane origin's coords
721  else
722  mooseError("element ", elem->id(), " does not have valid orig_node");
723 
724  // loop through element edges to add possible second cut points
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);
733  Real distance = 0.0;
734  bool edge_cut = false;
735 
736  for (unsigned int i = 0; i < nsides; ++i)
737  {
738  if (!orig_edge->isPartialOverlap(*CEMElem->getEdge(i)))
739  {
740  edge_ends[0] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(0), CEMElem, elem);
741  edge_ends[1] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(1), CEMElem, elem);
743  crack_tip_origin, normal, edge_ends[0], edge_ends[1], distance) &&
744  (!CEMElem->isEdgePhantom(i))))
745  {
746  cut_edge_point = distance * edge_ends[1] + (1.0 - distance) * edge_ends[0];
747  distance_keep = distance;
748  edge_id_keep = i;
749  normal_keep = normal;
750  edge_cut = true;
751  break;
752  }
753  }
754  }
755 
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;
759 
760  if (angle_between_two_cuts > std::cos(45.0 / 180.0 * 3.14159)) // original cut direction is good
761  find_compatible_direction = true;
762 
763  if (!find_compatible_direction && edge_cut)
765  CEMElem,
766  orig_edge,
767  normal,
768  crack_tip_origin,
769  crack_tip_direction,
770  distance_keep,
771  edge_id_keep,
772  normal_keep);
773 
774  if (edge_cut)
775  {
777  _efa_mesh.addElemEdgeIntersection(elem->id(), edge_id_keep, distance_keep);
778  else
779  {
780  Point growth_direction(0.0, 0.0, 0.0);
781 
782  growth_direction(0) = -normal_keep(1);
783  growth_direction(1) = normal_keep(0);
784 
785  if (growth_direction * crack_tip_direction < 1.0e-10)
786  growth_direction *= (-1.0);
787 
788  Real x0 = crack_tip_origin(0);
789  Real y0 = crack_tip_origin(1);
790  Real x1 = x0 + _crack_growth_increment * growth_direction(0);
791  Real y1 = y0 + _crack_growth_increment * growth_direction(1);
792 
793  XFEMCrackGrowthIncrement2DCut geometric_cut(x0, y0, x1, y1, time * 0.9, time * 0.9);
794 
795  for (const auto & elem : _mesh->element_ptr_range())
796  {
797  std::vector<CutEdgeForCrackGrowthIncr> elem_cut_edges;
798  EFAElement2D * CEMElem = getEFAElem2D(elem);
799 
800  // continue if elem has been already cut twice - IMPORTANT
801  if (CEMElem->isFinalCut())
802  continue;
803 
804  // mark cut edges for the element and its fragment
805  geometric_cut.cutElementByCrackGrowthIncrement(elem, elem_cut_edges, time);
806 
807  for (unsigned int i = 0; i < elem_cut_edges.size(); ++i) // mark element edges
808  {
809  if (!CEMElem->isEdgePhantom(
810  elem_cut_edges[i]._host_side_id)) // must not be phantom edge
811  {
813  elem->id(), elem_cut_edges[i]._host_side_id, elem_cut_edges[i]._distance);
814  }
815  }
816  }
817  }
818  }
819  // loop though framgent boundary edges to add possible second cut points
820  // N.B. must do this after marking element edges
821  if (CEMElem->numFragments() > 0 && !edge_cut)
822  {
823  for (unsigned int i = 0; i < CEMElem->getFragment(0)->numEdges(); ++i)
824  {
825  if (!orig_edge->isPartialOverlap(*CEMElem->getFragmentEdge(0, i)))
826  {
827  edge_ends[0] =
828  getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(0), CEMElem, elem);
829  edge_ends[1] =
830  getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(1), CEMElem, elem);
832  crack_tip_origin, normal, edge_ends[0], edge_ends[1], distance) &&
833  (!CEMElem->getFragment(0)->isSecondaryInteriorEdge(i)))
834  {
835  if (_efa_mesh.addFragEdgeIntersection(elem->id(), edge_id_keep, distance_keep))
836  if (!isElemAtCrackTip(elem))
837  _has_secondary_cut = true;
838  break;
839  }
840  }
841  }
842  }
843 
844  marked_edges = true;
845 
846  } // loop over all state_marked_elems
847 
848  return marked_edges;
849 }
850 
851 bool
853 {
854  bool marked_faces = false;
855 
856  for (const auto & gme : _geom_marked_elems_3d)
857  {
858  for (const auto & gmei : gme.second)
859  {
860  EFAElement3D * EFAElem = getEFAElem3D(gme.first);
861 
862  for (unsigned int i = 0; i < gmei._elem_cut_faces.size(); ++i) // mark element faces
863  {
864  if (!EFAElem->isFacePhantom(gmei._elem_cut_faces[i]._face_id)) // must not be phantom face
865  {
866  _efa_mesh.addElemFaceIntersection(gme.first->id(),
867  gmei._elem_cut_faces[i]._face_id,
868  gmei._elem_cut_faces[i]._face_edge,
869  gmei._elem_cut_faces[i]._position);
870  marked_faces = true;
871  }
872  }
873 
874  for (unsigned int i = 0; i < gmei._frag_cut_faces.size();
875  ++i) // MUST DO THIS AFTER MARKING ELEMENT EDGES
876  {
877  if (!EFAElem->getFragment(0)->isThirdInteriorFace(gmei._frag_cut_faces[i]._face_id))
878  {
879  _efa_mesh.addFragFaceIntersection(gme.first->id(),
880  gmei._frag_cut_faces[i]._face_id,
881  gmei._frag_cut_faces[i]._face_edge,
882  gmei._frag_cut_faces[i]._position);
883  marked_faces = true;
884  }
885  }
886  }
887  }
888 
889  return marked_faces;
890 }
891 
892 bool
894 {
895  bool marked_faces = false;
896  // TODO: need to finish this for 3D problems
897  return marked_faces;
898 }
899 
900 bool
902  Point cut_origin, RealVectorValue cut_normal, Point & edge_p1, Point & edge_p2, Real & dist)
903 {
904  dist = 0.0;
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);
910 
911  if (plane2p1 * plane2p2 < 0.0)
912  {
913  dist = -plane2p1 / (plane2p2 - plane2p1);
914  does_intersect = true;
915  }
916  return does_intersect;
917 }
918 
919 bool
921 {
922  bool mesh_changed = false;
923 
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;
929 
930  for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
931  {
932  if (_geometric_cuts[i]->shouldHealMesh())
933  {
934  healed_geometric_cuts.push_back(_geometric_cuts[i]->name());
935  for (auto & it : _sibling_elems[_geometric_cuts[i]->getInterfaceID()])
936  {
937  Elem * elem1 = const_cast<Elem *>(it.first);
938  Elem * elem2 = const_cast<Elem *>(it.second);
939 
940  std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
941  _cut_elem_map.find(elem1->unique_id());
942  if (cemit != _cut_elem_map.end())
943  {
944  const XFEMCutElem * xfce = cemit->second;
945 
946  cutelems_to_delete.insert(elem1->unique_id());
947 
948  for (unsigned int in = 0; in < elem1->n_nodes(); ++in)
949  {
950  Node * e1node = elem1->node_ptr(in);
951  Node * e2node = elem2->node_ptr(in);
952  if (!xfce->isPointPhysical(*e1node) &&
953  e1node != e2node) // This would happen at the crack tip
954  {
955  elem1->set_node(in) = e2node;
956  nodes_to_delete.insert(e1node);
957  }
958  else if (e1node != e2node)
959  nodes_to_delete.insert(e2node);
960  }
961  }
962  else
963  mooseError("Could not find XFEMCutElem for element to be kept in healing");
964 
965  if (_displaced_mesh)
966  {
967  Elem * elem1_displaced = _displaced_mesh->elem_ptr(it.first->id());
968  Elem * elem2_displaced = _displaced_mesh->elem_ptr(it.second->id());
969 
970  std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
971  _cut_elem_map.find(elem1_displaced->unique_id());
972  if (cemit != _cut_elem_map.end())
973  {
974  const XFEMCutElem * xfce = cemit->second;
975 
976  for (unsigned int in = 0; in < elem1_displaced->n_nodes(); ++in)
977  {
978  Node * e1node_displaced = elem1_displaced->node_ptr(in);
979  Node * e2node_displaced = elem2_displaced->node_ptr(in);
980  if (!xfce->isPointPhysical(*e1node_displaced) &&
981  e1node_displaced != e2node_displaced) // This would happen at the crack tip
982  {
983  elem1_displaced->set_node(in) = e2node_displaced;
984  nodes_to_delete_displaced.insert(e1node_displaced);
985  }
986  else if (e1node_displaced != e2node_displaced)
987  nodes_to_delete_displaced.insert(e2node_displaced);
988  }
989  }
990  else
991  mooseError("Could not find XFEMCutElem for element to be kept in healing");
992 
993  elem2_displaced->nullify_neighbors();
994  _displaced_mesh->boundary_info->remove(elem2_displaced);
995  _displaced_mesh->delete_elem(elem2_displaced);
996  }
997 
998  cutelems_to_delete.insert(elem2->unique_id());
999  elem2->nullify_neighbors();
1000  _mesh->boundary_info->remove(elem2);
1001  unsigned int deleted_elem_id = elem2->id();
1002  _mesh->delete_elem(elem2);
1003  if (_debug_output_level > 1)
1004  {
1005  if (deleted_elem_count == 0)
1006  _console << "\n";
1007  _console << "XFEM healing deleted element: " << deleted_elem_id << "\n";
1008  }
1009  ++deleted_elem_count;
1010  mesh_changed = true;
1011  }
1012  }
1013  }
1014 
1015  for (auto & sit : nodes_to_delete)
1016  {
1017  Node * node_to_delete = sit;
1018  dof_id_type deleted_node_id = node_to_delete->id();
1019  _mesh->boundary_info->remove(node_to_delete);
1020  _mesh->delete_node(node_to_delete);
1021  if (_debug_output_level > 1)
1022  _console << "XFEM healing deleted node: " << deleted_node_id << "\n";
1023  }
1024 
1025  if (_displaced_mesh)
1026  {
1027  for (auto & sit : nodes_to_delete_displaced)
1028  {
1029  Node * node_to_delete = sit;
1030  _displaced_mesh->boundary_info->remove(node_to_delete);
1031  _displaced_mesh->delete_node(node_to_delete);
1032  }
1033  }
1034 
1035  for (auto & ced : cutelems_to_delete)
1036  if (_cut_elem_map.find(ced) != _cut_elem_map.end())
1037  {
1038  delete _cut_elem_map.find(ced)->second;
1039  _cut_elem_map.erase(ced);
1040  }
1041 
1042  for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1043  if (_geometric_cuts[i]->shouldHealMesh())
1044  _sibling_elems[_geometric_cuts[i]->getInterfaceID()].clear();
1045 
1046  if (_displaced_mesh)
1047  {
1048  for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1049  if (_geometric_cuts[i]->shouldHealMesh())
1050  _sibling_displaced_elems[_geometric_cuts[i]->getInterfaceID()].clear();
1051  }
1052 
1053  for (auto & ceh : _crack_tip_elems_to_be_healed)
1054  {
1055  _crack_tip_elems.erase(ceh);
1057  delete _cut_elem_map.find(ceh->unique_id())->second;
1058  _cut_elem_map.erase(ceh->unique_id());
1059  }
1060 
1061  if (!healed_geometric_cuts.empty() && _debug_output_level > 0)
1062  {
1063  _console << "\nXFEM mesh healing complete\n";
1064  _console << "Names of healed geometric cut objects: ";
1065  for (auto geomcut : healed_geometric_cuts)
1066  _console << geomcut << " ";
1067  _console << "\n";
1068  _console << "# deleted nodes: " << nodes_to_delete.size() << "\n";
1069  _console << "# deleted elements: " << deleted_elem_count << "\n";
1070  _console << std::flush;
1071  }
1072 
1073  return mesh_changed;
1074 }
1075 
1076 bool
1077 XFEM::cutMeshWithEFA(NonlinearSystemBase & nl, AuxiliarySystem & aux)
1078 {
1079  std::map<unsigned int, Node *> efa_id_to_new_node;
1080  std::map<unsigned int, Node *> efa_id_to_new_node2;
1081  std::map<unsigned int, Elem *> efa_id_to_new_elem;
1082  _cached_solution.clear();
1083  _cached_aux_solution.clear();
1084 
1086 
1087  if (_debug_output_level > 2)
1088  {
1089  _console << "\nXFEM Element fragment algorithm mesh prior to cutting:\n";
1090  _console << std::flush;
1091  _efa_mesh.printMesh();
1092  }
1093 
1095 
1096  if (_debug_output_level > 2)
1097  {
1098  _console << "\nXFEM Element fragment algorithm mesh after cutting:\n";
1099  _console << std::flush;
1100  _efa_mesh.printMesh();
1101  }
1102 
1103  const std::vector<EFANode *> new_nodes = _efa_mesh.getNewNodes();
1104  const std::vector<EFAElement *> new_elements = _efa_mesh.getChildElements();
1105  const std::vector<EFAElement *> delete_elements = _efa_mesh.getParentElements();
1106 
1107  bool mesh_changed = (new_nodes.size() + new_elements.size() + delete_elements.size() > 0);
1108 
1109  // Prepare to cache solution on DOFs modified by XFEM
1110  if (mesh_changed)
1111  {
1112  nl.serializeSolution();
1113  aux.serializeSolution();
1114  if (_debug_output_level > 1)
1115  _console << "\n";
1116  }
1117  NumericVector<Number> & current_solution = *nl.system().current_local_solution;
1118  NumericVector<Number> & old_solution = nl.solutionOld();
1119  NumericVector<Number> & older_solution = nl.solutionOlder();
1120  NumericVector<Number> & current_aux_solution = *aux.system().current_local_solution;
1121  NumericVector<Number> & old_aux_solution = aux.solutionOld();
1122  NumericVector<Number> & older_aux_solution = aux.solutionOlder();
1123 
1124  std::map<Node *, Node *> new_nodes_to_parents;
1125 
1126  // Add new nodes
1127  for (unsigned int i = 0; i < new_nodes.size(); ++i)
1128  {
1129  unsigned int new_node_id = new_nodes[i]->id();
1130  unsigned int parent_id = new_nodes[i]->parent()->id();
1131 
1132  Node * parent_node = _mesh->node_ptr(parent_id);
1133  Node * new_node = Node::build(*parent_node, _mesh->n_nodes()).release();
1134  _mesh->add_node(new_node);
1135 
1136  new_nodes_to_parents[new_node] = parent_node;
1137 
1138  new_node->set_n_systems(parent_node->n_systems());
1139  efa_id_to_new_node.insert(std::make_pair(new_node_id, new_node));
1140  if (_debug_output_level > 1)
1141  _console << "XFEM added new node: " << new_node->id() << "\n";
1142  if (_displaced_mesh)
1143  {
1144  const Node * parent_node2 = _displaced_mesh->node_ptr(parent_id);
1145  Node * new_node2 = Node::build(*parent_node2, _displaced_mesh->n_nodes()).release();
1146  _displaced_mesh->add_node(new_node2);
1147 
1148  new_node2->set_n_systems(parent_node2->n_systems());
1149  efa_id_to_new_node2.insert(std::make_pair(new_node_id, new_node2));
1150  }
1151  }
1152 
1153  // Add new elements
1154  std::map<unsigned int, std::vector<const Elem *>> temporary_parent_children_map;
1155 
1156  std::vector<boundary_id_type> parent_boundary_ids;
1157 
1158  for (unsigned int i = 0; i < new_elements.size(); ++i)
1159  {
1160  unsigned int parent_id = new_elements[i]->getParent()->id();
1161  unsigned int efa_child_id = new_elements[i]->id();
1162 
1163  Elem * parent_elem = _mesh->elem_ptr(parent_id);
1164  Elem * libmesh_elem = Elem::build(parent_elem->type()).release();
1165 
1166  for (unsigned int m = 0; m < _geometric_cuts.size(); ++m)
1167  {
1168  for (auto & it : _sibling_elems[_geometric_cuts[m]->getInterfaceID()])
1169  {
1170  if (parent_elem == it.first)
1171  it.first = libmesh_elem;
1172  else if (parent_elem == it.second)
1173  it.second = libmesh_elem;
1174  }
1175  }
1176 
1177  // parent has at least two children
1178  if (new_elements[i]->getParent()->numChildren() > 1)
1179  temporary_parent_children_map[parent_elem->id()].push_back(libmesh_elem);
1180 
1181  Elem * parent_elem2 = NULL;
1182  Elem * libmesh_elem2 = NULL;
1183  if (_displaced_mesh)
1184  {
1185  parent_elem2 = _displaced_mesh->elem_ptr(parent_id);
1186  libmesh_elem2 = Elem::build(parent_elem2->type()).release();
1187 
1188  for (unsigned int m = 0; m < _geometric_cuts.size(); ++m)
1189  {
1190  for (auto & it : _sibling_displaced_elems[_geometric_cuts[m]->getInterfaceID()])
1191  {
1192  if (parent_elem2 == it.first)
1193  it.first = libmesh_elem2;
1194  else if (parent_elem2 == it.second)
1195  it.second = libmesh_elem2;
1196  }
1197  }
1198  }
1199 
1200  for (unsigned int j = 0; j < new_elements[i]->numNodes(); ++j)
1201  {
1202  unsigned int node_id = new_elements[i]->getNode(j)->id();
1203  Node * libmesh_node;
1204 
1205  std::map<unsigned int, Node *>::iterator nit = efa_id_to_new_node.find(node_id);
1206  if (nit != efa_id_to_new_node.end())
1207  libmesh_node = nit->second;
1208  else
1209  libmesh_node = _mesh->node_ptr(node_id);
1210 
1211  if (libmesh_node->processor_id() == DofObject::invalid_processor_id)
1212  libmesh_node->processor_id() = parent_elem->processor_id();
1213 
1214  libmesh_elem->set_node(j) = libmesh_node;
1215 
1216  // Store solution for all nodes affected by XFEM (even existing nodes)
1217  if (parent_elem->is_semilocal(_mesh->processor_id()))
1218  {
1219  Node * solution_node = libmesh_node; // Node from which to store solution
1220  if (new_nodes_to_parents.find(libmesh_node) != new_nodes_to_parents.end())
1221  solution_node = new_nodes_to_parents[libmesh_node];
1222 
1223  if ((_moose_mesh->isSemiLocal(solution_node)) ||
1224  (solution_node->processor_id() == _mesh->processor_id()))
1225  {
1226  storeSolutionForNode(libmesh_node,
1227  solution_node,
1228  nl,
1230  current_solution,
1231  old_solution,
1232  older_solution);
1233  storeSolutionForNode(libmesh_node,
1234  solution_node,
1235  aux,
1237  current_aux_solution,
1238  old_aux_solution,
1239  older_aux_solution);
1240  }
1241  }
1242 
1243  Node * parent_node = parent_elem->node_ptr(j);
1244  _mesh->boundary_info->boundary_ids(parent_node, parent_boundary_ids);
1245  _mesh->boundary_info->add_node(libmesh_node, parent_boundary_ids);
1246 
1247  if (_displaced_mesh)
1248  {
1249  std::map<unsigned int, Node *>::iterator nit2 = efa_id_to_new_node2.find(node_id);
1250  if (nit2 != efa_id_to_new_node2.end())
1251  libmesh_node = nit2->second;
1252  else
1253  libmesh_node = _displaced_mesh->node_ptr(node_id);
1254 
1255  if (libmesh_node->processor_id() == DofObject::invalid_processor_id)
1256  libmesh_node->processor_id() = parent_elem2->processor_id();
1257 
1258  libmesh_elem2->set_node(j) = libmesh_node;
1259 
1260  parent_node = parent_elem2->node_ptr(j);
1261  _displaced_mesh->boundary_info->boundary_ids(parent_node, parent_boundary_ids);
1262  _displaced_mesh->boundary_info->add_node(libmesh_node, parent_boundary_ids);
1263  }
1264  }
1265 
1266  libmesh_elem->set_p_level(parent_elem->p_level());
1267  libmesh_elem->set_p_refinement_flag(parent_elem->p_refinement_flag());
1268  _mesh->add_elem(libmesh_elem);
1269  libmesh_elem->set_n_systems(parent_elem->n_systems());
1270  libmesh_elem->subdomain_id() = parent_elem->subdomain_id();
1271  libmesh_elem->processor_id() = parent_elem->processor_id();
1272 
1273  // TODO: The 0 here is the thread ID. Need to sort out how to do this correctly
1274  // TODO: Also need to copy neighbor material data
1275  if (parent_elem->processor_id() == _mesh->processor_id())
1276  {
1277  (*_material_data)[0]->copy(*libmesh_elem, *parent_elem, 0);
1278  for (unsigned int side = 0; side < parent_elem->n_sides(); ++side)
1279  {
1280  _mesh->boundary_info->boundary_ids(parent_elem, side, parent_boundary_ids);
1281  std::vector<boundary_id_type>::iterator it_bd = parent_boundary_ids.begin();
1282  for (; it_bd != parent_boundary_ids.end(); ++it_bd)
1283  {
1284  if (_fe_problem->needBoundaryMaterialOnSide(*it_bd, 0))
1285  (*_bnd_material_data)[0]->copy(*libmesh_elem, *parent_elem, side);
1286  }
1287  }
1288 
1289  // Store solution for all elements affected by XFEM
1290  storeSolutionForElement(libmesh_elem,
1291  parent_elem,
1292  nl,
1294  current_solution,
1295  old_solution,
1296  older_solution);
1297  storeSolutionForElement(libmesh_elem,
1298  parent_elem,
1299  aux,
1301  current_aux_solution,
1302  old_aux_solution,
1303  older_aux_solution);
1304  }
1305 
1306  // The crack tip origin map is stored before cut, thus the elem should be updated with new
1307  // element.
1308  std::map<const Elem *, std::vector<Point>>::iterator mit =
1309  _elem_crack_origin_direction_map.find(parent_elem);
1310  if (mit != _elem_crack_origin_direction_map.end())
1311  {
1312  std::vector<Point> crack_data = _elem_crack_origin_direction_map[parent_elem];
1314  _elem_crack_origin_direction_map[libmesh_elem] = crack_data;
1315  }
1316 
1317  if (_debug_output_level > 1)
1318  _console << "XFEM added new element: " << libmesh_elem->id() << "\n";
1319 
1320  XFEMCutElem * xfce = NULL;
1321  if (_mesh->mesh_dimension() == 2)
1322  {
1323  EFAElement2D * new_efa_elem2d = dynamic_cast<EFAElement2D *>(new_elements[i]);
1324  if (!new_efa_elem2d)
1325  mooseError("EFAelem is not of EFAelement2D type");
1326  xfce = new XFEMCutElem2D(libmesh_elem,
1327  new_efa_elem2d,
1328  _fe_problem->assembly(0).qRule()->n_points(),
1329  libmesh_elem->n_sides());
1330  }
1331  else if (_mesh->mesh_dimension() == 3)
1332  {
1333  EFAElement3D * new_efa_elem3d = dynamic_cast<EFAElement3D *>(new_elements[i]);
1334  if (!new_efa_elem3d)
1335  mooseError("EFAelem is not of EFAelement3D type");
1336  xfce = new XFEMCutElem3D(libmesh_elem,
1337  new_efa_elem3d,
1338  _fe_problem->assembly(0).qRule()->n_points(),
1339  libmesh_elem->n_sides());
1340  }
1341  _cut_elem_map.insert(std::pair<unique_id_type, XFEMCutElem *>(libmesh_elem->unique_id(), xfce));
1342  efa_id_to_new_elem.insert(std::make_pair(efa_child_id, libmesh_elem));
1343 
1344  if (_displaced_mesh)
1345  {
1346  libmesh_elem2->set_p_level(parent_elem2->p_level());
1347  libmesh_elem2->set_p_refinement_flag(parent_elem2->p_refinement_flag());
1348  _displaced_mesh->add_elem(libmesh_elem2);
1349  libmesh_elem2->set_n_systems(parent_elem2->n_systems());
1350  libmesh_elem2->subdomain_id() = parent_elem2->subdomain_id();
1351  libmesh_elem2->processor_id() = parent_elem2->processor_id();
1352  }
1353 
1354  unsigned int n_sides = parent_elem->n_sides();
1355  for (unsigned int side = 0; side < n_sides; ++side)
1356  {
1357  _mesh->boundary_info->boundary_ids(parent_elem, side, parent_boundary_ids);
1358  _mesh->boundary_info->add_side(libmesh_elem, side, parent_boundary_ids);
1359  }
1360  if (_displaced_mesh)
1361  {
1362  n_sides = parent_elem2->n_sides();
1363  for (unsigned int side = 0; side < n_sides; ++side)
1364  {
1365  _displaced_mesh->boundary_info->boundary_ids(parent_elem2, side, parent_boundary_ids);
1366  _displaced_mesh->boundary_info->add_side(libmesh_elem2, side, parent_boundary_ids);
1367  }
1368  }
1369 
1370  unsigned int n_edges = parent_elem->n_edges();
1371  for (unsigned int edge = 0; edge < n_edges; ++edge)
1372  {
1373  _mesh->boundary_info->edge_boundary_ids(parent_elem, edge, parent_boundary_ids);
1374  _mesh->boundary_info->add_edge(libmesh_elem, edge, parent_boundary_ids);
1375  }
1376  if (_displaced_mesh)
1377  {
1378  n_edges = parent_elem2->n_edges();
1379  for (unsigned int edge = 0; edge < n_edges; ++edge)
1380  {
1381  _displaced_mesh->boundary_info->edge_boundary_ids(parent_elem2, edge, parent_boundary_ids);
1382  _displaced_mesh->boundary_info->add_edge(libmesh_elem2, edge, parent_boundary_ids);
1383  }
1384  }
1385  }
1386 
1387  // delete elements
1388  for (std::size_t i = 0; i < delete_elements.size(); ++i)
1389  {
1390  Elem * elem_to_delete = _mesh->elem_ptr(delete_elements[i]->id());
1391 
1392  // delete the XFEMCutElem object for any elements that are to be deleted
1393  std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
1394  _cut_elem_map.find(elem_to_delete->unique_id());
1395  if (cemit != _cut_elem_map.end())
1396  {
1397  delete cemit->second;
1398  _cut_elem_map.erase(cemit);
1399  }
1400 
1401  elem_to_delete->nullify_neighbors();
1402  _mesh->boundary_info->remove(elem_to_delete);
1403  unsigned int deleted_elem_id = elem_to_delete->id();
1404  _mesh->delete_elem(elem_to_delete);
1405  if (_debug_output_level > 1)
1406  _console << "XFEM deleted element: " << deleted_elem_id << "\n";
1407 
1408  if (_displaced_mesh)
1409  {
1410  Elem * elem_to_delete2 = _displaced_mesh->elem_ptr(delete_elements[i]->id());
1411  elem_to_delete2->nullify_neighbors();
1412  _displaced_mesh->boundary_info->remove(elem_to_delete2);
1413  _displaced_mesh->delete_elem(elem_to_delete2);
1414  }
1415  }
1416 
1417  for (std::map<unsigned int, std::vector<const Elem *>>::iterator it =
1418  temporary_parent_children_map.begin();
1419  it != temporary_parent_children_map.end();
1420  ++it)
1421  {
1422  std::vector<const Elem *> & sibling_elem_vec = it->second;
1423  // TODO: for cut-node case, how to find the sibling elements?
1424  // if (sibling_elem_vec.size() != 2)
1425  // mooseError("Must have exactly 2 sibling elements");
1426 
1427  for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1428  for (auto const & elem_id : _geom_marker_id_elems[_geometric_cuts[i]->getInterfaceID()])
1429  if (it->first == elem_id)
1430  _sibling_elems[_geometric_cuts[i]->getInterfaceID()].push_back(
1431  std::make_pair(sibling_elem_vec[0], sibling_elem_vec[1]));
1432  }
1433 
1434  // add sibling elems on displaced mesh
1435  if (_displaced_mesh)
1436  {
1437  for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1438  {
1439  for (auto & se : _sibling_elems[_geometric_cuts[i]->getInterfaceID()])
1440  {
1441  Elem * elem = _displaced_mesh->elem_ptr(se.first->id());
1442  Elem * elem_pair = _displaced_mesh->elem_ptr(se.second->id());
1443  _sibling_displaced_elems[_geometric_cuts[i]->getInterfaceID()].push_back(
1444  std::make_pair(elem, elem_pair));
1445  }
1446  }
1447  }
1448 
1449  // clear the temporary map
1450  temporary_parent_children_map.clear();
1451 
1452  // Store information about crack tip elements
1453  if (mesh_changed)
1454  {
1455  _crack_tip_elems.clear();
1457  const std::set<EFAElement *> CrackTipElements = _efa_mesh.getCrackTipElements();
1458  std::set<EFAElement *>::const_iterator sit;
1459  for (sit = CrackTipElements.begin(); sit != CrackTipElements.end(); ++sit)
1460  {
1461  unsigned int eid = (*sit)->id();
1462  Elem * crack_tip_elem;
1463  std::map<unsigned int, Elem *>::iterator eit = efa_id_to_new_elem.find(eid);
1464  if (eit != efa_id_to_new_elem.end())
1465  crack_tip_elem = eit->second;
1466  else
1467  crack_tip_elem = _mesh->elem_ptr(eid);
1468  _crack_tip_elems.insert(crack_tip_elem);
1469 
1470  // Store the crack tip elements which are going to be healed
1471  for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1472  {
1473  if (_geometric_cuts[i]->shouldHealMesh())
1474  {
1475  for (auto const & mie : _geom_marker_id_elems[_geometric_cuts[i]->getInterfaceID()])
1476  if ((*sit)->getParent() != nullptr)
1477  {
1478  if ((*sit)->getParent()->id() == mie)
1479  _crack_tip_elems_to_be_healed.insert(crack_tip_elem);
1480  }
1481  }
1482  }
1483  }
1484  }
1485  if (_debug_output_level > 0)
1486  {
1487  _console << "\nXFEM mesh cutting with element fragment algorithm complete\n";
1488  _console << "# new nodes: " << new_nodes.size() << "\n";
1489  _console << "# new elements: " << new_elements.size() << "\n";
1490  _console << "# deleted elements: " << delete_elements.size() << "\n";
1491  _console << std::flush;
1492  }
1493 
1494  // store virtual nodes
1495  // store cut edge info
1496  return mesh_changed;
1497 }
1498 
1499 Point
1501  EFAElement * CEMElem,
1502  const Elem * elem,
1503  MeshBase * displaced_mesh) const
1504 {
1505  Point node_coor(0.0, 0.0, 0.0);
1506  std::vector<EFANode *> master_nodes;
1507  std::vector<Point> master_points;
1508  std::vector<double> master_weights;
1509 
1510  CEMElem->getMasterInfo(CEMnode, master_nodes, master_weights);
1511  for (std::size_t i = 0; i < master_nodes.size(); ++i)
1512  {
1513  if (master_nodes[i]->category() == EFANode::N_CATEGORY_PERMANENT)
1514  {
1515  unsigned int local_node_id = CEMElem->getLocalNodeIndex(master_nodes[i]);
1516  const Node * node = elem->node_ptr(local_node_id);
1517  if (displaced_mesh)
1518  node = displaced_mesh->node_ptr(node->id());
1519  Point node_p((*node)(0), (*node)(1), (*node)(2));
1520  master_points.push_back(node_p);
1521  }
1522  else
1523  mooseError("master nodes must be permanent");
1524  }
1525  for (std::size_t i = 0; i < master_nodes.size(); ++i)
1526  node_coor += master_weights[i] * master_points[i];
1527 
1528  return node_coor;
1529 }
1530 
1531 Real
1532 XFEM::getPhysicalVolumeFraction(const Elem * elem) const
1533 {
1534  Real phys_volfrac = 1.0;
1535  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1536  it = _cut_elem_map.find(elem->unique_id());
1537  if (it != _cut_elem_map.end())
1538  {
1539  XFEMCutElem * xfce = it->second;
1540  const EFAElement * EFAelem = xfce->getEFAElement();
1541  if (EFAelem->isPartial())
1542  { // exclude the full crack tip elements
1544  phys_volfrac = xfce->getPhysicalVolumeFraction();
1545  }
1546  }
1547 
1548  return phys_volfrac;
1549 }
1550 
1551 bool
1552 XFEM::isPointInsidePhysicalDomain(const Elem * elem, const Point & point) const
1553 {
1554  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1555  it = _cut_elem_map.find(elem->unique_id());
1556  if (it != _cut_elem_map.end())
1557  {
1558  XFEMCutElem * xfce = it->second;
1559 
1560  if (xfce->isPointPhysical(point))
1561  return true;
1562  }
1563  else
1564  return true;
1565 
1566  return false;
1567 }
1568 
1569 Real
1570 XFEM::getCutPlane(const Elem * elem,
1571  const Xfem::XFEM_CUTPLANE_QUANTITY quantity,
1572  unsigned int plane_id) const
1573 {
1574  Real comp = 0.0;
1575  Point planedata(0.0, 0.0, 0.0);
1576  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1577  it = _cut_elem_map.find(elem->unique_id());
1578  if (it != _cut_elem_map.end())
1579  {
1580  const XFEMCutElem * xfce = it->second;
1581  const EFAElement * EFAelem = xfce->getEFAElement();
1582  if (EFAelem->isPartial()) // exclude the full crack tip elements
1583  {
1584  if ((unsigned int)quantity < 3)
1585  {
1586  unsigned int index = (unsigned int)quantity;
1587  planedata = xfce->getCutPlaneOrigin(plane_id, _displaced_mesh);
1588  comp = planedata(index);
1589  }
1590  else if ((unsigned int)quantity < 6)
1591  {
1592  unsigned int index = (unsigned int)quantity - 3;
1593  planedata = xfce->getCutPlaneNormal(plane_id, _displaced_mesh);
1594  comp = planedata(index);
1595  }
1596  else
1597  mooseError("In get_cut_plane index out of range");
1598  }
1599  }
1600  return comp;
1601 }
1602 
1603 bool
1604 XFEM::isElemAtCrackTip(const Elem * elem) const
1605 {
1606  return (_crack_tip_elems.find(elem) != _crack_tip_elems.end());
1607 }
1608 
1609 bool
1610 XFEM::isElemCut(const Elem * elem, XFEMCutElem *& xfce) const
1611 {
1612  xfce = NULL;
1613  bool is_cut = false;
1614  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1615  it = _cut_elem_map.find(elem->unique_id());
1616  if (it != _cut_elem_map.end())
1617  {
1618  xfce = it->second;
1619  const EFAElement * EFAelem = xfce->getEFAElement();
1620  if (EFAelem->isPartial()) // exclude the full crack tip elements
1621  is_cut = true;
1622  }
1623  return is_cut;
1624 }
1625 
1626 bool
1627 XFEM::isElemCut(const Elem * elem) const
1628 {
1629  XFEMCutElem * xfce = NULL;
1630  return isElemCut(elem, xfce);
1631 }
1632 
1633 void
1634 XFEM::getFragmentFaces(const Elem * elem,
1635  std::vector<std::vector<Point>> & frag_faces,
1636  bool displaced_mesh) const
1637 {
1638  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1639  it = _cut_elem_map.find(elem->unique_id());
1640  if (it != _cut_elem_map.end())
1641  {
1642  const XFEMCutElem * xfce = it->second;
1643  if (displaced_mesh)
1644  xfce->getFragmentFaces(frag_faces, _displaced_mesh);
1645  else
1646  xfce->getFragmentFaces(frag_faces);
1647  }
1648 }
1649 
1650 EFAElement2D *
1651 XFEM::getEFAElem2D(const Elem * elem)
1652 {
1653  EFAElement * EFAelem = _efa_mesh.getElemByID(elem->id());
1654  EFAElement2D * EFAelem2D = dynamic_cast<EFAElement2D *>(EFAelem);
1655 
1656  if (!EFAelem2D)
1657  mooseError("EFAelem is not of EFAelement2D type");
1658 
1659  return EFAelem2D;
1660 }
1661 
1662 EFAElement3D *
1663 XFEM::getEFAElem3D(const Elem * elem)
1664 {
1665  EFAElement * EFAelem = _efa_mesh.getElemByID(elem->id());
1666  EFAElement3D * EFAelem3D = dynamic_cast<EFAElement3D *>(EFAelem);
1667 
1668  if (!EFAelem3D)
1669  mooseError("EFAelem is not of EFAelement3D type");
1670 
1671  return EFAelem3D;
1672 }
1673 
1674 void
1675 XFEM::getFragmentEdges(const Elem * elem,
1676  EFAElement2D * CEMElem,
1677  std::vector<std::vector<Point>> & frag_edges) const
1678 {
1679  // N.B. CEMElem here has global EFAnode
1680  frag_edges.clear();
1681  if (CEMElem->numFragments() > 0)
1682  {
1683  if (CEMElem->numFragments() > 1)
1684  mooseError("element ", elem->id(), " has more than one fragment at this point");
1685  for (unsigned int i = 0; i < CEMElem->getFragment(0)->numEdges(); ++i)
1686  {
1687  std::vector<Point> p_line(2, Point(0.0, 0.0, 0.0));
1688  p_line[0] = getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(0), CEMElem, elem);
1689  p_line[1] = getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(1), CEMElem, elem);
1690  frag_edges.push_back(p_line);
1691  }
1692  }
1693 }
1694 
1695 void
1696 XFEM::getFragmentFaces(const Elem * elem,
1697  EFAElement3D * CEMElem,
1698  std::vector<std::vector<Point>> & frag_faces) const
1699 {
1700  // N.B. CEMElem here has global EFAnode
1701  frag_faces.clear();
1702  if (CEMElem->numFragments() > 0)
1703  {
1704  if (CEMElem->numFragments() > 1)
1705  mooseError("element ", elem->id(), " has more than one fragment at this point");
1706  for (unsigned int i = 0; i < CEMElem->getFragment(0)->numFaces(); ++i)
1707  {
1708  unsigned int num_face_nodes = CEMElem->getFragmentFace(0, i)->numNodes();
1709  std::vector<Point> p_line(num_face_nodes, Point(0.0, 0.0, 0.0));
1710  for (unsigned int j = 0; j < num_face_nodes; ++j)
1711  p_line[j] = getEFANodeCoords(CEMElem->getFragmentFace(0, i)->getNode(j), CEMElem, elem);
1712  frag_faces.push_back(p_line);
1713  }
1714  }
1715 }
1716 
1719 {
1720  return _XFEM_qrule;
1721 }
1722 
1723 void
1724 XFEM::setXFEMQRule(std::string & xfem_qrule)
1725 {
1726  if (xfem_qrule == "volfrac")
1728  else if (xfem_qrule == "moment_fitting")
1730  else if (xfem_qrule == "direct")
1732 }
1733 
1734 void
1735 XFEM::setCrackGrowthMethod(bool use_crack_growth_increment, Real crack_growth_increment)
1736 {
1737  _use_crack_growth_increment = use_crack_growth_increment;
1738  _crack_growth_increment = crack_growth_increment;
1739 }
1740 
1741 void
1742 XFEM::setDebugOutputLevel(unsigned int debug_output_level)
1743 {
1744  _debug_output_level = debug_output_level;
1745 }
1746 
1747 bool
1748 XFEM::getXFEMWeights(MooseArray<Real> & weights,
1749  const Elem * elem,
1750  QBase * qrule,
1751  const MooseArray<Point> & q_points)
1752 {
1753  bool have_weights = false;
1754  XFEMCutElem * xfce = NULL;
1755  if (isElemCut(elem, xfce))
1756  {
1757  mooseAssert(xfce != NULL, "Must have valid XFEMCutElem object here");
1758  xfce->getWeightMultipliers(weights, qrule, getXFEMQRule(), q_points);
1759  have_weights = true;
1760  }
1761  return have_weights;
1762 }
1763 
1764 bool
1765 XFEM::getXFEMFaceWeights(MooseArray<Real> & weights,
1766  const Elem * elem,
1767  QBase * qrule,
1768  const MooseArray<Point> & q_points,
1769  unsigned int side)
1770 {
1771  bool have_weights = false;
1772  XFEMCutElem * xfce = NULL;
1773  if (isElemCut(elem, xfce))
1774  {
1775  mooseAssert(xfce != NULL, "Must have valid XFEMCutElem object here");
1776  xfce->getFaceWeightMultipliers(weights, qrule, getXFEMQRule(), q_points, side);
1777  have_weights = true;
1778  }
1779  return have_weights;
1780 }
1781 
1782 void
1784  unsigned int plane_id,
1785  Point & normal,
1786  std::vector<Point> & intersectionPoints,
1787  bool displaced_mesh) const
1788 {
1789  std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1790  it = _cut_elem_map.find(elem->unique_id());
1791  if (it != _cut_elem_map.end())
1792  {
1793  const XFEMCutElem * xfce = it->second;
1794  if (displaced_mesh)
1795  xfce->getIntersectionInfo(plane_id, normal, intersectionPoints, _displaced_mesh);
1796  else
1797  xfce->getIntersectionInfo(plane_id, normal, intersectionPoints);
1798  }
1799 }
1800 
1801 void
1802 XFEM::getXFEMqRuleOnLine(std::vector<Point> & intersection_points,
1803  std::vector<Point> & quad_pts,
1804  std::vector<Real> & quad_wts) const
1805 {
1806  Point p1 = intersection_points[0];
1807  Point p2 = intersection_points[1];
1808 
1809  // number of quadrature points
1810  std::size_t num_qpoints = 2;
1811 
1812  // quadrature coordinates
1813  Real xi0 = -std::sqrt(1.0 / 3.0);
1814  Real xi1 = std::sqrt(1.0 / 3.0);
1815 
1816  quad_wts.resize(num_qpoints);
1817  quad_pts.resize(num_qpoints);
1818 
1819  Real integ_jacobian = pow((p1 - p2).norm_sq(), 0.5) * 0.5;
1820 
1821  quad_wts[0] = 1.0 * integ_jacobian;
1822  quad_wts[1] = 1.0 * integ_jacobian;
1823 
1824  quad_pts[0] = (1.0 - xi0) / 2.0 * p1 + (1.0 + xi0) / 2.0 * p2;
1825  quad_pts[1] = (1.0 - xi1) / 2.0 * p1 + (1.0 + xi1) / 2.0 * p2;
1826 }
1827 
1828 void
1829 XFEM::getXFEMqRuleOnSurface(std::vector<Point> & intersection_points,
1830  std::vector<Point> & quad_pts,
1831  std::vector<Real> & quad_wts) const
1832 {
1833  std::size_t nnd_pe = intersection_points.size();
1834  Point xcrd(0.0, 0.0, 0.0);
1835  for (std::size_t i = 0; i < nnd_pe; ++i)
1836  xcrd += intersection_points[i];
1837  xcrd /= nnd_pe;
1838 
1839  quad_pts.resize(nnd_pe);
1840  quad_wts.resize(nnd_pe);
1841 
1842  Real jac = 0.0;
1843 
1844  for (std::size_t j = 0; j < nnd_pe; ++j) // loop all sub-tris
1845  {
1846  std::vector<std::vector<Real>> shape(3, std::vector<Real>(3, 0.0));
1847  std::vector<Point> subtrig_points(3, Point(0.0, 0.0, 0.0)); // sub-trig nodal coords
1848 
1849  int jplus1 = j < nnd_pe - 1 ? j + 1 : 0;
1850  subtrig_points[0] = xcrd;
1851  subtrig_points[1] = intersection_points[j];
1852  subtrig_points[2] = intersection_points[jplus1];
1853 
1854  std::vector<std::vector<Real>> sg2;
1855  Xfem::stdQuadr2D(3, 1, sg2); // get sg2
1856  for (std::size_t l = 0; l < sg2.size(); ++l) // loop all int pts on a sub-trig
1857  {
1858  Xfem::shapeFunc2D(3, sg2[l], subtrig_points, shape, jac, true); // Get shape
1859  std::vector<Real> tsg_line(3, 0.0);
1860  for (std::size_t k = 0; k < 3; ++k) // loop sub-trig nodes
1861  {
1862  tsg_line[0] += shape[k][2] * subtrig_points[k](0);
1863  tsg_line[1] += shape[k][2] * subtrig_points[k](1);
1864  tsg_line[2] += shape[k][2] * subtrig_points[k](2);
1865  }
1866  quad_pts[j + l] = Point(tsg_line[0], tsg_line[1], tsg_line[2]);
1867  quad_wts[j + l] = sg2[l][3] * jac;
1868  }
1869  }
1870 }
1871 
1872 void
1873 XFEM::storeSolutionForNode(const Node * node_to_store_to,
1874  const Node * node_to_store_from,
1875  SystemBase & sys,
1876  std::map<unique_id_type, std::vector<Real>> & stored_solution,
1877  const NumericVector<Number> & current_solution,
1878  const NumericVector<Number> & old_solution,
1879  const NumericVector<Number> & older_solution)
1880 {
1881  std::vector<dof_id_type> stored_solution_dofs = getNodeSolutionDofs(node_to_store_from, sys);
1882  std::vector<Real> stored_solution_scratch;
1883  // Size for current solution, as well as for old, and older solution only for transient case
1884  std::size_t stored_solution_size =
1885  (_fe_problem->isTransient() ? stored_solution_dofs.size() * 3 : stored_solution_dofs.size());
1886  stored_solution_scratch.reserve(stored_solution_size);
1887 
1888  // Store in the order defined in stored_solution_dofs first for the current, then for old and
1889  // older if applicable
1890  for (auto dof : stored_solution_dofs)
1891  stored_solution_scratch.push_back(current_solution(dof));
1892 
1893  if (_fe_problem->isTransient())
1894  {
1895  for (auto dof : stored_solution_dofs)
1896  stored_solution_scratch.push_back(old_solution(dof));
1897 
1898  for (auto dof : stored_solution_dofs)
1899  stored_solution_scratch.push_back(older_solution(dof));
1900  }
1901 
1902  if (stored_solution_scratch.size() > 0)
1903  stored_solution[node_to_store_to->unique_id()] = stored_solution_scratch;
1904 }
1905 
1906 void
1907 XFEM::storeSolutionForElement(const Elem * elem_to_store_to,
1908  const Elem * elem_to_store_from,
1909  SystemBase & sys,
1910  std::map<unique_id_type, std::vector<Real>> & stored_solution,
1911  const NumericVector<Number> & current_solution,
1912  const NumericVector<Number> & old_solution,
1913  const NumericVector<Number> & older_solution)
1914 {
1915  std::vector<dof_id_type> stored_solution_dofs = getElementSolutionDofs(elem_to_store_from, sys);
1916  std::vector<Real> stored_solution_scratch;
1917  // Size for current solution, as well as for old, and older solution only for transient case
1918  std::size_t stored_solution_size =
1919  (_fe_problem->isTransient() ? stored_solution_dofs.size() * 3 : stored_solution_dofs.size());
1920  stored_solution_scratch.reserve(stored_solution_size);
1921 
1922  // Store in the order defined in stored_solution_dofs first for the current, then for old and
1923  // older if applicable
1924  for (auto dof : stored_solution_dofs)
1925  stored_solution_scratch.push_back(current_solution(dof));
1926 
1927  if (_fe_problem->isTransient())
1928  {
1929  for (auto dof : stored_solution_dofs)
1930  stored_solution_scratch.push_back(old_solution(dof));
1931 
1932  for (auto dof : stored_solution_dofs)
1933  stored_solution_scratch.push_back(older_solution(dof));
1934  }
1935 
1936  if (stored_solution_scratch.size() > 0)
1937  stored_solution[elem_to_store_to->unique_id()] = stored_solution_scratch;
1938 }
1939 
1940 void
1941 XFEM::setSolution(SystemBase & sys,
1942  const std::map<unique_id_type, std::vector<Real>> & stored_solution,
1943  NumericVector<Number> & current_solution,
1944  NumericVector<Number> & old_solution,
1945  NumericVector<Number> & older_solution)
1946 {
1947  for (auto & node : _mesh->local_node_ptr_range())
1948  {
1949  auto mit = stored_solution.find(node->unique_id());
1950  if (mit != stored_solution.end())
1951  {
1952  const std::vector<Real> & stored_node_solution = mit->second;
1953  std::vector<dof_id_type> stored_solution_dofs = getNodeSolutionDofs(node, sys);
1954  setSolutionForDOFs(stored_node_solution,
1955  stored_solution_dofs,
1956  current_solution,
1957  old_solution,
1958  older_solution);
1959  }
1960  }
1961 
1962  for (auto & elem : as_range(_mesh->local_elements_begin(), _mesh->local_elements_end()))
1963  {
1964  auto mit = stored_solution.find(elem->unique_id());
1965  if (mit != stored_solution.end())
1966  {
1967  const std::vector<Real> & stored_elem_solution = mit->second;
1968  std::vector<dof_id_type> stored_solution_dofs = getElementSolutionDofs(elem, sys);
1969  setSolutionForDOFs(stored_elem_solution,
1970  stored_solution_dofs,
1971  current_solution,
1972  old_solution,
1973  older_solution);
1974  }
1975  }
1976 }
1977 
1978 void
1979 XFEM::setSolutionForDOFs(const std::vector<Real> & stored_solution,
1980  const std::vector<dof_id_type> & stored_solution_dofs,
1981  NumericVector<Number> & current_solution,
1982  NumericVector<Number> & old_solution,
1983  NumericVector<Number> & older_solution)
1984 {
1985  // Solution vector is stored first for current, then old and older solutions.
1986  // These are the offsets to the beginning of the old and older solutions in the vector.
1987  const auto old_solution_offset = stored_solution_dofs.size();
1988  const auto older_solution_offset = old_solution_offset * 2;
1989 
1990  for (std::size_t i = 0; i < stored_solution_dofs.size(); ++i)
1991  {
1992  current_solution.set(stored_solution_dofs[i], stored_solution[i]);
1993  if (_fe_problem->isTransient())
1994  {
1995  old_solution.set(stored_solution_dofs[i], stored_solution[old_solution_offset + i]);
1996  older_solution.set(stored_solution_dofs[i], stored_solution[older_solution_offset + i]);
1997  }
1998  }
1999 }
2000 
2001 std::vector<dof_id_type>
2002 XFEM::getElementSolutionDofs(const Elem * elem, SystemBase & sys) const
2003 {
2004  SubdomainID sid = elem->subdomain_id();
2005  const std::vector<MooseVariableFEBase *> & vars = sys.getVariables(0);
2006  std::vector<dof_id_type> solution_dofs;
2007  solution_dofs.reserve(vars.size()); // just an approximation
2008  for (auto var : vars)
2009  {
2010  if (!var->isNodal())
2011  {
2012  const std::set<SubdomainID> & var_subdomains = sys.getSubdomainsForVar(var->number());
2013  if (var_subdomains.empty() || var_subdomains.find(sid) != var_subdomains.end())
2014  {
2015  unsigned int n_comp = elem->n_comp(sys.number(), var->number());
2016  for (unsigned int icomp = 0; icomp < n_comp; ++icomp)
2017  {
2018  dof_id_type elem_dof = elem->dof_number(sys.number(), var->number(), icomp);
2019  solution_dofs.push_back(elem_dof);
2020  }
2021  }
2022  }
2023  }
2024  return solution_dofs;
2025 }
2026 
2027 std::vector<dof_id_type>
2028 XFEM::getNodeSolutionDofs(const Node * node, SystemBase & sys) const
2029 {
2030  const std::set<SubdomainID> & sids = _moose_mesh->getNodeBlockIds(*node);
2031  const std::vector<MooseVariableFEBase *> & vars = sys.getVariables(0);
2032  std::vector<dof_id_type> solution_dofs;
2033  solution_dofs.reserve(vars.size()); // just an approximation
2034  for (auto var : vars)
2035  {
2036  if (var->isNodal())
2037  {
2038  const std::set<SubdomainID> & var_subdomains = sys.getSubdomainsForVar(var->number());
2039  std::set<SubdomainID> intersect;
2040  set_intersection(var_subdomains.begin(),
2041  var_subdomains.end(),
2042  sids.begin(),
2043  sids.end(),
2044  std::inserter(intersect, intersect.begin()));
2045  if (var_subdomains.empty() || !intersect.empty())
2046  {
2047  unsigned int n_comp = node->n_comp(sys.number(), var->number());
2048  for (unsigned int icomp = 0; icomp < n_comp; ++icomp)
2049  {
2050  dof_id_type node_dof = node->dof_number(sys.number(), var->number(), icomp);
2051  solution_dofs.push_back(node_dof);
2052  }
2053  }
2054  }
2055  }
2056  return solution_dofs;
2057 }
XFEM::_geom_marker_id_elems
std::map< unsigned int, std::set< unsigned int > > _geom_marker_id_elems
Data structure for storing the elements cut by specific geometric cutters.
Definition: XFEM.h:290
ElementFragmentAlgorithm::updatePhysicalLinksAndFragments
void updatePhysicalLinksAndFragments()
Definition: ElementFragmentAlgorithm.C:290
EFAFragment2D::getInteriorEdgeID
std::vector< unsigned int > getInteriorEdgeID() const
Definition: EFAFragment2D.C:266
ElementFragmentAlgorithm::initCrackTipTopology
void initCrackTipTopology()
Definition: ElementFragmentAlgorithm.C:200
EFANode::id
unsigned int id() const
Definition: EFANode.C:36
EFAElement2D::getEdge
EFAEdge * getEdge(unsigned int edge_id) const
Definition: EFAElement2D.C:1475
XFEM::isElemAtCrackTip
bool isElemAtCrackTip(const Elem *elem) const
Definition: XFEM.C:1604
XFEM::storeSolutionForElement
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 > &current_solution, const NumericVector< Number > &old_solution, const NumericVector< Number > &older_solution)
Store the solution in stored_solution for a given element.
Definition: XFEM.C:1907
EFAElement2D::isFinalCut
virtual bool isFinalCut() const
Definition: EFAElement2D.C:791
EFAElement
Definition: EFAElement.h:19
XFEMCutElem2D.h
ElementFragmentAlgorithm::getNewNodes
const std::vector< EFANode * > & getNewNodes()
Definition: ElementFragmentAlgorithm.h:81
Xfem::shapeFunc2D
void shapeFunc2D(unsigned int nen, std::vector< Real > &ss, std::vector< Point > &xl, std::vector< std::vector< Real >> &shp, Real &xsj, bool natl_flg)
Definition: XFEMFuncs.C:269
EFAElement3D::getFragmentFace
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
Definition: EFAElement3D.C:1706
XFEM::_XFEM_qrule
Xfem::XFEM_QRULE _XFEM_qrule
Definition: XFEM.h:262
EFAFragment3D::numFaces
unsigned int numFaces() const
Definition: EFAFragment3D.C:271
XFEM::getCutPlane
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.
Definition: XFEM.C:1570
Xfem::GeomMarkedElemInfo2D
Data structure describing geometrically described cut through 2D element.
Definition: GeometricCutUserObject.h:75
XFEMCutElem::getIntersectionInfo
virtual void getIntersectionInfo(unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, MeshBase *displaced_mesh=NULL) const =0
XFEM::storeSolutionForNode
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 > &current_solution, const NumericVector< Number > &old_solution, const NumericVector< Number > &older_solution)
Store the solution in stored_solution for a given node.
Definition: XFEM.C:1873
XFEM::_state_marked_frags
std::set< const Elem * > _state_marked_frags
Definition: XFEM.h:280
XFEM::getXFEMqRuleOnSurface
virtual void getXFEMqRuleOnSurface(std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
Definition: XFEM.C:1829
EFANode.h
XFEM::addStateMarkedElem
void addStateMarkedElem(unsigned int elem_id, RealVectorValue &normal)
Definition: XFEM.C:112
EXEC_XFEM_MARK
const ExecFlagType EXEC_XFEM_MARK
Exec flag used to execute MooseObjects while elements are being marked for cutting by XFEM.
XFEM::setCrackGrowthMethod
void setCrackGrowthMethod(bool use_crack_growth_increment, Real crack_growth_increment)
Definition: XFEM.C:1735
EFAFuncs.h
XFEM::getEFAElem3D
EFAElement3D * getEFAElem3D(const Elem *elem)
Get the EFAElement3D object for a specified libMesh element.
Definition: XFEM.C:1663
EFAFragment3D.h
pow
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
Definition: ExpressionBuilder.h:673
EFAElement3D::getFragment
EFAFragment3D * getFragment(unsigned int frag_id) const
Definition: EFAElement3D.C:1372
EFAFace::getNode
EFANode * getNode(unsigned int node_id) const
Definition: EFAFace.C:99
XFEMCutElem::getPhysicalVolumeFraction
Real getPhysicalVolumeFraction() const
Returns the volume fraction of the element fragment.
Definition: XFEMCutElem.C:49
ElementFragmentAlgorithm::add3DElement
EFAElement * add3DElement(std::vector< unsigned int > quad, unsigned int id)
Definition: ElementFragmentAlgorithm.C:133
XFEM::getXFEMIntersectionInfo
virtual void getXFEMIntersectionInfo(const Elem *elem, unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, bool displaced_mesh=false) const
Definition: XFEM.C:1783
XFEM::_geom_marked_elems_2d
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.
Definition: XFEM.h:284
XFEMCutElem::getFragmentFaces
virtual void getFragmentFaces(std::vector< std::vector< Point >> &frag_faces, MeshBase *displaced_mesh=NULL) const =0
EFAFragment3D::isThirdInteriorFace
bool isThirdInteriorFace(unsigned int face_id) const
Definition: EFAFragment3D.C:253
XFEM::cutMeshWithEFA
bool cutMeshWithEFA(NonlinearSystemBase &nl, AuxiliarySystem &aux)
Definition: XFEM.C:1077
XFEM::getXFEMqRuleOnLine
virtual void getXFEMqRuleOnLine(std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
Definition: XFEM.C:1802
XFEM::setDebugOutputLevel
void setDebugOutputLevel(unsigned int debug_output_level)
Controls amount of debugging information output.
Definition: XFEM.C:1742
XFEM::getElementSolutionDofs
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.
Definition: XFEM.C:2002
ElementFragmentAlgorithm::addFragFaceIntersection
void addFragFaceIntersection(unsigned int ElemID, unsigned int FragFaceID, std::vector< unsigned int > FragFaceEdgeID, std::vector< double > position)
Definition: ElementFragmentAlgorithm.C:281
XFEM::clearStateMarkedElems
void clearStateMarkedElems()
Definition: XFEM.C:154
XFEM::_state_marked_elems
std::map< const Elem *, RealVectorValue > _state_marked_elems
Definition: XFEM.h:279
XFEM::isElemCut
bool isElemCut(const Elem *elem, XFEMCutElem *&xfce) const
Definition: XFEM.C:1610
ElementFragmentAlgorithm::updateTopology
void updateTopology(bool mergeUncutVirtualEdges=true)
Definition: ElementFragmentAlgorithm.C:302
Xfem::DIRECT
Definition: XFEM.h:41
XFEMAppTypes.h
XFEM::markCutFacesByGeometry
bool markCutFacesByGeometry()
Definition: XFEM.C:852
EFAElement::getLocalNodeIndex
unsigned int getLocalNodeIndex(EFANode *node) const
Definition: EFAElement.C:111
XFEM::addStateMarkedFrag
void addStateMarkedFrag(unsigned int elem_id, RealVectorValue &normal)
Definition: XFEM.C:138
XFEM::buildEFAMesh
void buildEFAMesh()
Definition: XFEM.C:340
XFEM::setSolutionForDOFs
void setSolutionForDOFs(const std::vector< Real > &stored_solution, const std::vector< dof_id_type > &stored_solution_dofs, NumericVector< Number > &current_solution, NumericVector< Number > &old_solution, NumericVector< Number > &older_solution)
Set the solution for a set of DOFs.
Definition: XFEM.C:1979
XFEM::correctCrackExtensionDirection
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)
Definition: XFEM.C:447
GeometricCutUserObject
Definition: GeometricCutUserObject.h:106
XFEMCutElem::getFaceWeightMultipliers
void getFaceWeightMultipliers(MooseArray< Real > &face_weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points, unsigned int side)
Definition: XFEMCutElem.C:75
XFEM::initSolution
virtual void initSolution(NonlinearSystemBase &nl, AuxiliarySystem &aux) override
Definition: XFEM.C:313
EFAElement2D::getFragmentEdge
EFAEdge * getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const
Definition: EFAElement2D.C:1481
XFEM::_geom_marked_elems_3d
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.
Definition: XFEM.h:287
XFEM::markCutFacesByState
bool markCutFacesByState()
Definition: XFEM.C:893
XFEM::getPhysicalVolumeFraction
Real getPhysicalVolumeFraction(const Elem *elem) const
Get the volume fraction of an element that is physical.
Definition: XFEM.C:1532
XFEM::getXFEMQRule
Xfem::XFEM_QRULE & getXFEMQRule()
Definition: XFEM.C:1718
XFEMFuncs.h
XFEM::getXFEMWeights
virtual bool getXFEMWeights(MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points) override
Definition: XFEM.C:1748
ElementFragmentAlgorithm::addElemFaceIntersection
void addElemFaceIntersection(unsigned int elemid, unsigned int faceid, std::vector< unsigned int > edgeid, std::vector< double > position)
Definition: ElementFragmentAlgorithm.C:261
EFAFace.h
EFAElement3D
Definition: EFAElement3D.h:20
XFEM::setXFEMQRule
void setXFEMQRule(std::string &xfem_qrule)
Definition: XFEM.C:1724
XFEMCutElem2D
Definition: XFEMCutElem2D.h:24
XFEM::_state_marked_elem_sides
std::map< const Elem *, unsigned int > _state_marked_elem_sides
Definition: XFEM.h:281
ElementFragmentAlgorithm::printMesh
void printMesh()
Definition: ElementFragmentAlgorithm.C:504
ElementFragmentAlgorithm::addFragEdgeIntersection
bool addFragEdgeIntersection(unsigned int elemid, unsigned int frag_edge_id, double position)
Definition: ElementFragmentAlgorithm.C:245
XFEM::_cached_solution
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...
Definition: XFEM.h:311
XFEM::updateHeal
virtual bool updateHeal() override
Definition: XFEM.C:228
XFEM::markCutEdgesByState
bool markCutEdgesByState(Real time)
Definition: XFEM.C:588
XFEM.h
XFEM::isPointInsidePhysicalDomain
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,...
Definition: XFEM.C:1552
EFAElement3D::isFacePhantom
bool isFacePhantom(unsigned int face_id) const
Definition: EFAElement3D.C:1814
EFAElement2D::isEdgePhantom
bool isEdgePhantom(unsigned int edge_id) const
Definition: EFAElement2D.C:1537
XFEM::getFragmentFaces
void getFragmentFaces(const Elem *elem, std::vector< std::vector< Point >> &frag_faces, bool displaced_mesh=false) const
Definition: XFEM.C:1634
XFEM::_geometric_cuts
std::vector< const GeometricCutUserObject * > _geometric_cuts
Definition: XFEM.h:267
XFEM::setSolution
void setSolution(SystemBase &sys, const std::map< unique_id_type, std::vector< Real >> &stored_solution, NumericVector< Number > &current_solution, NumericVector< Number > &old_solution, NumericVector< Number > &older_solution)
Set the solution for all locally-owned nodes/elements that have stored values.
Definition: XFEM.C:1941
Xfem::GeomMarkedElemInfo3D
Data structure describing geometrically described cut through 3D element.
Definition: GeometricCutUserObject.h:88
ElementFragmentAlgorithm::getParentElements
const std::vector< EFAElement * > & getParentElements()
Definition: ElementFragmentAlgorithm.h:80
EFAFragment2D.h
XFEMCutElem::getEFAElement
virtual const EFAElement * getEFAElement() const =0
XFEM::_use_crack_growth_increment
bool _use_crack_growth_increment
Definition: XFEM.h:264
ElementFragmentAlgorithm::updateEdgeNeighbors
void updateEdgeNeighbors()
Definition: ElementFragmentAlgorithm.C:177
XFEM::getEFAElem2D
EFAElement2D * getEFAElem2D(const Elem *elem)
Get the EFAElement2D object for a specified libMesh element.
Definition: XFEM.C:1651
EFAElement2D::getCrackTipSplitElementID
unsigned int getCrackTipSplitElementID() const
Definition: EFAElement2D.C:594
EFAElement::getMasterInfo
virtual void getMasterInfo(EFANode *node, std::vector< EFANode * > &master_nodes, std::vector< double > &master_weights) const =0
EFAEdge::getNode
EFANode * getNode(unsigned int index) const
Definition: EFAEdge.C:179
GeometricCutUserObject::setInterfaceID
void setInterfaceID(unsigned int interface_id)
Set the interface ID for this cutting object.
Definition: GeometricCutUserObject.h:178
XFEM::getNodeSolutionDofs
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.
Definition: XFEM.C:2028
EFAElement2D::getFragment
EFAFragment2D * getFragment(unsigned int frag_id) const
Definition: EFAElement2D.C:1388
name
const std::string name
Definition: Setup.h:21
ElementFragmentAlgorithm::getChildElements
const std::vector< EFAElement * > & getChildElements()
Definition: ElementFragmentAlgorithm.h:79
XFEM::getFragmentEdges
void getFragmentEdges(const Elem *elem, EFAElement2D *CEMElem, std::vector< std::vector< Point >> &frag_edges) const
Definition: XFEM.C:1675
XFEM::~XFEM
~XFEM()
Definition: XFEM.C:45
ElementFragmentAlgorithm::reset
void reset()
Definition: ElementFragmentAlgorithm.C:330
XFEM::_debug_output_level
unsigned int _debug_output_level
Controls amount of debugging output information 0: None 1: Summary 2: Details on modifications to mes...
Definition: XFEM.h:302
ElementFragmentAlgorithm::add2DElement
EFAElement * add2DElement(std::vector< unsigned int > quad, unsigned int id)
Definition: ElementFragmentAlgorithm.C:102
XFEMCutElem3D.h
XFEM::clearGeomMarkedElems
void clearGeomMarkedElems()
Clear out the list of elements to be marked for cutting.
Definition: XFEM.C:182
EFAFragment2D::isSecondaryInteriorEdge
bool isSecondaryInteriorEdge(unsigned int edge_id) const
Definition: EFAFragment2D.C:278
XFEM::_sibling_elems
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_elems
Definition: XFEM.h:272
XFEM::_crack_growth_increment
Real _crack_growth_increment
Definition: XFEM.h:265
XFEM::_crack_tip_elems_to_be_healed
std::set< const Elem * > _crack_tip_elems_to_be_healed
Definition: XFEM.h:271
XFEM::_cut_elem_map
std::map< unique_id_type, XFEMCutElem * > _cut_elem_map
Definition: XFEM.h:269
XFEMCutElem::getWeightMultipliers
void getWeightMultipliers(MooseArray< Real > &weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points)
Definition: XFEMCutElem.C:61
XFEMCrackGrowthIncrement2DCut::cutElementByCrackGrowthIncrement
virtual bool cutElementByCrackGrowthIncrement(const Elem *elem, std::vector< CutEdgeForCrackGrowthIncr > &cut_edges, Real time)
Definition: XFEMCrackGrowthIncrement2DCut.C:38
XFEM::_crack_tip_elems
std::set< const Elem * > _crack_tip_elems
Definition: XFEM.h:270
XFEMCrackGrowthIncrement2DCut
Definition: XFEMCrackGrowthIncrement2DCut.h:26
EFAEdge::getEmbeddedNode
EFANode * getEmbeddedNode(unsigned int index) const
Definition: EFAEdge.C:330
XFEM::getCrackTipOrigin
void getCrackTipOrigin(std::map< unsigned int, const Elem * > &elem_id_crack_tip, std::vector< Point > &crack_front_points)
Definition: XFEM.C:64
EFAEdge.h
EFANode::N_CATEGORY_PERMANENT
Definition: EFANode.h:19
XFEM::healMesh
bool healMesh()
Potentially heal the mesh by merging some of the pairs of partial elements cut by XFEM back into sing...
Definition: XFEM.C:920
Xfem::MOMENT_FITTING
Definition: XFEM.h:40
XFEMCutElem::computePhysicalVolumeFraction
virtual void computePhysicalVolumeFraction()=0
Computes the volume fraction of the element fragment.
XFEM::_sibling_displaced_elems
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_displaced_elems
Definition: XFEM.h:273
EFAElement3D::numFragments
virtual unsigned int numFragments() const
Definition: EFAElement3D.C:269
Xfem::XFEM_CUTPLANE_QUANTITY
XFEM_CUTPLANE_QUANTITY
Definition: XFEM.h:27
EFAEdge
Definition: EFAEdge.h:16
XFEM::initCutIntersectionEdge
bool initCutIntersectionEdge(Point cut_origin, RealVectorValue cut_normal, Point &edge_p1, Point &edge_p2, Real &dist)
Definition: XFEM.C:901
EFANode
Definition: EFANode.h:14
EFAEdge::hasIntersection
bool hasIntersection() const
Definition: EFAEdge.C:198
XFEM::getXFEMFaceWeights
virtual bool getXFEMFaceWeights(MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points, unsigned int side) override
Definition: XFEM.C:1765
XFEM::_cached_aux_solution
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...
Definition: XFEM.h:320
EFAEdge::isPartialOverlap
bool isPartialOverlap(const EFAEdge &other) const
Definition: EFAEdge.C:57
XFEM::getEFANodeCoords
Point getEFANodeCoords(EFANode *CEMnode, EFAElement *CEMElem, const Elem *elem, MeshBase *displaced_mesh=NULL) const
Definition: XFEM.C:1500
XFEMCutElem::isPointPhysical
bool isPointPhysical(const Point &p) const
Definition: XFEMCutElem.C:191
ElementFragmentAlgorithm::restoreFragmentInfo
void restoreFragmentInfo(EFAElement *const elem, const EFAElement *const from_elem)
Definition: ElementFragmentAlgorithm.C:410
EFAElement::isPartial
virtual bool isPartial() const =0
EFAElement2D::numFragments
virtual unsigned int numFragments() const
Definition: EFAElement2D.C:202
Xfem::stdQuadr2D
void stdQuadr2D(unsigned int nen, unsigned int iord, std::vector< std::vector< Real >> &sg2)
Definition: XFEMFuncs.C:96
EFAElement2D
Definition: EFAElement2D.h:20
EFAElement2D::getTipEmbeddedNode
EFANode * getTipEmbeddedNode() const
Definition: EFAElement2D.C:1636
EFAElement2D::numEdges
unsigned int numEdges() const
Definition: EFAElement2D.C:1447
EFAFace::numNodes
unsigned int numNodes() const
Definition: EFAFace.C:87
XFEM::addGeometricCut
void addGeometricCut(GeometricCutUserObject *geometric_cut)
Definition: XFEM.C:54
XFEM::markCuts
bool markCuts(Real time)
Definition: XFEM.C:378
XFEM::markCutEdgesByGeometry
bool markCutEdgesByGeometry()
Definition: XFEM.C:395
XFEMCutElem::getCutPlaneOrigin
virtual Point getCutPlaneOrigin(unsigned int plane_id, MeshBase *displaced_mesh=NULL) const =0
XFEMCutElem::getCutPlaneNormal
virtual Point getCutPlaneNormal(unsigned int plane_id, MeshBase *displaced_mesh=NULL) const =0
XFEMCutElem::getCrackTipOriginAndDirection
virtual void getCrackTipOriginAndDirection(unsigned tip_id, Point &origin, Point &direction) const =0
XFEM::XFEM
XFEM(const InputParameters &params)
Definition: XFEM.C:35
EFAFragment2D::numEdges
unsigned int numEdges() const
Definition: EFAFragment2D.C:296
XFEM::_efa_mesh
ElementFragmentAlgorithm _efa_mesh
Definition: XFEM.h:295
ElementFragmentAlgorithm::getElemByID
EFAElement * getElemByID(unsigned int id)
Definition: ElementFragmentAlgorithm.C:590
XFEM::update
virtual bool update(Real time, NonlinearSystemBase &nl, AuxiliarySystem &aux) override
Definition: XFEM.C:265
ElementFragmentAlgorithm::getCrackTipElements
const std::set< EFAElement * > & getCrackTipElements()
Definition: ElementFragmentAlgorithm.h:82
XFEMCutElem
Definition: XFEMCutElem.h:29
XFEM::_geom_marker_id_map
std::map< const GeometricCutUserObject *, unsigned int > _geom_marker_id_map
Data structure for storing the GeommetricCutUserObjects and their corresponding id.
Definition: XFEM.h:293
XFEM::addGeomMarkedElem3D
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.
Definition: XFEM.C:172
XFEM::storeCrackTipOriginAndDirection
void storeCrackTipOriginAndDirection()
Definition: XFEM.C:189
XFEM::addGeomMarkedElem2D
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.
Definition: XFEM.C:162
XFEMCutElem3D
Definition: XFEMCutElem3D.h:24
ElementFragmentAlgorithm::addElemEdgeIntersection
void addElemEdgeIntersection(unsigned int elemid, unsigned int edgeid, double position)
Definition: ElementFragmentAlgorithm.C:212
Xfem::VOLFRAC
Definition: XFEM.h:39
EFAElement2D::getTipEdgeID
unsigned int getTipEdgeID() const
Definition: EFAElement2D.C:1608
ElementFragmentAlgorithm::addElemNodeIntersection
void addElemNodeIntersection(unsigned int elemid, unsigned int nodeid)
Definition: ElementFragmentAlgorithm.C:228
Xfem::XFEM_QRULE
XFEM_QRULE
Definition: XFEM.h:37
XFEM::_has_secondary_cut
bool _has_secondary_cut
Definition: XFEM.h:260
XFEM::_elem_crack_origin_direction_map
std::map< const Elem *, std::vector< Point > > _elem_crack_origin_direction_map
Definition: XFEM.h:275