https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Protected Attributes | Private Member Functions | Private Attributes | List of all members
XFEM Class Referenceabstract

This is the XFEM class. More...

#include <XFEM.h>

Inheritance diagram for XFEM:
[legend]

Public Member Functions

 XFEM (const InputParameters &params)
 
 ~XFEM ()
 
void addGeometricCut (GeometricCutUserObject *geometric_cut)
 
void addStateMarkedElem (unsigned int elem_id, RealVectorValue &normal)
 
void addStateMarkedElem (unsigned int elem_id, RealVectorValue &normal, unsigned int marked_side)
 
void addStateMarkedFrag (unsigned int elem_id, RealVectorValue &normal)
 
void clearStateMarkedElems ()
 
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.
 
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.
 
void clearGeomMarkedElems ()
 Clear out the list of elements to be marked for cutting.
 
virtual bool update (Real time, const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux) override
 
virtual void initSolution (const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux) override
 
void buildEFAMesh ()
 
bool markCuts (Real time)
 
bool markCutEdgesByGeometry ()
 
bool markCutEdgesByState (Real time)
 
bool markCutFacesByGeometry ()
 
bool markCutFacesByState ()
 
bool initCutIntersectionEdge (Point cut_origin, RealVectorValue cut_normal, Point &edge_p1, Point &edge_p2, Real &dist)
 
bool cutMeshWithEFA (const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux)
 
bool healMesh ()
 Potentially heal the mesh by merging some of the pairs of partial elements cut by XFEM back into single elements if indicated by the cutting objects.
 
virtual bool updateHeal () override
 
Point getEFANodeCoords (EFANode *CEMnode, EFAElement *CEMElem, const Elem *elem, MeshBase *displaced_mesh=nullptr) const
 
Real getPhysicalVolumeFraction (const Elem *elem) const
 Get the volume fraction of an element that is physical.
 
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, return true too.
 
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.
 
bool isElemAtCrackTip (const Elem *elem) const
 
bool isElemCut (const Elem *elem, XFEMCutElem *&xfce) const
 
bool isElemCut (const Elem *elem) const
 
void getFragmentFaces (const Elem *elem, std::vector< std::vector< Point > > &frag_faces, bool displaced_mesh=false) const
 
void storeCrackTipOriginAndDirection ()
 
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)
 
void getCrackTipOrigin (std::map< unsigned int, const Elem * > &elem_id_crack_tip, std::vector< Point > &crack_front_points)
 
Xfem::XFEM_QRULEgetXFEMQRule ()
 
void setXFEMQRule (std::string &xfem_qrule)
 
void setCrackGrowthMethod (bool use_crack_growth_increment, Real crack_growth_increment)
 
void setDebugOutputLevel (unsigned int debug_output_level)
 Controls amount of debugging information output.
 
void setMinWeightMultiplier (Real min_weight_multiplier)
 Controls the minimum average weight multiplier for each element.
 
virtual bool getXFEMWeights (MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points) override
 
virtual bool getXFEMFaceWeights (MooseArray< Real > &weights, const Elem *elem, QBase *qrule, const MooseArray< Point > &q_points, unsigned int side) override
 
virtual const ElementPairLocator::ElementPairListgetXFEMCutElemPairs (unsigned int interface_id)
 Get the list of cut element pairs corresponding to a given interface ID.
 
virtual const ElementPairLocator::ElementPairListgetXFEMDisplacedCutElemPairs (unsigned int interface_id)
 Get the list of cut element pairs on the displaced mesh corresponding to a given interface ID.
 
virtual unsigned int getGeometricCutID (const GeometricCutUserObject *gcu)
 Get the interface ID corresponding to a given GeometricCutUserObject.
 
virtual void getXFEMIntersectionInfo (const Elem *elem, unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, bool displaced_mesh=false) const
 
