https://mooseframework.inl.gov
Loading...
Searching...
No Matches
XFEM.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
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"
32
33#include "libmesh/mesh_communication.h"
34#include "libmesh/partitioner.h"
35
37 : XFEMInterface(params),
38 _efa_mesh(Moose::out),
39 _debug_output_level(1),
40 _min_weight_multiplier(0.0)
41{
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!");
45#endif
46 _has_secondary_cut = false;
47}
48
50{
51 for (std::map<unique_id_type, XFEMCutElem *>::iterator cemit = _cut_elem_map.begin();
52 cemit != _cut_elem_map.end();
53 ++cemit)
54 delete cemit->second;
55}
56
57void
59{
60 _geometric_cuts.push_back(geometric_cut);
61
62 geometric_cut->setInterfaceID(_geometric_cuts.size() - 1);
63
64 _geom_marker_id_map[geometric_cut] = _geometric_cuts.size() - 1;
65}
66
67void
68XFEM::getCrackTipOrigin(std::map<unsigned int, const Elem *> & elem_id_crack_tip,
69 std::vector<Point> & crack_front_points)
70{
71 elem_id_crack_tip.clear();
72 crack_front_points.clear();
73 crack_front_points.resize(_elem_crack_origin_direction_map.size());
74
75 unsigned int crack_tip_index = 0;
76 // This map is used to sort the order in _elem_crack_origin_direction_map such that every process
77 // has same order
78 std::map<unsigned int, const Elem *> elem_id_map;
79
80 int m = -1;
81 for (std::map<const Elem *, std::vector<Point>>::iterator mit1 =
84 ++mit1)
85 {
86 unsigned int elem_id = mit1->first->id();
87 if (elem_id == std::numeric_limits<unsigned int>::max())
88 {
89 elem_id_map[m] = mit1->first;
90 m--;
91 }
92 else
93 elem_id_map[elem_id] = mit1->first;
94 }
95
96 for (std::map<unsigned int, const Elem *>::iterator mit1 = elem_id_map.begin();
97 mit1 != elem_id_map.end();
98 mit1++)
99 {
100 const Elem * elem = mit1->second;
101 std::map<const Elem *, std::vector<Point>>::iterator mit2 =
103 if (mit2 != _elem_crack_origin_direction_map.end())
104 {
105 elem_id_crack_tip[crack_tip_index] = mit2->first;
106 crack_front_points[crack_tip_index] =
107 (mit2->second)[0]; // [0] stores origin coordinates and [1] stores direction
108 crack_tip_index++;
109 }
110 }
111}
112
113void
114XFEM::addStateMarkedElem(unsigned int elem_id, RealVectorValue & normal)
115{
116 Elem * elem = _mesh->elem_ptr(elem_id);
117 std::map<const Elem *, RealVectorValue>::iterator mit;
118 mit = _state_marked_elems.find(elem);
119 if (mit != _state_marked_elems.end())
120 mooseError(" ERROR: element ", elem->id(), " already marked for crack growth.");
121 _state_marked_elems[elem] = normal;
122}
123
124void
125XFEM::addStateMarkedElem(unsigned int elem_id, RealVectorValue & normal, unsigned int marked_side)
126{
127 addStateMarkedElem(elem_id, normal);
128 Elem * elem = _mesh->elem_ptr(elem_id);
129 std::map<const Elem *, unsigned int>::iterator mit;
130 mit = _state_marked_elem_sides.find(elem);
131 if (mit != _state_marked_elem_sides.end())
132 mooseError(" ERROR: side of element ", elem->id(), " already marked for crack initiation.");
133
134 _state_marked_elem_sides[elem] = marked_side;
135}
136
137void
138XFEM::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())
146 " ERROR: element ", elem->id(), " already marked for fragment-secondary crack initiation.");
147
148 _state_marked_frags.insert(elem);
149}
150
151void
158
159void
160XFEM::addGeomMarkedElem2D(const unsigned int elem_id,
161 const Xfem::GeomMarkedElemInfo2D geom_info,
162 const unsigned int interface_id)
163{
164 Elem * elem = _mesh->elem_ptr(elem_id);
165 _geom_marked_elems_2d[elem].push_back(geom_info);
166 _geom_marker_id_elems[interface_id].insert(elem_id);
167}
168
169void
170XFEM::addGeomMarkedElem3D(const unsigned int elem_id,
171 const Xfem::GeomMarkedElemInfo3D geom_info,
172 const unsigned int interface_id)
173{
174 Elem * elem = _mesh->elem_ptr(elem_id);
175 _geom_marked_elems_3d[elem].push_back(geom_info);
176 _geom_marker_id_elems[interface_id].insert(elem_id);
177}
178
179void
185
186void
188{
190 std::set<EFAElement *> CrackTipElements = _efa_mesh.getCrackTipElements();
191 std::set<EFAElement *>::iterator sit;
192 for (sit = CrackTipElements.begin(); sit != CrackTipElements.end(); ++sit)
193 {
194 if (_mesh->mesh_dimension() == 2)
195 {
196 EFAElement2D * CEMElem = dynamic_cast<EFAElement2D *>(*sit);
197 EFANode * tip_node = CEMElem->getTipEmbeddedNode();
198 unsigned int cts_id = CEMElem->getCrackTipSplitElementID();
199
200 Point origin(0, 0, 0);
201 Point direction(0, 0, 0);
202
203 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
204 it = _cut_elem_map.find(_mesh->elem_ptr(cts_id)->unique_id());
205 if (it != _cut_elem_map.end())
206 {
207 const XFEMCutElem * xfce = it->second;
208 const EFAElement * EFAelem = xfce->getEFAElement();
209 if (EFAelem->isPartial()) // exclude the full crack tip elements
210 {
211 xfce->getCrackTipOriginAndDirection(tip_node->id(), origin, direction);
212 }
213 }
214
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));
221 }
222 }
223}
224
225bool
227{
228 bool mesh_changed = false;
229
230 mesh_changed = healMesh();
231
232 if (mesh_changed)
233 buildEFAMesh();
234
235 if (mesh_changed)
236 {
237 _mesh->update_parallel_id_counts();
238 MeshCommunication().make_elems_parallel_consistent(*_mesh);
239 MeshCommunication().make_nodes_parallel_consistent(*_mesh);
240 // _mesh->find_neighbors();
241 // _mesh->contract();
242 _mesh->allow_renumbering(false);
243 _mesh->skip_partitioning(true);
244 _mesh->prepare_for_use();
245
246 if (_displaced_mesh)
247 {
248 _displaced_mesh->update_parallel_id_counts();
249 MeshCommunication().make_elems_parallel_consistent(*_displaced_mesh);
250 MeshCommunication().make_nodes_parallel_consistent(*_displaced_mesh);
251 _displaced_mesh->allow_renumbering(false);
252 _displaced_mesh->skip_partitioning(true);
253 _displaced_mesh->prepare_for_use();
254 }
255 }
256
257 _geom_marker_id_elems.clear();
258
259 return mesh_changed;
260}
261
262bool
263XFEM::update(Real time,
264 const std::vector<std::shared_ptr<NonlinearSystemBase>> & nl,
265 AuxiliarySystem & aux)
266{
268 mooseError("Use of XFEM with distributed mesh is not yet supported");
269
270 for (const auto & elem : _mesh->active_element_ptr_range())
271 if (elem->level() > 0)
272 mooseError("XFEM does not currently support mesh adaptivity or adaptively refined meshes");
273
274 bool mesh_changed = false;
275
276 buildEFAMesh();
277
279
281
282 if (markCuts(time))
283 mesh_changed = cutMeshWithEFA(nl, aux);
284
285 if (mesh_changed)
286 {
287 buildEFAMesh();
289 }
290
291 if (mesh_changed)
292 {
293 _mesh->allow_renumbering(false);
294 _mesh->skip_partitioning(true);
295 _mesh->prepare_for_use();
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 }
303 }
304
307
308 return mesh_changed;
309}
310
311void
312XFEM::initSolution(const std::vector<std::shared_ptr<NonlinearSystemBase>> & nls,
313 AuxiliarySystem & aux)
314{
315 if (nls.size() != 1)
316 mooseError("XFEM does not currently support multiple nonlinear systems");
317
318 nls[0]->serializeSolution();
319 aux.serializeSolution();
320 NumericVector<Number> & current_solution = *nls[0]->system().current_local_solution;
321 NumericVector<Number> & old_solution = nls[0]->solutionOld();
322 NumericVector<Number> & older_solution = nls[0]->solutionOlder();
323 NumericVector<Number> & current_aux_solution = *aux.system().current_local_solution;
324 NumericVector<Number> & old_aux_solution = aux.solutionOld();
325 NumericVector<Number> & older_aux_solution = aux.solutionOlder();
326
327 setSolution(*nls[0], _cached_solution, current_solution, old_solution, older_solution);
329 aux, _cached_aux_solution, current_aux_solution, old_aux_solution, older_aux_solution);
330
331 current_solution.close();
332 old_solution.close();
333 older_solution.close();
334 current_aux_solution.close();
335 old_aux_solution.close();
336 older_aux_solution.close();
337
338 _cached_solution.clear();
339 _cached_aux_solution.clear();
340}
341
342void
344{
346
347 // Load all existing elements in to EFA mesh
348 for (auto & elem : _mesh->element_ptr_range())
349 {
350 std::vector<unsigned int> quad;
351 for (unsigned int i = 0; i < elem->n_nodes(); ++i)
352 quad.push_back(elem->node_id(i));
353
354 if (_mesh->mesh_dimension() == 2)
355 _efa_mesh.add2DElement(quad, elem->id());
356 else if (_mesh->mesh_dimension() == 3)
357 _efa_mesh.add3DElement(quad, elem->id());
358 else
359 mooseError("XFEM only works for 2D and 3D");
360 }
361
362 // Restore fragment information for elements that have been previously cut
363 for (auto & elem : _mesh->element_ptr_range())
364 {
365 std::map<unique_id_type, XFEMCutElem *>::iterator cemit = _cut_elem_map.find(elem->unique_id());
366 if (cemit != _cut_elem_map.end())
367 {
368 XFEMCutElem * xfce = cemit->second;
369 EFAElement * CEMElem = _efa_mesh.getElemByID(elem->id());
371 }
372 }
373
374 // Must update edge neighbors before restore edge intersections. Otherwise, when we
375 // add edge intersections, we do not have neighbor information to use.
376 // Correction: no need to use neighbor info now
379}
380
381bool
383{
384 bool marked_sides = false;
385 if (_mesh->mesh_dimension() == 2)
386 {
387 marked_sides = markCutEdgesByGeometry();
388 marked_sides |= markCutEdgesByState(time);
389 }
390 else if (_mesh->mesh_dimension() == 3)
391 {
392 marked_sides = markCutFacesByGeometry();
393 marked_sides |= markCutFacesByState();
394 }
395 return marked_sides;
396}
397
398bool
400{
401 bool marked_edges = false;
402 bool marked_nodes = false;
403
404 for (const auto & gme : _geom_marked_elems_2d)
405 {
406 for (const auto & gmei : gme.second)
407 {
408 EFAElement2D * EFAElem = getEFAElem2D(gme.first);
409
410 for (unsigned int i = 0; i < gmei._elem_cut_edges.size(); ++i) // mark element edges
411 {
412 if (!EFAElem->isEdgePhantom(
413 gmei._elem_cut_edges[i]._host_side_id)) // must not be phantom edge
414 {
415 _efa_mesh.addElemEdgeIntersection(gme.first->id(),
416 gmei._elem_cut_edges[i]._host_side_id,
417 gmei._elem_cut_edges[i]._distance);
418 marked_edges = true;
419 }
420 }
421
422 for (unsigned int i = 0; i < gmei._elem_cut_nodes.size(); ++i) // mark element edges
423 {
424 _efa_mesh.addElemNodeIntersection(gme.first->id(), gmei._elem_cut_nodes[i]._host_id);
425 marked_nodes = true;
426 }
427
428 for (unsigned int i = 0; i < gmei._frag_cut_edges.size();
429 ++i) // MUST DO THIS AFTER MARKING ELEMENT EDGES
430 {
431 if (!EFAElem->getFragment(0)->isSecondaryInteriorEdge(
432 gmei._frag_cut_edges[i]._host_side_id))
433 {
434 if (_efa_mesh.addFragEdgeIntersection(gme.first->id(),
435 gmei._frag_cut_edges[i]._host_side_id,
436 gmei._frag_cut_edges[i]._distance))
437 {
438 marked_edges = true;
439 if (!isElemAtCrackTip(gme.first))
440 _has_secondary_cut = true;
441 }
442 }
443 }
444 }
445 }
446
447 return marked_edges || marked_nodes;
448}
449
450void
452 EFAElement2D * CEMElem,
453 EFAEdge * orig_edge,
454 Point normal,
455 Point crack_tip_origin,
456 Point crack_tip_direction,
457 Real & distance_keep,
458 unsigned int & edge_id_keep,
459 Point & normal_keep)
460{
461 std::vector<Point> edge_ends(2, Point(0.0, 0.0, 0.0));
462 Point edge1(0.0, 0.0, 0.0);
463 Point edge2(0.0, 0.0, 0.0);
464 Point left_angle(0.0, 0.0, 0.0);
465 Point right_angle(0.0, 0.0, 0.0);
466 Point left_angle_normal(0.0, 0.0, 0.0);
467 Point right_angle_normal(0.0, 0.0, 0.0);
468 Point crack_direction_normal(0.0, 0.0, 0.0);
469 Point edge1_to_tip(0.0, 0.0, 0.0);
470 Point edge2_to_tip(0.0, 0.0, 0.0);
471 Point edge1_to_tip_normal(0.0, 0.0, 0.0);
472 Point edge2_to_tip_normal(0.0, 0.0, 0.0);
473
474 Real cos_45 = std::cos(45.0 / 180.0 * 3.14159);
475 Real sin_45 = std::sin(45.0 / 180.0 * 3.14159);
476
477 left_angle(0) = cos_45 * crack_tip_direction(0) - sin_45 * crack_tip_direction(1);
478 left_angle(1) = sin_45 * crack_tip_direction(0) + cos_45 * crack_tip_direction(1);
479
480 right_angle(0) = cos_45 * crack_tip_direction(0) + sin_45 * crack_tip_direction(1);
481 right_angle(1) = -sin_45 * crack_tip_direction(0) + cos_45 * crack_tip_direction(1);
482
483 left_angle_normal(0) = -left_angle(1);
484 left_angle_normal(1) = left_angle(0);
485
486 right_angle_normal(0) = -right_angle(1);
487 right_angle_normal(1) = right_angle(0);
488
489 crack_direction_normal(0) = -crack_tip_direction(1);
490 crack_direction_normal(1) = crack_tip_direction(0);
491
492 Real angle_min = 0.0;
493 Real distance = 0.0;
494 unsigned int nsides = CEMElem->numEdges();
495
496 for (unsigned int i = 0; i < nsides; ++i)
497 {
498 if (!orig_edge->isPartialOverlap(*CEMElem->getEdge(i)))
499 {
500 edge_ends[0] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(0), CEMElem, elem);
501 edge_ends[1] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(1), CEMElem, elem);
502
503 edge1_to_tip = (edge_ends[0] * 0.95 + edge_ends[1] * 0.05) - crack_tip_origin;
504 edge2_to_tip = (edge_ends[0] * 0.05 + edge_ends[1] * 0.95) - crack_tip_origin;
505
506 edge1_to_tip /= pow(edge1_to_tip.norm_sq(), 0.5);
507 edge2_to_tip /= pow(edge2_to_tip.norm_sq(), 0.5);
508
509 edge1_to_tip_normal(0) = -edge1_to_tip(1);
510 edge1_to_tip_normal(1) = edge1_to_tip(0);
511
512 edge2_to_tip_normal(0) = -edge2_to_tip(1);
513 edge2_to_tip_normal(1) = edge2_to_tip(0);
514
515 Real angle_edge1_normal = edge1_to_tip_normal * normal;
516 Real angle_edge2_normal = edge2_to_tip_normal * normal;
517
518 if (std::abs(angle_edge1_normal) > std::abs(angle_min) &&
519 (edge1_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
520 {
521 edge_id_keep = i;
522 distance_keep = 0.05;
523 normal_keep = edge1_to_tip_normal;
524 angle_min = angle_edge1_normal;
525 }
526 else if (std::abs(angle_edge2_normal) > std::abs(angle_min) &&
527 (edge2_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
528 {
529 edge_id_keep = i;
530 distance_keep = 0.95;
531 normal_keep = edge2_to_tip_normal;
532 angle_min = angle_edge2_normal;
533 }
534
536 crack_tip_origin, left_angle_normal, edge_ends[0], edge_ends[1], distance) &&
537 (!CEMElem->isEdgePhantom(i)))
538 {
539 if (std::abs(left_angle_normal * normal) > std::abs(angle_min) &&
540 (edge1_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
541 {
542 edge_id_keep = i;
543 distance_keep = distance;
544 normal_keep = left_angle_normal;
545 angle_min = left_angle_normal * normal;
546 }
547 }
549 crack_tip_origin, right_angle_normal, edge_ends[0], edge_ends[1], distance) &&
550 (!CEMElem->isEdgePhantom(i)))
551 {
552 if (std::abs(right_angle_normal * normal) > std::abs(angle_min) &&
553 (edge2_to_tip * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
554 {
555 edge_id_keep = i;
556 distance_keep = distance;
557 normal_keep = right_angle_normal;
558 angle_min = right_angle_normal * normal;
559 }
560 }
561 else if (initCutIntersectionEdge(crack_tip_origin,
562 crack_direction_normal,
563 edge_ends[0],
564 edge_ends[1],
565 distance) &&
566 (!CEMElem->isEdgePhantom(i)))
567 {
568 if (std::abs(crack_direction_normal * normal) > std::abs(angle_min) &&
569 (crack_tip_direction * crack_tip_direction) > std::cos(45.0 / 180.0 * 3.14159))
570 {
571 edge_id_keep = i;
572 distance_keep = distance;
573 normal_keep = crack_direction_normal;
574 angle_min = crack_direction_normal * normal;
575 }
576 }
577 }
578 }
579
580 // avoid small volume fraction cut
581 if ((distance_keep - 0.05) < 0.0)
582 {
583 distance_keep = 0.05;
584 }
585 else if ((distance_keep - 0.95) > 0.0)
586 {
587 distance_keep = 0.95;
588 }
589}
590
591bool
593{
594 bool marked_edges = false;
595 for (std::map<const Elem *, RealVectorValue>::iterator pmeit = _state_marked_elems.begin();
596 pmeit != _state_marked_elems.end();
597 ++pmeit)
598 {
599 const Elem * elem = pmeit->first;
600 RealVectorValue normal = pmeit->second;
601 EFAElement2D * CEMElem = getEFAElem2D(elem);
602
603 Real volfrac_elem = getPhysicalVolumeFraction(elem);
604 if (volfrac_elem < 0.25)
605 continue;
606
607 // continue if elem is already cut twice - IMPORTANT
608 if (CEMElem->isFinalCut())
609 continue;
610
611 // find the first cut edge
612 unsigned int nsides = CEMElem->numEdges();
613 unsigned int orig_cut_side_id = std::numeric_limits<unsigned int>::max();
614 Real orig_cut_distance = -1.0;
615 EFANode * orig_node = nullptr;
616 EFAEdge * orig_edge = nullptr;
617
618 // crack tip origin coordinates and direction
619 Point crack_tip_origin(0, 0, 0);
620 Point crack_tip_direction(0, 0, 0);
621
622 if (isElemAtCrackTip(elem)) // crack tip element's crack intiation
623 {
624 orig_cut_side_id = CEMElem->getTipEdgeID();
625 if (orig_cut_side_id < nsides) // valid crack-tip edge found
626 {
627 orig_edge = CEMElem->getEdge(orig_cut_side_id);
628 orig_node = CEMElem->getTipEmbeddedNode();
629 }
630 else
631 mooseError("element ", elem->id(), " has no valid crack-tip edge");
632
633 // obtain the crack tip origin coordinates and direction.
634 std::map<const Elem *, std::vector<Point>>::iterator ecodm =
636 if (ecodm != _elem_crack_origin_direction_map.end())
637 {
638 crack_tip_origin = (ecodm->second)[0];
639 crack_tip_direction = (ecodm->second)[1];
640 }
641 else
642 mooseError("element ", elem->id(), " cannot find its crack tip origin and direction.");
643 }
644 else
645 {
646 std::map<const Elem *, unsigned int>::iterator mit1;
647 mit1 = _state_marked_elem_sides.find(elem);
648 std::set<const Elem *>::iterator mit2;
649 mit2 = _state_marked_frags.find(elem);
650
651 if (mit1 != _state_marked_elem_sides.end()) // specified boundary crack initiation
652 {
653 orig_cut_side_id = mit1->second;
654 if (!CEMElem->isEdgePhantom(orig_cut_side_id) &&
655 !CEMElem->getEdge(orig_cut_side_id)->hasIntersection())
656 {
657 orig_cut_distance = 0.5;
658 _efa_mesh.addElemEdgeIntersection(elem->id(), orig_cut_side_id, orig_cut_distance);
659 orig_edge = CEMElem->getEdge(orig_cut_side_id);
660 orig_node = orig_edge->getEmbeddedNode(0);
661 // get a virtual crack tip direction
662 Point elem_center(0.0, 0.0, 0.0);
663 Point edge_center;
664 for (unsigned int i = 0; i < nsides; ++i)
665 {
666 elem_center += getEFANodeCoords(CEMElem->getEdge(i)->getNode(0), CEMElem, elem);
667 elem_center += getEFANodeCoords(CEMElem->getEdge(i)->getNode(1), CEMElem, elem);
668 }
669 elem_center /= nsides * 2.0;
670 edge_center = getEFANodeCoords(orig_edge->getNode(0), CEMElem, elem) +
671 getEFANodeCoords(orig_edge->getNode(1), CEMElem, elem);
672 edge_center /= 2.0;
673 crack_tip_origin = edge_center;
674 crack_tip_direction = elem_center - edge_center;
675 crack_tip_direction /= pow(crack_tip_direction.norm_sq(), 0.5);
676 }
677 else
678 continue; // skip this elem if specified boundary edge is phantom
679 }
680 else if (mit2 != _state_marked_frags.end()) // cut-surface secondary crack initiation
681 {
682 if (CEMElem->numFragments() != 1)
683 mooseError("element ",
684 elem->id(),
685 " flagged for a secondary crack, but has ",
686 CEMElem->numFragments(),
687 " fragments");
688 std::vector<unsigned int> interior_edge_id = CEMElem->getFragment(0)->getInteriorEdgeID();
689 if (interior_edge_id.size() == 1)
690 orig_cut_side_id = interior_edge_id[0];
691 else
692 continue; // skip this elem if more than one interior edges found (i.e. elem's been cut
693 // twice)
694 orig_cut_distance = 0.5;
695 _efa_mesh.addFragEdgeIntersection(elem->id(), orig_cut_side_id, orig_cut_distance);
696 orig_edge = CEMElem->getFragmentEdge(0, orig_cut_side_id);
697 orig_node = orig_edge->getEmbeddedNode(0); // must be an interior embedded node
698 Point elem_center(0.0, 0.0, 0.0);
699 Point edge_center;
700 unsigned int nsides_frag = CEMElem->getFragment(0)->numEdges();
701 for (unsigned int i = 0; i < nsides_frag; ++i)
702 {
703 elem_center +=
704 getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(0), CEMElem, elem);
705 elem_center +=
706 getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(1), CEMElem, elem);
707 }
708 elem_center /= nsides_frag * 2.0;
709 edge_center = getEFANodeCoords(orig_edge->getNode(0), CEMElem, elem) +
710 getEFANodeCoords(orig_edge->getNode(1), CEMElem, elem);
711 edge_center /= 2.0;
712 crack_tip_origin = edge_center;
713 crack_tip_direction = elem_center - edge_center;
714 crack_tip_direction /= pow(crack_tip_direction.norm_sq(), 0.5);
715 }
716 else
717 mooseError("element ",
718 elem->id(),
719 " flagged for state-based growth, but has no edge intersections");
720 }
721
722 Point cut_origin(0.0, 0.0, 0.0);
723 if (orig_node)
724 cut_origin = getEFANodeCoords(orig_node, CEMElem, elem); // cutting plane origin's coords
725 else
726 mooseError("element ", elem->id(), " does not have valid orig_node");
727
728 // loop through element edges to add possible second cut points
729 std::vector<Point> edge_ends(2, Point(0.0, 0.0, 0.0));
730 Point edge1(0.0, 0.0, 0.0);
731 Point edge2(0.0, 0.0, 0.0);
732 Point cut_edge_point(0.0, 0.0, 0.0);
733 bool find_compatible_direction = false;
734 unsigned int edge_id_keep = 0;
735 Real distance_keep = 0.0;
736 Point normal_keep(0.0, 0.0, 0.0);
737 Real distance = 0.0;
738 bool edge_cut = false;
739
740 for (unsigned int i = 0; i < nsides; ++i)
741 {
742 if (!orig_edge->isPartialOverlap(*CEMElem->getEdge(i)))
743 {
744 edge_ends[0] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(0), CEMElem, elem);
745 edge_ends[1] = getEFANodeCoords(CEMElem->getEdge(i)->getNode(1), CEMElem, elem);
747 crack_tip_origin, normal, edge_ends[0], edge_ends[1], distance) &&
748 (!CEMElem->isEdgePhantom(i))))
749 {
750 cut_edge_point = distance * edge_ends[1] + (1.0 - distance) * edge_ends[0];
751 distance_keep = distance;
752 edge_id_keep = i;
753 normal_keep = normal;
754 edge_cut = true;
755 break;
756 }
757 }
758 }
759
760 Point between_two_cuts = (cut_edge_point - crack_tip_origin);
761 between_two_cuts /= pow(between_two_cuts.norm_sq(), 0.5);
762 Real angle_between_two_cuts = between_two_cuts * crack_tip_direction;
763
764 if (angle_between_two_cuts > std::cos(45.0 / 180.0 * 3.14159)) // original cut direction is good
765 find_compatible_direction = true;
766
767 if (!find_compatible_direction && edge_cut)
769 CEMElem,
770 orig_edge,
771 normal,
772 crack_tip_origin,
773 crack_tip_direction,
774 distance_keep,
775 edge_id_keep,
776 normal_keep);
777
778 if (edge_cut)
779 {
781 _efa_mesh.addElemEdgeIntersection(elem->id(), edge_id_keep, distance_keep);
782 else
783 {
784 Point growth_direction(0.0, 0.0, 0.0);
785
786 growth_direction(0) = -normal_keep(1);
787 growth_direction(1) = normal_keep(0);
788
789 if (growth_direction * crack_tip_direction < 1.0e-10)
790 growth_direction *= (-1.0);
791
792 Real x0 = crack_tip_origin(0);
793 Real y0 = crack_tip_origin(1);
794 Real x1 = x0 + _crack_growth_increment * growth_direction(0);
795 Real y1 = y0 + _crack_growth_increment * growth_direction(1);
796
797 XFEMCrackGrowthIncrement2DCut geometric_cut(x0, y0, x1, y1, time * 0.9, time * 0.9);
798
799 for (const auto & elem : _mesh->element_ptr_range())
800 {
801 std::vector<CutEdgeForCrackGrowthIncr> elem_cut_edges;
802 EFAElement2D * CEMElem = getEFAElem2D(elem);
803
804 // continue if elem has been already cut twice - IMPORTANT
805 if (CEMElem->isFinalCut())
806 continue;
807
808 // mark cut edges for the element and its fragment
809 geometric_cut.cutElementByCrackGrowthIncrement(elem, elem_cut_edges, time);
810
811 for (unsigned int i = 0; i < elem_cut_edges.size(); ++i) // mark element edges
812 {
813 if (!CEMElem->isEdgePhantom(
814 elem_cut_edges[i]._host_side_id)) // must not be phantom edge
815 {
817 elem->id(), elem_cut_edges[i]._host_side_id, elem_cut_edges[i]._distance);
818 }
819 }
820 }
821 }
822 }
823 // loop though framgent boundary edges to add possible second cut points
824 // N.B. must do this after marking element edges
825 if (CEMElem->numFragments() > 0 && !edge_cut)
826 {
827 for (unsigned int i = 0; i < CEMElem->getFragment(0)->numEdges(); ++i)
828 {
829 if (!orig_edge->isPartialOverlap(*CEMElem->getFragmentEdge(0, i)))
830 {
831 edge_ends[0] =
832 getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(0), CEMElem, elem);
833 edge_ends[1] =
834 getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(1), CEMElem, elem);
836 crack_tip_origin, normal, edge_ends[0], edge_ends[1], distance) &&
837 (!CEMElem->getFragment(0)->isSecondaryInteriorEdge(i)))
838 {
839 if (_efa_mesh.addFragEdgeIntersection(elem->id(), edge_id_keep, distance_keep))
840 if (!isElemAtCrackTip(elem))
841 _has_secondary_cut = true;
842 break;
843 }
844 }
845 }
846 }
847
848 marked_edges = true;
849
850 } // loop over all state_marked_elems
851
852 return marked_edges;
853}
854
855bool
857{
858 bool marked_faces = false;
859
860 for (const auto & gme : _geom_marked_elems_3d)
861 {
862 for (const auto & gmei : gme.second)
863 {
864 EFAElement3D * EFAElem = getEFAElem3D(gme.first);
865
866 for (unsigned int i = 0; i < gmei._elem_cut_faces.size(); ++i) // mark element faces
867 {
868 if (!EFAElem->isFacePhantom(gmei._elem_cut_faces[i]._face_id)) // must not be phantom face
869 {
870 _efa_mesh.addElemFaceIntersection(gme.first->id(),
871 gmei._elem_cut_faces[i]._face_id,
872 gmei._elem_cut_faces[i]._face_edge,
873 gmei._elem_cut_faces[i]._position);
874 marked_faces = true;
875 }
876 }
877
878 for (unsigned int i = 0; i < gmei._frag_cut_faces.size();
879 ++i) // MUST DO THIS AFTER MARKING ELEMENT EDGES
880 {
881 if (!EFAElem->getFragment(0)->isThirdInteriorFace(gmei._frag_cut_faces[i]._face_id))
882 {
883 _efa_mesh.addFragFaceIntersection(gme.first->id(),
884 gmei._frag_cut_faces[i]._face_id,
885 gmei._frag_cut_faces[i]._face_edge,
886 gmei._frag_cut_faces[i]._position);
887 marked_faces = true;
888 }
889 }
890 }
891 }
892
893 return marked_faces;
894}
895
896bool
898{
899 bool marked_faces = false;
900 // TODO: need to finish this for 3D problems
901 return marked_faces;
902}
903
904bool
906 Point cut_origin, RealVectorValue cut_normal, Point & edge_p1, Point & edge_p2, Real & dist)
907{
908 dist = 0.0;
909 bool does_intersect = false;
910 Point origin2p1 = edge_p1 - cut_origin;
911 Real plane2p1 = cut_normal(0) * origin2p1(0) + cut_normal(1) * origin2p1(1);
912 Point origin2p2 = edge_p2 - cut_origin;
913 Real plane2p2 = cut_normal(0) * origin2p2(0) + cut_normal(1) * origin2p2(1);
914
915 if (plane2p1 * plane2p2 < 0.0)
916 {
917 dist = -plane2p1 / (plane2p2 - plane2p1);
918 does_intersect = true;
919 }
920 return does_intersect;
921}
922
923bool
925{
926 bool mesh_changed = false;
927
928 std::set<Node *> nodes_to_delete;
929 std::set<Node *> nodes_to_delete_displaced;
930 std::set<unsigned int> cutelems_to_delete;
931 unsigned int deleted_elem_count = 0;
932 std::vector<std::string> healed_geometric_cuts;
933
934 for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
935 {
936 if (_geometric_cuts[i]->shouldHealMesh())
937 {
938 healed_geometric_cuts.push_back(_geometric_cuts[i]->name());
939 for (auto & it : _sibling_elems[_geometric_cuts[i]->getInterfaceID()])
940 {
941 Elem * elem1 = const_cast<Elem *>(it.first);
942 Elem * elem2 = const_cast<Elem *>(it.second);
943
944 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
945 _cut_elem_map.find(elem1->unique_id());
946 if (cemit != _cut_elem_map.end())
947 {
948 const XFEMCutElem * xfce = cemit->second;
949
950 cutelems_to_delete.insert(elem1->unique_id());
951
952 for (unsigned int in = 0; in < elem1->n_nodes(); ++in)
953 {
954 Node * e1node = elem1->node_ptr(in);
955 Node * e2node = elem2->node_ptr(in);
956 if (!xfce->isPointPhysical(*e1node) &&
957 e1node != e2node) // This would happen at the crack tip
958 {
959 elem1->set_node(in, e2node);
960 nodes_to_delete.insert(e1node);
961 }
962 else if (e1node != e2node)
963 nodes_to_delete.insert(e2node);
964 }
965 }
966 else
967 mooseError("Could not find XFEMCutElem for element to be kept in healing");
968
969 // Store the material properties of the elements to be healed. So that if the element is
970 // immediately re-cut, we can restore the material properties (especially those stateful
971 // ones).
972 std::vector<const Elem *> healed_elems = {elem1, elem2};
973
974 if (_geometric_cuts[i]->shouldHealMesh())
975 // If the parent element will not be re-cut, then all of its nodes must have the same
976 // CutSubdomainID. Therefore, just query the first node in this parent element to
977 // get its CutSubdomainID.
978 for (auto e : healed_elems)
979 if (elem1->processor_id() == _mesh->processor_id() &&
980 e->processor_id() == _mesh->processor_id())
981 {
982 storeMaterialPropertiesForElement(/*parent_elem = */ elem1, /*child_elem = */ e);
983 // In case the healed element is not re-cut, copy the corresponding material
984 // properties to the parent element now than later.
985 CutSubdomainID parent_gcsid =
986 _geometric_cuts[i]->getCutSubdomainID(elem1->node_ptr(0));
987 CutSubdomainID gcsid = _geom_cut_elems[e]._cut_subdomain_id;
988 if (parent_gcsid == gcsid)
990 }
991
992 if (_displaced_mesh)
993 {
994 Elem * elem1_displaced = _displaced_mesh->elem_ptr(it.first->id());
995 Elem * elem2_displaced = _displaced_mesh->elem_ptr(it.second->id());
996
997 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
998 _cut_elem_map.find(elem1_displaced->unique_id());
999 if (cemit != _cut_elem_map.end())
1000 {
1001 const XFEMCutElem * xfce = cemit->second;
1002
1003 for (unsigned int in = 0; in < elem1_displaced->n_nodes(); ++in)
1004 {
1005 Node * e1node_displaced = elem1_displaced->node_ptr(in);
1006 Node * e2node_displaced = elem2_displaced->node_ptr(in);
1007 if (!xfce->isPointPhysical(*elem1->node_ptr(in)) &&
1008 e1node_displaced != e2node_displaced)
1009 {
1010 elem1_displaced->set_node(in, e2node_displaced);
1011 nodes_to_delete_displaced.insert(e1node_displaced);
1012 }
1013 else if (e1node_displaced != e2node_displaced)
1014 nodes_to_delete_displaced.insert(e2node_displaced);
1015 }
1016 }
1017 else
1018 mooseError("Could not find XFEMCutElem for element to be kept in healing");
1019
1020 elem2_displaced->nullify_neighbors();
1021 _displaced_mesh->get_boundary_info().remove(elem2_displaced);
1022 _displaced_mesh->delete_elem(elem2_displaced);
1023 }
1024
1025 // remove the property storage of deleted element/side
1026 _material_data[0]->eraseProperty(elem2);
1027 _bnd_material_data[0]->eraseProperty(elem2);
1028
1029 cutelems_to_delete.insert(elem2->unique_id());
1030 elem2->nullify_neighbors();
1031 _mesh->get_boundary_info().remove(elem2);
1032 unsigned int deleted_elem_id = elem2->id();
1033 _mesh->delete_elem(elem2);
1034 if (_debug_output_level > 1)
1035 {
1036 if (deleted_elem_count == 0)
1037 _console << "\n";
1038 _console << "XFEM healing deleted element: " << deleted_elem_id << std::endl;
1039 }
1040 ++deleted_elem_count;
1041 mesh_changed = true;
1042 }
1043 }
1044 }
1045
1046 for (auto & sit : nodes_to_delete)
1047 {
1048 Node * node_to_delete = sit;
1049 dof_id_type deleted_node_id = node_to_delete->id();
1050 _mesh->get_boundary_info().remove(node_to_delete);
1051 _mesh->delete_node(node_to_delete);
1052 if (_debug_output_level > 1)
1053 _console << "XFEM healing deleted node: " << deleted_node_id << std::endl;
1054 }
1055
1056 if (_displaced_mesh)
1057 {
1058 for (auto & sit : nodes_to_delete_displaced)
1059 {
1060 Node * node_to_delete_displaced = sit;
1061 _displaced_mesh->get_boundary_info().remove(node_to_delete_displaced);
1062 _displaced_mesh->delete_node(node_to_delete_displaced);
1063 }
1064 }
1065
1066 for (auto & ced : cutelems_to_delete)
1067 if (_cut_elem_map.find(ced) != _cut_elem_map.end())
1068 {
1069 delete _cut_elem_map.find(ced)->second;
1070 _cut_elem_map.erase(ced);
1071 }
1072
1073 for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1074 if (_geometric_cuts[i]->shouldHealMesh())
1075 _sibling_elems[_geometric_cuts[i]->getInterfaceID()].clear();
1076
1077 if (_displaced_mesh)
1078 {
1079 for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1080 if (_geometric_cuts[i]->shouldHealMesh())
1081 _sibling_displaced_elems[_geometric_cuts[i]->getInterfaceID()].clear();
1082 }
1083
1084 for (auto & ceh : _crack_tip_elems_to_be_healed)
1085 {
1086 _crack_tip_elems.erase(ceh);
1088 delete _cut_elem_map.find(ceh->unique_id())->second;
1089 _cut_elem_map.erase(ceh->unique_id());
1090 }
1091
1092 if (!healed_geometric_cuts.empty() && _debug_output_level > 0)
1093 {
1094 _console << "\nXFEM mesh healing complete\n";
1095 _console << "Names of healed geometric cut objects: ";
1096 for (auto geomcut : healed_geometric_cuts)
1097 _console << geomcut << " ";
1098 _console << "\n";
1099 _console << "# deleted nodes: " << nodes_to_delete.size() << "\n";
1100 _console << "# deleted elements: " << deleted_elem_count << "\n";
1101 _console << std::flush;
1102 }
1103
1104 return mesh_changed;
1105}
1106
1107bool
1108XFEM::cutMeshWithEFA(const std::vector<std::shared_ptr<NonlinearSystemBase>> & nls,
1109 AuxiliarySystem & aux)
1110{
1111 if (nls.size() != 1)
1112 mooseError("XFEM does not currently support multiple nonlinear systems");
1113
1114 std::map<unsigned int, Node *> efa_id_to_new_node;
1115 std::map<unsigned int, Node *> efa_id_to_new_node2;
1116 std::map<unsigned int, Elem *> efa_id_to_new_elem;
1117 _cached_solution.clear();
1118 _cached_aux_solution.clear();
1119
1120 // Copy the current geometric cut element info (from last time) into the
1121 // _old_geom_cut_elems.
1123 _geom_cut_elems.clear();
1124
1126
1127 if (_debug_output_level > 2)
1128 {
1129 _console << "\nXFEM Element fragment algorithm mesh prior to cutting:\n";
1130 _console << std::flush;
1132 }
1133
1135
1136 if (_debug_output_level > 2)
1137 {
1138 _console << "\nXFEM Element fragment algorithm mesh after cutting:\n";
1139 _console << std::flush;
1141 }
1142
1143 const std::vector<EFANode *> new_nodes = _efa_mesh.getNewNodes();
1144 const std::vector<EFAElement *> new_elements = _efa_mesh.getChildElements();
1145 const std::vector<EFAElement *> delete_elements = _efa_mesh.getParentElements();
1146
1147 bool mesh_changed = (new_nodes.size() + new_elements.size() + delete_elements.size() > 0);
1148
1149 // Prepare to cache solution on DOFs modified by XFEM
1150 if (mesh_changed)
1151 {
1152 nls[0]->serializeSolution();
1153 aux.serializeSolution();
1154 if (_debug_output_level > 1)
1155 _console << "\n";
1156 }
1157 NumericVector<Number> & current_solution = *nls[0]->system().current_local_solution;
1158 NumericVector<Number> & old_solution = nls[0]->solutionOld();
1159 NumericVector<Number> & older_solution = nls[0]->solutionOlder();
1160 NumericVector<Number> & current_aux_solution = *aux.system().current_local_solution;
1161 NumericVector<Number> & old_aux_solution = aux.solutionOld();
1162 NumericVector<Number> & older_aux_solution = aux.solutionOlder();
1163
1164 std::map<Node *, Node *> new_nodes_to_parents;
1165
1166 // Add new nodes
1167 for (unsigned int i = 0; i < new_nodes.size(); ++i)
1168 {
1169 unsigned int new_node_id = new_nodes[i]->id();
1170 unsigned int parent_id = new_nodes[i]->parent()->id();
1171
1172 Node * parent_node = _mesh->node_ptr(parent_id);
1173 Node * new_node = Node::build(*parent_node, _mesh->max_node_id()).release();
1174 _mesh->add_node(new_node);
1175
1176 new_nodes_to_parents[new_node] = parent_node;
1177
1178 new_node->set_n_systems(parent_node->n_systems());
1179 efa_id_to_new_node.insert(std::make_pair(new_node_id, new_node));
1180 if (_debug_output_level > 1)
1181 _console << "XFEM added new node: " << new_node->id() << std::endl;
1182 if (_displaced_mesh)
1183 {
1184 const Node * parent_node2 = _displaced_mesh->node_ptr(parent_id);
1185 Node * new_node2 = Node::build(*parent_node2, _displaced_mesh->max_node_id()).release();
1186 _displaced_mesh->add_node(new_node2);
1187
1188 new_node2->set_n_systems(parent_node2->n_systems());
1189 efa_id_to_new_node2.insert(std::make_pair(new_node_id, new_node2));
1190 }
1191 }
1192
1193 // Add new elements
1194 std::map<unsigned int, std::vector<const Elem *>> temporary_parent_children_map;
1195
1196 std::vector<boundary_id_type> parent_boundary_ids;
1197
1198 for (unsigned int i = 0; i < new_elements.size(); ++i)
1199 {
1200 unsigned int parent_id = new_elements[i]->getParent()->id();
1201 unsigned int efa_child_id = new_elements[i]->id();
1202
1203 Elem * parent_elem = _mesh->elem_ptr(parent_id);
1204 Elem * libmesh_elem = Elem::build(parent_elem->type()).release();
1205
1206 for (unsigned int m = 0; m < _geometric_cuts.size(); ++m)
1207 {
1208 for (auto & it : _sibling_elems[_geometric_cuts[m]->getInterfaceID()])
1209 {
1210 if (parent_elem == it.first)
1211 it.first = libmesh_elem;
1212 else if (parent_elem == it.second)
1213 it.second = libmesh_elem;
1214 }
1215 }
1216
1217 // parent has at least two children
1218 if (new_elements[i]->getParent()->numChildren() > 1)
1219 temporary_parent_children_map[parent_elem->id()].push_back(libmesh_elem);
1220
1221 Elem * parent_elem2 = nullptr;
1222 Elem * libmesh_elem2 = nullptr;
1223 if (_displaced_mesh)
1224 {
1225 parent_elem2 = _displaced_mesh->elem_ptr(parent_id);
1226 libmesh_elem2 = Elem::build(parent_elem2->type()).release();
1227
1228 for (unsigned int m = 0; m < _geometric_cuts.size(); ++m)
1229 {
1230 for (auto & it : _sibling_displaced_elems[_geometric_cuts[m]->getInterfaceID()])
1231 {
1232 if (parent_elem2 == it.first)
1233 it.first = libmesh_elem2;
1234 else if (parent_elem2 == it.second)
1235 it.second = libmesh_elem2;
1236 }
1237 }
1238 }
1239
1240 for (unsigned int j = 0; j < new_elements[i]->numNodes(); ++j)
1241 {
1242 unsigned int node_id = new_elements[i]->getNode(j)->id();
1243 Node * libmesh_node;
1244
1245 std::map<unsigned int, Node *>::iterator nit = efa_id_to_new_node.find(node_id);
1246 if (nit != efa_id_to_new_node.end())
1247 libmesh_node = nit->second;
1248 else
1249 libmesh_node = _mesh->node_ptr(node_id);
1250
1251 if (libmesh_node->processor_id() == DofObject::invalid_processor_id)
1252 libmesh_node->processor_id() = parent_elem->processor_id();
1253
1254 libmesh_elem->set_node(j, libmesh_node);
1255
1256 // Store solution for all nodes affected by XFEM (even existing nodes)
1257 if (parent_elem->is_semilocal(_mesh->processor_id()))
1258 {
1259 Node * solution_node = libmesh_node; // Node from which to store solution
1260 if (new_nodes_to_parents.find(libmesh_node) != new_nodes_to_parents.end())
1261 solution_node = new_nodes_to_parents[libmesh_node];
1262
1263 if ((_moose_mesh->isSemiLocal(solution_node)) ||
1264 (libmesh_node->processor_id() == _mesh->processor_id()))
1265 {
1266 storeSolutionForNode(libmesh_node,
1267 solution_node,
1268 *nls[0],
1270 current_solution,
1271 old_solution,
1272 older_solution);
1273 storeSolutionForNode(libmesh_node,
1274 solution_node,
1275 aux,
1277 current_aux_solution,
1278 old_aux_solution,
1279 older_aux_solution);
1280 }
1281 }
1282
1283 Node * parent_node = parent_elem->node_ptr(j);
1284 _mesh->get_boundary_info().boundary_ids(parent_node, parent_boundary_ids);
1285 _mesh->get_boundary_info().add_node(libmesh_node, parent_boundary_ids);
1286
1287 if (_displaced_mesh)
1288 {
1289 std::map<unsigned int, Node *>::iterator nit2 = efa_id_to_new_node2.find(node_id);
1290 if (nit2 != efa_id_to_new_node2.end())
1291 libmesh_node = nit2->second;
1292 else
1293 libmesh_node = _displaced_mesh->node_ptr(node_id);
1294
1295 if (libmesh_node->processor_id() == DofObject::invalid_processor_id)
1296 libmesh_node->processor_id() = parent_elem2->processor_id();
1297
1298 libmesh_elem2->set_node(j, libmesh_node);
1299
1300 parent_node = parent_elem2->node_ptr(j);
1301 _displaced_mesh->get_boundary_info().boundary_ids(parent_node, parent_boundary_ids);
1302 _displaced_mesh->get_boundary_info().add_node(libmesh_node, parent_boundary_ids);
1303 }
1304 }
1305
1306 libmesh_elem->set_p_level(parent_elem->p_level());
1307 libmesh_elem->set_p_refinement_flag(parent_elem->p_refinement_flag());
1308 _mesh->add_elem(libmesh_elem);
1309 libmesh_elem->set_n_systems(parent_elem->n_systems());
1310 libmesh_elem->subdomain_id() = parent_elem->subdomain_id();
1311 libmesh_elem->processor_id() = parent_elem->processor_id();
1312
1313 // The crack tip origin map is stored before cut, thus the elem should be updated with new
1314 // element.
1315 std::map<const Elem *, std::vector<Point>>::iterator mit =
1316 _elem_crack_origin_direction_map.find(parent_elem);
1317 if (mit != _elem_crack_origin_direction_map.end())
1318 {
1319 std::vector<Point> crack_data = _elem_crack_origin_direction_map[parent_elem];
1321 _elem_crack_origin_direction_map[libmesh_elem] = crack_data;
1322 }
1323
1324 if (_debug_output_level > 1)
1325 _console << "XFEM added new element: " << libmesh_elem->id() << std::endl;
1326
1327 XFEMCutElem * xfce = nullptr;
1328 if (_mesh->mesh_dimension() == 2)
1329 {
1330 EFAElement2D * new_efa_elem2d = dynamic_cast<EFAElement2D *>(new_elements[i]);
1331 if (!new_efa_elem2d)
1332 mooseError("EFAelem is not of EFAelement2D type");
1333 xfce = new XFEMCutElem2D(libmesh_elem,
1334 new_efa_elem2d,
1335 _fe_problem->assembly(0, /*nl_sys_num=*/0).qRule()->n_points(),
1336 libmesh_elem->n_sides());
1337 }
1338 else if (_mesh->mesh_dimension() == 3)
1339 {
1340 EFAElement3D * new_efa_elem3d = dynamic_cast<EFAElement3D *>(new_elements[i]);
1341 if (!new_efa_elem3d)
1342 mooseError("EFAelem is not of EFAelement3D type");
1343 xfce = new XFEMCutElem3D(libmesh_elem,
1344 new_efa_elem3d,
1345 _fe_problem->assembly(0, /*nl_sys_num=*/0).qRule()->n_points(),
1346 libmesh_elem->n_sides());
1347 }
1348 _cut_elem_map.insert(std::pair<unique_id_type, XFEMCutElem *>(libmesh_elem->unique_id(), xfce));
1349 efa_id_to_new_elem.insert(std::make_pair(efa_child_id, libmesh_elem));
1350
1351 if (_displaced_mesh)
1352 {
1353 libmesh_elem2->set_p_level(parent_elem2->p_level());
1354 libmesh_elem2->set_p_refinement_flag(parent_elem2->p_refinement_flag());
1355 _displaced_mesh->add_elem(libmesh_elem2);
1356 libmesh_elem2->set_n_systems(parent_elem2->n_systems());
1357 libmesh_elem2->subdomain_id() = parent_elem2->subdomain_id();
1358 libmesh_elem2->processor_id() = parent_elem2->processor_id();
1359 }
1360
1361 unsigned int n_sides = parent_elem->n_sides();
1362 for (unsigned int side = 0; side < n_sides; ++side)
1363 {
1364 _mesh->get_boundary_info().boundary_ids(parent_elem, side, parent_boundary_ids);
1365 _mesh->get_boundary_info().add_side(libmesh_elem, side, parent_boundary_ids);
1366 }
1367 if (_displaced_mesh)
1368 {
1369 n_sides = parent_elem2->n_sides();
1370 for (unsigned int side = 0; side < n_sides; ++side)
1371 {
1372 _displaced_mesh->get_boundary_info().boundary_ids(parent_elem2, side, parent_boundary_ids);
1373 _displaced_mesh->get_boundary_info().add_side(libmesh_elem2, side, parent_boundary_ids);
1374 }
1375 }
1376
1377 unsigned int n_edges = parent_elem->n_edges();
1378 for (unsigned int edge = 0; edge < n_edges; ++edge)
1379 {
1380 _mesh->get_boundary_info().edge_boundary_ids(parent_elem, edge, parent_boundary_ids);
1381 _mesh->get_boundary_info().add_edge(libmesh_elem, edge, parent_boundary_ids);
1382 }
1383 if (_displaced_mesh)
1384 {
1385 n_edges = parent_elem2->n_edges();
1386 for (unsigned int edge = 0; edge < n_edges; ++edge)
1387 {
1388 _displaced_mesh->get_boundary_info().edge_boundary_ids(
1389 parent_elem2, edge, parent_boundary_ids);
1390 _displaced_mesh->get_boundary_info().add_edge(libmesh_elem2, edge, parent_boundary_ids);
1391 }
1392 }
1393
1394 // TODO: Also need to copy neighbor material data
1395 if (parent_elem->processor_id() == _mesh->processor_id())
1396 {
1397 if (_material_data[0]->getMaterialPropertyStorage().hasStatefulProperties())
1398 _material_data[0]->copy(*libmesh_elem, *parent_elem, 0);
1399
1400 if (_bnd_material_data[0]->getMaterialPropertyStorage().hasStatefulProperties())
1401 for (unsigned int side = 0; side < parent_elem->n_sides(); ++side)
1402 {
1403 _mesh->get_boundary_info().boundary_ids(parent_elem, side, parent_boundary_ids);
1404 std::vector<boundary_id_type>::iterator it_bd = parent_boundary_ids.begin();
1405 for (; it_bd != parent_boundary_ids.end(); ++it_bd)
1406 {
1408 _bnd_material_data[0]->copy(*libmesh_elem, *parent_elem, side);
1409 }
1410 }
1411
1412 // Store the current information about the geometrically cut element, and load cached material
1413 // properties into the new child element, if any.
1414 const GeometricCutUserObject * gcuo = getGeometricCutForElem(parent_elem);
1415 if (gcuo && gcuo->shouldHealMesh())
1416 {
1417 CutSubdomainID gcsid = getCutSubdomainID(gcuo, libmesh_elem, parent_elem);
1418 Xfem::CutElemInfo cei(parent_elem, gcuo, gcsid);
1419 _geom_cut_elems.emplace(libmesh_elem, cei);
1420 // Find the element to copy data from.
1421 // Iterate through the old geometrically cut elements, if its parent element AND the
1422 // geometric cut user object AND the cut subdomain ID are the same as the
1423 // current element, then that must be it.
1424 for (auto old_cei : _old_geom_cut_elems)
1425 if (cei.match(old_cei.second))
1426 {
1427 loadMaterialPropertiesForElement(libmesh_elem, old_cei.first, _old_geom_cut_elems);
1428 if (_debug_output_level > 1)
1429 _console << "XFEM set material properties for element: " << libmesh_elem->id()
1430 << "\n";
1431 break;
1432 }
1433 }
1434
1435 // Store solution for all elements affected by XFEM
1436 storeSolutionForElement(libmesh_elem,
1437 parent_elem,
1438 *nls[0],
1440 current_solution,
1441 old_solution,
1442 older_solution);
1443 storeSolutionForElement(libmesh_elem,
1444 parent_elem,
1445 aux,
1447 current_aux_solution,
1448 old_aux_solution,
1449 older_aux_solution);
1450 }
1451 }
1452
1453 // delete elements
1454 for (std::size_t i = 0; i < delete_elements.size(); ++i)
1455 {
1456 Elem * elem_to_delete = _mesh->elem_ptr(delete_elements[i]->id());
1457
1458 // delete the XFEMCutElem object for any elements that are to be deleted
1459 std::map<unique_id_type, XFEMCutElem *>::iterator cemit =
1460 _cut_elem_map.find(elem_to_delete->unique_id());
1461 if (cemit != _cut_elem_map.end())
1462 {
1463 delete cemit->second;
1464 _cut_elem_map.erase(cemit);
1465 }
1466
1467 // remove the property storage of deleted element/side
1468 _material_data[0]->eraseProperty(elem_to_delete);
1469 _bnd_material_data[0]->eraseProperty(elem_to_delete);
1470
1471 elem_to_delete->nullify_neighbors();
1472 _mesh->get_boundary_info().remove(elem_to_delete);
1473 unsigned int deleted_elem_id = elem_to_delete->id();
1474 _mesh->delete_elem(elem_to_delete);
1475 if (_debug_output_level > 1)
1476 _console << "XFEM deleted element: " << deleted_elem_id << std::endl;
1477
1478 if (_displaced_mesh)
1479 {
1480 Elem * elem_to_delete2 = _displaced_mesh->elem_ptr(delete_elements[i]->id());
1481 elem_to_delete2->nullify_neighbors();
1482 _displaced_mesh->get_boundary_info().remove(elem_to_delete2);
1483 _displaced_mesh->delete_elem(elem_to_delete2);
1484 }
1485 }
1486
1487 for (std::map<unsigned int, std::vector<const Elem *>>::iterator it =
1488 temporary_parent_children_map.begin();
1489 it != temporary_parent_children_map.end();
1490 ++it)
1491 {
1492 std::vector<const Elem *> & sibling_elem_vec = it->second;
1493 // TODO: for cut-node case, how to find the sibling elements?
1494 // if (sibling_elem_vec.size() != 2)
1495 // mooseError("Must have exactly 2 sibling elements");
1496
1497 for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1498 for (auto const & elem_id : _geom_marker_id_elems[_geometric_cuts[i]->getInterfaceID()])
1499 if (it->first == elem_id)
1500 _sibling_elems[_geometric_cuts[i]->getInterfaceID()].push_back(
1501 std::make_pair(sibling_elem_vec[0], sibling_elem_vec[1]));
1502 }
1503
1504 // add sibling elems on displaced mesh
1505 if (_displaced_mesh)
1506 {
1507 for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1508 {
1509 for (auto & se : _sibling_elems[_geometric_cuts[i]->getInterfaceID()])
1510 {
1511 Elem * elem = _displaced_mesh->elem_ptr(se.first->id());
1512 Elem * elem_pair = _displaced_mesh->elem_ptr(se.second->id());
1513 _sibling_displaced_elems[_geometric_cuts[i]->getInterfaceID()].push_back(
1514 std::make_pair(elem, elem_pair));
1515 }
1516 }
1517 }
1518
1519 // clear the temporary map
1520 temporary_parent_children_map.clear();
1521
1522 // Store information about crack tip elements
1523 if (mesh_changed)
1524 {
1525 _crack_tip_elems.clear();
1527 const std::set<EFAElement *> CrackTipElements = _efa_mesh.getCrackTipElements();
1528 std::set<EFAElement *>::const_iterator sit;
1529 for (sit = CrackTipElements.begin(); sit != CrackTipElements.end(); ++sit)
1530 {
1531 unsigned int eid = (*sit)->id();
1532 Elem * crack_tip_elem;
1533 std::map<unsigned int, Elem *>::iterator eit = efa_id_to_new_elem.find(eid);
1534 if (eit != efa_id_to_new_elem.end())
1535 crack_tip_elem = eit->second;
1536 else
1537 crack_tip_elem = _mesh->elem_ptr(eid);
1538 _crack_tip_elems.insert(crack_tip_elem);
1539
1540 // Store the crack tip elements which are going to be healed
1541 for (unsigned int i = 0; i < _geometric_cuts.size(); ++i)
1542 {
1543 if (_geometric_cuts[i]->shouldHealMesh())
1544 {
1545 for (auto const & mie : _geom_marker_id_elems[_geometric_cuts[i]->getInterfaceID()])
1546 if ((*sit)->getParent() != nullptr)
1547 {
1548 if (_mesh->mesh_dimension() == 2)
1549 {
1550 EFAElement2D * efa_elem2d = dynamic_cast<EFAElement2D *>((*sit)->getParent());
1551 if (!efa_elem2d)
1552 mooseError("EFAelem is not of EFAelement2D type");
1553
1554 for (unsigned int edge_id = 0; edge_id < efa_elem2d->numEdges(); ++edge_id)
1555 {
1556 for (unsigned int en_iter = 0; en_iter < efa_elem2d->numEdgeNeighbors(edge_id);
1557 ++en_iter)
1558 {
1559 EFAElement2D * edge_neighbor = efa_elem2d->getEdgeNeighbor(edge_id, en_iter);
1560 if (edge_neighbor != nullptr && edge_neighbor->id() == mie)
1561 _crack_tip_elems_to_be_healed.insert(crack_tip_elem);
1562 }
1563 }
1564 }
1565 else if (_mesh->mesh_dimension() == 3)
1566 {
1567 EFAElement3D * efa_elem3d = dynamic_cast<EFAElement3D *>((*sit)->getParent());
1568 if (!efa_elem3d)
1569 mooseError("EFAelem is not of EFAelement3D type");
1570
1571 for (unsigned int face_id = 0; face_id < efa_elem3d->numFaces(); ++face_id)
1572 {
1573 for (unsigned int fn_iter = 0; fn_iter < efa_elem3d->numFaceNeighbors(face_id);
1574 ++fn_iter)
1575 {
1576 EFAElement3D * face_neighbor = efa_elem3d->getFaceNeighbor(face_id, fn_iter);
1577 if (face_neighbor != nullptr && face_neighbor->id() == mie)
1578 _crack_tip_elems_to_be_healed.insert(crack_tip_elem);
1579 }
1580 }
1581 }
1582 }
1583 }
1584 }
1585 }
1586 }
1587
1588 if (_debug_output_level > 0)
1589 {
1590 _console << "\nXFEM mesh cutting with element fragment algorithm complete\n";
1591 _console << "# new nodes: " << new_nodes.size() << "\n";
1592 _console << "# new elements: " << new_elements.size() << "\n";
1593 _console << "# deleted elements: " << delete_elements.size() << "\n";
1594 _console << std::flush;
1595 }
1596
1597 // store virtual nodes
1598 // store cut edge info
1599 return mesh_changed;
1600}
1601
1602Point
1604 EFAElement * CEMElem,
1605 const Elem * elem,
1606 MeshBase * displaced_mesh) const
1607{
1608 Point node_coor(0.0, 0.0, 0.0);
1609 std::vector<EFANode *> master_nodes;
1610 std::vector<Point> master_points;
1611 std::vector<double> master_weights;
1612
1613 CEMElem->getMasterInfo(CEMnode, master_nodes, master_weights);
1614 for (std::size_t i = 0; i < master_nodes.size(); ++i)
1615 {
1616 if (master_nodes[i]->category() == EFANode::N_CATEGORY_PERMANENT)
1617 {
1618 unsigned int local_node_id = CEMElem->getLocalNodeIndex(master_nodes[i]);
1619 const Node * node = elem->node_ptr(local_node_id);
1620 if (displaced_mesh)
1621 node = displaced_mesh->node_ptr(node->id());
1622 Point node_p((*node)(0), (*node)(1), (*node)(2));
1623 master_points.push_back(node_p);
1624 }
1625 else
1626 mooseError("master nodes must be permanent");
1627 }
1628 for (std::size_t i = 0; i < master_nodes.size(); ++i)
1629 node_coor += master_weights[i] * master_points[i];
1630
1631 return node_coor;
1632}
1633
1634Real
1635XFEM::getPhysicalVolumeFraction(const Elem * elem) const
1636{
1637 Real phys_volfrac = 1.0;
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 XFEMCutElem * xfce = it->second;
1643 const EFAElement * EFAelem = xfce->getEFAElement();
1644 if (EFAelem->isPartial())
1645 { // exclude the full crack tip elements
1647 phys_volfrac = xfce->getPhysicalVolumeFraction();
1648 }
1649 }
1650
1651 return phys_volfrac;
1652}
1653
1654bool
1655XFEM::isPointInsidePhysicalDomain(const Elem * elem, const Point & point) const
1656{
1657 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1658 it = _cut_elem_map.find(elem->unique_id());
1659 if (it != _cut_elem_map.end())
1660 {
1661 XFEMCutElem * xfce = it->second;
1662
1663 if (xfce->isPointPhysical(point))
1664 return true;
1665 }
1666 else
1667 return true;
1668
1669 return false;
1670}
1671
1672Real
1673XFEM::getCutPlane(const Elem * elem,
1674 const Xfem::XFEM_CUTPLANE_QUANTITY quantity,
1675 unsigned int plane_id) const
1676{
1677 Real comp = 0.0;
1678 Point planedata(0.0, 0.0, 0.0);
1679 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1680 it = _cut_elem_map.find(elem->unique_id());
1681 if (it != _cut_elem_map.end())
1682 {
1683 const XFEMCutElem * xfce = it->second;
1684 const EFAElement * EFAelem = xfce->getEFAElement();
1685 if (EFAelem->isPartial()) // exclude the full crack tip elements
1686 {
1687 if ((unsigned int)quantity < 3)
1688 {
1689 unsigned int index = (unsigned int)quantity;
1690 planedata = xfce->getCutPlaneOrigin(plane_id, _displaced_mesh);
1691 comp = planedata(index);
1692 }
1693 else if ((unsigned int)quantity < 6)
1694 {
1695 unsigned int index = (unsigned int)quantity - 3;
1696 planedata = xfce->getCutPlaneNormal(plane_id, _displaced_mesh);
1697 comp = planedata(index);
1698 }
1699 else
1700 mooseError("In get_cut_plane index out of range");
1701 }
1702 }
1703 return comp;
1704}
1705
1706bool
1707XFEM::isElemAtCrackTip(const Elem * elem) const
1708{
1709 return (_crack_tip_elems.find(elem) != _crack_tip_elems.end());
1710}
1711
1712bool
1713XFEM::isElemCut(const Elem * elem, XFEMCutElem *& xfce) const
1714{
1715 const auto it = _cut_elem_map.find(elem->unique_id());
1716 if (it != _cut_elem_map.end())
1717 {
1718 xfce = it->second;
1719 const EFAElement * EFAelem = xfce->getEFAElement();
1720 if (EFAelem->isPartial()) // exclude the full crack tip elements
1721 return true;
1722 }
1723
1724 xfce = nullptr;
1725 return false;
1726}
1727
1728bool
1729XFEM::isElemCut(const Elem * elem) const
1730{
1731 XFEMCutElem * xfce;
1732 return isElemCut(elem, xfce);
1733}
1734
1735void
1736XFEM::getFragmentFaces(const Elem * elem,
1737 std::vector<std::vector<Point>> & frag_faces,
1738 bool displaced_mesh) const
1739{
1740 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1741 it = _cut_elem_map.find(elem->unique_id());
1742 if (it != _cut_elem_map.end())
1743 {
1744 const XFEMCutElem * xfce = it->second;
1745 if (displaced_mesh)
1746 xfce->getFragmentFaces(frag_faces, _displaced_mesh);
1747 else
1748 xfce->getFragmentFaces(frag_faces);
1749 }
1750}
1751
1753XFEM::getEFAElem2D(const Elem * elem)
1754{
1755 EFAElement * EFAelem = _efa_mesh.getElemByID(elem->id());
1756 EFAElement2D * EFAelem2D = dynamic_cast<EFAElement2D *>(EFAelem);
1757
1758 if (!EFAelem2D)
1759 mooseError("EFAelem is not of EFAelement2D type");
1760
1761 return EFAelem2D;
1762}
1763
1765XFEM::getEFAElem3D(const Elem * elem)
1766{
1767 EFAElement * EFAelem = _efa_mesh.getElemByID(elem->id());
1768 EFAElement3D * EFAelem3D = dynamic_cast<EFAElement3D *>(EFAelem);
1769
1770 if (!EFAelem3D)
1771 mooseError("EFAelem is not of EFAelement3D type");
1772
1773 return EFAelem3D;
1774}
1775
1776void
1777XFEM::getFragmentEdges(const Elem * elem,
1778 EFAElement2D * CEMElem,
1779 std::vector<std::vector<Point>> & frag_edges) const
1780{
1781 // N.B. CEMElem here has global EFAnode
1782 frag_edges.clear();
1783 if (CEMElem->numFragments() > 0)
1784 {
1785 if (CEMElem->numFragments() > 1)
1786 mooseError("element ", elem->id(), " has more than one fragment at this point");
1787 for (unsigned int i = 0; i < CEMElem->getFragment(0)->numEdges(); ++i)
1788 {
1789 std::vector<Point> p_line(2, Point(0.0, 0.0, 0.0));
1790 p_line[0] = getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(0), CEMElem, elem);
1791 p_line[1] = getEFANodeCoords(CEMElem->getFragmentEdge(0, i)->getNode(1), CEMElem, elem);
1792 frag_edges.push_back(p_line);
1793 }
1794 }
1795}
1796
1797void
1798XFEM::getFragmentFaces(const Elem * elem,
1799 EFAElement3D * CEMElem,
1800 std::vector<std::vector<Point>> & frag_faces) const
1801{
1802 // N.B. CEMElem here has global EFAnode
1803 frag_faces.clear();
1804 if (CEMElem->numFragments() > 0)
1805 {
1806 if (CEMElem->numFragments() > 1)
1807 mooseError("element ", elem->id(), " has more than one fragment at this point");
1808 for (unsigned int i = 0; i < CEMElem->getFragment(0)->numFaces(); ++i)
1809 {
1810 unsigned int num_face_nodes = CEMElem->getFragmentFace(0, i)->numNodes();
1811 std::vector<Point> p_line(num_face_nodes, Point(0.0, 0.0, 0.0));
1812 for (unsigned int j = 0; j < num_face_nodes; ++j)
1813 p_line[j] = getEFANodeCoords(CEMElem->getFragmentFace(0, i)->getNode(j), CEMElem, elem);
1814 frag_faces.push_back(p_line);
1815 }
1816 }
1817}
1818
1821{
1822 return _XFEM_qrule;
1823}
1824
1825void
1826XFEM::setXFEMQRule(std::string & xfem_qrule)
1827{
1828 if (xfem_qrule == "volfrac")
1830 else if (xfem_qrule == "moment_fitting")
1832 else if (xfem_qrule == "direct")
1834}
1835
1836void
1837XFEM::setCrackGrowthMethod(bool use_crack_growth_increment, Real crack_growth_increment)
1838{
1839 _use_crack_growth_increment = use_crack_growth_increment;
1840 _crack_growth_increment = crack_growth_increment;
1841}
1842
1843void
1844XFEM::setDebugOutputLevel(unsigned int debug_output_level)
1845{
1846 _debug_output_level = debug_output_level;
1847}
1848
1849void
1850XFEM::setMinWeightMultiplier(Real min_weight_multiplier)
1851{
1852 _min_weight_multiplier = min_weight_multiplier;
1853}
1854
1855bool
1857 const Elem * elem,
1858 QBase * qrule,
1859 const MooseArray<Point> & q_points)
1860{
1861 bool have_weights = false;
1862 XFEMCutElem * xfce = nullptr;
1863 if (isElemCut(elem, xfce))
1864 {
1865 mooseAssert(xfce != nullptr, "Must have valid XFEMCutElem object here");
1866 xfce->getWeightMultipliers(weights, qrule, getXFEMQRule(), q_points);
1867 have_weights = true;
1868
1869 Real ave_weight_multiplier = 0;
1870 for (unsigned int i = 0; i < weights.size(); ++i)
1871 ave_weight_multiplier += weights[i];
1872 ave_weight_multiplier /= weights.size();
1873
1874 if (ave_weight_multiplier < _min_weight_multiplier)
1875 {
1876 const Real amount_to_add = _min_weight_multiplier - ave_weight_multiplier;
1877 for (unsigned int i = 0; i < weights.size(); ++i)
1878 weights[i] += amount_to_add;
1879 }
1880 }
1881 return have_weights;
1882}
1883
1884bool
1886 const Elem * elem,
1887 QBase * qrule,
1888 const MooseArray<Point> & q_points,
1889 unsigned int side)
1890{
1891 bool have_weights = false;
1892 XFEMCutElem * xfce = nullptr;
1893 if (isElemCut(elem, xfce))
1894 {
1895 mooseAssert(xfce != nullptr, "Must have valid XFEMCutElem object here");
1896 xfce->getFaceWeightMultipliers(weights, qrule, getXFEMQRule(), q_points, side);
1897 have_weights = true;
1898 }
1899 return have_weights;
1900}
1901
1902void
1904 unsigned int plane_id,
1905 Point & normal,
1906 std::vector<Point> & intersectionPoints,
1907 bool displaced_mesh) const
1908{
1909 std::map<unique_id_type, XFEMCutElem *>::const_iterator it;
1910 it = _cut_elem_map.find(elem->unique_id());
1911 if (it != _cut_elem_map.end())
1912 {
1913 const XFEMCutElem * xfce = it->second;
1914 if (displaced_mesh)
1915 xfce->getIntersectionInfo(plane_id, normal, intersectionPoints, _displaced_mesh);
1916 else
1917 xfce->getIntersectionInfo(plane_id, normal, intersectionPoints);
1918 }
1919}
1920
1921void
1922XFEM::getXFEMqRuleOnLine(std::vector<Point> & intersection_points,
1923 std::vector<Point> & quad_pts,
1924 std::vector<Real> & quad_wts) const
1925{
1926 Point p1 = intersection_points[0];
1927 Point p2 = intersection_points[1];
1928
1929 // number of quadrature points
1930 std::size_t num_qpoints = 2;
1931
1932 // quadrature coordinates
1933 Real xi0 = -std::sqrt(1.0 / 3.0);
1934 Real xi1 = std::sqrt(1.0 / 3.0);
1935
1936 quad_wts.resize(num_qpoints);
1937 quad_pts.resize(num_qpoints);
1938
1939 Real integ_jacobian = pow((p1 - p2).norm_sq(), 0.5) * 0.5;
1940
1941 quad_wts[0] = 1.0 * integ_jacobian;
1942 quad_wts[1] = 1.0 * integ_jacobian;
1943
1944 quad_pts[0] = (1.0 - xi0) / 2.0 * p1 + (1.0 + xi0) / 2.0 * p2;
1945 quad_pts[1] = (1.0 - xi1) / 2.0 * p1 + (1.0 + xi1) / 2.0 * p2;
1946}
1947
1948void
1949XFEM::getXFEMqRuleOnSurface(std::vector<Point> & intersection_points,
1950 std::vector<Point> & quad_pts,
1951 std::vector<Real> & quad_wts) const
1952{
1953 std::size_t nnd_pe = intersection_points.size();
1954 Point xcrd(0.0, 0.0, 0.0);
1955 for (std::size_t i = 0; i < nnd_pe; ++i)
1956 xcrd += intersection_points[i];
1957 xcrd /= nnd_pe;
1958
1959 quad_pts.resize(nnd_pe);
1960 quad_wts.resize(nnd_pe);
1961
1962 Real jac = 0.0;
1963
1964 for (std::size_t j = 0; j < nnd_pe; ++j) // loop all sub-tris
1965 {
1966 std::vector<std::vector<Real>> shape(3, std::vector<Real>(3, 0.0));
1967 std::vector<Point> subtrig_points(3, Point(0.0, 0.0, 0.0)); // sub-trig nodal coords
1968
1969 int jplus1 = j < nnd_pe - 1 ? j + 1 : 0;
1970 subtrig_points[0] = xcrd;
1971 subtrig_points[1] = intersection_points[j];
1972 subtrig_points[2] = intersection_points[jplus1];
1973
1974 std::vector<std::vector<Real>> sg2;
1975 Xfem::stdQuadr2D(3, 1, sg2); // get sg2
1976 for (std::size_t l = 0; l < sg2.size(); ++l) // loop all int pts on a sub-trig
1977 {
1978 Xfem::shapeFunc2D(3, sg2[l], subtrig_points, shape, jac, true); // Get shape
1979 std::vector<Real> tsg_line(3, 0.0);
1980 for (std::size_t k = 0; k < 3; ++k) // loop sub-trig nodes
1981 {
1982 tsg_line[0] += shape[k][2] * subtrig_points[k](0);
1983 tsg_line[1] += shape[k][2] * subtrig_points[k](1);
1984 tsg_line[2] += shape[k][2] * subtrig_points[k](2);
1985 }
1986 quad_pts[j + l] = Point(tsg_line[0], tsg_line[1], tsg_line[2]);
1987 quad_wts[j + l] = sg2[l][3] * jac;
1988 }
1989 }
1990}
1991
1992void
1993XFEM::storeSolutionForNode(const Node * node_to_store_to,
1994 const Node * node_to_store_from,
1995 SystemBase & sys,
1996 std::map<unique_id_type, std::vector<Real>> & stored_solution,
1997 const NumericVector<Number> & current_solution,
1998 const NumericVector<Number> & old_solution,
1999 const NumericVector<Number> & older_solution)
2000{
2001 std::vector<dof_id_type> stored_solution_dofs = getNodeSolutionDofs(node_to_store_from, sys);
2002 std::vector<Real> stored_solution_scratch;
2003 // Size for current solution, as well as for old, and older solution only for transient case
2004 std::size_t stored_solution_size =
2005 (_fe_problem->isTransient() ? stored_solution_dofs.size() * 3 : stored_solution_dofs.size());
2006 stored_solution_scratch.reserve(stored_solution_size);
2007
2008 // Store in the order defined in stored_solution_dofs first for the current, then for old and
2009 // older if applicable
2010 for (auto dof : stored_solution_dofs)
2011 stored_solution_scratch.push_back(current_solution(dof));
2012
2013 if (_fe_problem->isTransient())
2014 {
2015 for (auto dof : stored_solution_dofs)
2016 stored_solution_scratch.push_back(old_solution(dof));
2017
2018 for (auto dof : stored_solution_dofs)
2019 stored_solution_scratch.push_back(older_solution(dof));
2020 }
2021
2022 if (stored_solution_scratch.size() > 0)
2023 stored_solution[node_to_store_to->unique_id()] = stored_solution_scratch;
2024}
2025
2026void
2027XFEM::storeSolutionForElement(const Elem * elem_to_store_to,
2028 const Elem * elem_to_store_from,
2029 SystemBase & sys,
2030 std::map<unique_id_type, std::vector<Real>> & stored_solution,
2031 const NumericVector<Number> & current_solution,
2032 const NumericVector<Number> & old_solution,
2033 const NumericVector<Number> & older_solution)
2034{
2035 std::vector<dof_id_type> stored_solution_dofs = getElementSolutionDofs(elem_to_store_from, sys);
2036 std::vector<Real> stored_solution_scratch;
2037 // Size for current solution, as well as for old, and older solution only for transient case
2038 std::size_t stored_solution_size =
2039 (_fe_problem->isTransient() ? stored_solution_dofs.size() * 3 : stored_solution_dofs.size());
2040 stored_solution_scratch.reserve(stored_solution_size);
2041
2042 // Store in the order defined in stored_solution_dofs first for the current, then for old and
2043 // older if applicable
2044 for (auto dof : stored_solution_dofs)
2045 stored_solution_scratch.push_back(current_solution(dof));
2046
2047 if (_fe_problem->isTransient())
2048 {
2049 for (auto dof : stored_solution_dofs)
2050 stored_solution_scratch.push_back(old_solution(dof));
2051
2052 for (auto dof : stored_solution_dofs)
2053 stored_solution_scratch.push_back(older_solution(dof));
2054 }
2055
2056 if (stored_solution_scratch.size() > 0)
2057 stored_solution[elem_to_store_to->unique_id()] = stored_solution_scratch;
2058}
2059
2060void
2062 const std::map<unique_id_type, std::vector<Real>> & stored_solution,
2063 NumericVector<Number> & current_solution,
2064 NumericVector<Number> & old_solution,
2065 NumericVector<Number> & older_solution)
2066{
2067 for (auto & node : _mesh->local_node_ptr_range())
2068 {
2069 auto mit = stored_solution.find(node->unique_id());
2070 if (mit != stored_solution.end())
2071 {
2072 const std::vector<Real> & stored_node_solution = mit->second;
2073 std::vector<dof_id_type> stored_solution_dofs = getNodeSolutionDofs(node, sys);
2074 setSolutionForDOFs(stored_node_solution,
2075 stored_solution_dofs,
2076 current_solution,
2077 old_solution,
2078 older_solution);
2079 }
2080 }
2081
2082 for (auto & elem : as_range(_mesh->local_elements_begin(), _mesh->local_elements_end()))
2083 {
2084 auto mit = stored_solution.find(elem->unique_id());
2085 if (mit != stored_solution.end())
2086 {
2087 const std::vector<Real> & stored_elem_solution = mit->second;
2088 std::vector<dof_id_type> stored_solution_dofs = getElementSolutionDofs(elem, sys);
2089 setSolutionForDOFs(stored_elem_solution,
2090 stored_solution_dofs,
2091 current_solution,
2092 old_solution,
2093 older_solution);
2094 }
2095 }
2096}
2097
2098void
2099XFEM::setSolutionForDOFs(const std::vector<Real> & stored_solution,
2100 const std::vector<dof_id_type> & stored_solution_dofs,
2101 NumericVector<Number> & current_solution,
2102 NumericVector<Number> & old_solution,
2103 NumericVector<Number> & older_solution)
2104{
2105 // Solution vector is stored first for current, then old and older solutions.
2106 // These are the offsets to the beginning of the old and older solutions in the vector.
2107 const auto old_solution_offset = stored_solution_dofs.size();
2108 const auto older_solution_offset = old_solution_offset * 2;
2109
2110 for (std::size_t i = 0; i < stored_solution_dofs.size(); ++i)
2111 {
2112 current_solution.set(stored_solution_dofs[i], stored_solution[i]);
2113 if (_fe_problem->isTransient())
2114 {
2115 old_solution.set(stored_solution_dofs[i], stored_solution[old_solution_offset + i]);
2116 older_solution.set(stored_solution_dofs[i], stored_solution[older_solution_offset + i]);
2117 }
2118 }
2119}
2120
2121std::vector<dof_id_type>
2122XFEM::getElementSolutionDofs(const Elem * elem, SystemBase & sys) const
2123{
2124 SubdomainID sid = elem->subdomain_id();
2125 const std::vector<MooseVariableFEBase *> & vars = sys.getVariables(0);
2126 std::vector<dof_id_type> solution_dofs;
2127 solution_dofs.reserve(vars.size()); // just an approximation
2128 for (auto var : vars)
2129 {
2130 if (!var->isNodal())
2131 {
2132 const std::set<SubdomainID> & var_subdomains = sys.getSubdomainsForVar(var->number());
2133 if (var_subdomains.empty() || var_subdomains.find(sid) != var_subdomains.end())
2134 {
2135 unsigned int n_comp = elem->n_comp(sys.number(), var->number());
2136 for (unsigned int icomp = 0; icomp < n_comp; ++icomp)
2137 {
2138 dof_id_type elem_dof = elem->dof_number(sys.number(), var->number(), icomp);
2139 solution_dofs.push_back(elem_dof);
2140 }
2141 }
2142 }
2143 }
2144 return solution_dofs;
2145}
2146
2147std::vector<dof_id_type>
2148XFEM::getNodeSolutionDofs(const Node * node, SystemBase & sys) const
2149{
2150 const std::set<SubdomainID> & sids = _moose_mesh->getNodeBlockIds(*node);
2151 const std::vector<MooseVariableFEBase *> & vars = sys.getVariables(0);
2152 std::vector<dof_id_type> solution_dofs;
2153 solution_dofs.reserve(vars.size()); // just an approximation
2154 for (auto var : vars)
2155 {
2156 if (var->isNodal())
2157 {
2158 const std::set<SubdomainID> & var_subdomains = sys.getSubdomainsForVar(var->number());
2159 std::set<SubdomainID> intersect;
2160 set_intersection(var_subdomains.begin(),
2161 var_subdomains.end(),
2162 sids.begin(),
2163 sids.end(),
2164 std::inserter(intersect, intersect.begin()));
2165 if (var_subdomains.empty() || !intersect.empty())
2166 {
2167 unsigned int n_comp = node->n_comp(sys.number(), var->number());
2168 for (unsigned int icomp = 0; icomp < n_comp; ++icomp)
2169 {
2170 dof_id_type node_dof = node->dof_number(sys.number(), var->number(), icomp);
2171 solution_dofs.push_back(node_dof);
2172 }
2173 }
2174 }
2175 }
2176 return solution_dofs;
2177}
2178
2180XFEM::getGeometricCutForElem(const Elem * elem) const
2181{
2182 for (auto gcmit : _geom_marker_id_elems)
2183 {
2184 std::set<unsigned int> elems = gcmit.second;
2185 if (elems.find(elem->id()) != elems.end())
2186 return _geometric_cuts[gcmit.first];
2187 }
2188 return nullptr;
2189}
2190
2191void
2193{
2194 for (const auto state : storage.statefulIndexRange())
2195 {
2196 const auto & elem_props = storage.props(state).at(elem);
2197 auto & serialized_props = _geom_cut_elems[elem]._elem_material_properties[state - 1];
2198 serialized_props.clear();
2199 for (const auto & side_props_pair : elem_props)
2200 {
2201 const auto side = side_props_pair.first;
2202 std::ostringstream oss;
2203 dataStore(oss, storage.setProps(elem, side, state), nullptr);
2204 serialized_props[side].assign(oss.str());
2205 }
2206 }
2207}
2208
2209void
2210XFEM::storeMaterialPropertiesForElement(const Elem * parent_elem, const Elem * child_elem)
2211{
2212 // Set the parent element so that it is consistent post-healing
2213 _geom_cut_elems[child_elem]._parent_elem = parent_elem;
2214
2215 // Locally store the element material properties
2217 _material_data[0]->getMaterialPropertyStorageForXFEM({}));
2218
2219 // Locally store the boundary material properties
2220 // First check if any of the side need material properties
2221 bool need_boundary_materials = false;
2222 for (unsigned int side = 0; side < child_elem->n_sides(); ++side)
2223 {
2224 std::vector<boundary_id_type> elem_boundary_ids;
2225 _mesh->get_boundary_info().boundary_ids(child_elem, side, elem_boundary_ids);
2226 for (auto bdid : elem_boundary_ids)
2228 need_boundary_materials = true;
2229 }
2230
2231 // If boundary material properties are needed for this element, then store them.
2232 if (need_boundary_materials)
2234 child_elem, _bnd_material_data[0]->getMaterialPropertyStorageForXFEM({}));
2235}
2236
2237void
2239 const Xfem::CachedMaterialProperties & cached_props,
2240 MaterialPropertyStorage & storage) const
2241{
2242 if (!storage.hasStatefulProperties())
2243 return;
2244
2245 for (const auto state : storage.statefulIndexRange())
2246 {
2247 const auto & serialized_props = cached_props[state - 1];
2248 for (const auto & [side, serialized_side_props] : serialized_props)
2249 {
2250 std::istringstream iss;
2251 iss.str(serialized_side_props);
2252 iss.clear();
2253
2254 // This is very dirty. We should not write to MOOSE's stateful properties.
2255 // Please remove me :(
2256 dataLoad(iss, storage.setProps(elem, side, state), nullptr);
2257 }
2258 }
2259}
2260
2261void
2263 const Elem * elem,
2264 const Elem * elem_from,
2265 std::unordered_map<const Elem *, Xfem::CutElemInfo> & cached_cei) const
2266{
2267 // Restore the element material properties
2268 mooseAssert(cached_cei.count(elem_from) > 0, "XFEM: Unable to find cached material properties.");
2269 Xfem::CutElemInfo & cei = cached_cei[elem_from];
2270
2271 // Load element material properties from cached properties
2274 _material_data[0]->getMaterialPropertyStorageForXFEM({}));
2275
2276 // Check if any of the element side need material properties
2277 bool need_boundary_materials = false;
2278 for (unsigned int side = 0; side < elem->n_sides(); ++side)
2279 {
2280 std::vector<boundary_id_type> elem_boundary_ids;
2281 _mesh->get_boundary_info().boundary_ids(elem, side, elem_boundary_ids);
2282 for (auto bdid : elem_boundary_ids)
2284 need_boundary_materials = true;
2285 }
2286
2287 // Load boundary material properties from cached properties
2288 if (need_boundary_materials)
2290 elem,
2292 _bnd_material_data[0]->getMaterialPropertyStorageForXFEM({}));
2293}
2294
2297 const Elem * cut_elem,
2298 const Elem * parent_elem) const
2299{
2300 if (!parent_elem)
2301 parent_elem = cut_elem;
2302 // Pick any node from the parent element that is inside the physical domain and return its
2303 // CutSubdomainID.
2304 const Node * node = pickFirstPhysicalNode(cut_elem, parent_elem);
2305 return gcuo->getCutSubdomainID(node);
2306}
2307
2308const Node *
2309XFEM::pickFirstPhysicalNode(const Elem * e, const Elem * e0) const
2310{
2311 for (auto i : e0->node_index_range())
2312 if (isPointInsidePhysicalDomain(e, e0->node_ref(i)))
2313 return e0->node_ptr(i);
2314 mooseError("cannot find a physical node in the current element");
2315 return nullptr;
2316}
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
void dataLoad(std::istream &stream, LineSegment &l, void *context)
void dataStore(std::ostream &stream, LineSegment &l, void *context)
void mooseError(Args &&... args)
PetscInt nsides
char ** vars
const std::string name
Definition Setup.h:21
const ExecFlagType EXEC_XFEM_MARK
Exec flag used to execute MooseObjects while elements are being marked for cutting by XFEM.
unsigned int CutSubdomainID
void ErrorVector unsigned int
const libMesh::QBase *const & qRule() const
virtual libMesh::System & system() override
virtual void serializeSolution()
const ConsoleStream _console
bool isPartialOverlap(const EFAEdge &other) const
Definition EFAEdge.C:59
EFANode * getNode(unsigned int index) const
Definition EFAEdge.C:181
EFANode * getEmbeddedNode(unsigned int index) const
Definition EFAEdge.C:332
bool hasIntersection() const
Definition EFAEdge.C:200
virtual unsigned int numFragments() const
EFAFragment2D * getFragment(unsigned int frag_id) const
unsigned int getCrackTipSplitElementID() const
bool isEdgePhantom(unsigned int edge_id) const
EFANode * getTipEmbeddedNode() const
EFAEdge * getEdge(unsigned int edge_id) const
unsigned int numEdges() const
EFAEdge * getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const
unsigned int numEdgeNeighbors(unsigned int edge_id) const
virtual bool isFinalCut() const
EFAElement2D * getEdgeNeighbor(unsigned int edge_id, unsigned int neighbor_id) const
unsigned int getTipEdgeID() const
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
EFAElement3D * getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
unsigned int numFaces() const
virtual unsigned int numFragments() const
EFAFragment3D * getFragment(unsigned int frag_id) const
bool isFacePhantom(unsigned int face_id) const
unsigned int numFaceNeighbors(unsigned int face_id) const
virtual void getMasterInfo(EFANode *node, std::vector< EFANode * > &master_nodes, std::vector< double > &master_weights) const =0
virtual bool isPartial() const =0
unsigned int getLocalNodeIndex(EFANode *node) const
Definition EFAElement.C:111
unsigned int id() const
Definition EFAElement.C:28
unsigned int numNodes() const
Definition EFAFace.C:87
EFANode * getNode(unsigned int node_id) const
Definition EFAFace.C:99
std::vector< unsigned int > getInteriorEdgeID() const
unsigned int numEdges() const
bool isSecondaryInteriorEdge(unsigned int edge_id) const
bool isThirdInteriorFace(unsigned int face_id) const
@ N_CATEGORY_PERMANENT
Definition EFANode.h:19
unsigned int id() const
Definition EFANode.C:36
void addElemNodeIntersection(unsigned int elemid, unsigned int nodeid)
const std::vector< EFANode * > & getNewNodes()
EFAElement * add3DElement(const std::vector< unsigned int > &quad, unsigned int id)
EFAElement * getElemByID(unsigned int id)
void addFragFaceIntersection(unsigned int ElemID, unsigned int FragFaceID, const std::vector< unsigned int > &FragFaceEdgeID, const std::vector< double > &position)
const std::vector< EFAElement * > & getChildElements()
void addElemFaceIntersection(unsigned int elemid, unsigned int faceid, const std::vector< unsigned int > &edgeid, const std::vector< double > &position)
void restoreFragmentInfo(EFAElement *const elem, const EFAElement *const from_elem)
void addElemEdgeIntersection(unsigned int elemid, unsigned int edgeid, double position)
const std::set< EFAElement * > & getCrackTipElements()
EFAElement * add2DElement(const std::vector< unsigned int > &quad, unsigned int id)
bool addFragEdgeIntersection(unsigned int elemid, unsigned int frag_edge_id, double position)
void updateTopology(bool mergeUncutVirtualEdges=true)
const std::vector< EFAElement * > & getParentElements()
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num) override
virtual void execute(const ExecFlagType &exec_type)
bool needBoundaryMaterialOnSide(BoundaryID bnd_id, const THREAD_ID tid)
virtual bool isTransient() const override
bool shouldHealMesh() const
Should the elements cut by this cutting object be healed in the current time step?
void setInterfaceID(unsigned int interface_id)
Set the interface ID for this cutting object.
virtual CutSubdomainID getCutSubdomainID(const Node *) const
Get CutSubdomainID telling which side the node belongs to relative to the cut.
bool hasStatefulProperties() const
const PropsType & props(const unsigned int state=0) const
libMesh::IntRange< unsigned int > statefulIndexRange() const
MaterialProperties & setProps(const Elem *elem, unsigned int side, const unsigned int state=0)
unsigned int size() const
virtual bool isDistributedMesh() const
const std::set< SubdomainID > & getNodeBlockIds(const Node &node) const
bool isSemiLocal(Node *const node) const
const std::set< SubdomainID > & getSubdomainsForVar(unsigned int var_number) const
unsigned int number() const
const std::vector< MooseVariableFieldBase * > & getVariables(THREAD_ID tid)
NumericVector< Number > & solutionOld()
NumericVector< Number > & solutionOlder()
virtual bool cutElementByCrackGrowthIncrement(const Elem *elem, std::vector< CutEdgeForCrackGrowthIncr > &cut_edges, Real time)
virtual void getCrackTipOriginAndDirection(unsigned tip_id, Point &origin, Point &direction) const =0
virtual const EFAElement * getEFAElement() const =0
void getWeightMultipliers(MooseArray< Real > &weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points)
Definition XFEMCutElem.C:63
virtual Point getCutPlaneNormal(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const =0
void getFaceWeightMultipliers(MooseArray< Real > &face_weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points, unsigned int side)
Definition XFEMCutElem.C:77
Real getPhysicalVolumeFraction() const
Returns the volume fraction of the element fragment.
Definition XFEMCutElem.C:51
virtual Point getCutPlaneOrigin(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const =0
virtual void getIntersectionInfo(unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, MeshBase *displaced_mesh=nullptr) const =0
virtual void computePhysicalVolumeFraction()=0
Computes the volume fraction of the element fragment.
bool isPointPhysical(const Point &p) const
virtual void getFragmentFaces(std::vector< std::vector< Point > > &frag_faces, MeshBase *displaced_mesh=nullptr) const =0
MeshBase * _displaced_mesh
MooseMesh * _moose_mesh
std::vector< MaterialData * > _material_data
MeshBase * _mesh
FEProblemBase * _fe_problem
std::vector< MaterialData * > _bnd_material_data
void storeMaterialPropertiesForElementHelper(const Elem *elem, MaterialPropertyStorage &storage)
Definition XFEM.C:2192
virtual void getXFEMIntersectionInfo(const Elem *elem, unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, bool displaced_mesh=false) const
Definition XFEM.C:1903
std::vector< const GeometricCutUserObject * > _geometric_cuts
Definition XFEM.h:334
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.
Definition XFEM.C:2309
virtual bool updateHeal() override
Definition XFEM.C:226
EFAElement2D * getEFAElem2D(const Elem *elem)
Get the EFAElement2D object for a specified libMesh element.
Definition XFEM.C:1753
bool markCutFacesByState()
Definition XFEM.C:897
std::map< const GeometricCutUserObject *, unsigned int > _geom_marker_id_map
Data structure for storing the GeommetricCutUserObjects and their corresponding id.
Definition XFEM.h:360
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:2099
virtual void initSolution(const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux) override
Definition XFEM.C:312
virtual void getXFEMqRuleOnSurface(std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
Definition XFEM.C:1949
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:2027
void storeCrackTipOriginAndDirection()
Definition XFEM.C:187
bool _has_secondary_cut
Definition XFEM.h:327
Real _crack_growth_increment
Definition XFEM.h:332
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:170
void loadMaterialPropertiesForElementHelper(const Elem *elem, const Xfem::CachedMaterialProperties &cached_props, MaterialPropertyStorage &storage) const
Load the material properties.
Definition XFEM.C:2238
void addGeometricCut(GeometricCutUserObject *geometric_cut)
Definition XFEM.C:58
bool markCutFacesByGeometry()
Definition XFEM.C:856
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:357
virtual void getXFEMqRuleOnLine(std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
Definition XFEM.C:1922
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_displaced_elems
Definition XFEM.h:340
bool cutMeshWithEFA(const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux)
Definition XFEM.C:1108
std::map< unique_id_type, XFEMCutElem * > _cut_elem_map
Definition XFEM.h:336
bool markCutEdgesByGeometry()
Definition XFEM.C:399
ElementFragmentAlgorithm _efa_mesh
Definition XFEM.h:362
bool isElemCut(const Elem *elem, XFEMCutElem *&xfce) const
Definition XFEM.C:1713
bool markCuts(Real time)
Definition XFEM.C:382
void setDebugOutputLevel(unsigned int debug_output_level)
Controls amount of debugging information output.
Definition XFEM.C:1844
void setMinWeightMultiplier(Real min_weight_multiplier)
Controls the minimum average weight multiplier for each element.
Definition XFEM.C:1850
Point getEFANodeCoords(EFANode *CEMnode, EFAElement *CEMElem, const Elem *elem, MeshBase *displaced_mesh=nullptr) const
Definition XFEM.C:1603
~XFEM()
Definition XFEM.C:49
Real getPhysicalVolumeFraction(const Elem *elem) const
Get the volume fraction of an element that is physical.
Definition XFEM.C:1635
std::map< const Elem *, RealVectorValue > _state_marked_elems
Definition XFEM.h:346
void addStateMarkedFrag(unsigned int elem_id, RealVectorValue &normal)
Definition XFEM.C:138
Xfem::XFEM_QRULE _XFEM_qrule
Definition XFEM.h:329
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_elems
Definition XFEM.h:339
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:351
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:2148
bool isElemAtCrackTip(const Elem *elem) const
Definition XFEM.C:1707
virtual bool getXFEMFaceWeights(MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points, unsigned int side) override
Definition XFEM.C:1885
bool healMesh()
Potentially heal the mesh by merging some of the pairs of partial elements cut by XFEM back into sing...
Definition XFEM.C:924
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:2061
void getFragmentFaces(const Elem *elem, std::vector< std::vector< Point > > &frag_faces, bool displaced_mesh=false) const
Definition XFEM.C:1736
std::map< const Elem *, unsigned int > _state_marked_elem_sides
Definition XFEM.h:348
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:382
void setCrackGrowthMethod(bool use_crack_growth_increment, Real crack_growth_increment)
Definition XFEM.C:1837
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.
Definition XFEM.C:2296
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:1993
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.
Definition XFEM.h:403
std::unordered_map< const Elem *, Xfem::CutElemInfo > _geom_cut_elems
All geometrically cut elements and their CutElemInfo during the current execution of XFEM_MARK.
Definition XFEM.h:397
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.
Definition XFEM.C:2262
void clearGeomMarkedElems()
Clear out the list of elements to be marked for cutting.
Definition XFEM.C:180
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:1673
void getCrackTipOrigin(std::map< unsigned int, const Elem * > &elem_id_crack_tip, std::vector< Point > &crack_front_points)
Definition XFEM.C:68
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:451
EFAElement3D * getEFAElem3D(const Elem *elem)
Get the EFAElement3D object for a specified libMesh element.
Definition XFEM.C:1765
bool markCutEdgesByState(Real time)
Definition XFEM.C:592
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:160
void getFragmentEdges(const Elem *elem, EFAElement2D *CEMElem, std::vector< std::vector< Point > > &frag_edges) const
Definition XFEM.C:1777
Xfem::XFEM_QRULE & getXFEMQRule()
Definition XFEM.C:1820
void addStateMarkedElem(unsigned int elem_id, RealVectorValue &normal)
Definition XFEM.C:114
virtual bool update(Real time, const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux) override
Definition XFEM.C:263
virtual bool getXFEMWeights(MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points) override
Definition XFEM.C:1856
std::set< const Elem * > _crack_tip_elems
Definition XFEM.h:337
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:1655
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:2122
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:354
unsigned int _debug_output_level
Controls amount of debugging output information 0: None 1: Summary 2: Details on modifications to mes...
Definition XFEM.h:369
XFEM(const InputParameters &params)
Definition XFEM.C:36
void storeMaterialPropertiesForElement(const Elem *parent_elem, const Elem *child_elem)
Helper function to store the material properties of a healed element.
Definition XFEM.C:2210
std::map< const Elem *, std::vector< Point > > _elem_crack_origin_direction_map
Definition XFEM.h:342
const GeometricCutUserObject * getGeometricCutForElem(const Elem *elem) const
Get the GeometricCutUserObject associated with an element.
Definition XFEM.C:2180
void setXFEMQRule(std::string &xfem_qrule)
Definition XFEM.C:1826
void buildEFAMesh()
Definition XFEM.C:343
bool initCutIntersectionEdge(Point cut_origin, RealVectorValue cut_normal, Point &edge_p1, Point &edge_p2, Real &dist)
Definition XFEM.C:905
Real _min_weight_multiplier
The minimum average multiplier applied by XFEM to the standard quadrature weights to integrate partia...
Definition XFEM.h:373
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:391
std::set< const Elem * > _crack_tip_elems_to_be_healed
Definition XFEM.h:338
std::set< const Elem * > _state_marked_frags
Definition XFEM.h:347
bool _use_crack_growth_increment
Definition XFEM.h:331
void clearStateMarkedElems()
Definition XFEM.C:152
virtual void insert(const T *v, const std::vector< numeric_index_type > &dof_indices)
unsigned int n_points() const
std::unique_ptr< NumericVector< Number > > current_local_solution
XFEM_CUTPLANE_QUANTITY
Definition XFEM.h:28
void stdQuadr2D(unsigned int nen, unsigned int iord, std::vector< std::vector< Real > > &sg2)
Definition XFEMFuncs.C:96
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
std::array< std::unordered_map< unsigned int, std::string >, 2 > CachedMaterialProperties
Convenient typedef for local storage of stateful material properties.
Definition XFEM.h:50
XFEM_QRULE
Definition XFEM.h:38
@ DIRECT
Definition XFEM.h:41
@ VOLFRAC
Definition XFEM.h:39
@ MOMENT_FITTING
Definition XFEM.h:40
Information about a cut element.
Definition XFEM.h:58
CachedMaterialProperties _elem_material_properties
Definition XFEM.h:62
bool match(const CutElemInfo &rhs)
Definition XFEM.h:83
CachedMaterialProperties _bnd_material_properties
Definition XFEM.h:63
Data structure describing geometrically described cut through 2D element.
Data structure describing geometrically described cut through 3D element.
Real distance(const Point &p)