LCOV - code coverage report
Current view: top level - src/efa - EFAFragment2D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31730 (e8b711) with base e0c998 Lines: 152 176 86.4 %
Date: 2025-10-29 16:56:32 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      457611 : EFAFragment2D::EFAFragment2D(EFAElement2D * host,
      22             :                              bool create_boundary_edges,
      23             :                              const EFAElement2D * from_host,
      24      457611 :                              unsigned int frag_id)
      25      457611 :   : EFAFragment(), _host_elem(host)
      26             : {
      27      457611 :   if (create_boundary_edges)
      28             :   {
      29      436341 :     if (!from_host)
      30           0 :       EFAError("EFAfragment2D constructor must have a from_host to copy from");
      31      436341 :     if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself
      32             :     {
      33     1889487 :       for (unsigned int i = 0; i < from_host->numEdges(); ++i)
      34     1509364 :         _boundary_edges.push_back(new EFAEdge(*from_host->getEdge(i)));
      35             :     }
      36             :     else
      37             :     {
      38       56218 :       if (frag_id > from_host->numFragments() - 1)
      39           0 :         EFAError("In EFAfragment2D constructor fragment_copy_index out of bounds");
      40      280626 :       for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numEdges(); ++i)
      41      224408 :         _boundary_edges.push_back(new EFAEdge(*from_host->getFragmentEdge(frag_id, i)));
      42             :     }
      43             :   }
      44      457611 : }
      45             : 
      46        6289 : EFAFragment2D::EFAFragment2D(EFAElement2D * host, const EFAFace * from_face)
      47        6289 :   : EFAFragment(), _host_elem(host)
      48             : {
      49        6289 :   for (unsigned int i = 0; i < from_face->numEdges(); ++i)
      50       22756 :     _boundary_edges.push_back(new EFAEdge(*from_face->getEdge(i)));
      51        6289 : }
      52             : 
      53      927800 : EFAFragment2D::~EFAFragment2D()
      54             : {
      55     2303883 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      56             :   {
      57     1839983 :     if (_boundary_edges[i])
      58             :     {
      59     1839983 :       delete _boundary_edges[i];
      60     1839983 :       _boundary_edges[i] = nullptr;
      61             :     }
      62             :   }
      63      927800 : }
      64             : 
      65             : void
      66      331401 : EFAFragment2D::switchNode(EFANode * new_node, EFANode * old_node)
      67             : {
      68     1636358 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      69     1304957 :     _boundary_edges[i]->switchNode(new_node, old_node);
      70      331401 : }
      71             : 
      72             : bool
      73     4265455 : EFAFragment2D::containsNode(EFANode * node) const
      74             : {
      75             :   bool contains = false;
      76    10954070 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      77             :   {
      78     9593483 :     if (_boundary_edges[i]->containsNode(node))
      79             :     {
      80             :       contains = true;
      81             :       break;
      82             :     }
      83             :   }
      84     4265455 :   return contains;
      85             : }
      86             : 
      87             : unsigned int
      88      422213 : EFAFragment2D::getNumCuts() const
      89             : {
      90             :   unsigned int num_cut_edges = 0;
      91     2096557 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      92             :   {
      93     1674344 :     if (_boundary_edges[i]->hasIntersection())
      94       11055 :       num_cut_edges += _boundary_edges[i]->numEmbeddedNodes();
      95             :   }
      96      422213 :   return num_cut_edges;
      97             : }
      98             : 
      99             : unsigned int
     100      401168 : EFAFragment2D::getNumCutNodes() const
     101             : {
     102             :   unsigned int num_cut_nodes = 0;
     103     1993022 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     104     1591854 :     if (_boundary_edges[i]->getNode(0)->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
     105         200 :       num_cut_nodes++;
     106      401168 :   return num_cut_nodes;
     107             : }
     108             : 
     109             : std::set<EFANode *>
     110       13876 : EFAFragment2D::getAllNodes() const
     111             : {
     112             :   std::set<EFANode *> nodes;
     113       69156 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     114             :   {
     115       55280 :     nodes.insert(_boundary_edges[i]->getNode(0));
     116       55280 :     nodes.insert(_boundary_edges[i]->getNode(1));
     117             :   }
     118       13876 :   return nodes;
     119             : }
     120             : 
     121             : bool
     122       91361 : EFAFragment2D::isConnected(EFAFragment * other_fragment) const
     123             : {
     124             :   bool is_connected = false;
     125       91361 :   EFAFragment2D * other_frag2d = dynamic_cast<EFAFragment2D *>(other_fragment);
     126       91361 :   if (!other_frag2d)
     127           0 :     EFAError("in isConnected other_fragment is not of type EFAfragement2D");
     128             : 
     129      251664 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     130             :   {
     131      982521 :     for (unsigned int j = 0; j < other_frag2d->numEdges(); ++j)
     132             :     {
     133      822218 :       if (_boundary_edges[i]->equivalent(*other_frag2d->getEdge(j)))
     134             :       {
     135             :         is_connected = true;
     136             :         break;
     137             :       }
     138             :     }
     139      238602 :     if (is_connected)
     140             :       break;
     141             :   } // i
     142       91361 :   return is_connected;
     143             : }
     144             : 
     145             : void
     146       21045 : 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       21045 :   if (getNumCuts() == 1)
     151             :   {
     152        4333 :     for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     153             :     {
     154        3492 :       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       21045 : }
     166             : 
     167             : void
     168        1213 : 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        1213 :   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        3709 :   for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
     180             :   {
     181        3709 :     frag_tip_edge_id.clear();
     182        3709 :     if (_host_elem->getEdge(i)->hasIntersection())
     183             :     {
     184        8698 :       for (unsigned int j = 0; j < _boundary_edges.size(); ++j)
     185             :       {
     186        7243 :         if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[j]))
     187        2668 :           frag_tip_edge_id.push_back(j);
     188             :       }                                 // j
     189        1455 :       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        1213 :   if (has_tip_edges)
     198             :   {
     199             :     // frag_tip_edge_id[0] must precede frag_tip_edge_id[1]
     200        1213 :     unsigned int edge0_next(frag_tip_edge_id[0] < (numEdges() - 1) ? frag_tip_edge_id[0] + 1 : 0);
     201        1213 :     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        1213 :     EFANode * node1 = _boundary_edges[frag_tip_edge_id[0]]->getNode(0);
     206        1213 :     EFANode * emb_node = _boundary_edges[frag_tip_edge_id[0]]->getNode(1);
     207        1213 :     EFANode * node2 = _boundary_edges[frag_tip_edge_id[1]]->getNode(1);
     208        1213 :     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        1213 :     EFAEdge * elem_edge = _host_elem->getEdge(elem_tip_edge_id);
     213        1213 :     double xi_node1 = elem_edge->distanceFromNode1(node1);
     214        1213 :     double xi_node2 = elem_edge->distanceFromNode1(node2);
     215        1213 :     double xi_emb = elem_edge->distanceFromNode1(emb_node);
     216        1213 :     double position = (xi_emb - xi_node1) / (xi_node2 - xi_node1);
     217        1213 :     EFAEdge * full_edge = new EFAEdge(node1, node2);
     218        1213 :     full_edge->addIntersection(position, emb_node, node1);
     219             : 
     220             :     // combine the two original fragment edges
     221        1213 :     delete _boundary_edges[frag_tip_edge_id[0]];
     222        1213 :     delete _boundary_edges[frag_tip_edge_id[1]];
     223        1213 :     _boundary_edges[frag_tip_edge_id[0]] = full_edge;
     224        1213 :     _boundary_edges.erase(_boundary_edges.begin() + frag_tip_edge_id[1]);
     225             :   }
     226        1213 : }
     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     9839498 : EFAFragment2D::isEdgeInterior(unsigned int edge_id) const
     245             : {
     246     9839498 :   if (!_host_elem)
     247           0 :     EFAError("in isEdgeInterior fragment must have host elem");
     248             : 
     249             :   bool edge_in_elem_edge = false;
     250             : 
     251    31000153 :   for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
     252             :   {
     253    28501627 :     if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[edge_id]))
     254             :     {
     255             :       edge_in_elem_edge = true;
     256             :       break;
     257             :     }
     258             :   }
     259     9839498 :   if (!edge_in_elem_edge)
     260             :     return true; // yes, is interior
     261             :   else
     262     7340972 :     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       36457 : EFAFragment2D::isSecondaryInteriorEdge(unsigned int edge_id) const
     279             : {
     280             :   bool is_second_cut = false;
     281       36457 :   if (!_host_elem)
     282           0 :     EFAError("in isSecondaryInteriorEdge fragment must have host elem");
     283             : 
     284       36457 :   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       36457 :   return is_second_cut;
     293             : }
     294             : 
     295             : unsigned int
     296    15557371 : EFAFragment2D::numEdges() const
     297             : {
     298    15557371 :   return _boundary_edges.size();
     299             : }
     300             : 
     301             : EFAEdge *
     302     7525785 : EFAFragment2D::getEdge(unsigned int edge_id) const
     303             : {
     304     7525785 :   if (edge_id > _boundary_edges.size() - 1)
     305           0 :     EFAError("in EFAfragment2D::get_edge, index out of bounds");
     306     7525785 :   return _boundary_edges[edge_id];
     307             : }
     308             : 
     309             : void
     310       84668 : EFAFragment2D::addEdge(EFAEdge * new_edge)
     311             : {
     312       84668 :   _boundary_edges.push_back(new_edge);
     313       84668 : }
     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       11811 : 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       11811 :       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       56131 :   for (unsigned int iedge = 0; iedge < _boundary_edges.size(); ++iedge)
     343             :   {
     344       44320 :     fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getNode(0));
     345             : 
     346       44320 :     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       44320 :     if (_boundary_edges[iedge]->numEmbeddedNodes() > 1)
     355           0 :       EFAError("A fragment boundary edge can't have more than 1 cuts");
     356       44320 :     if (_boundary_edges[iedge]->hasIntersection()) // if current edge is cut add cut intersection //
     357             :                                                    // node to both fragments and and change fragment
     358             :     {
     359       20743 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
     360       20743 :       ++edge_cut_count;
     361       20743 :       frag_number = 1 - frag_number; // Toggle between 0 and 1
     362       20743 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
     363             :     }
     364             :   }
     365             : 
     366       11811 :   if ((edge_cut_count + node_cut_count) > 1) // any two cuts case
     367             :   {
     368       27396 :     for (unsigned int frag_idx = 0; frag_idx < 2; ++frag_idx) // Create 2 fragments
     369             :     {
     370       18264 :       auto & this_frag_nodes = fragment_nodes[frag_idx];
     371             :       // check to make sure an edge wasn't cut
     372       18264 :       if (this_frag_nodes.size() >= 3)
     373             :       {
     374       18208 :         EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     375       70188 :         for (unsigned int inode = 0; inode < this_frag_nodes.size() - 1; inode++)
     376       51980 :           new_frag->addEdge(new EFAEdge(this_frag_nodes[inode], this_frag_nodes[inode + 1]));
     377             : 
     378       18208 :         new_frag->addEdge(
     379       18208 :             new EFAEdge(this_frag_nodes[this_frag_nodes.size() - 1], this_frag_nodes[0]));
     380             : 
     381       18208 :         new_fragments.push_back(new_frag);
     382             :       }
     383             :     }
     384             :   }
     385        2679 :   else if (edge_cut_count == 1) // single edge cut case
     386             :   {
     387        2631 :     EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     388        9793 :     for (unsigned int inode = 0; inode < fragment_nodes[0].size() - 1;
     389             :          inode++) // assemble fragment part 1
     390        7162 :       new_frag->addEdge(new EFAEdge(fragment_nodes[0][inode], fragment_nodes[0][inode + 1]));
     391             : 
     392        5673 :     for (unsigned int inode = 0; inode < fragment_nodes[1].size() - 1;
     393             :          inode++) // assemble fragment part 2
     394        3042 :       new_frag->addEdge(new EFAEdge(fragment_nodes[1][inode], fragment_nodes[1][inode + 1]));
     395             : 
     396        2631 :     new_frag->addEdge(
     397        2631 :         new EFAEdge(fragment_nodes[1][fragment_nodes[1].size() - 1], fragment_nodes[0][0]));
     398             : 
     399        2631 :     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       11811 :   return new_fragments;
     415       11811 : }

Generated by: LCOV version 1.14