virtual void getXFEMqRuleOnLine (std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
 
virtual void getXFEMqRuleOnSurface (std::vector< Point > &intersection_points, std::vector< Point > &quad_pts, std::vector< Real > &quad_wts) const
 
bool has_secondary_cut ()
 
EFAElement2DgetEFAElem2D (const Elem *elem)
 Get the EFAElement2D object for a specified libMesh element.
 
EFAElement3DgetEFAElem3D (const Elem *elem)
 Get the EFAElement3D object for a specified libMesh element.
 
void getFragmentEdges (const Elem *elem, EFAElement2D *CEMElem, std::vector< std::vector< Point > > &frag_edges) const
 
void getFragmentFaces (const Elem *elem, EFAElement3D *CEMElem, std::vector< std::vector< Point > > &frag_faces) const
 
const std::map< const Elem *, std::vector< Point > > & getCrackTipOriginMap () const
 
CutSubdomainID getCutSubdomainID (const GeometricCutUserObject *gcuo, const Elem *cut_elem, const Elem *parent_elem=nullptr) const
 Determine which cut subdomain the element belongs to relative to the cut.
 
void setMesh (MooseMesh *mesh)
 
void setDisplacedMesh (MooseMesh *displaced_mesh)
 
void setMaterialData (const std::vector< MaterialData * > &data)
 
void setBoundaryMaterialData (const std::vector< MaterialData * > &data)
 
virtual bool getXFEMWeights (MooseArray< Real > &weights, const Elem *elem, libMesh::QBase *qrule, const MooseArray< Point > &q_points)=0
 
virtual bool getXFEMFaceWeights (MooseArray< Real > &weights, const Elem *elem, libMesh::QBase *qrule, const MooseArray< Point > &q_points, unsigned int side)=0
 

Public Attributes

const ConsoleStream _console
 

Protected Attributes

FEProblemBase_fe_problem
 
std::vector< MaterialData * > _material_data
 
std::vector< MaterialData * > _bnd_material_data
 
MooseMesh_moose_mesh
 
MooseMesh_moose_displaced_mesh
 
MeshBase * _mesh
 
MeshBase * _displaced_mesh
 

Private Member Functions

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.
 
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.
 
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.
 
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.
 
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.
 
std::vector< dof_id_type > getNodeSolutionDofs (const Node *node, SystemBase &sys) const
 Get a vector of the dof indices for all components of all variables associated with a node.
 
const GeometricCutUserObjectgetGeometricCutForElem (const Elem *elem) const
 Get the GeometricCutUserObject associated with an element.
 
void storeMaterialPropertiesForElementHelper (const Elem *elem, MaterialPropertyStorage &storage)
 
void storeMaterialPropertiesForElement (const Elem *parent_elem, const Elem *child_elem)
 Helper function to store the material properties of a healed element.
 
void loadMaterialPropertiesForElementHelper (const Elem *elem, const Xfem::CachedMaterialProperties &cached_props, MaterialPropertyStorage &storage) const
 Load the material properties.
 
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.
 
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.
 

Private Attributes

bool _has_secondary_cut
 
Xfem::XFEM_QRULE _XFEM_qrule
 
bool _use_crack_growth_increment
 
Real _crack_growth_increment
 
std::vector< const GeometricCutUserObject * > _geometric_cuts
 
std::map< unique_id_type, XFEMCutElem * > _cut_elem_map
 
std::set< const Elem * > _crack_tip_elems
 
std::set< const Elem * > _crack_tip_elems_to_be_healed
 
std::map< unsigned int, ElementPairLocator::ElementPairList_sibling_elems
 
std::map< unsigned int, ElementPairLocator::ElementPairList_sibling_displaced_elems
 
std::map< const Elem *, std::vector< Point > > _elem_crack_origin_direction_map
 
std::map< const Elem *, RealVectorValue > _state_marked_elems
 
std::set< const Elem * > _state_marked_frags
 
std::map< const Elem *, unsigned int_state_marked_elem_sides
 
std::map< const Elem *, std::vector< Xfem::GeomMarkedElemInfo2D > > _geom_marked_elems_2d
 Data structure for storing information about all 2D elements to be cut by geometry.
 
std::map< const Elem *, std::vector< Xfem::GeomMarkedElemInfo3D > > _geom_marked_elems_3d
 Data structure for storing information about all 3D elements to be cut by geometry.
 
std::map< unsigned int, std::set< unsigned int > > _geom_marker_id_elems
 Data structure for storing the elements cut by specific geometric cutters.
 
std::map< const GeometricCutUserObject *, unsigned int_geom_marker_id_map
 Data structure for storing the GeommetricCutUserObjects and their corresponding id.
 
ElementFragmentAlgorithm _efa_mesh
 
unsigned int _debug_output_level
 Controls amount of debugging output information 0: None 1: Summary 2: Details on modifications to mesh 3: Full dump of element fragment algorithm mesh.
 
Real _min_weight_multiplier
 The minimum average multiplier applied by XFEM to the standard quadrature weights to integrate partial elements.
 
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/element, this is stored as a vector that contains all components of all applicable variables in an order defined by getElementSolutionDofs() or getNodeSolutionDofs().
 
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/element, this is stored as a vector that contains all components of all applicable variables in an order defined by getElementSolutionDofs() or getNodeSolutionDofs().
 
std::unordered_map< const Elem *, Xfem::CutElemInfo_geom_cut_elems
 All geometrically cut elements and their CutElemInfo during the current execution of XFEM_MARK.
 
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.
 

Detailed Description

This is the XFEM class.

This class implements algorithms for dynamic mesh modification in support of a phantom node approach for XFEM

Definition at line 107 of file XFEM.h.

Constructor & Destructor Documentation

◆ XFEM()

XFEM::XFEM ( const InputParameters params)
explicit

Definition at line 36 of file XFEM.C.

37 : XFEMInterface(params),
38 _efa_mesh(Moose::out),
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}
void mooseError(Args &&... args)
bool _has_secondary_cut
Definition XFEM.h:327
ElementFragmentAlgorithm _efa_mesh
Definition XFEM.h:362
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
Real _min_weight_multiplier
The minimum average multiplier applied by XFEM to the standard quadrature weights to integrate partia...
Definition XFEM.h:373

◆ ~XFEM()

XFEM::~XFEM ( )

Definition at line 49 of file XFEM.C.

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}
std::map< unique_id_type, XFEMCutElem * > _cut_elem_map
Definition XFEM.h:336

Member Function Documentation

◆ addGeometricCut()

void XFEM::addGeometricCut ( GeometricCutUserObject geometric_cut)

Definition at line 58 of file XFEM.C.

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}
void setInterfaceID(unsigned int interface_id)
Set the interface ID for this cutting object.
std::vector< const GeometricCutUserObject * > _geometric_cuts
Definition XFEM.h:334
std::map< const GeometricCutUserObject *, unsigned int > _geom_marker_id_map
Data structure for storing the GeommetricCutUserObjects and their corresponding id.
Definition XFEM.h:360

◆ addGeomMarkedElem2D()

void XFEM::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.

Parameters
elem_idThe id of the element to be cut
geom_infoThe object containing information about the cut to be performed
interface_idThe ID of the interface

Definition at line 160 of file XFEM.C.

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}
MeshBase * _mesh
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
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

◆ addGeomMarkedElem3D()

void XFEM::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.

Parameters
elem_idThe id of the element to be cut
geom_infoThe object containing information about the cut to be performed
interface_idThe ID of the interface

Definition at line 170 of file XFEM.C.

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}
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

◆ addStateMarkedElem() [1/2]

void XFEM::addStateMarkedElem ( unsigned int  elem_id,
RealVectorValue &  normal 
)

Definition at line 114 of file XFEM.C.

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}
std::map< const Elem *, RealVectorValue > _state_marked_elems
Definition XFEM.h:346

Referenced by addStateMarkedElem(), and addStateMarkedFrag().

◆ addStateMarkedElem() [2/2]

void XFEM::addStateMarkedElem ( unsigned int  elem_id,
RealVectorValue &  normal,
unsigned int  marked_side 
)

