LCOV - code coverage report
Current view: top level - src/userobjects - MeshCut2DUserObjectBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31730 (e8b711) with base e0c998 Lines: 202 223 90.6 %
Date: 2025-10-29 16:56:32 Functions: 13 15 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "MeshCut2DUserObjectBase.h"
      11             : #include "MeshCut2DNucleationBase.h"
      12             : #include "CrackFrontDefinition.h"
      13             : 
      14             : #include "XFEMFuncs.h"
      15             : #include "MooseError.h"
      16             : #include "MooseMesh.h"
      17             : #include "libmesh/edge_edge2.h"
      18             : #include "libmesh/serial_mesh.h"
      19             : #include "libmesh/mesh_tools.h"
      20             : 
      21             : InputParameters
      22          99 : MeshCut2DUserObjectBase::validParams()
      23             : {
      24          99 :   InputParameters params = MeshCutUserObjectBase::validParams();
      25         198 :   params.addParam<UserObjectName>("nucleate_uo", "The MeshCutNucleation UO for nucleating cracks.");
      26         198 :   params.addParam<UserObjectName>("crack_front_definition",
      27             :                                   "crackFrontDefinition",
      28             :                                   "The CrackFrontDefinition user object name");
      29          99 :   params.addClassDescription("Creates a UserObject base class for a mesh cutter in 2D problems");
      30          99 :   return params;
      31           0 : }
      32             : 
      33          50 : MeshCut2DUserObjectBase::MeshCut2DUserObjectBase(const InputParameters & parameters)
      34             :   : MeshCutUserObjectBase(parameters),
      35         100 :     _mesh(_subproblem.mesh()),
      36          50 :     _nucleate_uo(isParamValid("nucleate_uo")
      37          67 :                      ? &getUserObject<MeshCut2DNucleationBase>("nucleate_uo")
      38             :                      : nullptr),
      39         100 :     _is_mesh_modified(false)
      40             : {
      41         150 :   _depend_uo.insert(getParam<UserObjectName>("crack_front_definition"));
      42             : 
      43             :   // test element type; only line elements are allowed
      44         318 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
      45             :   {
      46         109 :     if (cut_elem->n_nodes() != 2)
      47           0 :       mooseError("The input cut mesh should include EDGE2 elements only!");
      48         109 :     if (cut_elem->dim() != 1)
      49           0 :       mooseError("The input cut mesh should have 1D elements (in a 2D space) only!");
      50          50 :   }
      51             : 
      52             :   // find node fronts of the original cutmesh.  This is used to order EVERYTHING.
      53          50 :   findOriginalCrackFrontNodes();
      54          50 : }
      55             : 
      56             : void
      57          49 : MeshCut2DUserObjectBase::initialSetup()
      58             : {
      59          49 :   const auto uo_name = getParam<UserObjectName>("crack_front_definition");
      60          49 :   _crack_front_definition = &_fe_problem.getUserObject<CrackFrontDefinition>(uo_name);
      61          49 : }
      62             : 
      63             : bool
      64      266083 : MeshCut2DUserObjectBase::cutElementByGeometry(const Elem * elem,
      65             :                                               std::vector<Xfem::CutEdge> & cut_edges,
      66             :                                               std::vector<Xfem::CutNode> & cut_nodes) const
      67             : {
      68             :   // With the crack defined by a line, this method cuts a 2D elements by a line
      69             :   // Fixme lynn Copy and paste from InterfaceMeshCut2DUserObject::cutElementByGeometry
      70             :   mooseAssert(elem->dim() == 2, "Dimension of element to be cut must be 2");
      71             : 
      72             :   bool elem_cut = false;
      73             : 
      74     3651334 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
      75             :   {
      76     1559584 :     unsigned int n_sides = elem->n_sides();
      77             : 
      78     7797920 :     for (unsigned int i = 0; i < n_sides; ++i)
      79             :     {
      80     6238336 :       std::unique_ptr<const Elem> curr_side = elem->side_ptr(i);
      81             : 
      82             :       mooseAssert(curr_side->type() == EDGE2, "Element side type must be EDGE2.");
      83             : 
      84             :       const Node * node1 = curr_side->node_ptr(0);
      85             :       const Node * node2 = curr_side->node_ptr(1);
      86     6238336 :       Real seg_int_frac = 0.0;
      87             : 
      88     6238336 :       const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
      89             : 
      90     6238336 :       if (Xfem::intersectSegmentWithCutLine(*node1, *node2, elem_endpoints, 1.0, seg_int_frac))
      91             :       {
      92       18680 :         if (seg_int_frac > Xfem::tol && seg_int_frac < 1.0 - Xfem::tol)
      93             :         {
      94             :           elem_cut = true;
      95             :           Xfem::CutEdge mycut;
      96       18680 :           mycut._id1 = node1->id();
      97       18680 :           mycut._id2 = node2->id();
      98       18680 :           mycut._distance = seg_int_frac;
      99       18680 :           mycut._host_side_id = i;
     100       18680 :           cut_edges.push_back(mycut);
     101       18680 :         }
     102           0 :         else if (seg_int_frac < Xfem::tol)
     103             :         {
     104             :           elem_cut = true;
     105             :           Xfem::CutNode mycut;
     106           0 :           mycut._id = node1->id();
     107           0 :           mycut._host_id = i;
     108           0 :           cut_nodes.push_back(mycut);
     109             :         }
     110             :       }
     111     6238336 :     }
     112      266083 :   }
     113      266083 :   return elem_cut;
     114             : }
     115             : 
     116             : bool
     117           0 : MeshCut2DUserObjectBase::cutElementByGeometry(const Elem * /*elem*/,
     118             :                                               std::vector<Xfem::CutFace> & /*cut_faces*/) const
     119             : {
     120           0 :   mooseError("Invalid method for 2D mesh cutting.");
     121             :   return false;
     122             : }
     123             : 
     124             : bool
     125        8949 : MeshCut2DUserObjectBase::cutFragmentByGeometry(std::vector<std::vector<Point>> & frag_edges,
     126             :                                                std::vector<Xfem::CutEdge> & cut_edges) const
     127             : {
     128             :   bool cut_frag = false;
     129             : 
     130      247488 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
     131             :   {
     132      114795 :     const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
     133      114795 :     unsigned int n_sides = frag_edges.size();
     134      583174 :     for (unsigned int i = 0; i < n_sides; ++i)
     135             :     {
     136      468379 :       Real seg_int_frac = 0.0;
     137      468379 :       if (Xfem::intersectSegmentWithCutLine(
     138      468379 :               frag_edges[i][0], frag_edges[i][1], elem_endpoints, 1, seg_int_frac))
     139             :       {
     140             :         cut_frag = true;
     141             :         Xfem::CutEdge mycut;
     142       16494 :         mycut._id1 = i;
     143       16494 :         mycut._id2 = (i < (n_sides - 1) ? (i + 1) : 0);
     144       16494 :         mycut._distance = seg_int_frac;
     145       16494 :         mycut._host_side_id = i;
     146       16494 :         cut_edges.push_back(mycut);
     147             :       }
     148             :     }
     149        8949 :   }
     150        8949 :   return cut_frag;
     151             : }
     152             : 
     153             : bool
     154           0 : MeshCut2DUserObjectBase::cutFragmentByGeometry(std::vector<std::vector<Point>> & /*frag_faces*/,
     155             :                                                std::vector<Xfem::CutFace> & /*cut_faces*/) const
     156             : {
     157           0 :   mooseError("Invalid method for 2D mesh fragment cutting.");
     158             :   return false;
     159             : }
     160             : 
     161             : const std::vector<Point>
     162         457 : MeshCut2DUserObjectBase::getCrackFrontPoints(unsigned int number_crack_front_points) const
     163             : {
     164         457 :   std::vector<Point> crack_front_points(number_crack_front_points);
     165             :   // number_crack_front_points is updated via
     166             :   // _crack_front_definition->updateNumberOfCrackFrontPoints(_crack_front_points.size())
     167         457 :   if (number_crack_front_points != _original_and_current_front_node_ids.size())
     168           0 :     mooseError("Number of nodes in CrackFrontDefinition does not match the number of nodes in the "
     169           0 :                "cutter_mesh.\nCrackFrontDefinition nodes = " +
     170           0 :                Moose::stringify(number_crack_front_points) + "\ncutter_mesh nodes = " +
     171           0 :                Moose::stringify(_original_and_current_front_node_ids.size()));
     172             : 
     173        1769 :   for (unsigned int i = 0; i < number_crack_front_points; ++i)
     174             :   {
     175        1312 :     dof_id_type id = _original_and_current_front_node_ids[i].second;
     176        1312 :     Node * this_node = _cutter_mesh->node_ptr(id);
     177             :     mooseAssert(this_node, "Node is NULL");
     178             :     Point & this_point = *this_node;
     179        1312 :     crack_front_points[i] = this_point;
     180             :   }
     181         457 :   return crack_front_points;
     182           0 : }
     183             : 
     184             : const std::vector<RealVectorValue>
     185         457 : MeshCut2DUserObjectBase::getCrackPlaneNormals(unsigned int number_crack_front_points) const
     186             : {
     187         457 :   if (number_crack_front_points != _original_and_current_front_node_ids.size())
     188           0 :     mooseError("MeshCut2DFractureUserObject::getCrackPlaneNormals: number_crack_front_points=" +
     189           0 :                Moose::stringify(number_crack_front_points) +
     190             :                " does not match the number of nodes given in "
     191           0 :                "_original_and_current_front_node_ids=" +
     192             :                Moose::stringify(_original_and_current_front_node_ids.size()) +
     193             :                ".  This will happen if a crack front exits the boundary because the number of "
     194             :                "points in the CrackFrontDefinition is never updated.");
     195             : 
     196             :   std::vector<std::pair<dof_id_type, RealVectorValue>> crack_plane_normals;
     197        8248 :   for (const auto & elem : _cutter_mesh->element_ptr_range())
     198             :   {
     199        3667 :     dof_id_type id0 = elem->node_id(0);
     200        3667 :     dof_id_type id1 = elem->node_id(1);
     201             :     dof_id_type id;
     202             : 
     203        3667 :     auto it0 = std::find_if(_original_and_current_front_node_ids.begin(),
     204             :                             _original_and_current_front_node_ids.end(),
     205             :                             [&id0](const std::pair<dof_id_type, dof_id_type> & element)
     206        8816 :                             { return element.second == id0; });
     207        3667 :     auto it1 = std::find_if(_original_and_current_front_node_ids.begin(),
     208             :                             _original_and_current_front_node_ids.end(),
     209             :                             [&id1](const std::pair<dof_id_type, dof_id_type> & element)
     210        8040 :                             { return element.second == id1; });
     211             : 
     212             :     bool found_it0 = (it0 != _original_and_current_front_node_ids.end());
     213             :     bool found_it1 = (it1 != _original_and_current_front_node_ids.end());
     214             : 
     215             :     // Newly nucleated crack elements can have one normal if they are on the edge OR
     216             :     // two normals if they are in the bulk.
     217        3667 :     if (found_it0)
     218             :     {
     219             :       Point end_pt, connecting_pt;
     220             : 
     221         304 :       end_pt = elem->node_ref(0);
     222         304 :       connecting_pt = elem->node_ref(1);
     223         304 :       id = it0->first; // sort by original crack front node ids
     224             : 
     225             :       Point fracture_dir = end_pt - connecting_pt;
     226             :       // The crack normal is orthogonal to the crack extension direction (fracture_dir),
     227             :       // and is defined in this implementation as the cross product of the direction of crack
     228             :       // extension with the tangent direction, which is always (0, 0, 1) in 2D.
     229         304 :       RealVectorValue normal_dir{fracture_dir(1), -fracture_dir(0), 0};
     230         304 :       normal_dir /= normal_dir.norm();
     231         304 :       crack_plane_normals.push_back(std::make_pair(id, normal_dir));
     232             :     }
     233             : 
     234        3667 :     if (found_it1)
     235             :     {
     236             :       Point end_pt, connecting_pt;
     237             : 
     238        1008 :       end_pt = elem->node_ref(1);
     239        1008 :       connecting_pt = elem->node_ref(0);
     240        1008 :       id = it1->first; // sort by original crack front node ids
     241             : 
     242             :       Point fracture_dir = end_pt - connecting_pt;
     243             :       // The crack normal is orthogonal to the crack extension direction (fracture_dir),
     244             :       // and is defined in this implementation as the cross product of the direction of crack
     245             :       // extension with the tangent direction, which is always (0, 0, 1) in 2D.
     246        1008 :       RealVectorValue normal_dir{fracture_dir(1), -fracture_dir(0), 0};
     247        1008 :       normal_dir /= normal_dir.norm();
     248        1008 :       crack_plane_normals.push_back(std::make_pair(id, normal_dir));
     249             :     }
     250         457 :   }
     251             :   mooseAssert(
     252             :       _original_and_current_front_node_ids.size() == crack_plane_normals.size(),
     253             :       "Boundary nodes are attached to more than one element.  This should not happen for a 1D "
     254             :       "cutter mesh."
     255             :       "\n    Number of _original_and_current_front_node_ids=" +
     256             :           Moose::stringify(_original_and_current_front_node_ids.size()) +
     257             :           "\n    Number of crack_plane_normals=" + Moose::stringify(crack_plane_normals.size()));
     258             : 
     259             :   // the crack_plane_normals are now sorted by the ORIGINAL crack front ids
     260         457 :   std::sort(crack_plane_normals.begin(), crack_plane_normals.end());
     261             :   std::vector<RealVectorValue> sorted_crack_plane_normals;
     262        1769 :   for (auto & crack : crack_plane_normals)
     263        1312 :     sorted_crack_plane_normals.push_back(crack.second);
     264             : 
     265         457 :   return sorted_crack_plane_normals;
     266         457 : }
     267             : 
     268             : void
     269          50 : MeshCut2DUserObjectBase::findOriginalCrackFrontNodes()
     270             : {
     271          50 :   std::unique_ptr<PointLocatorBase> pl = _mesh.getPointLocator();
     272          50 :   pl->enable_out_of_mesh_mode();
     273          50 :   std::unordered_set boundary_nodes = MeshTools::find_boundary_nodes(*_cutter_mesh);
     274         150 :   for (const auto & node : boundary_nodes)
     275             :   {
     276         100 :     auto node_id = node;
     277         100 :     Node * this_node = _cutter_mesh->node_ptr(node_id);
     278             :     mooseAssert(this_node, "Node is NULL");
     279         100 :     Point & this_point = *this_node;
     280             : 
     281         100 :     bool is_on_bc = isPointOnEdgeBoundary(this_point);
     282             : 
     283         100 :     const Elem * elem = (*pl)(this_point);
     284         100 :     if (elem != NULL && !is_on_bc)
     285             :     {
     286          58 :       _original_and_current_front_node_ids.push_back(std::make_pair(node, node));
     287             :     }
     288             :   }
     289          50 :   std::sort(_original_and_current_front_node_ids.begin(),
     290             :             _original_and_current_front_node_ids.end());
     291          50 : }
     292             : 
     293             : bool
     294         100 : MeshCut2DUserObjectBase::isPointOnEdgeBoundary(const Point & point, Real tolerance)
     295             : {
     296       28876 :   for (const auto & bnd_elem : as_range(_mesh.bndElemsBegin(), _mesh.bndElemsEnd()))
     297             :   {
     298             :     // if (bnd_elem->_elem->processor_id() == processor_id())
     299             :     {
     300       14296 :       auto side = bnd_elem->_elem->side_ptr(bnd_elem->_side);
     301             : 
     302       14296 :       if (side->n_nodes() == 2)
     303             :       {
     304             :         // Create vectors for the endpoints of the edge
     305       14296 :         Point p1 = side->point(0);
     306       14296 :         Point p2 = side->point(1);
     307             : 
     308             :         // Compute the vector from p1 to p2 (edge vector) and from p1 to the point
     309             :         Point edge_vector = p2 - p1;
     310             :         Point point_vector = point - p1;
     311             : 
     312             :         // Compute the cross product magnitude to find if the point is collinear with the edge
     313       14296 :         Real cross_product_magnitude = std::sqrt(
     314       14296 :             std::pow(edge_vector(1) * point_vector(2) - edge_vector(2) * point_vector(1), 2) +
     315       14296 :             std::pow(edge_vector(2) * point_vector(0) - edge_vector(0) * point_vector(2), 2) +
     316       14296 :             std::pow(edge_vector(0) * point_vector(1) - edge_vector(1) * point_vector(0), 2));
     317             : 
     318             :         // Check if the point lies on the edge within a tolerance
     319       14296 :         if (cross_product_magnitude < tolerance)
     320             :         {
     321             :           // Check if the point lies within the edge segment bounds
     322             :           Real dot_product = point_vector * edge_vector;
     323             :           Real edge_length_squared = edge_vector * edge_vector;
     324             : 
     325          16 :           if (dot_product >= 0 && dot_product <= edge_length_squared)
     326             :             return true;
     327             :         }
     328             :       }
     329             :       else
     330           0 :         mooseError("MeshCut2DUserObjectBase currently only supports linear elements.\n");
     331       14296 :     }
     332         100 :   }
     333          92 :   return false;
     334             : }
     335             : 
     336             : void
     337         374 : MeshCut2DUserObjectBase::growFront()
     338             : {
     339             :   dof_id_type current_front_node_id;
     340        1320 :   for (std::size_t i = 0; i < _original_and_current_front_node_ids.size(); ++i)
     341             :   {
     342         946 :     current_front_node_id = _original_and_current_front_node_ids[i].second;
     343             :     // check if node front node id is active
     344             :     auto direction_iter =
     345         946 :         std::find_if(_active_front_node_growth_vectors.begin(),
     346             :                      _active_front_node_growth_vectors.end(),
     347             :                      [&current_front_node_id](const std::pair<dof_id_type, Point> & element)
     348         480 :                      { return element.first == current_front_node_id; });
     349             :     // only add an element for active node front ids
     350         946 :     if (direction_iter != _active_front_node_growth_vectors.end())
     351             :     {
     352         260 :       Node * this_node = _cutter_mesh->node_ptr(current_front_node_id);
     353             :       mooseAssert(this_node, "Node is NULL");
     354             :       Point & this_point = *this_node;
     355             : 
     356         260 :       Point new_node_offset = direction_iter->second;
     357             :       Point x = this_point + new_node_offset;
     358             : 
     359             :       // TODO:  Should check if cut line segment created between "this_point" and "x" crosses
     360             :       // another line element in the cutter mesh or solid mesh boundary.
     361             :       // Crossing another line element would be a special case that still needs to be handled,
     362             :       // however, it doesnot cause an error, it will just ignore the other line segment and recut
     363             :       // the solid mesh element.
     364             :       // Crossing a solid mesh boundary would be for aesthetics reasons so
     365             :       // that element was trimmed close to the boundary but would have not effect on the simulation.
     366             :       // Crossing a solid mesh boundary should be handled by something like
     367             :       // MeshCut2DRankTwoTensorNucleation::lineLineIntersect2D
     368             : 
     369             :       // add node to front
     370         520 :       this_node = Node::build(x, _cutter_mesh->n_nodes()).release();
     371         260 :       _cutter_mesh->add_node(this_node);
     372         260 :       dof_id_type new_front_node_id = _cutter_mesh->n_nodes() - 1;
     373             : 
     374             :       // add element to front
     375             :       std::vector<dof_id_type> elem;
     376         260 :       elem.push_back(current_front_node_id);
     377         260 :       elem.push_back(new_front_node_id);
     378         260 :       Elem * new_elem = Elem::build(EDGE2).release();
     379         780 :       for (unsigned int i = 0; i < new_elem->n_nodes(); ++i)
     380             :       {
     381             :         mooseAssert(_cutter_mesh->node_ptr(elem[i]) != nullptr, "Node is NULL");
     382         520 :         new_elem->set_node(i, _cutter_mesh->node_ptr(elem[i]));
     383             :       }
     384         260 :       _cutter_mesh->add_elem(new_elem);
     385             :       // now push to the end of _original_and_current_front_node_ids for tracking and fracture
     386             :       // integrals
     387         260 :       _original_and_current_front_node_ids[i].second = new_front_node_id;
     388         260 :       _is_mesh_modified = true;
     389         260 :     }
     390             :   }
     391         374 :   _cutter_mesh->prepare_for_use();
     392         374 : }
     393             : 
     394             : void
     395         374 : MeshCut2DUserObjectBase::addNucleatedCracksToMesh()
     396             : {
     397         374 :   if (_nucleate_uo)
     398             :   {
     399             :     std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> nucleated_elems_map =
     400             :         _nucleate_uo->getNucleatedElemsMap();
     401         180 :     const Real nucleationRadius = _nucleate_uo->getNucleationRadius();
     402             : 
     403         180 :     removeNucleatedCracksTooCloseToEachOther(nucleated_elems_map, nucleationRadius);
     404         180 :     removeNucleatedCracksTooCloseToExistingCracks(nucleated_elems_map, nucleationRadius);
     405             : 
     406         180 :     std::unique_ptr<PointLocatorBase> pl = _mesh.getPointLocator();
     407         180 :     pl->enable_out_of_mesh_mode();
     408         252 :     for (const auto & elem_nodes : nucleated_elems_map)
     409             :     {
     410          72 :       std::pair<RealVectorValue, RealVectorValue> nodes = elem_nodes.second;
     411             :       // add nodes for the elements that define the nucleated cracks
     412         144 :       Node * node_0 = Node::build(nodes.first, _cutter_mesh->n_nodes()).release();
     413          72 :       _cutter_mesh->add_node(node_0);
     414          72 :       dof_id_type node_id_0 = _cutter_mesh->n_nodes() - 1;
     415         144 :       Node * node_1 = Node::build(nodes.second, _cutter_mesh->n_nodes()).release();
     416          72 :       _cutter_mesh->add_node(node_1);
     417          72 :       dof_id_type node_id_1 = _cutter_mesh->n_nodes() - 1;
     418             :       // add elements that define nucleated cracks
     419             :       std::vector<dof_id_type> elem;
     420          72 :       elem.push_back(node_id_0);
     421          72 :       elem.push_back(node_id_1);
     422          72 :       Elem * new_elem = Elem::build(EDGE2).release();
     423         216 :       for (unsigned int i = 0; i < new_elem->n_nodes(); ++i)
     424             :       {
     425             :         mooseAssert(_cutter_mesh->node_ptr(elem[i]) != nullptr, "Node is NULL");
     426         144 :         new_elem->set_node(i, _cutter_mesh->node_ptr(elem[i]));
     427             :       }
     428          72 :       _cutter_mesh->add_elem(new_elem);
     429             :       // now add the nucleated nodes to the crack id data struct
     430             :       // edge nucleated cracks will add one node to _original_and_current_front_node_ids
     431             :       // bulk nucleated cracks will add two nodes to _original_and_current_front_node_ids
     432          72 :       Point & point_0 = *node_0;
     433          72 :       const Elem * crack_front_elem_0 = (*pl)(point_0);
     434          72 :       if (crack_front_elem_0 != NULL)
     435          36 :         _original_and_current_front_node_ids.push_back(std::make_pair(node_id_0, node_id_0));
     436             : 
     437          72 :       Point & point_1 = *node_1;
     438          72 :       const Elem * crack_front_elem_1 = (*pl)(point_1);
     439          72 :       if (crack_front_elem_1 != NULL)
     440          60 :         _original_and_current_front_node_ids.push_back(std::make_pair(node_id_1, node_id_1));
     441             : 
     442          72 :       _is_mesh_modified = true;
     443          72 :     }
     444         180 :     _cutter_mesh->prepare_for_use();
     445         180 :   }
     446         374 : }
     447             : 
     448             : void
     449         180 : MeshCut2DUserObjectBase::removeNucleatedCracksTooCloseToEachOther(
     450             :     std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
     451             :     const Real nucleationRadius)
     452             : {
     453             :   // remove nucleated elements that are too close too each other.  Lowest key wins
     454         710 :   for (auto it1 = nucleated_elems_map.begin(); it1 != nucleated_elems_map.end(); ++it1)
     455             :   {
     456         530 :     std::pair<RealVectorValue, RealVectorValue> nodes = it1->second;
     457             :     Point p2 = nodes.first;
     458             :     Point p1 = nodes.second;
     459             :     Point p = p1 + (p2 - p1) / 2;
     460        4608 :     for (auto it2 = nucleated_elems_map.begin(); it2 != nucleated_elems_map.end();)
     461             :     {
     462        4078 :       if (it1 == it2)
     463             :       {
     464             :         ++it2;
     465         530 :         continue;
     466             :       }
     467             : 
     468             :       nodes = it2->second;
     469             :       p2 = nodes.first;
     470             :       p1 = nodes.second;
     471             :       Point q = p1 + (p2 - p1) / 2;
     472             :       Point pq = q - p;
     473        3548 :       if (pq.norm() <= nucleationRadius)
     474         478 :         it2 = nucleated_elems_map.erase(it2);
     475             :       else
     476             :         ++it2;
     477             :     }
     478             :   }
     479         180 : }
     480             : 
     481             : void
     482         180 : MeshCut2DUserObjectBase::removeNucleatedCracksTooCloseToExistingCracks(
     483             :     std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
     484             :     const Real nucleationRadius)
     485             : {
     486         710 :   for (auto it = nucleated_elems_map.begin(); it != nucleated_elems_map.end();)
     487             :   {
     488         530 :     std::pair<RealVectorValue, RealVectorValue> nodes = it->second;
     489             :     Point p2 = nodes.first;
     490             :     Point p1 = nodes.second;
     491             :     Point p = p1 + (p2 - p1) / 2;
     492             :     bool removeNucleatedElem = false;
     493             :     for (const auto & cutter_elem :
     494        8312 :          as_range(_cutter_mesh->active_elements_begin(), _cutter_mesh->active_elements_end()))
     495             :     {
     496        3819 :       const Node * const * cutter_elem_nodes = cutter_elem->get_nodes();
     497        3819 :       Point m = *cutter_elem_nodes[1] - *cutter_elem_nodes[0];
     498        3819 :       Real t = m * (p - *cutter_elem_nodes[0]) / m.norm_sq();
     499             :       Real d = std::numeric_limits<Real>::max();
     500        3819 :       if (t <= 0)
     501             :       {
     502             :         Point j = p - *cutter_elem_nodes[0];
     503        1610 :         d = j.norm();
     504             :       }
     505        2209 :       else if (t >= 0)
     506             :       {
     507             :         Point j = p - *cutter_elem_nodes[1];
     508        2209 :         d = j.norm();
     509             :       }
     510             :       else
     511             :       {
     512             :         Point j = p - (*cutter_elem_nodes[0] + t * m);
     513           0 :         d = j.norm();
     514             :       }
     515        3819 :       if (d <= nucleationRadius)
     516             :       {
     517             :         removeNucleatedElem = true;
     518             :         break;
     519             :       }
     520         530 :     }
     521         530 :     if (removeNucleatedElem)
     522         458 :       it = nucleated_elems_map.erase(it);
     523             :     else
     524             :       ++it;
     525             :   }
     526         180 : }

Generated by: LCOV version 1.14