LCOV - code coverage report
Current view: top level - src/efa - EFAElement2D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 795 902 88.1 %
Date: 2025-09-04 07:58:55 Functions: 58 61 95.1 %
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 <iomanip>
      13             : 
      14             : #include "EFAFaceNode.h"
      15             : #include "EFANode.h"
      16             : #include "EFAEdge.h"
      17             : #include "EFAFace.h"
      18             : #include "EFAFragment2D.h"
      19             : #include "EFAFuncs.h"
      20             : #include "EFAError.h"
      21             : #include "XFEMFuncs.h"
      22             : 
      23      394707 : EFAElement2D::EFAElement2D(unsigned int eid, unsigned int n_nodes) : EFAElement(eid, n_nodes)
      24             : {
      25      394707 :   if (n_nodes == 4 || n_nodes == 8 || n_nodes == 9)
      26      370523 :     _num_edges = 4;
      27       24184 :   else if (n_nodes == 3 || n_nodes == 6 || n_nodes == 7)
      28       24184 :     _num_edges = 3;
      29             :   else
      30           0 :     EFAError(
      31             :         "In EFAelement2D the supported element types are QUAD4, QUAD8, QUAD9, TRI3, TRI6 and TRI7");
      32      394707 :   setLocalCoordinates();
      33      394707 :   _edges = std::vector<EFAEdge *>(_num_edges, nullptr);
      34      394707 :   _edge_neighbors = std::vector<std::vector<EFAElement2D *>>(_num_edges, {nullptr});
      35      394707 : }
      36             : 
      37        9298 : EFAElement2D::EFAElement2D(const EFAElement2D * from_elem, bool convert_to_local)
      38        9298 :   : EFAElement(from_elem->_id, from_elem->_num_nodes),
      39        9298 :     _num_edges(from_elem->_num_edges),
      40        9298 :     _edges(_num_edges, nullptr),
      41        9298 :     _edge_neighbors(_num_edges, {nullptr})
      42             : {
      43        9298 :   if (convert_to_local)
      44             :   {
      45             :     // build local nodes from global nodes
      46       50134 :     for (unsigned int i = 0; i < _num_nodes; ++i)
      47             :     {
      48       40968 :       if (from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_PERMANENT ||
      49       40968 :           from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_TEMP ||
      50         132 :           from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
      51             :       {
      52       40836 :         _nodes[i] = from_elem->createLocalNodeFromGlobalNode(from_elem->_nodes[i]);
      53       40836 :         _local_nodes.push_back(_nodes[i]); // convenient to delete local nodes
      54             :       }
      55             :       else
      56           0 :         EFAError("In EFAelement2D ",
      57             :                  from_elem->id(),
      58             :                  " the copy constructor must have from_elem w/ global nodes. node: ",
      59             :                  i,
      60             :                  " category: ",
      61             :                  from_elem->_nodes[i]->category());
      62             :     }
      63             : 
      64             :     // copy edges, fragments and interior nodes from from_elem
      65       45370 :     for (unsigned int i = 0; i < _num_edges; ++i)
      66       36072 :       _edges[i] = new EFAEdge(*from_elem->_edges[i]);
      67       18596 :     for (unsigned int i = 0; i < from_elem->_fragments.size(); ++i)
      68        9298 :       _fragments.push_back(new EFAFragment2D(this, true, from_elem, i));
      69        9346 :     for (unsigned int i = 0; i < from_elem->_interior_nodes.size(); ++i)
      70          48 :       _interior_nodes.push_back(new EFAFaceNode(*from_elem->_interior_nodes[i]));
      71             : 
      72             :     // replace all global nodes with local nodes
      73       50134 :     for (unsigned int i = 0; i < _num_nodes; ++i)
      74             :     {
      75       40836 :       if (_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
      76       40836 :         switchNode(
      77             :             _nodes[i],
      78             :             from_elem->_nodes[i],
      79             :             false); // when save to _cut_elem_map, the EFAelement is not a child of any parent
      80             :       else
      81           0 :         EFAError("In EFAelement2D copy constructor this elem's nodes must be local");
      82             :     }
      83             : 
      84        9298 :     _local_node_coor = from_elem->_local_node_coor;
      85             :   }
      86             :   else
      87           0 :     EFAError("this EFAelement2D constructor only converts global nodes to local nodes");
      88        9298 : }
      89             : 
      90           0 : EFAElement2D::EFAElement2D(const EFAFace * from_face)
      91             :   : EFAElement(0, from_face->numNodes()),
      92           0 :     _num_edges(from_face->numEdges()),
      93           0 :     _edges(_num_edges, nullptr),
      94           0 :     _edge_neighbors(_num_edges, {nullptr})
      95             : {
      96           0 :   for (unsigned int i = 0; i < _num_nodes; ++i)
      97           0 :     _nodes[i] = from_face->getNode(i);
      98           0 :   for (unsigned int i = 0; i < _num_edges; ++i)
      99           0 :     _edges[i] = new EFAEdge(*from_face->getEdge(i));
     100           0 :   for (unsigned int i = 0; i < from_face->numInteriorNodes(); ++i)
     101           0 :     _interior_nodes.push_back(new EFAFaceNode(*from_face->getInteriorNode(i)));
     102           0 : }
     103             : 
     104      798312 : EFAElement2D::~EFAElement2D()
     105             : {
     106      466748 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     107             :   {
     108       62943 :     if (_fragments[i])
     109             :     {
     110       62943 :       delete _fragments[i];
     111       62943 :       _fragments[i] = nullptr;
     112             :     }
     113             :   }
     114     1993721 :   for (unsigned int i = 0; i < _edges.size(); ++i)
     115             :   {
     116     1589916 :     if (_edges[i])
     117             :     {
     118     1589916 :       delete _edges[i];
     119     1589916 :       _edges[i] = nullptr;
     120             :     }
     121             :   }
     122      404081 :   for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
     123             :   {
     124         276 :     if (_interior_nodes[i])
     125             :     {
     126         276 :       delete _interior_nodes[i];
     127         276 :       _interior_nodes[i] = nullptr;
     128             :     }
     129             :   }
     130      444641 :   for (unsigned int i = 0; i < _local_nodes.size(); ++i)
     131             :   {
     132       40836 :     if (_local_nodes[i])
     133             :     {
     134       40836 :       delete _local_nodes[i];
     135       40836 :       _local_nodes[i] = nullptr;
     136             :     }
     137             :   }
     138      798312 : }
     139             : 
     140             : void
     141      394707 : EFAElement2D::setLocalCoordinates()
     142             : {
     143      394707 :   if (_num_edges == 4)
     144             :   {
     145             :     /*
     146             :                 3     6     2
     147             :     QUAD9(QUAD8): o-----o-----o
     148             :                   |           |
     149             :                   |     8     |
     150             :                 7 o     o     o 5
     151             :                   |           |
     152             :                   |           |
     153             :                   o-----o-----o
     154             :                   0     4     1
     155             : 
     156             :     */
     157      370523 :     _local_node_coor.resize(_num_nodes);
     158      370523 :     _local_node_coor[0] = EFAPoint(0.0, 0.0, 0.0);
     159      370523 :     _local_node_coor[1] = EFAPoint(1.0, 0.0, 0.0);
     160      370523 :     _local_node_coor[2] = EFAPoint(1.0, 1.0, 0.0);
     161      370523 :     _local_node_coor[3] = EFAPoint(0.0, 1.0, 0.0);
     162             : 
     163      370523 :     if (_num_nodes > 4)
     164             :     {
     165        8496 :       _local_node_coor[4] = EFAPoint(0.5, 0.0, 0.0);
     166        8496 :       _local_node_coor[5] = EFAPoint(1.0, 0.5, 0.0);
     167        8496 :       _local_node_coor[6] = EFAPoint(0.5, 1.0, 0.0);
     168        8496 :       _local_node_coor[7] = EFAPoint(0.0, 0.5, 0.0);
     169             :     }
     170             : 
     171      370523 :     if (_num_nodes > 8)
     172        4320 :       _local_node_coor[8] = EFAPoint(0.5, 0.5, 0.0);
     173             :   }
     174             :   else
     175             :   {
     176             :     /*
     177             :       TRI7: 2
     178             :             o
     179             :             | \
     180             :             |   \
     181             :           5 o     o 4
     182             :             |  o    \
     183             :             |  6      \
     184             :             o-----o-----o
     185             :             0     3     1
     186             :     */
     187       24184 :     _local_node_coor.resize(_num_nodes);
     188       24184 :     _local_node_coor[0] = EFAPoint(0.0, 0.0, 0.0);
     189       24184 :     _local_node_coor[1] = EFAPoint(1.0, 0.0, 0.0);
     190       24184 :     _local_node_coor[2] = EFAPoint(0.0, 1.0, 0.0);
     191             : 
     192       24184 :     if (_num_nodes > 3)
     193             :     {
     194       16664 :       _local_node_coor[3] = EFAPoint(0.5, 0.0, 0.0);
     195       16664 :       _local_node_coor[4] = EFAPoint(0.5, 0.5, 0.0);
     196       16664 :       _local_node_coor[5] = EFAPoint(0.0, 0.5, 0.0);
     197             :     }
     198             : 
     199       24184 :     if (_num_nodes > 6)
     200             :     {
     201        8332 :       _local_node_coor[6] = EFAPoint(1 / 3., 1 / 3., 0.0);
     202             :     }
     203             :   }
     204      394707 : }
     205             : 
     206             : unsigned int
     207     2067148 : EFAElement2D::numFragments() const
     208             : {
     209     2067148 :   return _fragments.size();
     210             : }
     211             : 
     212             : bool
     213     1483694 : EFAElement2D::isPartial() const
     214             : {
     215             :   bool partial = false;
     216     1483694 :   if (_fragments.size() > 0)
     217             :   {
     218     3525904 :     for (unsigned int i = 0; i < _num_edges; ++i)
     219             :     {
     220             :       bool node_in_frag = false;
     221     4471106 :       for (unsigned int j = 0; j < _fragments.size(); ++j)
     222             :       {
     223     3256658 :         if (_fragments[j]->containsNode(_nodes[i]))
     224             :         {
     225             :           node_in_frag = true;
     226             :           break;
     227             :         }
     228             :       } // j
     229     3256658 :       if (!node_in_frag)
     230             :       {
     231             :         partial = true;
     232             :         break;
     233             :       }
     234             :     } // i
     235             :   }
     236     1483694 :   return partial;
     237             : }
     238             : 
     239             : void
     240       20577 : EFAElement2D::getNonPhysicalNodes(std::set<EFANode *> & non_physical_nodes) const
     241             : {
     242             :   // Any nodes that don't belong to any fragment are non-physical
     243             :   // First add all nodes in the element to the set
     244      114393 :   for (unsigned int i = 0; i < _nodes.size(); ++i)
     245       93816 :     non_physical_nodes.insert(_nodes[i]);
     246             : 
     247             :   // Now delete any nodes that are contained in fragments
     248             :   std::set<EFANode *>::iterator sit;
     249      114393 :   for (sit = non_physical_nodes.begin(); sit != non_physical_nodes.end();)
     250             :   {
     251             :     bool erased = false;
     252      146846 :     for (unsigned int i = 0; i < _fragments.size(); ++i)
     253             :     {
     254       93816 :       if (_fragments[i]->containsNode(*sit))
     255             :       {
     256       40786 :         non_physical_nodes.erase(sit++);
     257             :         erased = true;
     258       40786 :         break;
     259             :       }
     260             :     }
     261       93816 :     if (!erased)
     262             :       ++sit;
     263             :   }
     264       20577 : }
     265             : 
     266             : void
     267      393757 : EFAElement2D::switchNode(EFANode * new_node, EFANode * old_node, bool descend_to_parent)
     268             : {
     269             :   // We are not switching any embedded nodes here
     270     2255089 :   for (unsigned int i = 0; i < _num_nodes; ++i)
     271             :   {
     272     1861332 :     if (_nodes[i] == old_node)
     273       19921 :       _nodes[i] = new_node;
     274             :   }
     275      719730 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     276      325973 :     _fragments[i]->switchNode(new_node, old_node);
     277             : 
     278     1892933 :   for (unsigned int i = 0; i < _edges.size(); ++i)
     279     1499176 :     _edges[i]->switchNode(new_node, old_node);
     280             : 
     281      393757 :   if (_parent && descend_to_parent)
     282             :   {
     283       15468 :     _parent->switchNode(new_node, old_node, false);
     284      141337 :     for (unsigned int i = 0; i < _parent->numGeneralNeighbors(); ++i)
     285             :     {
     286      125869 :       EFAElement * neigh_elem = _parent->getGeneralNeighbor(i); // generalized neighbor element
     287      283202 :       for (unsigned int k = 0; k < neigh_elem->numChildren(); ++k)
     288      157333 :         neigh_elem->getChild(k)->switchNode(new_node, old_node, false);
     289             :     }
     290             :   }
     291      393757 : }
     292             : 
     293             : void
     294           0 : EFAElement2D::switchEmbeddedNode(EFANode * new_emb_node, EFANode * old_emb_node)
     295             : {
     296           0 :   for (unsigned int i = 0; i < _num_edges; ++i)
     297           0 :     _edges[i]->switchNode(new_emb_node, old_emb_node);
     298           0 :   for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
     299           0 :     _interior_nodes[i]->switchNode(new_emb_node, old_emb_node);
     300           0 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     301           0 :     _fragments[i]->switchNode(new_emb_node, old_emb_node);
     302           0 : }
     303             : 
     304             : void
     305     4375567 : EFAElement2D::getMasterInfo(EFANode * node,
     306             :                             std::vector<EFANode *> & master_nodes,
     307             :                             std::vector<double> & master_weights) const
     308             : {
     309             :   // Given a EFANode, find the element edge or fragment edge that contains it
     310             :   // Return its master nodes and weights
     311     4375567 :   master_nodes.clear();
     312     4375567 :   master_weights.clear();
     313             :   bool masters_found = false;
     314    11655400 :   for (unsigned int i = 0; i < _num_edges; ++i) // check element exterior edges
     315             :   {
     316    11649178 :     if (_edges[i]->containsNode(node))
     317             :     {
     318     4369345 :       masters_found = _edges[i]->getNodeMasters(node, master_nodes, master_weights);
     319     4369345 :       if (masters_found)
     320             :         break;
     321             :       else
     322           0 :         EFAError("In getMasterInfo: cannot find master nodes in element edges");
     323             :     }
     324             :   }
     325             : 
     326             :   if (!masters_found) // check element interior embedded nodes
     327             :   {
     328        6222 :     for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
     329             :     {
     330        6222 :       if (_interior_nodes[i]->getNode() == node)
     331             :       {
     332        6222 :         std::vector<double> emb_xi(2, 0.0);
     333        6222 :         emb_xi[0] = _interior_nodes[i]->getParametricCoordinates(0);
     334        6222 :         emb_xi[1] = _interior_nodes[i]->getParametricCoordinates(1);
     335       27942 :         for (unsigned int j = 0; j < _num_edges; ++j)
     336             :         {
     337       21720 :           master_nodes.push_back(_nodes[j]);
     338       21720 :           double weight = 0.0;
     339       21720 :           if (_num_edges == 4)
     340       12216 :             weight = Efa::linearQuadShape2D(j, emb_xi);
     341        9504 :           else if (_num_edges == 3)
     342        9504 :             weight = Efa::linearTriShape2D(j, emb_xi);
     343             :           else
     344           0 :             EFAError("unknown 2D element");
     345       21720 :           master_weights.push_back(weight);
     346             :         }
     347             :         masters_found = true;
     348             :         break;
     349        6222 :       }
     350             :     }
     351             :   }
     352             : 
     353     4369345 :   if (!masters_found)
     354           0 :     EFAError("In EFAelement2D::getMaterInfo, cannot find the given EFAnode");
     355     4375567 : }
     356             : 
     357             : unsigned int
     358       40761 : EFAElement2D::numInteriorNodes() const
     359             : {
     360       40761 :   return _interior_nodes.size();
     361             : }
     362             : 
     363             : bool
     364     1384624 : EFAElement2D::overlaysElement(const EFAElement2D * other_elem) const
     365             : {
     366             :   bool overlays = false;
     367             : 
     368     1384624 :   if (other_elem->numEdges() != _num_edges)
     369             :     return overlays;
     370             : 
     371     1384624 :   std::vector<EFANode *> common_nodes = getCommonNodes(other_elem);
     372             : 
     373             :   // Find indices of common nodes
     374     1384624 :   if (common_nodes.size() == 2)
     375             :   {
     376     1383520 :     std::vector<EFANode *> common_nodes_vec(common_nodes.begin(), common_nodes.end());
     377             : 
     378     1383520 :     unsigned int e1n1idx = _num_edges + 1;
     379             :     unsigned int e1n2idx = _num_edges + 1;
     380     6855608 :     for (unsigned int i = 0; i < _num_edges; ++i)
     381             :     {
     382     5472088 :       if (_nodes[i] == common_nodes_vec[0])
     383             :       {
     384             :         e1n1idx = i;
     385             :       }
     386     4088568 :       else if (_nodes[i] == common_nodes_vec[1])
     387             :       {
     388             :         e1n2idx = i;
     389             :       }
     390             :     }
     391             : 
     392     1383520 :     if (e1n1idx > _num_edges || e1n2idx > _num_edges)
     393           0 :       EFAError("in overlays_elem() couldn't find common node");
     394             : 
     395             :     bool e1ascend = false;
     396     1383520 :     unsigned int e1n1idx_plus1(e1n1idx < (_num_edges - 1) ? e1n1idx + 1 : 0);
     397     1383520 :     unsigned int e1n1idx_minus1(e1n1idx > 0 ? e1n1idx - 1 : _num_edges - 1);
     398     1383520 :     if (e1n2idx == e1n1idx_plus1)
     399             :     {
     400             :       e1ascend = true;
     401             :     }
     402             :     else
     403             :     {
     404      691620 :       if (e1n2idx != e1n1idx_minus1)
     405           0 :         EFAError("in overlays_elem() common nodes must be adjacent to each other");
     406             :     }
     407             : 
     408             :     unsigned int e2n1idx = _num_edges + 1;
     409             :     unsigned int e2n2idx = _num_edges + 1;
     410     6855608 :     for (unsigned int i = 0; i < _num_edges; ++i)
     411             :     {
     412     5472088 :       if (other_elem->getNode(i) == common_nodes_vec[0])
     413             :       {
     414             :         e2n1idx = i;
     415             :       }
     416     4088568 :       else if (other_elem->getNode(i) == common_nodes_vec[1])
     417             :       {
     418             :         e2n2idx = i;
     419             :       }
     420             :     }
     421     1383520 :     if (e2n1idx > other_elem->numNodes() || e2n2idx > other_elem->numNodes())
     422           0 :       EFAError("in overlays_elem() couldn't find common node");
     423             : 
     424             :     bool e2ascend = false;
     425     1383520 :     unsigned int e2n1idx_plus1(e2n1idx < (_num_edges - 1) ? e2n1idx + 1 : 0);
     426     1383520 :     unsigned int e2n1idx_minus1(e2n1idx > 0 ? e2n1idx - 1 : _num_edges - 1);
     427     1383520 :     if (e2n2idx == e2n1idx_plus1)
     428             :     {
     429             :       e2ascend = true;
     430             :     }
     431             :     else
     432             :     {
     433      691772 :       if (e2n2idx != e2n1idx_minus1)
     434           0 :         EFAError("in overlays_elem() common nodes must be adjacent to each other");
     435             :     }
     436             : 
     437             :     // if indices both ascend or descend, they overlay
     438     1383520 :     if ((e1ascend && e2ascend) || (!e1ascend && !e2ascend))
     439             :     {
     440             :       overlays = true;
     441             :     }
     442     1383520 :   }
     443        1104 :   else if (common_nodes.size() > 2)
     444             :   {
     445             :     // TODO: We probably need more error checking here.
     446             :     overlays = true;
     447             :   }
     448             :   return overlays;
     449     1384624 : }
     450             : 
     451             : unsigned int
     452       82343 : EFAElement2D::getNeighborIndex(const EFAElement * neighbor_elem) const
     453             : {
     454      211970 :   for (unsigned int i = 0; i < _num_edges; ++i)
     455      343549 :     for (unsigned int j = 0; j < _edge_neighbors[i].size(); ++j)
     456      213922 :       if (_edge_neighbors[i][j] == neighbor_elem)
     457       82343 :         return i;
     458             : 
     459           0 :   EFAError(
     460             :       "in get_neighbor_index() element: ", _id, " does not have neighbor: ", neighbor_elem->id());
     461             : }
     462             : 
     463             : void
     464      385423 : EFAElement2D::clearNeighbors()
     465             : {
     466      385423 :   _general_neighbors.clear();
     467     1904051 :   for (unsigned int edge_iter = 0; edge_iter < _num_edges; ++edge_iter)
     468     1518628 :     _edge_neighbors[edge_iter] = {nullptr};
     469      385423 : }
     470             : 
     471             : void
     472      385423 : EFAElement2D::setupNeighbors(std::map<EFANode *, std::set<EFAElement *>> & inverse_connectivity_map)
     473             : {
     474      385423 :   findGeneralNeighbors(inverse_connectivity_map);
     475     3135301 :   for (unsigned int eit2 = 0; eit2 < _general_neighbors.size(); ++eit2)
     476             :   {
     477     2749878 :     EFAElement2D * neigh_elem = dynamic_cast<EFAElement2D *>(_general_neighbors[eit2]);
     478     2749878 :     if (!neigh_elem)
     479           0 :       EFAError("neighbor_elem is not of EFAelement2D type");
     480             : 
     481     2749878 :     std::vector<EFANode *> common_nodes = getCommonNodes(neigh_elem);
     482     2749878 :     if (common_nodes.size() >= 2)
     483             :     {
     484     6836588 :       for (unsigned int edge_iter = 0; edge_iter < _num_edges; ++edge_iter)
     485             :       {
     486     5456888 :         std::set<EFANode *> edge_nodes = getEdgeNodes(edge_iter);
     487             :         bool is_edge_neighbor = false;
     488             : 
     489             :         // Must share nodes on this edge
     490     5456888 :         if (Efa::numCommonElems(edge_nodes, common_nodes) == 2 && (!overlaysElement(neigh_elem)))
     491             :         {
     492             :           // Fragments must match up.
     493     1375880 :           if ((_fragments.size() > 1) || (neigh_elem->numFragments() > 1))
     494           0 :             EFAError("in updateEdgeNeighbors: Cannot have more than 1 fragment");
     495     1375880 :           else if ((_fragments.size() == 1) && (neigh_elem->numFragments() == 1))
     496             :           {
     497       67698 :             if (_fragments[0]->isConnected(neigh_elem->getFragment(0)))
     498             :               is_edge_neighbor = true;
     499             :           }
     500             :           else // If there are no fragments to match up, consider them neighbors
     501             :             is_edge_neighbor = true;
     502             :         }
     503             : 
     504             :         if (is_edge_neighbor)
     505             :         {
     506     1375880 :           if (_edge_neighbors[edge_iter][0])
     507             :           {
     508        2324 :             if (_edge_neighbors[edge_iter].size() > 1)
     509             :             {
     510           0 :               EFAError("Element ",
     511             :                        _id,
     512             :                        " already has 2 edge neighbors: ",
     513             :                        _edge_neighbors[edge_iter][0]->id(),
     514             :                        " ",
     515             :                        _edge_neighbors[edge_iter][1]->id());
     516             :             }
     517        2324 :             _edge_neighbors[edge_iter].push_back(neigh_elem);
     518             :           }
     519             :           else
     520     1373556 :             _edge_neighbors[edge_iter][0] = neigh_elem;
     521             :         }
     522             :       }
     523             :     }
     524     2749878 :   }
     525      385423 : }
     526             : 
     527             : void
     528      385423 : EFAElement2D::neighborSanityCheck() const
     529             : {
     530     1904051 :   for (unsigned int edge_iter = 0; edge_iter < _num_edges; ++edge_iter)
     531             :   {
     532     3039580 :     for (unsigned int en_iter = 0; en_iter < _edge_neighbors[edge_iter].size(); ++en_iter)
     533             :     {
     534     1520952 :       EFAElement2D * neigh_elem = _edge_neighbors[edge_iter][en_iter];
     535     1520952 :       if (neigh_elem != nullptr)
     536             :       {
     537             :         bool found_neighbor = false;
     538     6817568 :         for (unsigned int edge_iter2 = 0; edge_iter2 < neigh_elem->numEdges(); ++edge_iter2)
     539             :         {
     540     9133600 :           for (unsigned int en_iter2 = 0; en_iter2 < neigh_elem->numEdgeNeighbors(edge_iter2);
     541             :                ++en_iter2)
     542             :           {
     543     5067792 :             if (neigh_elem->getEdgeNeighbor(edge_iter2, en_iter2) == this)
     544             :             {
     545     1375880 :               if ((en_iter2 > 1) && (en_iter > 1))
     546           0 :                 EFAError(
     547             :                     "Element and neighbor element cannot both have >1 neighbors on a common edge");
     548             :               found_neighbor = true;
     549             :               break;
     550             :             }
     551             :           }
     552             :         }
     553     1375880 :         if (!found_neighbor)
     554           0 :           EFAError("Neighbor element doesn't recognize current element as neighbor");
     555             :       }
     556             :     }
     557             :   }
     558      385423 : }
     559             : 
     560             : void
     561      385375 : EFAElement2D::initCrackTip(std::set<EFAElement *> & CrackTipElements)
     562             : {
     563      385375 :   if (isCrackTipElement())
     564             :   {
     565        2048 :     CrackTipElements.insert(this);
     566       10200 :     for (unsigned int edge_iter = 0; edge_iter < _num_edges; ++edge_iter)
     567             :     {
     568        8152 :       if ((_edge_neighbors[edge_iter].size() == 2) && (_edges[edge_iter]->hasIntersection()))
     569             :       {
     570             :         // Neither neighbor overlays current element.  We are on the uncut element ahead of the tip.
     571             :         // Flag neighbors as crack tip split elements and add this element as their crack tip
     572             :         // neighbor.
     573        4096 :         if (_edge_neighbors[edge_iter][0]->overlaysElement(this) ||
     574        2048 :             _edge_neighbors[edge_iter][1]->overlaysElement(this))
     575           0 :           EFAError("Element has a neighbor that overlays itself");
     576             : 
     577             :         // Make sure the current elment hasn't been flagged as a tip element
     578        2048 :         if (_crack_tip_split_element)
     579           0 :           EFAError("crack_tip_split_element already flagged.  In elem: ",
     580             :                    _id,
     581             :                    " flags: ",
     582             :                    _crack_tip_split_element,
     583             :                    " ",
     584             :                    _edge_neighbors[edge_iter][0]->isCrackTipSplit(),
     585             :                    " ",
     586             :                    _edge_neighbors[edge_iter][1]->isCrackTipSplit());
     587             : 
     588        2048 :         _edge_neighbors[edge_iter][0]->setCrackTipSplit();
     589        2048 :         _edge_neighbors[edge_iter][1]->setCrackTipSplit();
     590             : 
     591        2048 :         _edge_neighbors[edge_iter][0]->addCrackTipNeighbor(this);
     592        2048 :         _edge_neighbors[edge_iter][1]->addCrackTipNeighbor(this);
     593             :       }
     594             :     } // edge_iter
     595             :   }
     596      385375 : }
     597             : 
     598             : unsigned int
     599        2011 : EFAElement2D::getCrackTipSplitElementID() const
     600             : {
     601        2011 :   if (isCrackTipElement())
     602             :   {
     603        6092 :     for (unsigned int edge_iter = 0; edge_iter < _num_edges; ++edge_iter)
     604             :     {
     605        6092 :       if ((_edge_neighbors[edge_iter].size() == 2) && (_edges[edge_iter]->hasIntersection()))
     606             :       {
     607        4022 :         if (_edge_neighbors[edge_iter][0] != nullptr &&
     608        2011 :             _edge_neighbors[edge_iter][0]->isCrackTipSplit())
     609             :         {
     610        2011 :           return _edge_neighbors[edge_iter][0]->id();
     611             :         }
     612             :       }
     613             :     }
     614             :   }
     615           0 :   EFAError("In getCrackTipSplitElementID could not find element id");
     616             :   return 0;
     617             : }
     618             : 
     619             : bool
     620      235747 : EFAElement2D::shouldDuplicateForCrackTip(const std::set<EFAElement *> & CrackTipElements)
     621             : {
     622             :   // This method is called in createChildElements()
     623             :   // Only duplicate when
     624             :   // 1) currElem will be a NEW crack tip element
     625             :   // 2) currElem is a crack tip split element at last time step and the tip will extend
     626             :   // 3) currElem is the neighbor of a to-be-second-split element which has another neighbor
     627             :   //    sharing a phantom node with currElem
     628             :   bool should_duplicate = false;
     629      235747 :   if (_fragments.size() == 1)
     630             :   {
     631             :     std::set<EFAElement *>::iterator sit;
     632       33436 :     sit = CrackTipElements.find(this);
     633       33436 :     if (sit == CrackTipElements.end() && isCrackTipElement())
     634             :       should_duplicate = true;
     635       27515 :     else if (shouldDuplicateCrackTipSplitElement(CrackTipElements))
     636             :       should_duplicate = true;
     637       20060 :     else if (shouldDuplicateForPhantomCorner())
     638             :       should_duplicate = true;
     639             :   }
     640      235747 :   return should_duplicate;
     641             : }
     642             : 
     643             : bool
     644       27515 : EFAElement2D::shouldDuplicateCrackTipSplitElement(const std::set<EFAElement *> & CrackTipElements)
     645             : {
     646             :   // Determine whether element at crack tip should be duplicated.  It should be duplicated
     647             :   // if the crack will extend into the next element, or if it has a non-physical node
     648             :   // connected to a face where a crack terminates, but will extend.
     649             : 
     650             :   bool should_duplicate = false;
     651       27515 :   if (_fragments.size() == 1)
     652             :   {
     653             :     std::vector<unsigned int> split_neighbors;
     654       27515 :     if (willCrackTipExtend(split_neighbors))
     655             :       should_duplicate = true;
     656             :     else
     657             :     {
     658             :       // The element may not be at the crack tip, but could have a non-physical node
     659             :       // connected to a crack tip face (on a neighbor element) that will be split.  We need to
     660             :       // duplicate in that case as well.
     661             :       std::set<EFANode *> non_physical_nodes;
     662       20577 :       getNonPhysicalNodes(non_physical_nodes);
     663             : 
     664      138212 :       for (unsigned int eit = 0; eit < _general_neighbors.size(); ++eit)
     665             :       {
     666      118152 :         EFAElement2D * neigh_elem = dynamic_cast<EFAElement2D *>(_general_neighbors[eit]);
     667      118152 :         if (!neigh_elem)
     668           0 :           EFAError("general elem is not of type EFAelement2D");
     669             : 
     670             :         // check if a general neighbor is an old crack tip element and will be split
     671             :         std::set<EFAElement *>::iterator sit;
     672      118152 :         sit = CrackTipElements.find(neigh_elem);
     673      118152 :         if (sit != CrackTipElements.end() && neigh_elem->numFragments() > 1)
     674             :         {
     675        1455 :           for (unsigned int i = 0; i < neigh_elem->numEdges(); ++i)
     676             :           {
     677        1398 :             std::set<EFANode *> neigh_edge_nodes = neigh_elem->getEdgeNodes(i);
     678        1972 :             if (neigh_elem->numEdgeNeighbors(i) == 2 &&
     679         574 :                 Efa::numCommonElems(neigh_edge_nodes, non_physical_nodes) > 0)
     680             :             {
     681             :               should_duplicate = true;
     682             :               break;
     683             :             }
     684             :           } // i
     685             :         }
     686             :         if (should_duplicate)
     687             :           break;
     688             :       } // eit
     689             :     }
     690       27515 :   } // IF one fragment
     691       27515 :   return should_duplicate;
     692             : }
     693             : 
     694             : bool
     695       20060 : EFAElement2D::shouldDuplicateForPhantomCorner()
     696             : {
     697             :   // if a partial element will be split for a second time and it has two neighbor elements
     698             :   // sharing one phantom node with the aforementioned partial element, then the two neighbor
     699             :   // elements should be duplicated
     700             :   bool should_duplicate = false;
     701       20060 :   if (_fragments.size() == 1 && (!_crack_tip_split_element))
     702             :   {
     703       88098 :     for (unsigned int i = 0; i < _num_edges; ++i)
     704             :     {
     705       70132 :       std::set<EFANode *> phantom_nodes = getPhantomNodeOnEdge(i);
     706       70132 :       if (phantom_nodes.size() > 0 && numEdgeNeighbors(i) == 1)
     707             :       {
     708       32511 :         EFAElement2D * neighbor_elem = _edge_neighbors[i][0];
     709       32511 :         if (neighbor_elem->numFragments() > 1) // neighbor will be split
     710             :         {
     711        1480 :           for (unsigned int j = 0; j < neighbor_elem->numEdges(); ++j)
     712             :           {
     713        2628 :             if (!neighbor_elem->getEdge(j)->equivalent(*_edges[i]) &&
     714        1152 :                 neighbor_elem->numEdgeNeighbors(j) > 0)
     715             :             {
     716        1148 :               std::set<EFANode *> neigh_phantom_nodes = neighbor_elem->getPhantomNodeOnEdge(j);
     717        1148 :               if (Efa::numCommonElems(phantom_nodes, neigh_phantom_nodes) > 0)
     718             :               {
     719             :                 should_duplicate = true;
     720             :                 break;
     721             :               }
     722             :             }
     723             :           } // j
     724             :         }
     725             :       }
     726             :       if (should_duplicate)
     727             :         break;
     728             :     } // i
     729             :   }
     730       20060 :   return should_duplicate;
     731             : }
     732             : 
     733             : bool
     734       27515 : EFAElement2D::willCrackTipExtend(std::vector<unsigned int> & split_neighbors) const
     735             : {
     736             :   // Determine whether the current element is a crack tip element for which the crack will
     737             :   // extend into the next element.
     738             :   // N.B. this is called at the beginning of createChildElements
     739             :   bool will_extend = false;
     740       27515 :   if (_fragments.size() == 1 && _crack_tip_split_element)
     741             :   {
     742       17076 :     for (unsigned int i = 0; i < _crack_tip_neighbors.size(); ++i)
     743             :     {
     744        8684 :       unsigned int neigh_idx = _crack_tip_neighbors[i];
     745        8684 :       if (numEdgeNeighbors(neigh_idx) != 1)
     746           0 :         EFAError("in will_crack_tip_extend() element: ",
     747             :                  _id,
     748             :                  " has: ",
     749             :                  _edge_neighbors[neigh_idx].size(),
     750             :                  " on edge: ",
     751             :                  neigh_idx);
     752             : 
     753        8684 :       EFAElement2D * neighbor_elem = _edge_neighbors[neigh_idx][0];
     754        8684 :       if (neighbor_elem->numFragments() > 2)
     755           0 :         EFAError("in will_crack_tip_extend() element: ",
     756             :                  neighbor_elem->id(),
     757             :                  " has: ",
     758             :                  neighbor_elem->numFragments(),
     759             :                  " fragments");
     760        8684 :       else if (neighbor_elem->numFragments() == 2)
     761             :       {
     762        7082 :         EFAFragment2D * frag1 = neighbor_elem->getFragment(0);
     763        7082 :         EFAFragment2D * frag2 = neighbor_elem->getFragment(1);
     764        7082 :         std::vector<EFANode *> neigh_cut_nodes = frag1->getCommonNodes(frag2);
     765        7082 :         if (neigh_cut_nodes.size() != 2)
     766           0 :           EFAError("2 frags in a elem does not share 2 common nodes");
     767       10868 :         if (_edges[neigh_idx]->isEmbeddedNode(neigh_cut_nodes[0]) ||
     768        3786 :             _edges[neigh_idx]->isEmbeddedNode(neigh_cut_nodes[1]))
     769             :         {
     770        7082 :           split_neighbors.push_back(neigh_idx);
     771             :           will_extend = true;
     772             :         }
     773        7082 :       }
     774             :     } // i
     775             :   }
     776       27515 :   return will_extend;
     777             : }
     778             : 
     779             : bool
     780      429394 : EFAElement2D::isCrackTipElement() const
     781             : {
     782      429394 :   return fragmentHasTipEdges();
     783             : }
     784             : 
     785             : unsigned int
     786       36295 : EFAElement2D::getNumCuts() const
     787             : {
     788             :   unsigned int num_cuts = 0;
     789      176467 :   for (unsigned int i = 0; i < _num_edges; ++i)
     790      140172 :     if (_edges[i]->hasIntersection())
     791           0 :       num_cuts += _edges[i]->numEmbeddedNodes();
     792       36295 :   return num_cuts;
     793             : }
     794             : 
     795             : bool
     796      193983 : EFAElement2D::isFinalCut() const
     797             : {
     798             :   // if an element has been cut twice its fragment must have two interior edges
     799             :   bool cut_twice = false;
     800      193983 :   if (_fragments.size() > 0)
     801             :   {
     802             :     unsigned int num_interior_edges = 0;
     803       83012 :     for (unsigned int i = 0; i < _fragments[0]->numEdges(); ++i)
     804             :     {
     805       66261 :       if (_fragments[0]->isEdgeInterior(i))
     806       15800 :         num_interior_edges += 1;
     807             :     }
     808       16751 :     if (num_interior_edges == 2)
     809             :       cut_twice = true;
     810             :   }
     811      193983 :   return cut_twice;
     812             : }
     813             : 
     814             : void
     815      226846 : EFAElement2D::updateFragments(const std::set<EFAElement *> & CrackTipElements,
     816             :                               std::map<unsigned int, EFANode *> & EmbeddedNodes)
     817             : {
     818             :   // combine the crack-tip edges in a fragment to a single intersected edge
     819             :   std::set<EFAElement *>::iterator sit;
     820      226846 :   sit = CrackTipElements.find(this);
     821      226846 :   if (sit != CrackTipElements.end()) // curr_elem is a crack tip element
     822             :   {
     823        1181 :     if (_fragments.size() == 1)
     824        1181 :       _fragments[0]->combineTipEdges();
     825             :     else
     826           0 :       EFAError("crack tip elem ", _id, " must have 1 fragment");
     827             :   }
     828             : 
     829             :   // if a fragment only has 1 intersection which is in an interior edge
     830             :   // remove this embedded node (MUST DO THIS AFTER combine_tip_edges())
     831      226846 :   if (_fragments.size() == 1)
     832       20453 :     _fragments[0]->removeInvalidEmbeddedNodes(EmbeddedNodes);
     833             : 
     834             :   // for an element with no fragment, create one fragment identical to the element
     835      226846 :   if (_fragments.size() == 0)
     836      206393 :     _fragments.push_back(new EFAFragment2D(this, true, this));
     837      226846 :   if (_fragments.size() != 1)
     838           0 :     EFAError("Element ", _id, " must have 1 fragment at this point");
     839             : 
     840             :   // count fragment's cut edges
     841      226846 :   unsigned int num_cut_frag_edges = _fragments[0]->getNumCuts();
     842      226846 :   unsigned int num_cut_nodes = _fragments[0]->getNumCutNodes();
     843      226846 :   unsigned int num_frag_edges = _fragments[0]->numEdges();
     844      226846 :   if (num_cut_frag_edges > 3)
     845           0 :     EFAError("In element ", _id, " there are more than 2 cut fragment edges");
     846             : 
     847      226846 :   if (num_cut_frag_edges == 0 && num_cut_nodes == 0)
     848             :   {
     849      221415 :     if (!isPartial()) // delete the temp frag for an uncut elem
     850             :     {
     851      202311 :       delete _fragments[0];
     852      202311 :       _fragments.clear();
     853             :     }
     854             :     // Element has already been cut. Don't recreate fragments because we
     855             :     // would create multiple fragments to cover the entire element and
     856             :     // lose the information about what part of this element is physical.
     857      221415 :     return;
     858             :   }
     859             : 
     860             :   // split one fragment into one, two or three new fragments
     861             :   std::vector<EFAFragment2D *> new_frags;
     862        5431 :   if (num_cut_frag_edges == 3)
     863           2 :     new_frags = branchingSplit(EmbeddedNodes);
     864             :   else
     865       10860 :     new_frags = _fragments[0]->split();
     866             : 
     867        5431 :   delete _fragments[0]; // delete the old fragment
     868        5431 :   _fragments.clear();
     869       14757 :   for (unsigned int i = 0; i < new_frags.size(); ++i)
     870        9326 :     _fragments.push_back(new_frags[i]);
     871             : 
     872        5431 :   fragmentSanityCheck(num_frag_edges, num_cut_frag_edges);
     873        5431 : }
     874             : 
     875             : void
     876        5431 : EFAElement2D::fragmentSanityCheck(unsigned int n_old_frag_edges, unsigned int n_old_frag_cuts) const
     877             : {
     878        5431 :   if (n_old_frag_cuts > 3)
     879           0 :     EFAError("Sanity check: in element ", _id, " frag has more than 3 cut edges");
     880             : 
     881             :   // count permanent and embedded nodes for new fragments
     882             :   std::vector<unsigned int> num_emb;
     883             :   std::vector<unsigned int> num_perm;
     884             :   std::vector<unsigned int> num_emb_perm;
     885       14757 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     886             :   {
     887        9326 :     num_emb.push_back(0);
     888        9326 :     num_perm.push_back(0);
     889        9326 :     num_emb_perm.push_back(0);
     890             :     std::set<EFANode *> perm_nodes;
     891             :     std::set<EFANode *> emb_nodes;
     892             :     std::set<EFANode *> emb_perm_nodes;
     893       47500 :     for (unsigned int j = 0; j < _fragments[i]->numEdges(); ++j)
     894             :     {
     895      114522 :       for (unsigned int k = 0; k < 2; ++k)
     896             :       {
     897       76348 :         EFANode * temp_node = _fragments[i]->getEdge(j)->getNode(k);
     898       76348 :         if (temp_node->category() == EFANode::N_CATEGORY_PERMANENT)
     899       41844 :           perm_nodes.insert(temp_node);
     900       34504 :         else if (temp_node->category() == EFANode::N_CATEGORY_EMBEDDED)
     901       34024 :           emb_nodes.insert(temp_node);
     902         480 :         else if (temp_node->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
     903         480 :           emb_perm_nodes.insert(temp_node);
     904             :         else
     905           0 :           EFAError("Invalid node category");
     906             :       }
     907             :     }
     908        9326 :     num_perm[i] = perm_nodes.size();
     909        9326 :     num_emb[i] = emb_nodes.size();
     910        9326 :     num_emb_perm[i] = emb_perm_nodes.size();
     911             :   }
     912             : 
     913             :   // TODO: For cut-node case, how to check fragment sanity
     914       14605 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     915        9302 :     if (num_emb_perm[i] != 0)
     916             :       return;
     917             : 
     918        5303 :   unsigned int n_interior_nodes = numInteriorNodes();
     919        5303 :   if (n_interior_nodes > 0 && n_interior_nodes != 1)
     920           0 :     EFAError("After update_fragments this element has ", n_interior_nodes, " interior nodes");
     921             : 
     922        5303 :   if (n_old_frag_cuts == 0)
     923             :   {
     924           0 :     if (_fragments.size() != 1 || _fragments[0]->numEdges() != n_old_frag_edges)
     925           0 :       EFAError("Incorrect link size for element with 0 cuts");
     926             :   }
     927        5303 :   else if (n_old_frag_cuts == 1) // crack tip case
     928             :   {
     929        1433 :     if (_fragments.size() != 1 || _fragments[0]->numEdges() != n_old_frag_edges + 1)
     930           0 :       EFAError("Incorrect link size for element with 1 cut");
     931             :   }
     932        3870 :   else if (n_old_frag_cuts == 2)
     933             :   {
     934        3869 :     if (_fragments.size() != 2 ||
     935        3869 :         (_fragments[0]->numEdges() + _fragments[1]->numEdges()) != n_old_frag_edges + 4)
     936           0 :       EFAError("Incorrect link size for element with 2 cuts");
     937             :   }
     938             :   else if (n_old_frag_cuts == 3)
     939             :   {
     940           1 :     if (_fragments.size() != 3 || (_fragments[0]->numEdges() + _fragments[1]->numEdges() +
     941           1 :                                    _fragments[2]->numEdges()) != n_old_frag_edges + 9)
     942           0 :       EFAError("Incorrect link size for element with 3 cuts");
     943             :   }
     944             :   else
     945             :     EFAError("Unexpected number of old fragment cuts");
     946        5431 : }
     947             : 
     948             : void
     949       36295 : EFAElement2D::restoreFragment(const EFAElement * const from_elem)
     950             : {
     951       36295 :   const EFAElement2D * from_elem2d = dynamic_cast<const EFAElement2D *>(from_elem);
     952       36295 :   if (!from_elem2d)
     953           0 :     EFAError("from_elem is not of EFAelement2D type");
     954             : 
     955             :   // restore fragments
     956       36295 :   if (_fragments.size() != 0)
     957           0 :     EFAError("in restoreFragmentInfo elements must not have any pre-existing fragments");
     958       72590 :   for (unsigned int i = 0; i < from_elem2d->numFragments(); ++i)
     959       36295 :     _fragments.push_back(new EFAFragment2D(this, true, from_elem2d, i));
     960             : 
     961             :   // restore interior nodes
     962       36295 :   if (_interior_nodes.size() != 0)
     963           0 :     EFAError("in restoreFragmentInfo elements must not have any pre-exsiting interior nodes");
     964       36439 :   for (unsigned int i = 0; i < from_elem2d->_interior_nodes.size(); ++i)
     965         144 :     _interior_nodes.push_back(new EFAFaceNode(*from_elem2d->_interior_nodes[i]));
     966             : 
     967             :   // restore edge intersections
     968       36295 :   if (getNumCuts() != 0)
     969           0 :     EFAError("In restoreEdgeIntersection: edge cuts already exist in element ", _id);
     970      176467 :   for (unsigned int i = 0; i < _num_edges; ++i)
     971             :   {
     972      140172 :     if (from_elem2d->_edges[i]->hasIntersection())
     973       69899 :       _edges[i]->copyIntersection(*from_elem2d->_edges[i], 0);
     974      140172 :     if (_edges[i]->numEmbeddedNodes() > 2)
     975           0 :       EFAError("elem ", _id, " has an edge with >2 cuts");
     976             :   }
     977             : 
     978             :   // replace all local nodes with global nodes
     979      196503 :   for (unsigned int i = 0; i < from_elem2d->numNodes(); ++i)
     980             :   {
     981      160208 :     if (from_elem2d->_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
     982      160208 :       switchNode(
     983             :           _nodes[i], from_elem2d->_nodes[i], false); // EFAelement is not a child of any parent
     984             :     else
     985           0 :       EFAError("In restoreFragmentInfo all of from_elem's nodes must be local");
     986             :   }
     987       36295 : }
     988             : 
     989             : void
     990      226849 : EFAElement2D::createChild(const std::set<EFAElement *> & CrackTipElements,
     991             :                           std::map<unsigned int, EFAElement *> & Elements,
     992             :                           std::map<unsigned int, EFAElement *> & newChildElements,
     993             :                           std::vector<EFAElement *> & ChildElements,
     994             :                           std::vector<EFAElement *> & ParentElements,
     995             :                           std::map<unsigned int, EFANode *> & TempNodes)
     996             : {
     997      226849 :   if (_children.size() != 0)
     998           0 :     EFAError("Element cannot have existing children in createChildElements");
     999             : 
    1000             :   bool shouldDuplicateForCutNodeElement = false;
    1001     1176941 :   for (unsigned int j = 0; j < _num_nodes; ++j)
    1002             :   {
    1003      950092 :     if (_nodes[j]->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
    1004             :       shouldDuplicateForCutNodeElement = true;
    1005             :   }
    1006             : 
    1007      226849 :   if (_fragments.size() > 1 || shouldDuplicateForCrackTip(CrackTipElements) ||
    1008             :       shouldDuplicateForCutNodeElement)
    1009             :   {
    1010        5478 :     if (_fragments.size() > 3)
    1011           0 :       EFAError("More than 3 fragments not yet supported");
    1012             : 
    1013             :     // set up the children
    1014        5478 :     ParentElements.push_back(this);
    1015       14851 :     for (unsigned int ichild = 0; ichild < _fragments.size(); ++ichild)
    1016             :     {
    1017             :       unsigned int new_elem_id;
    1018        9373 :       if (newChildElements.size() == 0)
    1019         871 :         new_elem_id = Efa::getNewID(Elements);
    1020             :       else
    1021        8502 :         new_elem_id = Efa::getNewID(newChildElements);
    1022             : 
    1023        9373 :       EFAElement2D * childElem = new EFAElement2D(new_elem_id, this->numNodes());
    1024        9373 :       newChildElements.insert(std::make_pair(new_elem_id, childElem));
    1025             : 
    1026        9373 :       ChildElements.push_back(childElem);
    1027        9373 :       childElem->setParent(this);
    1028        9373 :       _children.push_back(childElem);
    1029             : 
    1030             :       std::vector<EFAPoint> local_embedded_node_coor;
    1031             : 
    1032       46854 :       for (unsigned int i = 0; i < this->getFragment(ichild)->numEdges(); ++i)
    1033             :       {
    1034       37481 :         if (this->getFragment(ichild)->isEdgeInterior(i))
    1035             :         {
    1036             :           std::vector<EFANode *> master_nodes;
    1037             :           std::vector<double> master_weights;
    1038             : 
    1039       26118 :           for (unsigned int j = 0; j < 2; ++j)
    1040             :           {
    1041       17412 :             this->getMasterInfo(
    1042             :                 this->getFragmentEdge(ichild, i)->getNode(j), master_nodes, master_weights);
    1043       17412 :             EFAPoint coor(0.0, 0.0, 0.0);
    1044       52336 :             for (unsigned int k = 0; k < master_nodes.size(); ++k)
    1045             :             {
    1046       34924 :               EFANode * local = this->createLocalNodeFromGlobalNode(master_nodes[k]);
    1047       34924 :               coor += _local_node_coor[local->id()] * master_weights[k];
    1048       34924 :               delete local;
    1049             :             }
    1050       17412 :             local_embedded_node_coor.push_back(coor);
    1051             :           }
    1052        8706 :         }
    1053             :       }
    1054             : 
    1055        9373 :       EFAPoint normal(0.0, 0.0, 0.0);
    1056        9373 :       EFAPoint origin(0.0, 0.0, 0.0);
    1057        9373 :       EFAPoint normal2(0.0, 0.0, 0.0);
    1058        9373 :       EFAPoint origin2(0.0, 0.0, 0.0);
    1059             : 
    1060        9373 :       if (local_embedded_node_coor.size())
    1061             :       {
    1062        8637 :         EFAPoint cut_line = local_embedded_node_coor[1] - local_embedded_node_coor[0];
    1063        8637 :         normal = EFAPoint(cut_line(1), -cut_line(0), 0.0);
    1064        8637 :         Xfem::normalizePoint(normal);
    1065        8637 :         origin = (local_embedded_node_coor[0] + local_embedded_node_coor[1]) * 0.5;
    1066             :       }
    1067             : 
    1068        9373 :       if (local_embedded_node_coor.size() == 4)
    1069             :       {
    1070          69 :         EFAPoint cut_line = local_embedded_node_coor[3] - local_embedded_node_coor[2];
    1071          69 :         normal2 = EFAPoint(cut_line(1), -cut_line(0), 0.0);
    1072          69 :         Xfem::normalizePoint(normal2);
    1073          69 :         origin2 = (local_embedded_node_coor[2] + local_embedded_node_coor[3]) * 0.5;
    1074             :       }
    1075             : 
    1076             :       // get child element's nodes
    1077       50509 :       for (unsigned int j = 0; j < _num_nodes; ++j)
    1078             :       {
    1079       41136 :         EFAPoint p(0.0, 0.0, 0.0);
    1080       41136 :         p = _local_node_coor[j];
    1081             : 
    1082       41136 :         EFAPoint origin_to_point = p - origin;
    1083       41136 :         EFAPoint origin2_to_point = p - origin2;
    1084             : 
    1085       47820 :         if (_fragments.size() == 1 &&
    1086        6684 :             _nodes[j]->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT) // create temp node for
    1087             :                                                                              // embedded permanent
    1088             :                                                                              // node
    1089             :         {
    1090         160 :           unsigned int new_node_id = Efa::getNewID(TempNodes);
    1091         160 :           EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
    1092         160 :           TempNodes.insert(std::make_pair(new_node_id, newNode));
    1093         160 :           childElem->setNode(j, newNode); // be a temp node
    1094             :         }
    1095       40976 :         else if (_fragments.size() == 1 && !shouldDuplicateForCrackTip(CrackTipElements))
    1096             :         {
    1097         256 :           childElem->setNode(j, _nodes[j]); // inherit parent's node
    1098             :         }
    1099       40720 :         else if (std::abs(origin_to_point * normal) < Xfem::tol &&
    1100             :                  _fragments.size() > 1) // cut through node case
    1101             :         {
    1102          80 :           unsigned int new_node_id = Efa::getNewID(TempNodes);
    1103          80 :           EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
    1104          80 :           TempNodes.insert(std::make_pair(new_node_id, newNode));
    1105          80 :           childElem->setNode(j, newNode); // be a temp node
    1106             :         }
    1107       40640 :         else if (origin_to_point * normal < Xfem::tol && origin2_to_point * normal2 < Xfem::tol &&
    1108        4321 :                  (_fragments.size() > 1 || shouldDuplicateForCrackTip(CrackTipElements)))
    1109             :         {
    1110       21433 :           childElem->setNode(j, _nodes[j]); // inherit parent's node
    1111             :         }
    1112       19207 :         else if (normal.norm() < Xfem::tol && normal2.norm() < Xfem::tol &&
    1113             :                  _fragments.size() == 1) // cut along edge case
    1114             :         {
    1115           0 :           childElem->setNode(j, _nodes[j]); // inherit parent's node
    1116             :         }
    1117       21154 :         else if ((_fragments.size() > 1 ||
    1118        1947 :                   shouldDuplicateForCrackTip(
    1119             :                       CrackTipElements))) // parent element's node is not in fragment
    1120             :         {
    1121       19207 :           unsigned int new_node_id = Efa::getNewID(TempNodes);
    1122       19207 :           EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
    1123       19207 :           TempNodes.insert(std::make_pair(new_node_id, newNode));
    1124       19207 :           childElem->setNode(j, newNode); // be a temp node
    1125             :         }
    1126             :       }
    1127             : 
    1128             :       // get child element's fragments
    1129        9373 :       EFAFragment2D * new_frag = new EFAFragment2D(childElem, true, this, ichild);
    1130        9373 :       childElem->_fragments.push_back(new_frag);
    1131             : 
    1132             :       // get child element's edges
    1133       45745 :       for (unsigned int j = 0; j < _num_edges; ++j)
    1134             :       {
    1135       36372 :         unsigned int jplus1(j < (_num_edges - 1) ? j + 1 : 0);
    1136       36372 :         EFAEdge * new_edge = new EFAEdge(childElem->getNode(j), childElem->getNode(jplus1));
    1137       36372 :         if (_edges[j]->hasIntersection())
    1138       17882 :           new_edge->copyIntersection(*_edges[j], 0);
    1139       36372 :         if ((_num_edges == 4 && _num_nodes > 4) || (_num_edges == 3 && _num_nodes > 3))
    1140        4136 :           new_edge->setInteriorNode(childElem->getNode(_num_edges + j));
    1141       36372 :         childElem->setEdge(j, new_edge);
    1142             :       }
    1143        9373 :       childElem->removePhantomEmbeddedNode(); // IMPORTANT
    1144             : 
    1145             :       // inherit old interior nodes
    1146        9430 :       for (unsigned int j = 0; j < _interior_nodes.size(); ++j)
    1147          57 :         childElem->_interior_nodes.push_back(new EFAFaceNode(*_interior_nodes[j]));
    1148        9373 :     }
    1149             :   }
    1150             :   else // num_links == 1 || num_links == 0
    1151             :     // child is itself - but don't insert into the list of ChildElements!!!
    1152      221371 :     _children.push_back(this);
    1153      226849 : }
    1154             : 
    1155             : void
    1156        9373 : EFAElement2D::removePhantomEmbeddedNode()
    1157             : {
    1158             :   // remove the embedded nodes on edge that are not inside the real part
    1159        9373 :   if (_fragments.size() > 0)
    1160             :   {
    1161       45745 :     for (unsigned int i = 0; i < _num_edges; ++i)
    1162             :     {
    1163             :       std::vector<EFANode *> nodes_to_delete;
    1164       54302 :       for (unsigned int j = 0; j < _edges[i]->numEmbeddedNodes(); ++j)
    1165             :       {
    1166       17930 :         if (!_fragments[0]->containsNode(_edges[i]->getEmbeddedNode(j)))
    1167          79 :           nodes_to_delete.push_back(_edges[i]->getEmbeddedNode(j));
    1168             :       }
    1169       36451 :       for (unsigned int j = 0; j < nodes_to_delete.size(); ++j)
    1170          79 :         _edges[i]->removeEmbeddedNode(nodes_to_delete[j]);
    1171       36372 :     } // i
    1172             :   }
    1173        9373 : }
    1174             : 
    1175             : void
    1176        9373 : EFAElement2D::connectNeighbors(std::map<unsigned int, EFANode *> & PermanentNodes,
    1177             :                                std::map<unsigned int, EFANode *> & TempNodes,
    1178             :                                std::map<EFANode *, std::set<EFAElement *>> & InverseConnectivityMap,
    1179             :                                bool merge_phantom_edges)
    1180             : {
    1181             :   // N.B. "this" must point to a child element that was just created
    1182        9373 :   if (!_parent)
    1183           0 :     EFAError("no parent element for child element ", _id, " in connect_neighbors");
    1184        9373 :   EFAElement2D * parent2d = dynamic_cast<EFAElement2D *>(_parent);
    1185        9373 :   if (!parent2d)
    1186           0 :     EFAError("cannot dynamic cast to parent2d in connect_neighbors");
    1187             : 
    1188             :   // First loop through edges and merge nodes with neighbors as appropriate
    1189       45745 :   for (unsigned int j = 0; j < _num_edges; ++j)
    1190             :   {
    1191       69596 :     for (unsigned int k = 0; k < parent2d->numEdgeNeighbors(j); ++k)
    1192             :     {
    1193       33224 :       EFAElement2D * NeighborElem = parent2d->getEdgeNeighbor(j, k);
    1194       33224 :       unsigned int neighbor_edge_id = NeighborElem->getNeighborIndex(parent2d);
    1195             : 
    1196       33224 :       if (_edges[j]->hasIntersection())
    1197             :       {
    1198       45877 :         for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
    1199             :         {
    1200             :           EFAElement2D * childOfNeighborElem =
    1201       29271 :               dynamic_cast<EFAElement2D *>(NeighborElem->getChild(l));
    1202       29271 :           if (!childOfNeighborElem)
    1203           0 :             EFAError("dynamic cast childOfNeighborElem fails");
    1204             : 
    1205             :           // Check to see if the nodes are already merged.  There's nothing else to do in that case.
    1206       29271 :           EFAEdge * neighborChildEdge = childOfNeighborElem->getEdge(neighbor_edge_id);
    1207       29271 :           if (_edges[j]->equivalent(*neighborChildEdge))
    1208        7828 :             continue;
    1209             : 
    1210       21443 :           if (_fragments[0]->isConnected(childOfNeighborElem->getFragment(0)))
    1211             :           {
    1212             :             unsigned int num_edge_nodes = 2;
    1213       25575 :             for (unsigned int i = 0; i < num_edge_nodes; ++i)
    1214             :             {
    1215             :               unsigned int childNodeIndex = i;
    1216       17050 :               unsigned int neighborChildNodeIndex = num_edge_nodes - 1 - childNodeIndex;
    1217             : 
    1218       17050 :               EFANode * childNode = _edges[j]->getNode(childNodeIndex);
    1219       17050 :               EFANode * childOfNeighborNode = neighborChildEdge->getNode(neighborChildNodeIndex);
    1220             : 
    1221       17050 :               mergeNodes(
    1222             :                   childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
    1223             :             }
    1224             : 
    1225        8525 :             EFANode * childNode = _edges[j]->getInteriorNode();
    1226        8525 :             EFANode * childOfNeighborNode = neighborChildEdge->getInteriorNode();
    1227             : 
    1228        8525 :             mergeNodes(
    1229             :                 childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
    1230             :           }
    1231             :         } // l, loop over NeighborElem's children
    1232             :       }
    1233             :       else // No edge intersection -- optionally merge non-material nodes if they share a common
    1234             :            // parent
    1235             :       {
    1236       16618 :         if (merge_phantom_edges)
    1237             :         {
    1238       33229 :           for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
    1239             :           {
    1240             :             EFAElement2D * childOfNeighborElem =
    1241       16618 :                 dynamic_cast<EFAElement2D *>(NeighborElem->getChild(l));
    1242       16618 :             if (!childOfNeighborElem)
    1243           0 :               EFAError("dynamic cast childOfNeighborElem fails");
    1244             : 
    1245       16618 :             EFAEdge * neighborChildEdge = childOfNeighborElem->getEdge(neighbor_edge_id);
    1246       16618 :             if (!neighborChildEdge->hasIntersection()) // neighbor edge must NOT have
    1247             :                                                        // intersection either
    1248             :             {
    1249             :               // Check to see if the nodes are already merged.  There's nothing else to do in that
    1250             :               // case.
    1251             :               unsigned int num_edge_nodes = 2;
    1252       49680 :               for (unsigned int i = 0; i < num_edge_nodes; ++i)
    1253             :               {
    1254             :                 unsigned int childNodeIndex = i;
    1255       33120 :                 unsigned int neighborChildNodeIndex = num_edge_nodes - 1 - childNodeIndex;
    1256             : 
    1257       33120 :                 EFANode * childNode = _edges[j]->getNode(childNodeIndex);
    1258       33120 :                 EFANode * childOfNeighborNode = neighborChildEdge->getNode(neighborChildNodeIndex);
    1259             : 
    1260       45921 :                 if (childNode->parent() != nullptr &&
    1261       12801 :                     childNode->parent() ==
    1262             :                         childOfNeighborNode
    1263       12801 :                             ->parent()) // non-material node and both come from same parent
    1264           4 :                   mergeNodes(childNode,
    1265             :                              childOfNeighborNode,
    1266             :                              childOfNeighborElem,
    1267             :                              PermanentNodes,
    1268             :                              TempNodes);
    1269             :               } // i
    1270             :             }
    1271             :           } // loop over NeighborElem's children
    1272             :         }   // if (merge_phantom_edges)
    1273             :       }     // IF edge-j has_intersection()
    1274             :     }       // k, loop over neighbors on edge j
    1275             :   }         // j, loop over all edges
    1276             : 
    1277             :   // Now do a second loop through edges and convert remaining nodes to permanent nodes.
    1278             :   // Important: temp nodes are not shared by any neighbor, so no need to switch nodes on neighbors
    1279       50509 :   for (unsigned int j = 0; j < _num_nodes; ++j)
    1280             :   {
    1281       41136 :     EFANode * childNode = _nodes[j];
    1282       41136 :     if (childNode->category() == EFANode::N_CATEGORY_TEMP)
    1283             :     {
    1284             :       // if current child element does not have siblings, and if current temp node is a lone one
    1285             :       // this temp node should be merged back to its parent permanent node. Otherwise we would have
    1286             :       // permanent nodes that are not connected to any element
    1287        4204 :       std::set<EFAElement *> patch_elems = InverseConnectivityMap[childNode->parent()];
    1288        4204 :       if (parent2d->numFragments() == 1 && patch_elems.size() == 1)
    1289         301 :         switchNode(childNode->parent(), childNode, false);
    1290             :       else
    1291             :       {
    1292        3903 :         unsigned int new_node_id = Efa::getNewID(PermanentNodes);
    1293             :         EFANode * newNode =
    1294        3903 :             new EFANode(new_node_id, EFANode::N_CATEGORY_PERMANENT, childNode->parent());
    1295        3903 :         PermanentNodes.insert(std::make_pair(new_node_id, newNode));
    1296        3903 :         switchNode(newNode, childNode, false);
    1297             :       }
    1298        4204 :       if (!Efa::deleteFromMap(TempNodes, childNode))
    1299           0 :         EFAError(
    1300             :             "Attempted to delete node: ", childNode->id(), " from TempNodes, but couldn't find it");
    1301             :     }
    1302             :   }
    1303        9373 : }
    1304             : 
    1305             : void
    1306        9373 : EFAElement2D::updateFragmentNode()
    1307             : {
    1308       50509 :   for (unsigned int j = 0; j < _num_nodes; ++j)
    1309             :   {
    1310       58188 :     if (_nodes[j]->parent() != nullptr &&
    1311       17052 :         _nodes[j]->parent()->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
    1312         240 :       switchNode(_nodes[j], _nodes[j]->parent(), false);
    1313             :   }
    1314        9373 : }
    1315             : 
    1316             : void
    1317         603 : EFAElement2D::printElement(std::ostream & ostream) const
    1318             : {
    1319             :   ostream << std::setw(4);
    1320         603 :   ostream << _id << " | ";
    1321        3015 :   for (unsigned int j = 0; j < _num_nodes; ++j)
    1322             :   {
    1323        4824 :     ostream << std::setw(5) << _nodes[j]->idCatString();
    1324             :   }
    1325             : 
    1326         603 :   ostream << "  | ";
    1327        3015 :   for (unsigned int j = 0; j < _num_edges; ++j)
    1328             :   {
    1329             :     ostream << std::setw(4);
    1330        2412 :     if (_edges[j]->hasIntersection())
    1331             :     {
    1332         579 :       if (_edges[j]->numEmbeddedNodes() > 1)
    1333             :       {
    1334           0 :         ostream << "[";
    1335           0 :         for (unsigned int k = 0; k < _edges[j]->numEmbeddedNodes(); ++k)
    1336             :         {
    1337           0 :           ostream << _edges[j]->getEmbeddedNode(k)->id();
    1338           0 :           if (k == _edges[j]->numEmbeddedNodes() - 1)
    1339           0 :             ostream << "]";
    1340             :           else
    1341           0 :             ostream << " ";
    1342             :         }
    1343             :       }
    1344             :       else
    1345        1158 :         ostream << _edges[j]->getEmbeddedNode(0)->id() << " ";
    1346             :     }
    1347             :     else
    1348        1833 :       ostream << "  -- ";
    1349             :   }
    1350         603 :   ostream << "  | ";
    1351        3015 :   for (unsigned int j = 0; j < _num_edges; ++j)
    1352             :   {
    1353        2412 :     if (numEdgeNeighbors(j) > 1)
    1354             :     {
    1355          12 :       ostream << "[";
    1356          36 :       for (unsigned int k = 0; k < numEdgeNeighbors(j); ++k)
    1357             :       {
    1358          24 :         ostream << getEdgeNeighbor(j, k)->id();
    1359          24 :         if (k == numEdgeNeighbors(j) - 1)
    1360          12 :           ostream << "]";
    1361             :         else
    1362          12 :           ostream << " ";
    1363             :       }
    1364          12 :       ostream << " ";
    1365             :     }
    1366             :     else
    1367             :     {
    1368             :       ostream << std::setw(4);
    1369        2400 :       if (numEdgeNeighbors(j) == 1)
    1370        2904 :         ostream << getEdgeNeighbor(j, 0)->id() << " ";
    1371             :       else
    1372         948 :         ostream << "  -- ";
    1373             :     }
    1374             :   }
    1375         603 :   ostream << "  | ";
    1376        1020 :   for (unsigned int j = 0; j < _fragments.size(); ++j)
    1377             :   {
    1378             :     ostream << std::setw(4);
    1379         834 :     ostream << " " << j << " | ";
    1380        2112 :     for (unsigned int k = 0; k < _fragments[j]->numEdges(); ++k)
    1381             :     {
    1382        1695 :       EFANode * prt_node = getFragmentEdge(j, k)->getNode(0);
    1383        1695 :       unsigned int kprev(k > 0 ? k - 1 : _fragments[j]->numEdges() - 1);
    1384        1695 :       if (!getFragmentEdge(j, kprev)->containsNode(prt_node))
    1385           0 :         prt_node = getFragmentEdge(j, k)->getNode(1);
    1386        3390 :       ostream << std::setw(5) << prt_node->idCatString();
    1387             :     }
    1388             :   }
    1389             :   ostream << std::endl;
    1390         603 : }
    1391             : 
    1392             : EFAFragment2D *
    1393    22374899 : EFAElement2D::getFragment(unsigned int frag_id) const
    1394             : {
    1395    22374899 :   if (frag_id < _fragments.size())
    1396    22374899 :     return _fragments[frag_id];
    1397             :   else
    1398           0 :     EFAError("frag_id out of bounds");
    1399             : }
    1400             : 
    1401             : std::set<EFANode *>
    1402     5458286 : EFAElement2D::getEdgeNodes(unsigned int edge_id) const
    1403             : {
    1404             :   std::set<EFANode *> edge_nodes;
    1405     5458286 :   edge_nodes.insert(_edges[edge_id]->getNode(0));
    1406     5458286 :   edge_nodes.insert(_edges[edge_id]->getNode(1));
    1407     5458286 :   return edge_nodes;
    1408             : }
    1409             : 
    1410             : bool
    1411         199 : EFAElement2D::getEdgeNodeParametricCoordinate(EFANode * node, std::vector<double> & para_coor) const
    1412             : {
    1413             :   // get the parametric coords of a node in an element edge
    1414             :   unsigned int edge_id = std::numeric_limits<unsigned int>::max();
    1415             :   bool edge_found = false;
    1416         446 :   for (unsigned int i = 0; i < _num_edges; ++i)
    1417             :   {
    1418         446 :     if (_edges[i]->containsNode(node))
    1419             :     {
    1420             :       edge_id = i;
    1421             :       edge_found = true;
    1422             :       break;
    1423             :     }
    1424             :   }
    1425         199 :   if (edge_found)
    1426             :   {
    1427         199 :     double rel_dist = _edges[edge_id]->distanceFromNode1(node);
    1428         199 :     double xi_1d = 2.0 * rel_dist - 1.0; // translate to [-1,1] parent coord syst
    1429         199 :     mapParametricCoordFrom1Dto2D(edge_id, xi_1d, para_coor);
    1430             :   }
    1431         199 :   return edge_found;
    1432             : }
    1433             : 
    1434             : EFAFaceNode *
    1435           0 : EFAElement2D::getInteriorNode(unsigned int interior_node_id) const
    1436             : {
    1437           0 :   if (interior_node_id < _interior_nodes.size())
    1438           0 :     return _interior_nodes[interior_node_id];
    1439             :   else
    1440           0 :     EFAError("interior_node_id out of bounds");
    1441             : }
    1442             : 
    1443             : void
    1444          72 : EFAElement2D::deleteInteriorNodes()
    1445             : {
    1446         144 :   for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
    1447          72 :     delete _interior_nodes[i];
    1448          72 :   _interior_nodes.clear();
    1449          72 : }
    1450             : 
    1451             : unsigned int
    1452    39379974 : EFAElement2D::numEdges() const
    1453             : {
    1454    39379974 :   return _num_edges;
    1455             : }
    1456             : 
    1457             : void
    1458       36372 : EFAElement2D::setEdge(unsigned int edge_id, EFAEdge * edge)
    1459             : {
    1460       36372 :   _edges[edge_id] = edge;
    1461       36372 : }
    1462             : 
    1463             : void
    1464      385334 : EFAElement2D::createEdges()
    1465             : {
    1466     1903606 :   for (unsigned int i = 0; i < _num_edges; ++i)
    1467             :   {
    1468     1518272 :     unsigned int i_plus1(i < (_num_edges - 1) ? i + 1 : 0);
    1469     1518272 :     EFAEdge * new_edge = new EFAEdge(_nodes[i], _nodes[i_plus1]);
    1470             : 
    1471     1518272 :     if ((_num_edges == 4 && _num_nodes > 4) || (_num_edges == 3 && _num_nodes > 3))
    1472       79840 :       new_edge->setInteriorNode(
    1473       79840 :           _nodes[i + _num_edges]); // '_num_edges' is the offset of interior edge node numbering
    1474             : 
    1475     1518272 :     _edges[i] = new_edge;
    1476             :   }
    1477      385334 : }
    1478             : 
    1479             : EFAEdge *
    1480    28633850 : EFAElement2D::getEdge(unsigned int edge_id) const
    1481             : {
    1482    28633850 :   return _edges[edge_id];
    1483             : }
    1484             : 
    1485             : EFAEdge *
    1486     5603222 : EFAElement2D::getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const
    1487             : {
    1488     5603222 :   if (frag_id < _fragments.size())
    1489     5603222 :     return _fragments[frag_id]->getEdge(edge_id);
    1490             :   else
    1491           0 :     EFAError("frag_id out of bounds in get_frag_edge()");
    1492             : }
    1493             : 
    1494             : std::set<EFANode *>
    1495       71280 : EFAElement2D::getPhantomNodeOnEdge(unsigned int edge_id) const
    1496             : {
    1497             :   std::set<EFANode *> phantom_nodes;
    1498       71280 :   if (_fragments.size() > 0)
    1499             :   {
    1500      213840 :     for (unsigned int j = 0; j < 2; ++j) // loop ove 2 edge nodes
    1501             :     {
    1502             :       bool node_in_frag = false;
    1503      211040 :       for (unsigned int k = 0; k < _fragments.size(); ++k)
    1504             :       {
    1505      144350 :         if (_fragments[k]->containsNode(_edges[edge_id]->getNode(j)))
    1506             :         {
    1507             :           node_in_frag = true;
    1508             :           break;
    1509             :         }
    1510             :       }
    1511      142560 :       if (!node_in_frag)
    1512       66690 :         phantom_nodes.insert(_edges[edge_id]->getNode(j));
    1513             :     }
    1514             :   }
    1515       71280 :   return phantom_nodes;
    1516             : }
    1517             : 
    1518             : bool
    1519        8789 : EFAElement2D::getFragmentEdgeID(unsigned int elem_edge_id, unsigned int & frag_edge_id) const
    1520             : {
    1521             :   // find the fragment edge that is contained by given element edge
    1522             :   // N.B. if the elem edge contains two frag edges, this method will only return
    1523             :   // the first frag edge ID
    1524             :   bool frag_edge_found = false;
    1525        8789 :   frag_edge_id = std::numeric_limits<unsigned int>::max();
    1526        8789 :   if (_fragments.size() == 1)
    1527             :   {
    1528        3176 :     for (unsigned int j = 0; j < _fragments[0]->numEdges(); ++j)
    1529             :     {
    1530        3176 :       if (_edges[elem_edge_id]->containsEdge(*_fragments[0]->getEdge(j)))
    1531             :       {
    1532        1244 :         frag_edge_id = j;
    1533             :         frag_edge_found = true;
    1534        1244 :         break;
    1535             :       }
    1536             :     }
    1537             :   }
    1538        8789 :   return frag_edge_found;
    1539             : }
    1540             : 
    1541             : bool
    1542       47247 : EFAElement2D::isEdgePhantom(unsigned int edge_id) const
    1543             : {
    1544             :   bool is_phantom = false;
    1545       47247 :   if (_fragments.size() > 0)
    1546             :   {
    1547             :     bool contain_frag_edge = false;
    1548       39801 :     for (unsigned int i = 0; i < _fragments.size(); ++i)
    1549             :     {
    1550       93954 :       for (unsigned int j = 0; j < _fragments[i]->numEdges(); ++j)
    1551             :       {
    1552       93858 :         if (_edges[edge_id]->containsEdge(*_fragments[i]->getEdge(j)))
    1553             :         {
    1554             :           contain_frag_edge = true;
    1555             :           break;
    1556             :         }
    1557             :       } // j
    1558       39705 :       if (contain_frag_edge)
    1559             :         break;
    1560             :     } // i
    1561       39705 :     if (!contain_frag_edge)
    1562             :       is_phantom = true;
    1563             :   }
    1564       47247 :   return is_phantom;
    1565             : }
    1566             : 
    1567             : unsigned int
    1568     9365040 : EFAElement2D::numEdgeNeighbors(unsigned int edge_id) const
    1569             : {
    1570             :   unsigned int num_neighbors = 0;
    1571     9365040 :   if (_edge_neighbors[edge_id][0])
    1572     8955027 :     num_neighbors = _edge_neighbors[edge_id].size();
    1573     9365040 :   return num_neighbors;
    1574             : }
    1575             : 
    1576             : EFAElement2D *
    1577     5149099 : EFAElement2D::getEdgeNeighbor(unsigned int edge_id, unsigned int neighbor_id) const
    1578             : {
    1579     5149099 :   if (_edge_neighbors[edge_id][0] != nullptr && neighbor_id < _edge_neighbors[edge_id].size())
    1580     5149099 :     return _edge_neighbors[edge_id][neighbor_id];
    1581             :   else
    1582           0 :     EFAError("edge neighbor does not exist");
    1583             : }
    1584             : 
    1585             : bool
    1586      429394 : EFAElement2D::fragmentHasTipEdges() const
    1587             : {
    1588             :   bool has_tip_edges = false;
    1589      429394 :   if (_fragments.size() == 1)
    1590             :   {
    1591      370661 :     for (unsigned int i = 0; i < _num_edges; ++i)
    1592             :     {
    1593             :       unsigned int num_frag_edges = 0; // count how many fragment edges this element edge contains
    1594      300888 :       if (_edges[i]->hasIntersection())
    1595             :       {
    1596      743004 :         for (unsigned int j = 0; j < _fragments[0]->numEdges(); ++j)
    1597             :         {
    1598      594166 :           if (_edges[i]->containsEdge(*_fragments[0]->getEdge(j)))
    1599      159371 :             num_frag_edges += 1;
    1600             :         } // j
    1601      148838 :         if (num_frag_edges == 2)
    1602             :         {
    1603             :           has_tip_edges = true;
    1604             :           break;
    1605             :         }
    1606             :       }
    1607             :     } // i
    1608             :   }
    1609      429394 :   return has_tip_edges;
    1610             : }
    1611             : 
    1612             : unsigned int
    1613           9 : EFAElement2D::getTipEdgeID() const
    1614             : {
    1615             :   // if this element is a crack tip element, returns the crack tip edge's ID
    1616             :   unsigned int tip_edge_id = std::numeric_limits<unsigned int>::max();
    1617           9 :   if (_fragments.size() == 1) // crack tip element with a partial fragment saved
    1618             :   {
    1619          18 :     for (unsigned int i = 0; i < _num_edges; ++i)
    1620             :     {
    1621             :       unsigned int num_frag_edges = 0; // count how many fragment edges this element edge contains
    1622          18 :       if (_edges[i]->hasIntersection())
    1623             :       {
    1624          54 :         for (unsigned int j = 0; j < _fragments[0]->numEdges(); ++j)
    1625             :         {
    1626          45 :           if (_edges[i]->containsEdge(*_fragments[0]->getEdge(j)))
    1627          18 :             num_frag_edges += 1;
    1628             :         }
    1629           9 :         if (num_frag_edges == 2) // element edge contains two fragment edges
    1630             :         {
    1631             :           tip_edge_id = i;
    1632             :           break;
    1633             :         }
    1634             :       }
    1635             :     }
    1636             :   }
    1637           9 :   return tip_edge_id;
    1638             : }
    1639             : 
    1640             : EFANode *
    1641        2020 : EFAElement2D::getTipEmbeddedNode() const
    1642             : {
    1643             :   // if this element is a crack tip element, returns the crack tip edge's ID
    1644             :   EFANode * tip_emb = nullptr;
    1645        2020 :   if (_fragments.size() == 1) // crack tip element with a partial fragment saved
    1646             :   {
    1647        6110 :     for (unsigned int i = 0; i < _num_edges; ++i)
    1648             :     {
    1649             :       std::vector<EFAEdge *> frag_edges; // count how many fragment edges this element edge contains
    1650        6110 :       if (_edges[i]->hasIntersection())
    1651             :       {
    1652       12080 :         for (unsigned int j = 0; j < _fragments[0]->numEdges(); ++j)
    1653             :         {
    1654       10060 :           if (_edges[i]->containsEdge(*_fragments[0]->getEdge(j)))
    1655        4040 :             frag_edges.push_back(_fragments[0]->getEdge(j));
    1656             :         }                           // j
    1657        2020 :         if (frag_edges.size() == 2) // element edge contains two fragment edges
    1658             :         {
    1659        2020 :           if (frag_edges[1]->containsNode(frag_edges[0]->getNode(1)))
    1660        2020 :             tip_emb = frag_edges[0]->getNode(1);
    1661           0 :           else if (frag_edges[1]->containsNode(frag_edges[0]->getNode(0)))
    1662           0 :             tip_emb = frag_edges[0]->getNode(0);
    1663             :           else
    1664           0 :             EFAError("Common node can't be found between 2 tip frag edges");
    1665             :           break;
    1666             :         }
    1667             :       }
    1668        6110 :     }
    1669             :   }
    1670        2020 :   return tip_emb;
    1671             : }
    1672             : 
    1673             : bool
    1674         622 : EFAElement2D::edgeContainsTip(unsigned int edge_id) const
    1675             : {
    1676             :   bool contains_tip = false;
    1677         622 :   if (_fragments.size() == 1)
    1678             :   {
    1679             :     unsigned int num_frag_edges = 0; // count how many fragment edges this element edge contains
    1680         622 :     if (_edges[edge_id]->hasIntersection())
    1681             :     {
    1682         936 :       for (unsigned int j = 0; j < _fragments[0]->numEdges(); ++j)
    1683             :       {
    1684         720 :         if (_edges[edge_id]->containsEdge(*_fragments[0]->getEdge(j)))
    1685         216 :           num_frag_edges += 1;
    1686             :       } // j
    1687         216 :       if (num_frag_edges == 2)
    1688             :         contains_tip = true;
    1689             :     }
    1690             :   }
    1691         622 :   return contains_tip;
    1692             : }
    1693             : 
    1694             : bool
    1695         622 : EFAElement2D::fragmentEdgeAlreadyCut(unsigned int ElemEdgeID) const
    1696             : {
    1697             :   // when marking cuts, check if the corresponding frag edge already has been cut
    1698             :   bool has_cut = false;
    1699         622 :   if (edgeContainsTip(ElemEdgeID))
    1700             :     has_cut = true;
    1701             :   else
    1702             :   {
    1703         622 :     unsigned int FragEdgeID = std::numeric_limits<unsigned int>::max();
    1704         622 :     if (getFragmentEdgeID(ElemEdgeID, FragEdgeID))
    1705             :     {
    1706         622 :       EFAEdge * frag_edge = getFragmentEdge(0, FragEdgeID);
    1707         622 :       if (frag_edge->hasIntersection())
    1708             :         has_cut = true;
    1709             :     }
    1710             :   }
    1711         622 :   return has_cut;
    1712             : }
    1713             : 
    1714             : void
    1715       92206 : EFAElement2D::addEdgeCut(unsigned int edge_id,
    1716             :                          double position,
    1717             :                          EFANode * embedded_node,
    1718             :                          std::map<unsigned int, EFANode *> & EmbeddedNodes,
    1719             :                          bool add_to_neighbor)
    1720             : {
    1721             :   EFANode * local_embedded = nullptr;
    1722       92206 :   EFANode * edge_node1 = _edges[edge_id]->getNode(0);
    1723             :   if (embedded_node) // use the existing embedded node if it was passed in
    1724             :     local_embedded = embedded_node;
    1725             : 
    1726       92206 :   if (_edges[edge_id]->hasIntersectionAtPosition(position, edge_node1) && position > Xfem::tol &&
    1727             :       position < 1.0 - Xfem::tol)
    1728             :   {
    1729       84039 :     unsigned int emb_id = _edges[edge_id]->getEmbeddedNodeIndex(position, edge_node1);
    1730       84039 :     EFANode * old_emb = _edges[edge_id]->getEmbeddedNode(emb_id);
    1731       84039 :     if (embedded_node && embedded_node != old_emb)
    1732             :     {
    1733           0 :       EFAError("Attempting to add edge intersection when one already exists with different node.",
    1734             :                " elem: ",
    1735             :                _id,
    1736             :                " edge: ",
    1737             :                edge_id,
    1738             :                " position: ",
    1739             :                position);
    1740             :     }
    1741             :     local_embedded = old_emb;
    1742             :   }
    1743             :   else // if no cut exists at the input position
    1744             :   {
    1745             :     bool add2elem = true;
    1746             : 
    1747             :     // check if it is necessary to add cuts to fragment
    1748             :     // id of partially overlapping fragment edge
    1749        8167 :     unsigned int frag_edge_id = std::numeric_limits<unsigned int>::max();
    1750             :     EFAEdge * frag_edge = nullptr;
    1751             :     EFANode * frag_edge_node1 = nullptr;
    1752             :     double frag_pos = -1.0;
    1753             :     bool add2frag = false;
    1754             : 
    1755        8167 :     if (getFragmentEdgeID(edge_id, frag_edge_id)) // elem edge contains a frag edge
    1756             :     {
    1757         622 :       frag_edge = getFragmentEdge(0, frag_edge_id);
    1758         622 :       if (!fragmentEdgeAlreadyCut(edge_id))
    1759             :       {
    1760             :         double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
    1761         622 :         xi[0] = _edges[edge_id]->distanceFromNode1(frag_edge->getNode(0));
    1762         622 :         xi[1] = _edges[edge_id]->distanceFromNode1(frag_edge->getNode(1));
    1763         622 :         if ((position - xi[0]) * (position - xi[1]) <
    1764             :             0.0) // the cut to be added is within the real part of the edge
    1765             :         {
    1766         430 :           frag_edge_node1 = frag_edge->getNode(0);
    1767         430 :           frag_pos = (position - xi[0]) / (xi[1] - xi[0]);
    1768             :           add2frag = true;
    1769             :         }
    1770             :         else                // the emb node to be added is in the phantom part of the elem edge
    1771             :           add2elem = false; // DO NOT ADD INTERSECT IN THIS CASE
    1772             :       }
    1773             :       else
    1774             :       {
    1775             :         EFAWarning("attempting to add new cut to a cut fragment edge");
    1776             :         add2elem = false; // DO NOT ADD INTERSECT IN THIS CASE
    1777             :       }
    1778             :     }
    1779             : 
    1780             :     // If elem edge has 2 cuts but they have not been restored yet, it's OK because
    1781             :     // getFragmentEdgeID = false so we won't add anything to the restored fragment.
    1782             :     // add to elem edge (IMPORTANT to do it AFTER the above fragment check)
    1783        8167 :     if (add2elem)
    1784             :     {
    1785        7975 :       if (!local_embedded) // need to create new embedded node
    1786             :       {
    1787        4555 :         unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
    1788        4555 :         local_embedded = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
    1789        4555 :         EmbeddedNodes.insert(std::make_pair(new_node_id, local_embedded));
    1790             :       }
    1791        7975 :       _edges[edge_id]->addIntersection(position, local_embedded, edge_node1);
    1792        7975 :       if (_edges[edge_id]->numEmbeddedNodes() > 2)
    1793           0 :         EFAError("element edge can't have >2 embedded nodes");
    1794             :     }
    1795             : 
    1796             :     // add to frag edge
    1797        8167 :     if (add2frag)
    1798             :     {
    1799         430 :       frag_edge->addIntersection(frag_pos, local_embedded, frag_edge_node1);
    1800         430 :       if (frag_edge->numEmbeddedNodes() > 1)
    1801           0 :         EFAError("fragment edge can't have >1 embedded nodes");
    1802             :     }
    1803             :   } // IF the input embedded node already exists on this elem edge
    1804             : 
    1805       92206 :   if (add_to_neighbor)
    1806             :   {
    1807       92206 :     for (unsigned int en_iter = 0; en_iter < numEdgeNeighbors(edge_id); ++en_iter)
    1808             :     {
    1809       45023 :       EFAElement2D * edge_neighbor = getEdgeNeighbor(edge_id, en_iter);
    1810       45023 :       unsigned int neighbor_edge_id = edge_neighbor->getNeighborIndex(this);
    1811       45023 :       if (edge_neighbor->getEdge(neighbor_edge_id)->getNode(0) == edge_node1) // same direction
    1812           0 :         EFAError("neighbor edge has the same direction as this edge");
    1813       45023 :       double neigh_pos = 1.0 - position; // get emb node's postion on neighbor edge
    1814       45023 :       edge_neighbor->addEdgeCut(neighbor_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false);
    1815             :     }
    1816             :   } // If add_to_neighbor required
    1817       92206 : }
    1818             : 
    1819             : void
    1820         136 : EFAElement2D::addNodeCut(unsigned int node_id,
    1821             :                          EFANode * embedded_permanent_node,
    1822             :                          std::map<unsigned int, EFANode *> & PermanentNodes,
    1823             :                          std::map<unsigned int, EFANode *> & EmbeddedPermanentNodes)
    1824             : {
    1825             :   EFANode * local_embedded_permanent = nullptr;
    1826         136 :   EFANode * node = _nodes[node_id];
    1827             :   if (embedded_permanent_node) // use the existing embedded node if it was passed in
    1828             :     local_embedded_permanent = embedded_permanent_node;
    1829             : 
    1830         136 :   if (node->category() == EFANode::N_CATEGORY_PERMANENT)
    1831             :   {
    1832          60 :     node->setCategory(EFANode::N_CATEGORY_EMBEDDED_PERMANENT);
    1833             :     local_embedded_permanent = node;
    1834          60 :     EmbeddedPermanentNodes.insert(std::make_pair(node->id(), local_embedded_permanent));
    1835          60 :     if (!Efa::deleteFromMap(PermanentNodes, local_embedded_permanent, false))
    1836           0 :       EFAError("Attempted to delete node: ",
    1837             :                local_embedded_permanent->id(),
    1838             :                " from PermanentNodes, but couldn't find it");
    1839             :   }
    1840         136 : }
    1841             : 
    1842             : bool
    1843       35290 : EFAElement2D::addFragmentEdgeCut(unsigned int frag_edge_id,
    1844             :                                  double position,
    1845             :                                  std::map<unsigned int, EFANode *> & EmbeddedNodes)
    1846             : {
    1847       35290 :   if (_fragments.size() != 1)
    1848           0 :     EFAError("Element: ", _id, " should have only 1 fragment in addFragEdgeIntersection");
    1849             :   EFANode * local_embedded = nullptr;
    1850             : 
    1851             :   // check if this intersection coincide with any embedded node on this edge
    1852             :   bool isValidIntersection = true;
    1853       35290 :   EFAEdge * frag_edge = getFragmentEdge(0, frag_edge_id); // we're considering this edge
    1854       35290 :   EFANode * edge_node1 = frag_edge->getNode(0);
    1855       35290 :   EFANode * edge_node2 = frag_edge->getNode(1);
    1856       35290 :   if ((std::abs(position) < Xfem::tol && edge_node1->category() == EFANode::N_CATEGORY_EMBEDDED) ||
    1857       35365 :       (std::abs(1.0 - position) < Xfem::tol &&
    1858       17338 :        edge_node2->category() == EFANode::N_CATEGORY_EMBEDDED))
    1859             :     isValidIntersection = false;
    1860             : 
    1861             :   // TODO: do not allow to cut fragment's node
    1862       35290 :   if (std::abs(position) < Xfem::tol || std::abs(1.0 - position) < Xfem::tol)
    1863             :     isValidIntersection = false;
    1864             : 
    1865             :   // add valid intersection point to an edge
    1866         514 :   if (isValidIntersection)
    1867             :   {
    1868         514 :     if (frag_edge->hasIntersection())
    1869             :     {
    1870         416 :       if (!frag_edge->hasIntersectionAtPosition(position, edge_node1))
    1871           0 :         EFAError("Attempting to add fragment edge intersection when one already exists with "
    1872             :                  "different position.",
    1873             :                  " elem: ",
    1874             :                  _id,
    1875             :                  " edge: ",
    1876             :                  frag_edge_id,
    1877             :                  " position: ",
    1878             :                  position,
    1879             :                  " old position: ",
    1880             :                  frag_edge->getIntersection(0, edge_node1));
    1881             :     }
    1882             :     else // blank edge - in fact, it can only be a blank element interior edge
    1883             :     {
    1884         196 :       if (!_fragments[0]->isEdgeInterior(frag_edge_id) ||
    1885          98 :           _fragments[0]->isSecondaryInteriorEdge(frag_edge_id))
    1886           0 :         EFAError("Attemping to add intersection to an invalid fragment edge. Element: ",
    1887             :                  _id,
    1888             :                  " fragment_edge: ",
    1889             :                  frag_edge_id);
    1890             : 
    1891             :       // create the embedded node and add it to the fragment's boundary edge
    1892          98 :       unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
    1893          98 :       local_embedded = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
    1894          98 :       EmbeddedNodes.insert(std::make_pair(new_node_id, local_embedded));
    1895          98 :       frag_edge->addIntersection(position, local_embedded, edge_node1);
    1896             : 
    1897             :       // save this interior embedded node to FaceNodes
    1898             :       // TODO: for unstructured elements, the following calution gives you inaccurate position of
    1899             :       // face nodes
    1900             :       // must solve this issue for 3D!
    1901          98 :       std::vector<double> node1_para_coor(2, 0.0);
    1902          98 :       std::vector<double> node2_para_coor(2, 0.0);
    1903         196 :       if (getEdgeNodeParametricCoordinate(edge_node1, node1_para_coor) &&
    1904          98 :           getEdgeNodeParametricCoordinate(edge_node2, node2_para_coor))
    1905             :       {
    1906          98 :         double xi = (1.0 - position) * node1_para_coor[0] + position * node2_para_coor[0];
    1907          98 :         double eta = (1.0 - position) * node1_para_coor[1] + position * node2_para_coor[1];
    1908          98 :         _interior_nodes.push_back(new EFAFaceNode(local_embedded, xi, eta));
    1909             :       }
    1910             :       else
    1911           0 :         EFAError("elem: ", _id, " cannot get the parametric coords of two end embedded nodes");
    1912          98 :     }
    1913             :     // no need to add intersection for neighbor fragment - if this fragment has a
    1914             :     // neighbor fragment, the neighbor has already been treated in addEdgeIntersection;
    1915             :     // for an interior edge, there is no neighbor fragment
    1916             :   }
    1917             : 
    1918       35290 :   return isValidIntersection;
    1919             : }
    1920             : 
    1921             : std::vector<EFAFragment2D *>
    1922           1 : EFAElement2D::branchingSplit(std::map<unsigned int, EFANode *> & EmbeddedNodes)
    1923             : {
    1924           1 :   if (isPartial())
    1925           0 :     EFAError("branching is only allowed for an uncut element");
    1926             : 
    1927             :   // collect all emb nodes counterclockwise
    1928             :   std::vector<EFANode *> three_nodes;
    1929           5 :   for (unsigned int i = 0; i < _edges.size(); ++i)
    1930             :   {
    1931           4 :     EFANode * node1 = _edges[i]->getNode(0);
    1932           4 :     if (_edges[i]->numEmbeddedNodes() == 1)
    1933           3 :       three_nodes.push_back(_edges[i]->getEmbeddedNode(0));
    1934           1 :     else if (_edges[i]->numEmbeddedNodes() == 2)
    1935             :     {
    1936             :       unsigned int id0(
    1937           0 :           _edges[i]->getIntersection(0, node1) < _edges[i]->getIntersection(1, node1) ? 0 : 1);
    1938           0 :       unsigned int id1 = 1 - id0;
    1939           0 :       three_nodes.push_back(_edges[i]->getEmbeddedNode(id0));
    1940           0 :       three_nodes.push_back(_edges[i]->getEmbeddedNode(id1));
    1941             :     }
    1942             :   }
    1943           1 :   if (three_nodes.size() != 3)
    1944           0 :     EFAError("three_nodes.size() != 3");
    1945             : 
    1946             :   // get the parent coords of the braycenter of the three nodes
    1947             :   // TODO: may need a better way to compute this "branching point"
    1948           1 :   std::vector<double> center_xi(2, 0.0);
    1949           4 :   for (unsigned int i = 0; i < 3; ++i)
    1950             :   {
    1951           3 :     std::vector<double> xi_2d(2, 0.0);
    1952           3 :     getEdgeNodeParametricCoordinate(three_nodes[i], xi_2d);
    1953           3 :     center_xi[0] += xi_2d[0];
    1954           3 :     center_xi[1] += xi_2d[1];
    1955           3 :   }
    1956           1 :   center_xi[0] /= 3.0;
    1957           1 :   center_xi[1] /= 3.0;
    1958             : 
    1959             :   // create a new interior node for current element
    1960           1 :   unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
    1961           1 :   EFANode * new_emb = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
    1962           1 :   EmbeddedNodes.insert(std::make_pair(new_node_id, new_emb));
    1963           1 :   _interior_nodes.push_back(new EFAFaceNode(new_emb, center_xi[0], center_xi[1]));
    1964             : 
    1965             :   // generate the three fragments
    1966             :   std::vector<EFAFragment2D *> new_fragments;
    1967           4 :   for (unsigned int i = 0; i < 3; ++i) // loop over 3 sectors
    1968             :   {
    1969           3 :     EFAFragment2D * new_frag = new EFAFragment2D(this, false, nullptr);
    1970           3 :     unsigned int iplus1(i < 2 ? i + 1 : 0);
    1971           3 :     new_frag->addEdge(new EFAEdge(three_nodes[iplus1], new_emb));
    1972           3 :     new_frag->addEdge(new EFAEdge(new_emb, three_nodes[i]));
    1973             : 
    1974             :     unsigned int iedge = 0;
    1975             :     bool add_more_edges = true;
    1976           6 :     for (unsigned int j = 0; j < _edges.size(); ++j)
    1977             :     {
    1978           6 :       if (_edges[j]->containsNode(three_nodes[i]))
    1979             :       {
    1980           3 :         if (_edges[j]->containsNode(three_nodes[iplus1]))
    1981             :         {
    1982           0 :           new_frag->addEdge(new EFAEdge(three_nodes[i], three_nodes[iplus1]));
    1983             :           add_more_edges = false;
    1984             :         }
    1985             :         else
    1986             :         {
    1987           3 :           new_frag->addEdge(new EFAEdge(three_nodes[i], _edges[j]->getNode(1)));
    1988             :         }
    1989             :         iedge = j;
    1990             :         break;
    1991             :       }
    1992             :     } // j
    1993           4 :     while (add_more_edges)
    1994             :     {
    1995           4 :       iedge += 1;
    1996           4 :       if (iedge == _edges.size())
    1997             :         iedge = 0;
    1998           4 :       if (_edges[iedge]->containsNode(three_nodes[iplus1]))
    1999             :       {
    2000           3 :         new_frag->addEdge(new EFAEdge(_edges[iedge]->getNode(0), three_nodes[iplus1]));
    2001             :         add_more_edges = false;
    2002             :       }
    2003             :       else
    2004           1 :         new_frag->addEdge(new EFAEdge(_edges[iedge]->getNode(0), _edges[iedge]->getNode(1)));
    2005             :     }
    2006           3 :     new_fragments.push_back(new_frag);
    2007             :   } // i
    2008           1 :   return new_fragments;
    2009           1 : }
    2010             : 
    2011             : void
    2012         199 : EFAElement2D::mapParametricCoordFrom1Dto2D(unsigned int edge_id,
    2013             :                                            double xi_1d,
    2014             :                                            std::vector<double> & para_coor) const
    2015             : {
    2016         199 :   para_coor.resize(2, 0.0);
    2017         199 :   if (_num_edges == 4)
    2018             :   {
    2019         103 :     if (edge_id == 0)
    2020             :     {
    2021          51 :       para_coor[0] = xi_1d;
    2022          51 :       para_coor[1] = -1.0;
    2023             :     }
    2024          52 :     else if (edge_id == 1)
    2025             :     {
    2026           1 :       para_coor[0] = 1.0;
    2027           1 :       para_coor[1] = xi_1d;
    2028             :     }
    2029          51 :     else if (edge_id == 2)
    2030             :     {
    2031           3 :       para_coor[0] = -xi_1d;
    2032           3 :       para_coor[1] = 1.0;
    2033             :     }
    2034          48 :     else if (edge_id == 3)
    2035             :     {
    2036          48 :       para_coor[0] = -1.0;
    2037          48 :       para_coor[1] = -xi_1d;
    2038             :     }
    2039             :     else
    2040           0 :       EFAError("edge_id out of bounds");
    2041             :   }
    2042          96 :   else if (_num_edges == 3)
    2043             :   {
    2044          96 :     if (edge_id == 0)
    2045             :     {
    2046          48 :       para_coor[0] = 0.5 * (1.0 - xi_1d);
    2047          48 :       para_coor[1] = 0.5 * (1.0 + xi_1d);
    2048             :     }
    2049          48 :     else if (edge_id == 1)
    2050             :     {
    2051           0 :       para_coor[0] = 0.0;
    2052           0 :       para_coor[1] = 0.5 * (1.0 - xi_1d);
    2053             :     }
    2054          48 :     else if (edge_id == 2)
    2055             :     {
    2056          48 :       para_coor[0] = 0.5 * (1.0 + xi_1d);
    2057          48 :       para_coor[1] = 0.0;
    2058             :     }
    2059             :     else
    2060           0 :       EFAError("edge_id out of bounds");
    2061             :   }
    2062             :   else
    2063           0 :     EFAError("unknown element for 2D");
    2064         199 : }
    2065             : 
    2066             : std::vector<EFANode *>
    2067     4134502 : EFAElement2D::getCommonNodes(const EFAElement2D * other_elem) const
    2068             : {
    2069             :   std::set<EFANode *> e1nodes(_nodes.begin(),
    2070     4134502 :                               _nodes.begin() + _num_edges); // only account for corner nodes
    2071     4134502 :   std::set<EFANode *> e2nodes(other_elem->_nodes.begin(), other_elem->_nodes.begin() + _num_edges);
    2072     4134502 :   std::vector<EFANode *> common_nodes = Efa::getCommonElems(e1nodes, e2nodes);
    2073     4134502 :   return common_nodes;
    2074             : }

Generated by: LCOV version 1.14