Definition at line 125 of file XFEM.C.

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}
std::map< const Elem *, unsigned int > _state_marked_elem_sides
Definition XFEM.h:348
void addStateMarkedElem(unsigned int elem_id, RealVectorValue &normal)
Definition XFEM.C:114

◆ addStateMarkedFrag()

void XFEM::addStateMarkedFrag ( unsigned int  elem_id,
RealVectorValue &  normal 
)

Definition at line 138 of file XFEM.C.

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}
std::set< const Elem * > _state_marked_frags
Definition XFEM.h:347

◆ buildEFAMesh()

void XFEM::buildEFAMesh ( )

Definition at line 343 of file XFEM.C.

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}
EFAElement * add3DElement(const std::vector< unsigned int > &quad, unsigned int id)
EFAElement * getElemByID(unsigned int id)
void restoreFragmentInfo(EFAElement *const elem, const EFAElement *const from_elem)
EFAElement * add2DElement(const std::vector< unsigned int > &quad, unsigned int id)
virtual const EFAElement * getEFAElement() const =0

Referenced by update(), and updateHeal().

◆ clearGeomMarkedElems()

void XFEM::clearGeomMarkedElems ( )

Clear out the list of elements to be marked for cutting.

Called after cutting is done.

Definition at line 180 of file XFEM.C.

181{
182 _geom_marked_elems_2d.clear();
183 _geom_marked_elems_3d.clear();
184}

Referenced by update().

◆ clearStateMarkedElems()

void XFEM::clearStateMarkedElems ( )

Definition at line 152 of file XFEM.C.

153{
154 _state_marked_elems.clear();
155 _state_marked_frags.clear();
157}

Referenced by update().

◆ correctCrackExtensionDirection()

void XFEM::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 at line 451 of file XFEM.C.

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}
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
PetscInt nsides
bool isPartialOverlap(const EFAEdge &other) const
Definition EFAEdge.C:59
EFANode * getNode(unsigned int index) const
Definition EFAEdge.C:181
bool isEdgePhantom(unsigned int edge_id) const
EFAEdge * getEdge(unsigned int edge_id) const
unsigned int numEdges() const
Point getEFANodeCoords(EFANode *CEMnode, EFAElement *CEMElem, const Elem *elem, MeshBase *displaced_mesh=nullptr) const
Definition XFEM.C:1603
bool initCutIntersectionEdge(Point cut_origin, RealVectorValue cut_normal, Point &edge_p1, Point &edge_p2, Real &dist)
Definition XFEM.C:905
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real distance(const Point &p)

Referenced by markCutEdgesByState().

◆ cutMeshWithEFA()

bool XFEM::cutMeshWithEFA ( const std::vector< std::shared_ptr< NonlinearSystemBase > > &  nl,
AuxiliarySystem aux 
)

Definition at line 1108 of file XFEM.C.

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}
unsigned int CutSubdomainID
const libMesh::QBase *const & qRule() const
virtual libMesh::System & system() override
virtual void serializeSolution()
const ConsoleStream _console
unsigned int numEdgeNeighbors(unsigned int edge_id) const
EFAElement2D * getEdgeNeighbor(unsigned int edge_id, unsigned int neighbor_id) const
EFAElement3D * getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
unsigned int numFaces() const
unsigned int numFaceNeighbors(unsigned int face_id) const
unsigned int id() const
Definition EFAElement.C:28
const std::vector< EFANode * > & getNewNodes()
const std::vector< EFAElement * > & getChildElements()
const std::set< EFAElement * > & getCrackTipElements()
void updateTopology(bool mergeUncutVirtualEdges=true)
const std::vector< EFAElement * > & getParentElements()
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num) override
bool needBoundaryMaterialOnSide(BoundaryID bnd_id, const THREAD_ID tid)
bool shouldHealMesh() const
Should the elements cut by this cutting object be healed in the current time step?
bool isSemiLocal(Node *const node) const
NumericVector< Number > & solutionOld()
NumericVector< Number > & solutionOlder()
MeshBase * _displaced_mesh
MooseMesh * _moose_mesh
std::vector< MaterialData * > _material_data
FEProblemBase * _fe_problem
std::vector< MaterialData * > _bnd_material_data
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
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_displaced_elems
Definition XFEM.h:340
std::map< unsigned int, ElementPairLocator::ElementPairList > _sibling_elems
Definition XFEM.h:339
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
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
std::set< const Elem * > _crack_tip_elems
Definition XFEM.h:337
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
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
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
if(subdm)
Information about a cut element.
Definition XFEM.h:58

Referenced by update().

◆ getCrackTipOrigin()

void XFEM::getCrackTipOrigin ( std::map< unsigned int, const Elem * > &  elem_id_crack_tip,
std::vector< Point > &  crack_front_points 
)

Definition at line 68 of file XFEM.C.

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}

◆ getCrackTipOriginMap()

const std::map< const Elem *, std::vector< Point > > & XFEM::getCrackTipOriginMap ( ) const
inline

Definition at line 311 of file XFEM.h.

312 {
314 }

◆ getCutPlane()

Real XFEM::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 at line 1673 of file XFEM.C.

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}
void ErrorVector unsigned int
virtual bool isPartial() const =0
virtual Point getCutPlaneNormal(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const =0
virtual Point getCutPlaneOrigin(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const =0

◆ getCutSubdomainID()

CutSubdomainID XFEM::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.

Parameters
gcuoThe GeometricCutUserObject for the cut
cut_elemThe element being cut
parent_elemThe parent element

Definition at line 2296 of file XFEM.C.

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}
virtual CutSubdomainID getCutSubdomainID(const Node *) const
Get CutSubdomainID telling which side the node belongs to relative to the cut.
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

Referenced by cutMeshWithEFA().

◆ getEFAElem2D()

EFAElement2D * XFEM::getEFAElem2D ( const Elem *  elem)

Get the EFAElement2D object for a specified libMesh element.

Parameters
elemPointer to the libMesh element for which the object is requested

Definition at line 1753 of file XFEM.C.

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}

