LCOV - code coverage report
Current view: top level - src/efa - EFAFragment2D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 152 176 86.4 %
Date: 2025-09-04 07:58:55 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      281525 : EFAFragment2D::EFAFragment2D(EFAElement2D * host,
      22             :                              bool create_boundary_edges,
      23             :                              const EFAElement2D * from_host,
      24      281525 :                              unsigned int frag_id)
      25      281525 :   : EFAFragment(), _host_elem(host)
      26             : {
      27      281525 :   if (create_boundary_edges)
      28             :   {
      29      261359 :     if (!from_host)
      30           0 :       EFAError("EFAfragment2D constructor must have a from_host to copy from");
      31      261359 :     if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself
      32             :     {
      33     1020837 :       for (unsigned int i = 0; i < from_host->numEdges(); ++i)
      34      814444 :         _boundary_edges.push_back(new EFAEdge(*from_host->getEdge(i)));
      35             :     }
      36             :     else
      37             :     {
      38       54966 :       if (frag_id > from_host->numFragments() - 1)
      39           0 :         EFAError("In EFAfragment2D constructor fragment_copy_index out of bounds");
      40      274266 :       for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numEdges(); ++i)
      41      219300 :         _boundary_edges.push_back(new EFAEdge(*from_host->getFragmentEdge(frag_id, i)));
      42             :     }
      43             :   }
      44      281525 : }
      45             : 
      46        5733 : EFAFragment2D::EFAFragment2D(EFAElement2D * host, const EFAFace * from_face)
      47        5733 :   : EFAFragment(), _host_elem(host)
      48             : {
      49        5733 :   for (unsigned int i = 0; i < from_face->numEdges(); ++i)
      50       20532 :     _boundary_edges.push_back(new EFAEdge(*from_face->getEdge(i)));
      51        5733 : }
      52             : 
      53      574516 : EFAFragment2D::~EFAFragment2D()
      54             : {
      55     1420297 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      56             :   {
      57     1133039 :     if (_boundary_edges[i])
      58             :     {
      59     1133039 :       delete _boundary_edges[i];
      60     1133039 :       _boundary_edges[i] = nullptr;
      61             :     }
      62             :   }
      63      574516 : }
      64             : 
      65             : void
      66      325973 : EFAFragment2D::switchNode(EFANode * new_node, EFANode * old_node)
      67             : {
      68     1608874 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      69     1282901 :     _boundary_edges[i]->switchNode(new_node, old_node);
      70      325973 : }
      71             : 
      72             : bool
      73     3512754 : EFAFragment2D::containsNode(EFANode * node) const
      74             : {
      75             :   bool contains = false;
      76     9573286 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      77             :   {
      78     8237249 :     if (_boundary_edges[i]->containsNode(node))
      79             :     {
      80             :       contains = true;
      81             :       break;
      82             :     }
      83             :   }
      84     3512754 :   return contains;
      85             : }
      86             : 
      87             : unsigned int
      88      247299 : EFAFragment2D::getNumCuts() const
      89             : {
      90             :   unsigned int num_cut_edges = 0;
      91     1221987 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
      92             :   {
      93      974688 :     if (_boundary_edges[i]->hasIntersection())
      94       10891 :       num_cut_edges += _boundary_edges[i]->numEmbeddedNodes();
      95             :   }
      96      247299 :   return num_cut_edges;
      97             : }
      98             : 
      99             : unsigned int
     100      226846 : EFAFragment2D::getNumCutNodes() const
     101             : {
     102             :   unsigned int num_cut_nodes = 0;
     103     1121412 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     104      894566 :     if (_boundary_edges[i]->getNode(0)->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
     105         200 :       num_cut_nodes++;
     106      226846 :   return num_cut_nodes;
     107             : }
     108             : 
     109             : std::set<EFANode *>
     110       14164 : EFAFragment2D::getAllNodes() const
     111             : {
     112             :   std::set<EFANode *> nodes;
     113       70596 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     114             :   {
     115       56432 :     nodes.insert(_boundary_edges[i]->getNode(0));
     116       56432 :     nodes.insert(_boundary_edges[i]->getNode(1));
     117             :   }
     118       14164 :   return nodes;
     119             : }
     120             : 
     121             : bool
     122       89141 : EFAFragment2D::isConnected(EFAFragment * other_fragment) const
     123             : {
     124             :   bool is_connected = false;
     125       89141 :   EFAFragment2D * other_frag2d = dynamic_cast<EFAFragment2D *>(other_fragment);
     126       89141 :   if (!other_frag2d)
     127           0 :     EFAError("in isConnected other_fragment is not of type EFAfragement2D");
     128             : 
     129      245408 :   for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     130             :   {
     131      956449 :     for (unsigned int j = 0; j < other_frag2d->numEdges(); ++j)
     132             :     {
     133      800182 :       if (_boundary_edges[i]->equivalent(*other_frag2d->getEdge(j)))
     134             :       {
     135             :         is_connected = true;
     136             :         break;
     137             :       }
     138             :     }
     139      232490 :     if (is_connected)
     140             :       break;
     141             :   } // i
     142       89141 :   return is_connected;
     143             : }
     144             : 
     145             : void
     146       20453 : 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       20453 :   if (getNumCuts() == 1)
     151             :   {
     152        4133 :     for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
     153             :     {
     154        3332 :       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       20453 : }
     166             : 
     167             : void
     168        1181 : 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        1181 :   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        3605 :   for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
     180             :   {
     181        3605 :     frag_tip_edge_id.clear();
     182        3605 :     if (_host_elem->getEdge(i)->hasIntersection())
     183             :     {
     184        8458 :       for (unsigned int j = 0; j < _boundary_edges.size(); ++j)
     185             :       {
     186        7043 :         if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[j]))
     187        2596 :           frag_tip_edge_id.push_back(j);
     188             :       }                                 // j
     189        1415 :       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        1181 :   if (has_tip_edges)
     198             :   {
     199             :     // frag_tip_edge_id[0] must precede frag_tip_edge_id[1]
     200        1181 :     unsigned int edge0_next(frag_tip_edge_id[0] < (numEdges() - 1) ? frag_tip_edge_id[0] + 1 : 0);
     201        1181 :     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        1181 :     EFANode * node1 = _boundary_edges[frag_tip_edge_id[0]]->getNode(0);
     206        1181 :     EFANode * emb_node = _boundary_edges[frag_tip_edge_id[0]]->getNode(1);
     207        1181 :     EFANode * node2 = _boundary_edges[frag_tip_edge_id[1]]->getNode(1);
     208        1181 :     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        1181 :     EFAEdge * elem_edge = _host_elem->getEdge(elem_tip_edge_id);
     213        1181 :     double xi_node1 = elem_edge->distanceFromNode1(node1);
     214        1181 :     double xi_node2 = elem_edge->distanceFromNode1(node2);
     215        1181 :     double xi_emb = elem_edge->distanceFromNode1(emb_node);
     216        1181 :     double position = (xi_emb - xi_node1) / (xi_node2 - xi_node1);
     217        1181 :     EFAEdge * full_edge = new EFAEdge(node1, node2);
     218        1181 :     full_edge->addIntersection(position, emb_node, node1);
     219             : 
     220             :     // combine the two original fragment edges
     221        1181 :     delete _boundary_edges[frag_tip_edge_id[0]];
     222        1181 :     delete _boundary_edges[frag_tip_edge_id[1]];
     223        1181 :     _boundary_edges[frag_tip_edge_id[0]] = full_edge;
     224        1181 :     _boundary_edges.erase(_boundary_edges.begin() + frag_tip_edge_id[1]);
     225             :   }
     226        1181 : }
     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     9577984 : EFAFragment2D::isEdgeInterior(unsigned int edge_id) const
     245             : {
     246     9577984 :   if (!_host_elem)
     247           0 :     EFAError("in isEdgeInterior fragment must have host elem");
     248             : 
     249             :   bool edge_in_elem_edge = false;
     250             : 
     251    30148316 :   for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
     252             :   {
     253    27715072 :     if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[edge_id]))
     254             :     {
     255             :       edge_in_elem_edge = true;
     256             :       break;
     257             :     }
     258             :   }
     259     9577984 :   if (!edge_in_elem_edge)
     260             :     return true; // yes, is interior
     261             :   else
     262     7144740 :     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       35386 : EFAFragment2D::isSecondaryInteriorEdge(unsigned int edge_id) const
     279             : {
     280             :   bool is_second_cut = false;
     281       35386 :   if (!_host_elem)
     282           0 :     EFAError("in isSecondaryInteriorEdge fragment must have host elem");
     283             : 
     284       35386 :   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       35386 :   return is_second_cut;
     293             : }
     294             : 
     295             : unsigned int
     296    14982198 : EFAFragment2D::numEdges() const
     297             : {
     298    14982198 :   return _boundary_edges.size();
     299             : }
     300             : 
     301             : EFAEdge *
     302     7312519 : EFAFragment2D::getEdge(unsigned int edge_id) const
     303             : {
     304     7312519 :   if (edge_id > _boundary_edges.size() - 1)
     305           0 :     EFAError("in EFAfragment2D::get_edge, index out of bounds");
     306     7312519 :   return _boundary_edges[edge_id];
     307             : }
     308             : 
     309             : void
     310       79944 : EFAFragment2D::addEdge(EFAEdge * new_edge)
     311             : {
     312       79944 :   _boundary_edges.push_back(new_edge);
     313       79944 : }
     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       11163 : 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       11163 :       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       52891 :   for (unsigned int iedge = 0; iedge < _boundary_edges.size(); ++iedge)
     343             :   {
     344       41728 :     fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getNode(0));
     345             : 
     346       41728 :     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       41728 :     if (_boundary_edges[iedge]->numEmbeddedNodes() > 1)
     355           0 :       EFAError("A fragment boundary edge can't have more than 1 cuts");
     356       41728 :     if (_boundary_edges[iedge]->hasIntersection()) // if current edge is cut add cut intersection //
     357             :                                                    // node to both fragments and and change fragment
     358             :     {
     359       19755 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
     360       19755 :       ++edge_cut_count;
     361       19755 :       frag_number = 1 - frag_number; // Toggle between 0 and 1
     362       19755 :       fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
     363             :     }
     364             :   }
     365             : 
     366       11163 :   if ((edge_cut_count + node_cut_count) > 1) // any two cuts case
     367             :   {
     368       26376 :     for (unsigned int frag_idx = 0; frag_idx < 2; ++frag_idx) // Create 2 fragments
     369             :     {
     370       17584 :       auto & this_frag_nodes = fragment_nodes[frag_idx];
     371             :       // check to make sure an edge wasn't cut
     372       17584 :       if (this_frag_nodes.size() >= 3)
     373             :       {
     374       17528 :         EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     375       67468 :         for (unsigned int inode = 0; inode < this_frag_nodes.size() - 1; inode++)
     376       49940 :           new_frag->addEdge(new EFAEdge(this_frag_nodes[inode], this_frag_nodes[inode + 1]));
     377             : 
     378       17528 :         new_frag->addEdge(
     379       17528 :             new EFAEdge(this_frag_nodes[this_frag_nodes.size() - 1], this_frag_nodes[0]));
     380             : 
     381       17528 :         new_fragments.push_back(new_frag);
     382             :       }
     383             :     }
     384             :   }
     385        2371 :   else if (edge_cut_count == 1) // single edge cut case
     386             :   {
     387        2323 :     EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
     388        8677 :     for (unsigned int inode = 0; inode < fragment_nodes[0].size() - 1;
     389             :          inode++) // assemble fragment part 1
     390        6354 :       new_frag->addEdge(new EFAEdge(fragment_nodes[0][inode], fragment_nodes[0][inode + 1]));
     391             : 
     392        4941 :     for (unsigned int inode = 0; inode < fragment_nodes[1].size() - 1;
     393             :          inode++) // assemble fragment part 2
     394        2618 :       new_frag->addEdge(new EFAEdge(fragment_nodes[1][inode], fragment_nodes[1][inode + 1]));
     395             : 
     396        2323 :     new_frag->addEdge(
     397        2323 :         new EFAEdge(fragment_nodes[1][fragment_nodes[1].size() - 1], fragment_nodes[0][0]));
     398             : 
     399        2323 :     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       11163 :   return new_fragments;
     415       11163 : }

Generated by: LCOV version 1.14