LCOV - code coverage report
Current view: top level - src/userobjects - MeshCut2DUserObjectBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31782 (60f35e) with base ee0740 Lines: 186 206 90.3 %
Date: 2025-10-31 18:33:45 Functions: 12 14 85.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          83 : MeshCut2DUserObjectBase::validParams()
      23             : {
      24          83 :   InputParameters params = MeshCutUserObjectBase::validParams();
      25         166 :   params.addParam<UserObjectName>("nucleate_uo", "The MeshCutNucleation UO for nucleating cracks.");
      26         166 :   params.addParam<UserObjectName>("crack_front_definition",
      27             :                                   "crackFrontDefinition",
      28             :                                   "The CrackFrontDefinition user object name");
      29          83 :   params.addClassDescription("Creates a UserObject base class for a mesh cutter in 2D problems");
      30          83 :   return params;
      31           0 : }
      32             : 
      33          42 : MeshCut2DUserObjectBase::MeshCut2DUserObjectBase(const InputParameters & parameters)
      34             :   : MeshCutUserObjectBase(parameters),
      35          84 :     _mesh(_subproblem.mesh()),
      36          42 :     _nucleate_uo(isParamValid("nucleate_uo")
      37          59 :                      ? &getUserObject<MeshCut2DNucleationBase>("nucleate_uo")
      38             :                      : nullptr),
      39          84 :     _is_mesh_modified(false)
      40             : {
      41         126 :   _depend_uo.insert(getParam<UserObjectName>("crack_front_definition"));
      42             : 
      43             :   // test element type; only line elements are allowed
      44         286 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
      45             :   {
      46         101 :     if (cut_elem->n_nodes() != 2)
      47           0 :       mooseError("The input cut mesh should include EDGE2 elements only!");
      48         101 :     if (cut_elem->dim() != 1)
      49           0 :       mooseError("The input cut mesh should have 1D elements (in a 2D space) only!");
      50          42 :   }
      51             : 
      52             :   // find node fronts of the original cutmesh.  This is used to order EVERYTHING.
      53          42 :   findOriginalCrackFrontNodes();
      54          42 : }
      55             : 
      56             : void
      57          41 : MeshCut2DUserObjectBase::initialSetup()
      58             : {
      59          41 :   const auto uo_name = getParam<UserObjectName>("crack_front_definition");
      60          41 :   _crack_front_definition = &_fe_problem.getUserObject<CrackFrontDefinition>(uo_name);
      61          41 : }
      62             : 
      63             : bool
      64      265843 : 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     3649618 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
      75             :   {
      76     1558966 :     unsigned int n_sides = elem->n_sides();
      77             : 
      78     7794830 :     for (unsigned int i = 0; i < n_sides; ++i)
      79             :     {
      80     6235864 :       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     6235864 :       Real seg_int_frac = 0.0;
      87             : 
      88     6235864 :       const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
      89             : 
      90     6235864 :       if (Xfem::intersectSegmentWithCutLine(*node1, *node2, elem_endpoints, 1.0, seg_int_frac))
      91             :       {
      92       18536 :         if (seg_int_frac > Xfem::tol && seg_int_frac < 1.0 - Xfem::tol)
      93             :         {
      94             :           elem_cut = true;
      95             :           Xfem::CutEdge mycut;
      96       18536 :           mycut._id1 = node1->id();
      97       18536 :           mycut._id2 = node2->id();
      98       18536 :           mycut._distance = seg_int_frac;
      99       18536 :           mycut._host_side_id = i;
     100       18536 :           cut_edges.push_back(mycut);
     101       18536 :         }
     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     6235864 :     }
     112      265843 :   }
     113      265843 :   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        8883 : 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      246936 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
     131             :   {
     132      114585 :     const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
     133      114585 :     unsigned int n_sides = frag_edges.size();
     134      582070 :     for (unsigned int i = 0; i < n_sides; ++i)
     135             :     {
     136      467485 :       Real seg_int_frac = 0.0;
     137      467485 :       if (Xfem::intersectSegmentWithCutLine(
     138      467485 :               frag_edges[i][0], frag_edges[i][1], elem_endpoints, 1, seg_int_frac))
     139             :       {
     140             :         cut_frag = true;
     141             :         Xfem::CutEdge mycut;
     142       16386 :         mycut._id1 = i;
     143       16386 :         mycut._id2 = (i < (n_sides - 1) ? (i + 1) : 0);
     144       16386 :         mycut._distance = seg_int_frac;
     145       16386 :         mycut._host_side_id = i;
     146       16386 :         cut_edges.push_back(mycut);
     147             :       }
     148             :     }
     149        8883 :   }
     150        8883 :   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         229 : MeshCut2DUserObjectBase::getCrackFrontPoints(unsigned int number_crack_front_points) const
     163             : {
     164         229 :   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         229 :   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         913 :   for (unsigned int i = 0; i < number_crack_front_points; ++i)
     174             :   {
     175         684 :     dof_id_type id = _original_and_current_front_node_ids[i].second;
     176         684 :     Node * this_node = _cutter_mesh->node_ptr(id);
     177             :     mooseAssert(this_node, "Node is NULL");
     178             :     Point & this_point = *this_node;
     179         684 :     crack_front_points[i] = this_point;
     180             :   }
     181         229 :   return crack_front_points;
     182           0 : }
     183             : 
     184             : const std::vector<RealVectorValue>
     185         229 : MeshCut2DUserObjectBase::getCrackPlaneNormals(unsigned int number_crack_front_points) const
     186             : {
     187         229 :   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        4216 :   for (const auto & elem : _cutter_mesh->element_ptr_range())
     198             :   {
     199        1879 :     dof_id_type id0 = elem->node_id(0);
     200        1879 :     dof_id_type id1 = elem->node_id(1);
     201             :     dof_id_type id;
     202             : 
     203        1879 :     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        4508 :                             { return element.second == id0; });
     207        1879 :     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        4128 :                             { 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        1879 :     if (found_it0)
     218             :     {
     219             :       Point end_pt, connecting_pt;
     220             : 
     221         176 :       end_pt = elem->node_ref(0);
     222         176 :       connecting_pt = elem->node_ref(1);
     223         176 :       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         176 :       RealVectorValue normal_dir{fracture_dir(1), -fracture_dir(0), 0};
     230         176 :       normal_dir /= normal_dir.norm();
     231         176 :       crack_plane_normals.push_back(std::make_pair(id, normal_dir));
     232             :     }
     233             : 
     234        1879 :     if (found_it1)
     235             :     {
     236             :       Point end_pt, connecting_pt;
     237             : 
     238         508 :       end_pt = elem->node_ref(1);
     239         508 :       connecting_pt = elem->node_ref(0);
     240         508 :       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         508 :       RealVectorValue normal_dir{fracture_dir(1), -fracture_dir(0), 0};
     247         508 :       normal_dir /= normal_dir.norm();
     248         508 :       crack_plane_normals.push_back(std::make_pair(id, normal_dir));
     249             :     }
     250         229 :   }
     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         229 :   std::sort(crack_plane_normals.begin(), crack_plane_normals.end());
     261             :   std::vector<RealVectorValue> sorted_crack_plane_normals;
     262         913 :   for (auto & crack : crack_plane_normals)
     263         684 :     sorted_crack_plane_normals.push_back(crack.second);
     264             : 
     265         229 :   return sorted_crack_plane_normals;
     266         229 : }
     267             : 
     268             : void
     269          42 : MeshCut2DUserObjectBase::findOriginalCrackFrontNodes()
     270             : {
     271          42 :   std::unique_ptr<PointLocatorBase> pl = _mesh.getPointLocator();
     272          42 :   pl->enable_out_of_mesh_mode();
     273          42 :   std::unordered_set boundary_nodes = MeshTools::find_boundary_nodes(*_cutter_mesh);
     274         126 :   for (const auto & node : boundary_nodes)
     275             :   {
     276          84 :     auto node_id = node;
     277          84 :     Node * this_node = _cutter_mesh->node_ptr(node_id);
     278             :     mooseAssert(this_node, "Node is NULL");
     279          84 :     Point & this_point = *this_node;
     280             : 
     281          84 :     const Elem * elem = (*pl)(this_point);
     282          84 :     if (elem != NULL)
     283          50 :       _original_and_current_front_node_ids.push_back(std::make_pair(node, node));
     284             :   }
     285          42 :   std::sort(_original_and_current_front_node_ids.begin(),
     286             :             _original_and_current_front_node_ids.end());
     287          42 : }
     288             : 
     289             : void
     290         342 : MeshCut2DUserObjectBase::growFront()
     291             : {
     292             :   dof_id_type current_front_node_id;
     293        1256 :   for (std::size_t i = 0; i < _original_and_current_front_node_ids.size(); ++i)
     294             :   {
     295         914 :     current_front_node_id = _original_and_current_front_node_ids[i].second;
     296             :     // check if node front node id is active
     297             :     auto direction_iter =
     298         914 :         std::find_if(_active_front_node_growth_vectors.begin(),
     299             :                      _active_front_node_growth_vectors.end(),
     300             :                      [&current_front_node_id](const std::pair<dof_id_type, Point> & element)
     301         456 :                      { return element.first == current_front_node_id; });
     302             :     // only add an element for active node front ids
     303         914 :     if (direction_iter != _active_front_node_growth_vectors.end())
     304             :     {
     305         236 :       Node * this_node = _cutter_mesh->node_ptr(current_front_node_id);
     306             :       mooseAssert(this_node, "Node is NULL");
     307             :       Point & this_point = *this_node;
     308             : 
     309         236 :       Point new_node_offset = direction_iter->second;
     310             :       Point x = this_point + new_node_offset;
     311             : 
     312             :       // TODO:  Should check if cut line segment created between "this_point" and "x" crosses
     313             :       // another line element in the cutter mesh or solid mesh boundary.
     314             :       // Crossing another line element would be a special case that still needs to be handled,
     315             :       // however, it doesnot cause an error, it will just ignore the other line segment and recut
     316             :       // the solid mesh element.
     317             :       // Crossing a solid mesh boundary would be for aesthetics reasons so
     318             :       // that element was trimmed close to the boundary but would have not effect on the simulation.
     319             :       // Crossing a solid mesh boundary should be handled by something like
     320             :       // MeshCut2DRankTwoTensorNucleation::lineLineIntersect2D
     321             : 
     322             :       // add node to front
     323         472 :       this_node = Node::build(x, _cutter_mesh->n_nodes()).release();
     324         236 :       _cutter_mesh->add_node(this_node);
     325         236 :       dof_id_type new_front_node_id = _cutter_mesh->n_nodes() - 1;
     326             : 
     327             :       // add element to front
     328             :       std::vector<dof_id_type> elem;
     329         236 :       elem.push_back(current_front_node_id);
     330         236 :       elem.push_back(new_front_node_id);
     331         236 :       Elem * new_elem = Elem::build(EDGE2).release();
     332         708 :       for (unsigned int i = 0; i < new_elem->n_nodes(); ++i)
     333             :       {
     334             :         mooseAssert(_cutter_mesh->node_ptr(elem[i]) != nullptr, "Node is NULL");
     335         472 :         new_elem->set_node(i, _cutter_mesh->node_ptr(elem[i]));
     336             :       }
     337         236 :       _cutter_mesh->add_elem(new_elem);
     338             :       // now push to the end of _original_and_current_front_node_ids for tracking and fracture
     339             :       // integrals
     340         236 :       _original_and_current_front_node_ids[i].second = new_front_node_id;
     341         236 :       _is_mesh_modified = true;
     342         236 :     }
     343             :   }
     344         342 :   _cutter_mesh->prepare_for_use();
     345         342 : }
     346             : 
     347             : void
     348         342 : MeshCut2DUserObjectBase::addNucleatedCracksToMesh()
     349             : {
     350         342 :   if (_nucleate_uo)
     351             :   {
     352             :     std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> nucleated_elems_map =
     353             :         _nucleate_uo->getNucleatedElemsMap();
     354         180 :     const Real nucleationRadius = _nucleate_uo->getNucleationRadius();
     355             : 
     356         180 :     removeNucleatedCracksTooCloseToEachOther(nucleated_elems_map, nucleationRadius);
     357         180 :     removeNucleatedCracksTooCloseToExistingCracks(nucleated_elems_map, nucleationRadius);
     358             : 
     359         180 :     std::unique_ptr<PointLocatorBase> pl = _mesh.getPointLocator();
     360         180 :     pl->enable_out_of_mesh_mode();
     361         252 :     for (const auto & elem_nodes : nucleated_elems_map)
     362             :     {
     363          72 :       std::pair<RealVectorValue, RealVectorValue> nodes = elem_nodes.second;
     364             :       // add nodes for the elements that define the nucleated cracks
     365         144 :       Node * node_0 = Node::build(nodes.first, _cutter_mesh->n_nodes()).release();
     366          72 :       _cutter_mesh->add_node(node_0);
     367          72 :       dof_id_type node_id_0 = _cutter_mesh->n_nodes() - 1;
     368         144 :       Node * node_1 = Node::build(nodes.second, _cutter_mesh->n_nodes()).release();
     369          72 :       _cutter_mesh->add_node(node_1);
     370          72 :       dof_id_type node_id_1 = _cutter_mesh->n_nodes() - 1;
     371             :       // add elements that define nucleated cracks
     372             :       std::vector<dof_id_type> elem;
     373          72 :       elem.push_back(node_id_0);
     374          72 :       elem.push_back(node_id_1);
     375          72 :       Elem * new_elem = Elem::build(EDGE2).release();
     376         216 :       for (unsigned int i = 0; i < new_elem->n_nodes(); ++i)
     377             :       {
     378             :         mooseAssert(_cutter_mesh->node_ptr(elem[i]) != nullptr, "Node is NULL");
     379         144 :         new_elem->set_node(i, _cutter_mesh->node_ptr(elem[i]));
     380             :       }
     381          72 :       _cutter_mesh->add_elem(new_elem);
     382             :       // now add the nucleated nodes to the crack id data struct
     383             :       // edge nucleated cracks will add one node to _original_and_current_front_node_ids
     384             :       // bulk nucleated cracks will add two nodes to _original_and_current_front_node_ids
     385          72 :       Point & point_0 = *node_0;
     386          72 :       const Elem * crack_front_elem_0 = (*pl)(point_0);
     387          72 :       if (crack_front_elem_0 != NULL)
     388          36 :         _original_and_current_front_node_ids.push_back(std::make_pair(node_id_0, node_id_0));
     389             : 
     390          72 :       Point & point_1 = *node_1;
     391          72 :       const Elem * crack_front_elem_1 = (*pl)(point_1);
     392          72 :       if (crack_front_elem_1 != NULL)
     393          60 :         _original_and_current_front_node_ids.push_back(std::make_pair(node_id_1, node_id_1));
     394             : 
     395          72 :       _is_mesh_modified = true;
     396          72 :     }
     397         180 :     _cutter_mesh->prepare_for_use();
     398         180 :   }
     399         342 : }
     400             : 
     401             : void
     402         180 : MeshCut2DUserObjectBase::removeNucleatedCracksTooCloseToEachOther(
     403             :     std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
     404             :     const Real nucleationRadius)
     405             : {
     406             :   // remove nucleated elements that are too close too each other.  Lowest key wins
     407         710 :   for (auto it1 = nucleated_elems_map.begin(); it1 != nucleated_elems_map.end(); ++it1)
     408             :   {
     409         530 :     std::pair<RealVectorValue, RealVectorValue> nodes = it1->second;
     410             :     Point p2 = nodes.first;
     411             :     Point p1 = nodes.second;
     412             :     Point p = p1 + (p2 - p1) / 2;
     413        4608 :     for (auto it2 = nucleated_elems_map.begin(); it2 != nucleated_elems_map.end();)
     414             :     {
     415        4078 :       if (it1 == it2)
     416             :       {
     417             :         ++it2;
     418         530 :         continue;
     419             :       }
     420             : 
     421             :       nodes = it2->second;
     422             :       p2 = nodes.first;
     423             :       p1 = nodes.second;
     424             :       Point q = p1 + (p2 - p1) / 2;
     425             :       Point pq = q - p;
     426        3548 :       if (pq.norm() <= nucleationRadius)
     427         478 :         it2 = nucleated_elems_map.erase(it2);
     428             :       else
     429             :         ++it2;
     430             :     }
     431             :   }
     432         180 : }
     433             : 
     434             : void
     435         180 : MeshCut2DUserObjectBase::removeNucleatedCracksTooCloseToExistingCracks(
     436             :     std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
     437             :     const Real nucleationRadius)
     438             : {
     439         710 :   for (auto it = nucleated_elems_map.begin(); it != nucleated_elems_map.end();)
     440             :   {
     441         530 :     std::pair<RealVectorValue, RealVectorValue> nodes = it->second;
     442             :     Point p2 = nodes.first;
     443             :     Point p1 = nodes.second;
     444             :     Point p = p1 + (p2 - p1) / 2;
     445             :     bool removeNucleatedElem = false;
     446             :     for (const auto & cutter_elem :
     447        8312 :          as_range(_cutter_mesh->active_elements_begin(), _cutter_mesh->active_elements_end()))
     448             :     {
     449        3819 :       const Node * const * cutter_elem_nodes = cutter_elem->get_nodes();
     450        3819 :       Point m = *cutter_elem_nodes[1] - *cutter_elem_nodes[0];
     451        3819 :       Real t = m * (p - *cutter_elem_nodes[0]) / m.norm_sq();
     452             :       Real d = std::numeric_limits<Real>::max();
     453        3819 :       if (t <= 0)
     454             :       {
     455             :         Point j = p - *cutter_elem_nodes[0];
     456        1610 :         d = j.norm();
     457             :       }
     458        2209 :       else if (t >= 0)
     459             :       {
     460             :         Point j = p - *cutter_elem_nodes[1];
     461        2209 :         d = j.norm();
     462             :       }
     463             :       else
     464             :       {
     465             :         Point j = p - (*cutter_elem_nodes[0] + t * m);
     466           0 :         d = j.norm();
     467             :       }
     468        3819 :       if (d <= nucleationRadius)
     469             :       {
     470             :         removeNucleatedElem = true;
     471             :         break;
     472             :       }
     473         530 :     }
     474         530 :     if (removeNucleatedElem)
     475         458 :       it = nucleated_elems_map.erase(it);
     476             :     else
     477             :       ++it;
     478             :   }
     479         180 : }

Generated by: LCOV version 1.14