Referenced by markCutEdgesByGeometry(), and markCutEdgesByState().

◆ getEFAElem3D()

EFAElement3D * XFEM::getEFAElem3D ( const Elem *  elem)

Get the EFAElement3D object for a specified libMesh element.

Parameters
elemPointer to the libMesh element for which the object is requested

Definition at line 1765 of file XFEM.C.

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}

Referenced by markCutFacesByGeometry().

◆ getEFANodeCoords()

Point XFEM::getEFANodeCoords ( EFANode CEMnode,
EFAElement CEMElem,
const Elem *  elem,
MeshBase *  displaced_mesh = nullptr 
) const

Definition at line 1603 of file XFEM.C.

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}
virtual void getMasterInfo(EFANode *node, std::vector< EFANode * > &master_nodes, std::vector< double > &master_weights) const =0
unsigned int getLocalNodeIndex(EFANode *node) const
Definition EFAElement.C:111
@ N_CATEGORY_PERMANENT
Definition EFANode.h:19

Referenced by correctCrackExtensionDirection(), getFragmentEdges(), getFragmentFaces(), and markCutEdgesByState().

◆ getElementSolutionDofs()

std::vector< dof_id_type > XFEM::getElementSolutionDofs ( const Elem *  elem,
SystemBase sys 
) const
private

Get a vector of the dof indices for all components of all variables associated with an element.

Parameters
elemElement for which dof indices are found
sysSystem for which the dof indices are found

Definition at line 2122 of file XFEM.C.

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}
char ** vars
const std::set< SubdomainID > & getSubdomainsForVar(unsigned int var_number) const
unsigned int number() const
const std::vector< MooseVariableFieldBase * > & getVariables(THREAD_ID tid)
uint8_t dof_id_type

Referenced by setSolution(), and storeSolutionForElement().

◆ getFragmentEdges()

void XFEM::getFragmentEdges ( const Elem *  elem,
EFAElement2D CEMElem,
std::vector< std::vector< Point > > &  frag_edges 
) const

Definition at line 1777 of file XFEM.C.

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}
virtual unsigned int numFragments() const
EFAFragment2D * getFragment(unsigned int frag_id) const
EFAEdge * getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const

◆ getFragmentFaces() [1/2]

void XFEM::getFragmentFaces ( const Elem *  elem,
EFAElement3D CEMElem,
std::vector< std::vector< Point > > &  frag_faces 
) const

Definition at line 1798 of file XFEM.C.

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}
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
virtual unsigned int numFragments() const
EFAFragment3D * getFragment(unsigned int frag_id) const
unsigned int numNodes() const
Definition EFAFace.C:87
EFANode * getNode(unsigned int node_id) const
Definition EFAFace.C:99

◆ getFragmentFaces() [2/2]

void XFEM::getFragmentFaces ( const Elem *  elem,
std::vector< std::vector< Point > > &  frag_faces,
bool  displaced_mesh = false 
) const

Definition at line 1736 of file XFEM.C.

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}
virtual void getFragmentFaces(std::vector< std::vector< Point > > &frag_faces, MeshBase *displaced_mesh=nullptr) const =0

◆ getGeometricCutForElem()

const GeometricCutUserObject * XFEM::getGeometricCutForElem ( const Elem *  elem) const
private

Get the GeometricCutUserObject associated with an element.

Parameters
elemThe element
Returns
A constant pointer to the GeometricCutUserObject, nullptr if nothing found

Definition at line 2180 of file XFEM.C.

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}

Referenced by cutMeshWithEFA().

◆ getGeometricCutID()

virtual unsigned int XFEM::getGeometricCutID ( const GeometricCutUserObject gcu)
inlinevirtual

Get the interface ID corresponding to a given GeometricCutUserObject.

Parameters
gcupointer to the GeometricCutUserObject
Returns
the interface ID

Definition at line 274 of file XFEM.h.

275 {
276 return _geom_marker_id_map[gcu];
277 };

◆ getNodeSolutionDofs()

std::vector< dof_id_type > XFEM::getNodeSolutionDofs ( const Node *  node,
SystemBase sys 
) const
private

Get a vector of the dof indices for all components of all variables associated with a node.

Parameters
nodeNode for which dof indices are found
sysSystem for which the dof indices are found

Definition at line 2148 of file XFEM.C.

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}
const std::set< SubdomainID > & getNodeBlockIds(const Node &node) const

Referenced by setSolution(), and storeSolutionForNode().

◆ getPhysicalVolumeFraction()

Real XFEM::getPhysicalVolumeFraction ( const Elem *  elem) const

Get the volume fraction of an element that is physical.

Definition at line 1635 of file XFEM.C.

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}
Real getPhysicalVolumeFraction() const
Returns the volume fraction of the element fragment.
Definition XFEMCutElem.C:51
virtual void computePhysicalVolumeFraction()=0
Computes the volume fraction of the element fragment.

Referenced by markCutEdgesByState().

◆ getXFEMCutElemPairs()

virtual const ElementPairLocator::ElementPairList * XFEM::getXFEMCutElemPairs ( unsigned int  interface_id)
inlinevirtual

Get the list of cut element pairs corresponding to a given interface ID.

Parameters
interface_idThe ID of the interface
Returns
the list of elements cut by that interface

Definition at line 252 of file XFEM.h.

253 {
254 return &_sibling_elems[interface_id];
255 }

◆ getXFEMDisplacedCutElemPairs()

virtual const ElementPairLocator::ElementPairList * XFEM::getXFEMDisplacedCutElemPairs ( unsigned int  interface_id)
inlinevirtual

Get the list of cut element pairs on the displaced mesh corresponding to a given interface ID.

Parameters
interface_idThe ID of the interface
Returns
the list of elements cut by that interface

Definition at line 264 of file XFEM.h.

265 {
266 return &_sibling_displaced_elems[interface_id];
267 }

◆ getXFEMFaceWeights()

