LCOV - code coverage report
Current view: top level - src/efa - EFAFragment2D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #32971 (54bef8) with base c6cf66 Lines: 152 176 86.4 %
Date: 2026-05-29 20:41:31 Functions: 18 21 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 "EFAElement2D.h"
      11             : 
      12             : #include "EFANode.h"
      13             : #include "EFAEdge.h"
      14             : #include "EFAFace.h"
      15             : #include "EFAFragment2D.h"
      16             : 
      17             : #include "EFAFaceNode.h"
      18             : #include "EFAFuncs.h"
      19             : #include "EFAError.h"
      20             : 
      21      552979 : EFAFragment2D::EFAFragment2D(EFAElement2D * host,
      22             :                              bool create_boundary_edges,
      23             :                              const EFAElement2D * from_host,
      24      552979 :                              unsigned int frag_id)
      25      552979 :   : EFAFragment(), _host_elem(host)
      26             : {
      27      552979 :   if (create_boundary_edges)
      28             :   {
      29      528843 :     if (!from_host)
      30           0 :       EFAError("EFAfragment2D constructor must have a from_host to copy from");
      31      528843 :     if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself
      32             :     {
      33     2341967 :       for (unsigned int i = 0; i < from_host->numEdges(); ++i)
      34     1871348 :         _boundary_edges.push_back(new EFAEdge(*from_host->getEdge(i)));
      35             :     }
      36             :     else
      37             :     {
      38       58224 :       if (frag_id > from_host->numFragments() - 1)
      39           0 :         EFAError("In EFAfragment2D constructor fragment_copy_index out of bounds");
      40      290700 :       for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numEdges(); ++i)
      41      232476 :         _boundary_edges.push_back(new EFAEdge(*from_host->getFragmentEdge(frag_id, i)));
      42             :     }
      43             :   }
      44      552979 : }
      45             : 
      46        7713 : EFAFragment2D::EFAFragment2D(EFAElement2D * host, const EFAFace * from_face)
      47        7713 :   : EFAFragment(), _host_elem(host)
      48             : {
      49        7713 :   for (unsigned int i = 0; i < from_face->numEdges(); ++i)
      50       28452 :     _boundary_edges.push_back(new EFAEdge(*from_face->getEdge(i)));
      51        7713 : }
      52             : 
      53     1121384 : EFAFragment2D::~EFAFragment2D()
      54             : {
      55     2788171 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      56             :   {
      57     2227479 :     if (_boundary_edges[i])
      58             :     {
      59     2227479 :       delete _boundary_edges[i];
      60     2227479 :       _boundary_edges[i] = nullptr;
      61             :     }
      62             :   }
      63     1121384 : }
      64             : 
      65             : void
      66      342357 : EFAFragment2D::switchNode(EFANode * new_node, EFANode * old_node)
      67             : {
      68     1691282 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      69     1348925 :     _boundary_edges[i]->switchNode(new_node, old_node);
      70      342357 : }
      71             : 
      72             : bool
      73     4705827 : EFAFragment2D::containsNode(EFANode * node) const
      74             : {
      75             :   bool contains = false;
      76    11834865 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      77             :   {
      78    10435546 :     if (_boundary_edges[i]->containsNode(node))
      79             :     {
      80             :       contains = true;
      81             :       break;
      82             :     }
      83             :   }
      84     4705827 :   return contains;
      85             : }
      86             : 
      87             : unsigned int
      88      514229 : EFAFragment2D::getNumCuts() const
      89             : {
      90             :   unsigned int num_cut_edges = 0;
      91     2556637 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      92             :   {
      93     2042408 :     if (_boundary_edges[i]->hasIntersection())
      94       11289 :       num_cut_edges += _boundary_edges[i]->numEmbeddedNodes();
      95             :   }
      96      514229 :   return num_cut_edges;
      97             : }
      98             : 
      99             : unsigned int
     100      492424 : EFAFragment2D::getNumCutNodes() const
     101             : {
     102             :   unsigned int num_cut_nodes = 0;
     103     2449302 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     104     1956878 :     if (_boundary_edges[i]->getNode(0)->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
     105         200 :       num_cut_nodes++;
     106      492424 :   return num_cut_nodes;
     107             : }
     108             : 
     109             : std::set<EFANode *>
     110       14740 : EFAFragment2D::getAllNodes() const
     111             : {
     112             :   std::set<EFANode *> nodes;
     113       73476 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     114             :   {
     115       58736 :     nodes.insert(_boundary_edges[i]->getNode(0));
     116       58736 :     nodes.insert(_boundary_edges[i]->getNode(1));
     117             :   }
     118       14740 :   return nodes;
     119             : }
     120             : 
     121             : bool
     122       94945 : EFAFragment2D::isConnected(EFAFragment * other_fragment) const
     123             : {
     124             :   bool is_connected = false;
     125       94945 :   EFAFragment2D * other_frag2d = dynamic_cast<EFAFragment2D *>(other_fragment);
     126       94945 :   if (!other_frag2d)
     127           0 :     EFAError("in isConnected other_fragment is not of type EFAfragement2D");
     128             : 
     129      260044 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     130             :   {
     131     1013011 :     for (unsigned int j = 0; j < other_frag2d->numEdges(); ++j)
     132             :     {
     133      847912 :       if (_boundary_edges[i]->equivalent(*other_frag2d->getEdge(j)))
     134             :       {
     135             :         is_connected = true;
     136             :         break;
     137             :       }
     138             :     }
     139      246662 :     if (is_connected)
     140             :       break;
     141             :   } // i
     142       94945 :   return is_connected;
     143             : }
     144             : 
     145             : void
     146       21805 : EFAFragment2D::removeInvalidEmbeddedNodes(std::map<unsigned int, EFANode *> & EmbeddedNodes)
     147             : {
     148             :   // if a fragment only has 1 intersection which is in an interior edge
     149             :   // remove this embedded node (MUST DO THIS AFTER combine_tip_edges())
     150       21805 :   if (getNumCuts() == 1)
     151             :   {
     152        4373 :     for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     153             :     {
     154        3524 :       if (isEdgeInterior(i) && _boundary_edges[i]->hasIntersection())
     155             :       {
     156          72 :         if (_host_elem->numInteriorNodes() != 1)
     157           0 :           EFAError("host element must have 1 interior node at this point");
     158          72 :         Efa::deleteFromMap(EmbeddedNodes, _boundary_edges[i]->getEmbeddedNode(0));
     159          72 :         _boundary_edges[i]->removeEmbeddedNodes();
     160          72 :         _host_elem->deleteInteriorNodes();
     161          72 :         break;
     162             :       }
     163             :     } // i
     164             :   }
     165       21805 : }
     166             : 
     167             : void
     168        1245 : EFAFragment2D::combineTipEdges()
     169             : {
     170             :   // combine the tip edges in a crack tip fragment
     171             :   // N.B. the host elem can only have one elem_tip_edge, otherwise it should have already been
     172             :   // completely split
     173        1245 :   if (!_host_elem)
     174           0 :     EFAError("In combine_tip_edges() the frag must have host_elem");
     175             : 
     176             :   bool has_tip_edges = false;
     177             :   unsigned int elem_tip_edge_id = std::numeric_limits<unsigned int>::max();
     178             :   std::vector<unsigned int> frag_tip_edge_id;
     179        3589 :   for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
     180             :   {
     181        3589 :     frag_tip_edge_id.clear();
     182        3589 :     if (_host_elem->getEdge(i)->hasIntersection())
     183             :     {
     184        8890 :       for (unsigned int j = 0; j < _boundary_edges.size(); ++j)
     185             :       {
     186        7403 :         if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[j]))
     187        2732 :           frag_tip_edge_id.push_back(j);
     188             :       }                                 // j
     189        1487 :       if (frag_tip_edge_id.size() == 2) // combine the two frag edges on this elem edge
     190             :       {
     191             :         has_tip_edges = true;
     192             :         elem_tip_edge_id = i;
     193             :         break;
     194             :       }
     195             :     }
     196             :   } // i
     197        1245 :   if (has_tip_edges)
     198             :   {
     199             :     // frag_tip_edge_id[0] must precede frag_tip_edge_id[1]
     200        1245 :     unsigned int edge0_next(frag_tip_edge_id[0] < (numEdges() - 1) ? frag_tip_edge_id[0] + 1 : 0);
     201        1245 :     if (edge0_next != frag_tip_edge_id[1])
     202           0 :       EFAError("frag_tip_edge_id[1] must be the next edge of frag_tip_edge_id[0]");
     203             : 
     204             :     // get the two end nodes of the new edge
     205        1245 :     EFANode * node1 = _boundary_edges[frag_tip_edge_id[0]]->getNode(0);
     206        1245 :     EFANode * emb_node = _boundary_edges[frag_tip_edge_id[0]]->getNode(1);
     207        1245 :     EFANode * node2 = _boundary_edges[frag_tip_edge_id[1]]->getNode(1);
     208        1245 :     if (emb_node != _boundary_edges[frag_tip_edge_id[1]]->getNode(0))
     209           0 :       EFAError("fragment edges are not correctly set up");
     210             : 
     211             :     // get the new edge with one intersection
     212        1245 :     EFAEdge * elem_edge = _host_elem->getEdge(elem_tip_edge_id);
     213        1245 :     double xi_node1 = elem_edge->distanceFromNode1(node1);
     214        1245 :     double xi_node2 = elem_edge->distanceFromNode1(node2);
     215        1245 :     double xi_emb = elem_edge->distanceFromNode1(emb_node);
     216        1245 :     double position = (xi_emb - xi_node1) / (xi_node2 - xi_node1);
     217        1245 :     EFAEdge * full_edge = new EFAEdge(node1, node2);
     218        1245 :     full_edge->addIntersection(position, emb_node, node1);
     219             : 
     220             :     // combine the two original fragment edges
     221        1245 :     delete _boundary_edges[frag_tip_edge_id[0]];
     222        1245 :     delete _boundary_edges[frag_tip_edge_id[1]];
     223        1245 :     _boundary_edges[frag_tip_edge_id[0]] = full_edge;
     224        1245 :     _boundary_edges.erase(_boundary_edges.begin() + frag_tip_edge_id[1]);
     225             :   }
     226        1245 : }
     227             : 
     228             : /*
     229             : std::vector<EFAnode*>
     230             : EFAfragment::commonNodesWithEdge(EFAEdge & other_edge)
     231             : {
     232             :   std::vector<EFAnode*> common_nodes;
     233             :   for (unsigned int i = 0; i < 2; ++i)
     234             :   {
     235             :     EFAnode* edge_node = other_edge.node_ptr(i);
     236             :     if (containsNode(edge_node))
     237             :       common_nodes.push_back(edge_node);
     238             :   }
     239             :   return common_nodes;
     240             : }
     241             : */
     242             : 
     243             : bool
     244    10036365 : EFAFragment2D::isEdgeInterior(unsigned int edge_id) const
     245             : {
     246    10036365 :   if (!_host_elem)
     247           0 :     EFAError("in isEdgeInterior fragment must have host elem");
     248             : 
     249             :   bool edge_in_elem_edge = false;
     250             : 
     251    31619048 :   for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
     252             :   {
     253    29071438 :     if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[edge_id]))
     254             :     {
     255             :       edge_in_elem_edge = true;
     256             :       break;
     257             :     }
     258             :   }
     259    10036365 :   if (!edge_in_elem_edge)
     260             :     return true; // yes, is interior
     261             :   else
     262     7488755 :     return false;
     263             : }
     264             : 
     265             : std::vector<unsigned int>
     266           0 : EFAFragment2D::getInteriorEdgeID() const
     267             : {
     268             :   std::vector<unsigned int> interior_edge_id;
     269           0 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     270             :   {
     271           0 :     if (isEdgeInterior(i))
     272           0 :       interior_edge_id.push_back(i);
     273             :   }
     274           0 :   return interior_edge_id;
     275           0 : }
     276             : 
     277             : bool
     278       37917 : EFAFragment2D::isSecondaryInteriorEdge(unsigned int edge_id) const
     279             : {
     280             :   bool is_second_cut = false;
     281       37917 :   if (!_host_elem)
     282           0 :     EFAError("in isSecondaryInteriorEdge fragment must have host elem");
     283             : 
     284       37917 :   for (unsigned int i = 0; i < _host_elem->numInteriorNodes(); ++i)
     285             :   {
     286           0 :     if (_boundary_edges[edge_id]->containsNode(_host_elem->getInteriorNode(i)->getNode()))
     287             :     {
     288             :       is_second_cut = true;
     289             :       break;
     290             :     }
     291             :   }
     292       37917 :   return is_second_cut;
     293             : }
     294             : 
     295             : unsigned int
     296    16016906 : EFAFragment2D::numEdges() const
     297             : {
     298    16016906 :   return _boundary_edges.size();
     299             : }
     300             : 
     301             : EFAEdge *
     302     7775593 : EFAFragment2D::getEdge(unsigned int edge_id) const
     303             : {
     304     7775593 :   if (edge_id > _boundary_edges.size() - 1)
     305           0 :     EFAError("in EFAfragment2D::get_edge, index out of bounds");
     306     7775593 :   return _boundary_edges[edge_id];
     307             : }
     308             : 
     309             : void
     310       96448 : EFAFragment2D::addEdge(EFAEdge * new_edge)
     311             : {
     312       96448 :   _boundary_edges.push_back(new_edge);
     313       96448 : }
     314             : 
     315             : std::set<EFANode *>
     316           0 : EFAFragment2D::getEdgeNodes(unsigned int edge_id) const
     317             : {
     318             :   std::set<EFANode *> edge_nodes;
     319           0 :   edge_nodes.insert(_boundary_edges[edge_id]->getNode(0));
     320           0 :   edge_nodes.insert(_boundary_edges[edge_id]->getNode(1));
     321           0 :   return edge_nodes;
     322             : }
     323             : 
     324             : EFAElement2D *
     325           0 : EFAFragment2D::getHostElement() const
     326             : {
     327           0 :   return _host_elem;
     328             : }
     329             : 
     330             : std::vector<EFAFragment2D *>
     331       13338 : EFAFragment2D::split()
     332             : {
     333             :   // This method will split one existing fragment into one or two
     334             :   // new fragments and return them.
     335             :   // N.B. each boundary each can only have 1 cut at most
     336             :   std::vector<EFAFragment2D *> new_fragments;
     337             :   std::vector<std::vector<EFANode *>> fragment_nodes(
     338       13338 :       2);                       // vectors of EFA nodes in the two fragments
     339             :   unsigned int frag_number = 0; // Index of the current fragment that we are assmbling nodes into
     340             :   unsigned int edge_cut_count = 0;
     341             :   unsigned int node_cut_count = 0;
     342       63766 :   for (unsigned int iedge = 0; iedge < _boundary_edges.size(); ++iedge)
     343             :   {
     344       50428 :     fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getNode(0));
     345             : 
     346       50428 :     if (_boundary_edges[iedge]->getNode(0)->category() ==
     347             :         EFANode::N_CATEGORY_EMBEDDED_PERMANENT) // if current node has been cut change fragment
     348             :     {
     349         200 :       ++node_cut_count;
     350         200 :       frag_number = 1 - frag_number; // Toggle between 0 and 1
     351         200 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getNode(0));
     352             :     }
     353             : 
     354       50428 :     if (_boundary_edges[iedge]->numEmbeddedNodes() > 1)
     355           0 :       EFAError("A fragment boundary edge can't have more than 1 cuts");
     356       50428 :     if (_boundary_edges[iedge]->hasIntersection()) // if current edge is cut add cut intersection //
     357             :                                                    // node to both fragments and and change fragment
     358             :     {
     359       23481 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
     360       23481 :       ++edge_cut_count;
     361       23481 :       frag_number = 1 - frag_number; // Toggle between 0 and 1
     362       23481 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
     363             :     }
     364             :   }
     365             : 
     366       13338 :   if ((edge_cut_count + node_cut_count) > 1) // any two cuts case
     367             :   {
     368       31029 :     for (unsigned int frag_idx = 0; frag_idx < 2; ++frag_idx) // Create 2 fragments
     369             :     {
     370       20686 :       auto & this_frag_nodes = fragment_nodes[frag_idx];
     371             :       // check to make sure an edge wasn't cut
     372       20686 :       if (this_frag_nodes.size() >= 3)
     373             :       {
     374       20630 :         EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     375       79876 :         for (unsigned int inode = 0; inode < this_frag_nodes.size() - 1; inode++)
     376       59246 :           new_frag->addEdge(new EFAEdge(this_frag_nodes[inode], this_frag_nodes[inode + 1]));
     377             : 
     378       20630 :         new_frag->addEdge(
     379       20630 :             new EFAEdge(this_frag_nodes[this_frag_nodes.size() - 1], this_frag_nodes[0]));
     380             : 
     381       20630 :         new_fragments.push_back(new_frag);
     382             :       }
     383             :     }
     384             :   }
     385        2995 :   else if (edge_cut_count == 1) // single edge cut case
     386             :   {
     387        2947 :     EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     388       10661 :     for (unsigned int inode = 0; inode < fragment_nodes[0].size() - 1;
     389             :          inode++) // assemble fragment part 1
     390        7714 :       new_frag->addEdge(new EFAEdge(fragment_nodes[0][inode], fragment_nodes[0][inode + 1]));
     391             : 
     392        6701 :     for (unsigned int inode = 0; inode < fragment_nodes[1].size() - 1;
     393             :          inode++) // assemble fragment part 2
     394        3754 :       new_frag->addEdge(new EFAEdge(fragment_nodes[1][inode], fragment_nodes[1][inode + 1]));
     395             : 
     396        2947 :     new_frag->addEdge(
     397        2947 :         new EFAEdge(fragment_nodes[1][fragment_nodes[1].size() - 1], fragment_nodes[0][0]));
     398             : 
     399        2947 :     new_fragments.push_back(new_frag);
     400             :   }
     401          48 :   else if (node_cut_count == 1) // single node cut case
     402             :   {
     403          48 :     EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     404         240 :     for (unsigned int iedge = 0; iedge < _boundary_edges.size(); ++iedge)
     405             :     {
     406         192 :       EFANode * first_node_on_edge = _boundary_edges[iedge]->getNode(0);
     407         192 :       EFANode * second_node_on_edge = _boundary_edges[iedge]->getNode(1);
     408         192 :       new_frag->addEdge(new EFAEdge(first_node_on_edge, second_node_on_edge));
     409             :     }
     410             : 
     411          48 :     new_fragments.push_back(new_frag);
     412             :   }
     413             : 
     414       13338 :   return new_fragments;
     415       13338 : }

Generated by: LCOV version 1.14