bool XFEM::getXFEMFaceWeights ( MooseArray< Real > &  weights,
const Elem *  elem,
QBase *  qrule,
const MooseArray< Point > &  q_points,
unsigned int  side 
)
overridevirtual

Definition at line 1885 of file XFEM.C.

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}
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
bool isElemCut(const Elem *elem, XFEMCutElem *&xfce) const
Definition XFEM.C:1713
Xfem::XFEM_QRULE & getXFEMQRule()
Definition XFEM.C:1820

◆ getXFEMIntersectionInfo()

void XFEM::getXFEMIntersectionInfo ( const Elem *  elem,
unsigned int  plane_id,
Point &  normal,
std::vector< Point > &  intersectionPoints,
bool  displaced_mesh = false 
) const
virtual

Definition at line 1903 of file XFEM.C.

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}
virtual void getIntersectionInfo(unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, MeshBase *displaced_mesh=nullptr) const =0

◆ getXFEMQRule()

Xfem::XFEM_QRULE & XFEM::getXFEMQRule ( )

Definition at line 1820 of file XFEM.C.

1821{
1822 return _XFEM_qrule;
1823}
Xfem::XFEM_QRULE _XFEM_qrule
Definition XFEM.h:329

Referenced by getXFEMFaceWeights(), and getXFEMWeights().

◆ getXFEMqRuleOnLine()

void XFEM::getXFEMqRuleOnLine ( std::vector< Point > &  intersection_points,
std::vector< Point > &  quad_pts,
std::vector< Real > &  quad_wts 
) const
virtual

Definition at line 1922 of file XFEM.C.

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}
auto norm_sq(const T &a)

◆ getXFEMqRuleOnSurface()

void XFEM::getXFEMqRuleOnSurface ( std::vector< Point > &  intersection_points,
std::vector< Point > &  quad_pts,
std::vector< Real > &  quad_wts 
) const
virtual

Definition at line 1949 of file XFEM.C.

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}
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

◆ getXFEMWeights()

bool XFEM::getXFEMWeights ( MooseArray< Real > &  weights,
const Elem *  elem,
QBase *  qrule,
const MooseArray< Point > &  q_points 
)
overridevirtual

Definition at line 1856 of file XFEM.C.

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}
unsigned int size() const
void getWeightMultipliers(MooseArray< Real > &weights, QBase *qrule, Xfem::XFEM_QRULE xfem_qrule, const MooseArray< Point > &q_points)
Definition XFEMCutElem.C:63

◆ has_secondary_cut()

bool XFEM::has_secondary_cut ( )
inline

Definition at line 290 of file XFEM.h.

290{ return _has_secondary_cut; }

◆ healMesh()

bool XFEM::healMesh ( )

Potentially heal the mesh by merging some of the pairs of partial elements cut by XFEM back into single elements if indicated by the cutting objects.

Returns
true if the mesh has been modified due to healing

Definition at line 924 of file XFEM.C.

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}
const std::string name
Definition Setup.h:21
bool isPointPhysical(const Point &p) const
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
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)

Referenced by updateHeal().

◆ initCutIntersectionEdge()

bool XFEM::initCutIntersectionEdge ( Point  cut_origin,
RealVectorValue  cut_normal,
Point &  edge_p1,
Point &  edge_p2,
Real &  dist 
)

Definition at line 905 of file XFEM.C.

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}

Referenced by correctCrackExtensionDirection(), and markCutEdgesByState().

◆ initSolution()

void XFEM::initSolution ( const std::vector< std::shared_ptr< NonlinearSystemBase > > &  nl,
AuxiliarySystem aux 
)
overridevirtual

Implements XFEMInterface.

Definition at line 312 of file XFEM.C.

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}
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

◆ isElemAtCrackTip()

bool XFEM::isElemAtCrackTip ( const Elem *  elem) const

Definition at line 1707 of file XFEM.C.

1708{
1709 return (_crack_tip_elems.find(elem) != _crack_tip_elems.end());
1710}

Referenced by markCutEdgesByGeometry(), and markCutEdgesByState().

◆ isElemCut() [1/2]

bool XFEM::isElemCut ( const Elem *  elem) const

Definition at line 1729 of file XFEM.C.

1730{
1731 XFEMCutElem * xfce;
1732 return isElemCut(elem, xfce);
1733}

◆ isElemCut() [2/2]

bool XFEM::isElemCut ( const Elem *  elem,
XFEMCutElem *&  xfce 
) const

Definition at line 1713 of file XFEM.C.

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}

Referenced by getXFEMFaceWeights(), getXFEMWeights(), and isElemCut().

◆ isPointInsidePhysicalDomain()

bool XFEM::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, return true too.

Definition at line 1655 of file XFEM.C.

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}

Referenced by pickFirstPhysicalNode().

◆ loadMaterialPropertiesForElement()

void XFEM::loadMaterialPropertiesForElement ( const Elem *  elem,
const Elem *  elem_from,
std::unordered_map< const Elem *, Xfem::CutElemInfo > &  cached_cei 
) const
private

Helper function to store the material properties of a healed element.

Parameters
elemThe cut element to restore material properties to.
elem_fromThe element to copy material properties from.
cached_ceiThe material properties cache to use.

Definition at line 2262 of file XFEM.C.

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)
2283 if (_fe_problem->needBoundaryMaterialOnSide(bdid, 0))
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}
void loadMaterialPropertiesForElementHelper(const Elem *elem, const Xfem::CachedMaterialProperties &cached_props, MaterialPropertyStorage &storage) const
Load the material properties.
Definition XFEM.C:2238
CachedMaterialProperties _elem_material_properties
Definition XFEM.h:62
CachedMaterialProperties _bnd_material_properties
Definition XFEM.h:63

Referenced by cutMeshWithEFA(), and healMesh().

◆ loadMaterialPropertiesForElementHelper()

void XFEM::loadMaterialPropertiesForElementHelper ( const Elem *  elem,
const Xfem::CachedMaterialProperties cached_props,
MaterialPropertyStorage storage 
) const
private

Load the material properties.

Parameters
props_deserializedThe material properties
props_serializedThe serialized material properties

This does very dirty things and writes back to MOOSE's stateful properties. It should not do this in the future.

Definition at line 2238 of file XFEM.C.

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}
void dataLoad(std::istream &stream, LineSegment &l, void *context)
bool hasStatefulProperties() const
MaterialProperties & setProps(const Elem *elem, unsigned int side, const unsigned int state=0)

Referenced by loadMaterialPropertiesForElement().

◆ markCutEdgesByGeometry()

bool XFEM::markCutEdgesByGeometry ( )

Definition at line 399 of file XFEM.C.

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}
bool isSecondaryInteriorEdge(unsigned int edge_id) const
void addElemNodeIntersection(unsigned int elemid, unsigned int nodeid)
void addElemEdgeIntersection(unsigned int elemid, unsigned int edgeid, double position)
bool addFragEdgeIntersection(unsigned int elemid, unsigned int frag_edge_id, double position)
EFAElement2D * getEFAElem2D(const Elem *elem)
Get the EFAElement2D object for a specified libMesh element.
Definition XFEM.C:1753
bool isElemAtCrackTip(const Elem *elem) const
Definition XFEM.C:1707

Referenced by markCuts().

◆ markCutEdgesByState()

bool XFEM::markCutEdgesByState ( Real  time)

Definition at line 592 of file XFEM.C.

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}
EFANode * getEmbeddedNode(unsigned int index) const
Definition EFAEdge.C:332
bool hasIntersection() const
Definition EFAEdge.C:200
EFANode * getTipEmbeddedNode() const
virtual bool isFinalCut() const
unsigned int getTipEdgeID() const
std::vector< unsigned int > getInteriorEdgeID() const
unsigned int numEdges() const
Real _crack_growth_increment
Definition XFEM.h:332
Real getPhysicalVolumeFraction(const Elem *elem) const
Get the volume fraction of an element that is physical.
Definition XFEM.C:1635
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
bool _use_crack_growth_increment
Definition XFEM.h:331
VectorValue< Real > RealVectorValue

Referenced by markCuts().

◆ markCutFacesByGeometry()

bool XFEM::markCutFacesByGeometry ( )

Definition at line 856 of file XFEM.C.

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}
bool isFacePhantom(unsigned int face_id) const
bool isThirdInteriorFace(unsigned int face_id) const
void addFragFaceIntersection(unsigned int ElemID, unsigned int FragFaceID, const std::vector< unsigned int > &FragFaceEdgeID, const std::vector< double > &position)
void addElemFaceIntersection(unsigned int elemid, unsigned int faceid, const std::vector< unsigned int > &edgeid, const std::vector< double > &position)
EFAElement3D * getEFAElem3D(const Elem *elem)
Get the EFAElement3D object for a specified libMesh element.
Definition XFEM.C:1765

Referenced by markCuts().

◆ markCutFacesByState()

bool XFEM::markCutFacesByState ( )

Definition at line 897 of file XFEM.C.

898{
899 bool marked_faces = false;
900 // TODO: need to finish this for 3D problems
901 return marked_faces;
902}

Referenced by markCuts().

◆ markCuts()

bool XFEM::markCuts ( Real  time)

Definition at line 382 of file XFEM.C.

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}
bool markCutFacesByState()
Definition XFEM.C:897
bool markCutFacesByGeometry()
Definition XFEM.C:856
bool markCutEdgesByGeometry()
Definition XFEM.C:399
bool markCutEdgesByState(Real time)
Definition XFEM.C:592

Referenced by update().

◆ pickFirstPhysicalNode()

const Node * XFEM::pickFirstPhysicalNode ( const Elem *  e,
const Elem *  e0 
) const
private

Return the first node in the provided element that is found to be in the physical domain.

Parameters
eConstant pointer to the child element
e0Constant pointer to the parent element whose nodes will be querried
Returns
A constant pointer to the node

Definition at line 2309 of file XFEM.C.

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}
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

Referenced by getCutSubdomainID().

◆ setCrackGrowthMethod()

void XFEM::setCrackGrowthMethod ( bool  use_crack_growth_increment,
Real  crack_growth_increment 
)

Definition at line 1837 of file XFEM.C.

1838{
1839 _use_crack_growth_increment = use_crack_growth_increment;
1840 _crack_growth_increment = crack_growth_increment;
1841}

◆ setDebugOutputLevel()

void XFEM::setDebugOutputLevel ( unsigned int  debug_output_level)

Controls amount of debugging information output.

Parameters
debug_output_levelHow much information to output (see description of _debug_output_level)

Definition at line 1844 of file XFEM.C.

1845{
1846 _debug_output_level = debug_output_level;
1847}

◆ setMinWeightMultiplier()

void XFEM::setMinWeightMultiplier ( Real  min_weight_multiplier)

Controls the minimum average weight multiplier for each element.

Parameters
min_weight_multiplierThe minimum average weight multiplier applied by XFEM to the standard quadrature weights

Definition at line 1850 of file XFEM.C.

1851{
1852 _min_weight_multiplier = min_weight_multiplier;
1853}

◆ setSolution()

void XFEM::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 
)
private

Set the solution for all locally-owned nodes/elements that have stored values.

Parameters
sysSystem for which the solution is set
stored_solutionData structure that the stored solution is obtained from
current_solutionCurrent solution vector that will be set
old_solutionOld solution vector that will be set
older_solutionOlder solution vector that will be set

Definition at line 2061 of file XFEM.C.

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}
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
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
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
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)

Referenced by initSolution().

◆ setSolutionForDOFs()

void XFEM::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 
)
private

Set the solution for a set of DOFs.

Parameters
stored_solutionStored solution values to set the solution to
stored_solution_dofsDof indices for the entries in stored_solution
current_solutionCurrent solution vector that will be set
old_solutionOld solution vector that will be set
older_solutionOlder solution vector that will be set

Definition at line 2099 of file XFEM.C.

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}
virtual bool isTransient() const override
virtual void set(const numeric_index_type i, const T value)=0

Referenced by setSolution().

◆ setXFEMQRule()

void XFEM::setXFEMQRule ( std::string &  xfem_qrule)

Definition at line 1826 of file XFEM.C.

1827{
1828 if (xfem_qrule == "volfrac")
1830 else if (xfem_qrule == "moment_fitting")
1832 else if (xfem_qrule == "direct")
1834}
@ DIRECT
Definition XFEM.h:41
@ VOLFRAC
Definition XFEM.h:39
@ MOMENT_FITTING
Definition XFEM.h:40

◆ storeCrackTipOriginAndDirection()

void XFEM::storeCrackTipOriginAndDirection ( )

Definition at line 187 of file XFEM.C.

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}
unsigned int getCrackTipSplitElementID() const
unsigned int id() const
Definition EFANode.C:36
virtual void getCrackTipOriginAndDirection(unsigned tip_id, Point &origin, Point &direction) const =0

Referenced by update().

◆ storeMaterialPropertiesForElement()

void XFEM::storeMaterialPropertiesForElement ( const Elem *  parent_elem,
const Elem *  child_elem 
)
private

Helper function to store the material properties of a healed element.

Parameters
parent_elemThe parent element
elem1The first child element
elem2The second child element

Definition at line 2210 of file XFEM.C.

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)
2227 if (_fe_problem->needBoundaryMaterialOnSide(bdid, 0))
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}
void storeMaterialPropertiesForElementHelper(const Elem *elem, MaterialPropertyStorage &storage)
Definition XFEM.C:2192

Referenced by healMesh().

◆ storeMaterialPropertiesForElementHelper()

void XFEM::storeMaterialPropertiesForElementHelper ( const Elem *  elem,
MaterialPropertyStorage storage 
)
private

Definition at line 2192 of file XFEM.C.

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}
void dataStore(std::ostream &stream, LineSegment &l, void *context)
const PropsType & props(const unsigned int state=0) const

Referenced by storeMaterialPropertiesForElement().

◆ storeSolutionForElement()

void XFEM::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 
)
private

Store the solution in stored_solution for a given element.

Parameters
elem_to_store_toElement for which the solution will be stored
elem_to_store_fromElement from which the solution to be stored is obtained
sysSystem from which the solution is stored
stored_solutionData structure that the stored solution is saved to
current_solutionCurrent solution vector that the solution is obtained from
old_solutionOld solution vector that the solution is obtained from
older_solutionOlder solution vector that the solution is obtained from

Definition at line 2027 of file XFEM.C.

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}

Referenced by cutMeshWithEFA().

◆ storeSolutionForNode()

void XFEM::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 
)
private

Store the solution in stored_solution for a given node.

Parameters
node_to_store_toNode for which the solution will be stored
node_to_store_fromNode from which the solution to be stored is obtained
sysSystem from which the solution is stored
stored_solutionData structure that the stored solution is saved to
current_solutionCurrent solution vector that the solution is obtained from
old_solutionOld solution vector that the solution is obtained from
older_solutionOlder solution vector that the solution is obtained from

Definition at line 1993 of file XFEM.C.

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}

Referenced by cutMeshWithEFA().

◆ update()

bool XFEM::update ( Real  time,
const std::vector< std::shared_ptr< NonlinearSystemBase > > &  nl,
AuxiliarySystem aux 
)
overridevirtual

Implements XFEMInterface.

Definition at line 263 of file XFEM.C.

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}
const ExecFlagType EXEC_XFEM_MARK
Exec flag used to execute MooseObjects while elements are being marked for cutting by XFEM.
virtual void execute(const ExecFlagType &exec_type)
virtual bool isDistributedMesh() const
void storeCrackTipOriginAndDirection()
Definition XFEM.C:187
bool cutMeshWithEFA(const std::vector< std::shared_ptr< NonlinearSystemBase > > &nl, AuxiliarySystem &aux)
Definition XFEM.C:1108
bool markCuts(Real time)
Definition XFEM.C:382
void clearGeomMarkedElems()
Clear out the list of elements to be marked for cutting.
Definition XFEM.C:180
void buildEFAMesh()
Definition XFEM.C:343
void clearStateMarkedElems()
Definition XFEM.C:152

◆ updateHeal()

bool XFEM::updateHeal ( )
overridevirtual

Implements XFEMInterface.

Definition at line 226 of file XFEM.C.

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}
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

Member Data Documentation

◆ _cached_aux_solution

std::map<unique_id_type, std::vector<Real> > XFEM::_cached_aux_solution
private

Data structure to store the auxiliary solution for nodes/elements affected by XFEM For each node/element, this is stored as a vector that contains all components of all applicable variables in an order defined by getElementSolutionDofs() or getNodeSolutionDofs().

This vector first contains the current solution in that order, followed by the old and older solutions, also in that same order.

Definition at line 391 of file XFEM.h.

Referenced by cutMeshWithEFA(), and initSolution().

◆ _cached_solution

std::map<unique_id_type, std::vector<Real> > XFEM::_cached_solution
private

Data structure to store the nonlinear solution for nodes/elements affected by XFEM For each node/element, this is stored as a vector that contains all components of all applicable variables in an order defined by getElementSolutionDofs() or getNodeSolutionDofs().

This vector first contains the current solution in that order, followed by the old and older solutions, also in that same order.

Definition at line 382 of file XFEM.h.

Referenced by cutMeshWithEFA(), and initSolution().

◆ _crack_growth_increment

Real XFEM::_crack_growth_increment
private

Definition at line 332 of file XFEM.h.

Referenced by markCutEdgesByState(), and setCrackGrowthMethod().

◆ _crack_tip_elems

std::set<const Elem *> XFEM::_crack_tip_elems
private

Definition at line 337 of file XFEM.h.

Referenced by cutMeshWithEFA(), healMesh(), and isElemAtCrackTip().

◆ _crack_tip_elems_to_be_healed

std::set<const Elem *> XFEM::_crack_tip_elems_to_be_healed
private

Definition at line 338 of file XFEM.h.

Referenced by cutMeshWithEFA(), and healMesh().

◆ _cut_elem_map

std::map<unique_id_type, XFEMCutElem *> XFEM::_cut_elem_map
private

◆ _debug_output_level

unsigned int XFEM::_debug_output_level
private

Controls amount of debugging output information 0: None 1: Summary 2: Details on modifications to mesh 3: Full dump of element fragment algorithm mesh.

Definition at line 369 of file XFEM.h.

Referenced by cutMeshWithEFA(), healMesh(), and setDebugOutputLevel().

◆ _efa_mesh

ElementFragmentAlgorithm XFEM::_efa_mesh
private

◆ _elem_crack_origin_direction_map

std::map<const Elem *, std::vector<Point> > XFEM::_elem_crack_origin_direction_map
private

◆ _geom_cut_elems

std::unordered_map<const Elem *, Xfem::CutElemInfo> XFEM::_geom_cut_elems
private

All geometrically cut elements and their CutElemInfo during the current execution of XFEM_MARK.

This data structure is updated everytime a new cut element is created.

Definition at line 397 of file XFEM.h.

Referenced by cutMeshWithEFA(), healMesh(), storeMaterialPropertiesForElement(), and storeMaterialPropertiesForElementHelper().

◆ _geom_marked_elems_2d

std::map<const Elem *, std::vector<Xfem::GeomMarkedElemInfo2D> > XFEM::_geom_marked_elems_2d
private

Data structure for storing information about all 2D elements to be cut by geometry.

Definition at line 351 of file XFEM.h.

Referenced by addGeomMarkedElem2D(), clearGeomMarkedElems(), and markCutEdgesByGeometry().

◆ _geom_marked_elems_3d

std::map<const Elem *, std::vector<Xfem::GeomMarkedElemInfo3D> > XFEM::_geom_marked_elems_3d
private

Data structure for storing information about all 3D elements to be cut by geometry.

Definition at line 354 of file XFEM.h.

Referenced by addGeomMarkedElem3D(), clearGeomMarkedElems(), and markCutFacesByGeometry().

◆ _geom_marker_id_elems

std::map<unsigned int, std::set<unsigned int> > XFEM::_geom_marker_id_elems
private

Data structure for storing the elements cut by specific geometric cutters.

Definition at line 357 of file XFEM.h.

Referenced by addGeomMarkedElem2D(), addGeomMarkedElem3D(), cutMeshWithEFA(), getGeometricCutForElem(), and updateHeal().

◆ _geom_marker_id_map

std::map<const GeometricCutUserObject *, unsigned int> XFEM::_geom_marker_id_map
private

Data structure for storing the GeommetricCutUserObjects and their corresponding id.

Definition at line 360 of file XFEM.h.

Referenced by addGeometricCut(), and getGeometricCutID().

◆ _geometric_cuts

std::vector<const GeometricCutUserObject *> XFEM::_geometric_cuts
private

Definition at line 334 of file XFEM.h.

Referenced by addGeometricCut(), cutMeshWithEFA(), getGeometricCutForElem(), and healMesh().

◆ _has_secondary_cut

bool XFEM::_has_secondary_cut
private

Definition at line 327 of file XFEM.h.

Referenced by has_secondary_cut(), markCutEdgesByGeometry(), markCutEdgesByState(), and XFEM().

◆ _min_weight_multiplier

Real XFEM::_min_weight_multiplier
private

The minimum average multiplier applied by XFEM to the standard quadrature weights to integrate partial elements.

Definition at line 373 of file XFEM.h.

Referenced by getXFEMWeights(), and setMinWeightMultiplier().

◆ _old_geom_cut_elems

std::unordered_map<const Elem *, Xfem::CutElemInfo> XFEM::_old_geom_cut_elems
private

All geometrically cut elements and their CutElemInfo before the current execution of XFEM_MARK.

Definition at line 403 of file XFEM.h.

Referenced by cutMeshWithEFA().

◆ _sibling_displaced_elems

std::map<unsigned int, ElementPairLocator::ElementPairList> XFEM::_sibling_displaced_elems
private

Definition at line 340 of file XFEM.h.

Referenced by cutMeshWithEFA(), getXFEMDisplacedCutElemPairs(), and healMesh().

◆ _sibling_elems

std::map<unsigned int, ElementPairLocator::ElementPairList> XFEM::_sibling_elems
private

Definition at line 339 of file XFEM.h.

Referenced by cutMeshWithEFA(), getXFEMCutElemPairs(), and healMesh().

◆ _state_marked_elem_sides

std::map<const Elem *, unsigned int> XFEM::_state_marked_elem_sides
private

Definition at line 348 of file XFEM.h.

Referenced by addStateMarkedElem(), clearStateMarkedElems(), and markCutEdgesByState().

◆ _state_marked_elems

std::map<const Elem *, RealVectorValue> XFEM::_state_marked_elems
private

Definition at line 346 of file XFEM.h.

Referenced by addStateMarkedElem(), clearStateMarkedElems(), and markCutEdgesByState().

◆ _state_marked_frags

std::set<const Elem *> XFEM::_state_marked_frags
private

Definition at line 347 of file XFEM.h.

Referenced by addStateMarkedFrag(), clearStateMarkedElems(), and markCutEdgesByState().

◆ _use_crack_growth_increment

bool XFEM::_use_crack_growth_increment
private

Definition at line 331 of file XFEM.h.

Referenced by markCutEdgesByState(), and setCrackGrowthMethod().

◆ _XFEM_qrule

Xfem::XFEM_QRULE XFEM::_XFEM_qrule
private

Definition at line 329 of file XFEM.h.

Referenced by getXFEMQRule(), and setXFEMQRule().


The documentation for this class was generated from the following files: