LCOV - code coverage report
Current view: top level - src/efa - EFAElement3D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 715 975 73.3 %
Date: 2025-09-04 07:58:55 Functions: 59 71 83.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 "EFAElement3D.h"
      11             : 
      12             : #include <iomanip>
      13             : 
      14             : #include "EFAFaceNode.h"
      15             : #include "EFAVolumeNode.h"
      16             : #include "EFANode.h"
      17             : #include "EFAEdge.h"
      18             : #include "EFAFace.h"
      19             : #include "EFAFragment3D.h"
      20             : #include "EFAFuncs.h"
      21             : #include "EFAError.h"
      22             : #include "XFEMFuncs.h"
      23             : 
      24             : #include "libmesh/int_range.h"
      25             : 
      26       43474 : EFAElement3D::EFAElement3D(unsigned int eid, unsigned int n_nodes, unsigned int n_faces)
      27             :   : EFAElement(eid, n_nodes),
      28       43474 :     _num_faces(n_faces),
      29       43474 :     _faces(_num_faces, nullptr),
      30       43474 :     _face_neighbors(_num_faces),
      31       86948 :     _face_edge_neighbors(_num_faces)
      32             : {
      33       43474 :   if (_num_faces == 4)
      34             :   {
      35       21368 :     _num_vertices = 4;
      36       21368 :     if (_num_nodes == 14)
      37       10684 :       _num_interior_face_nodes = 4;
      38       10684 :     else if (_num_nodes == 10)
      39       10684 :       _num_interior_face_nodes = 3;
      40           0 :     else if (_num_nodes == 4)
      41           0 :       _num_interior_face_nodes = 0;
      42             :     else
      43           0 :       EFAError("In EFAelement3D the supported TET element types are TET4, TET10 and TET14");
      44             :   }
      45       22106 :   else if (_num_faces == 6)
      46             :   {
      47       22106 :     _num_vertices = 8;
      48       22106 :     if (_num_nodes == 27)
      49         388 :       _num_interior_face_nodes = 5;
      50       21718 :     else if (_num_nodes == 20)
      51         388 :       _num_interior_face_nodes = 4;
      52       21330 :     else if (_num_nodes == 8)
      53       21330 :       _num_interior_face_nodes = 0;
      54             :     else
      55           0 :       EFAError("In EFAelement3D the supported HEX element types are HEX8, HEX20 and HEX27");
      56             :   }
      57             :   else
      58           0 :     EFAError("In EFAelement3D the supported element types are TET4, TET10, TET14, HEX8, HEX20 and "
      59             :              "HEX27");
      60       43474 :   setLocalCoordinates();
      61       43474 : }
      62             : 
      63        2560 : EFAElement3D::EFAElement3D(const EFAElement3D * from_elem, bool convert_to_local)
      64        2560 :   : EFAElement(from_elem->_id, from_elem->_num_nodes),
      65        2560 :     _num_faces(from_elem->_num_faces),
      66        2560 :     _faces(_num_faces, nullptr),
      67        2560 :     _face_neighbors(_num_faces),
      68        5120 :     _face_edge_neighbors(_num_faces)
      69             : {
      70        2560 :   if (convert_to_local)
      71             :   {
      72             :     // build local nodes from global nodes
      73       29400 :     for (unsigned int i = 0; i < _num_nodes; ++i)
      74             :     {
      75       26840 :       if (from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_PERMANENT ||
      76           0 :           from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_TEMP)
      77             :       {
      78       26840 :         _nodes[i] = from_elem->createLocalNodeFromGlobalNode(from_elem->_nodes[i]);
      79       26840 :         _local_nodes.push_back(_nodes[i]); // convenient to delete local nodes
      80             :       }
      81             :       else
      82           0 :         EFAError("In EFAelement3D ",
      83             :                  from_elem->id(),
      84             :                  " the copy constructor must have from_elem w/ global nodes. node: ",
      85             :                  i,
      86             :                  " category: ",
      87             :                  from_elem->_nodes[i]->category());
      88             :     }
      89             : 
      90             :     // copy faces, fragments and interior nodes from from_elem
      91       15360 :     for (unsigned int i = 0; i < _num_faces; ++i)
      92       12800 :       _faces[i] = new EFAFace(*from_elem->_faces[i]);
      93        5120 :     for (unsigned int i = 0; i < from_elem->_fragments.size(); ++i)
      94        2560 :       _fragments.push_back(new EFAFragment3D(this, true, from_elem, i));
      95        2560 :     for (unsigned int i = 0; i < from_elem->_interior_nodes.size(); ++i)
      96           0 :       _interior_nodes.push_back(new EFAVolumeNode(*from_elem->_interior_nodes[i]));
      97             : 
      98             :     // replace all global nodes with local nodes
      99       29400 :     for (unsigned int i = 0; i < _num_nodes; ++i)
     100             :     {
     101       26840 :       if (_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
     102       26840 :         switchNode(
     103             :             _nodes[i],
     104             :             from_elem->_nodes[i],
     105             :             false); // when save to _cut_elem_map, the EFAelement is not a child of any parent
     106             :       else
     107           0 :         EFAError("In EFAelement3D copy constructor this elem's nodes must be local");
     108             :     }
     109             : 
     110             :     // create element face connectivity array (IMPORTANT)
     111        2560 :     findFacesAdjacentToFaces();
     112             : 
     113        2560 :     _local_node_coor = from_elem->_local_node_coor;
     114        2560 :     _num_interior_face_nodes = from_elem->_num_interior_face_nodes;
     115        2560 :     _num_vertices = from_elem->_num_vertices;
     116             :   }
     117             :   else
     118           0 :     EFAError("this EFAelement3D constructor only converts global nodes to local nodes");
     119        2560 : }
     120             : 
     121       89508 : EFAElement3D::~EFAElement3D()
     122             : {
     123       59900 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     124       13866 :     if (_fragments[i])
     125       13866 :       delete _fragments[i];
     126             : 
     127      276942 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     128      230908 :     if (_faces[i])
     129      230908 :       delete _faces[i];
     130             : 
     131       46034 :   for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
     132           0 :     if (_interior_nodes[i])
     133           0 :       delete _interior_nodes[i];
     134             : 
     135       72874 :   for (unsigned int i = 0; i < _local_nodes.size(); ++i)
     136       26840 :     if (_local_nodes[i])
     137       26840 :       delete _local_nodes[i];
     138       89508 : }
     139             : 
     140             : void
     141       43474 : EFAElement3D::setLocalCoordinates()
     142             : {
     143       43474 :   if (_num_faces == 6)
     144             :   {
     145             :     /*
     146             :     HEX27(HEX20):  7              18             6
     147             :                    o--------------o--------------o
     148             :                   /:             /              /|
     149             :                  / :            /              / |
     150             :                 /  :           /              /  |
     151             :              19/   :        25/            17/   |
     152             :               o--------------o--------------o    |
     153             :              /     :        /              /|    |
     154             :             /    15o       /    23o       / |  14o
     155             :            /       :      /              /  |   /|
     156             :          4/        :   16/             5/   |  / |
     157             :          o--------------o--------------o    | /  |
     158             :          |         :    |   26         |    |/   |
     159             :          |  24o    :    |    o         |  22o    |
     160             :          |         :    |       10     |   /|    |
     161             :          |        3o....|.........o....|../.|....o
     162             :          |        .     |              | /  |   / 2
     163             :          |       .    21|            13|/   |  /
     164             :       12 o--------------o--------------o    | /
     165             :          |     .        |              |    |/
     166             :          |  11o         | 20o          |    o
     167             :          |   .          |              |   / 9
     168             :          |  .           |              |  /
     169             :          | .            |              | /
     170             :          |.             |              |/
     171             :          o--------------o--------------o
     172             :          0              8              1
     173             : 
     174             :      */
     175       22106 :     _local_node_coor.resize(_num_nodes);
     176       22106 :     _local_node_coor[0] = EFAPoint(0.0, 0.0, 0.0);
     177       22106 :     _local_node_coor[1] = EFAPoint(1.0, 0.0, 0.0);
     178       22106 :     _local_node_coor[2] = EFAPoint(1.0, 1.0, 0.0);
     179       22106 :     _local_node_coor[3] = EFAPoint(0.0, 1.0, 0.0);
     180       22106 :     _local_node_coor[4] = EFAPoint(0.0, 0.0, 1.0);
     181       22106 :     _local_node_coor[5] = EFAPoint(1.0, 0.0, 1.0);
     182       22106 :     _local_node_coor[6] = EFAPoint(1.0, 1.0, 1.0);
     183       22106 :     _local_node_coor[7] = EFAPoint(0.0, 1.0, 1.0);
     184             : 
     185       22106 :     if (_num_nodes > 8)
     186             :     {
     187         776 :       _local_node_coor[8] = EFAPoint(0.5, 0.0, 0.0);
     188         776 :       _local_node_coor[9] = EFAPoint(1.0, 0.5, 0.0);
     189         776 :       _local_node_coor[10] = EFAPoint(0.5, 1.0, 0.0);
     190         776 :       _local_node_coor[11] = EFAPoint(0.0, 0.5, 0.0);
     191         776 :       _local_node_coor[12] = EFAPoint(0.0, 0.0, 0.5);
     192         776 :       _local_node_coor[13] = EFAPoint(1.0, 0.0, 0.5);
     193         776 :       _local_node_coor[14] = EFAPoint(1.0, 1.0, 0.5);
     194         776 :       _local_node_coor[15] = EFAPoint(0.0, 1.0, 0.5);
     195         776 :       _local_node_coor[16] = EFAPoint(0.5, 0.0, 1.0);
     196         776 :       _local_node_coor[17] = EFAPoint(1.0, 0.5, 1.0);
     197         776 :       _local_node_coor[18] = EFAPoint(0.5, 1.0, 1.0);
     198         776 :       _local_node_coor[19] = EFAPoint(0.0, 0.5, 1.0);
     199             :     }
     200             : 
     201       22106 :     if (_num_nodes > 20)
     202             :     {
     203         388 :       _local_node_coor[20] = EFAPoint(0.5, 0.5, 0.0);
     204         388 :       _local_node_coor[21] = EFAPoint(0.5, 0.0, 0.5);
     205         388 :       _local_node_coor[22] = EFAPoint(1.0, 0.5, 0.5);
     206         388 :       _local_node_coor[23] = EFAPoint(0.5, 1.0, 0.5);
     207         388 :       _local_node_coor[24] = EFAPoint(0.0, 0.5, 0.5);
     208         388 :       _local_node_coor[25] = EFAPoint(0.5, 0.5, 1.0);
     209         388 :       _local_node_coor[26] = EFAPoint(0.5, 0.5, 0.5);
     210             :     }
     211             :   }
     212       21368 :   else if (_num_faces == 4)
     213             :   {
     214             :     /*
     215             :                   3
     216             :       TET10:      o
     217             :                  /|\
     218             :                 / | \
     219             :             7  /  |  \9
     220             :               o   |   o
     221             :              /    |8   \
     222             :             /     o     \
     223             :            /    6 |      \
     224             :         0 o.....o.|.......o 2
     225             :            \      |      /
     226             :             \     |     /
     227             :              \    |    /
     228             :             4 o   |   o 5
     229             :                \  |  /
     230             :                 \ | /
     231             :                  \|/
     232             :                   o
     233             :                   1
     234             : 
     235             :     */
     236             :     /*
     237             :       TET14 elements also include four face nodes:
     238             :       Node 10, centroid on side 0, arithmetic mean of 0/1/2 or 4/5/6
     239             :       Node 11, centroid on side 1, arithmetic mean of 0/1/3 or 4/7/8
     240             :       Node 12, centroid on side 2, arithmetic mean of 1/2/3 or 5/8/9
     241             :       Node 13, centroid on side 3, arithmetic mean of 0/2/3 or 6/7/9
     242             :     */
     243       21368 :     _local_node_coor.resize(_num_nodes);
     244       21368 :     _local_node_coor[0] = EFAPoint(0.0, 0.0, 0.0);
     245       21368 :     _local_node_coor[1] = EFAPoint(1.0, 0.0, 0.0);
     246       21368 :     _local_node_coor[2] = EFAPoint(0.0, 1.0, 0.0);
     247       21368 :     _local_node_coor[3] = EFAPoint(0.0, 0.0, 1.0);
     248             : 
     249       21368 :     if (_num_nodes > 4)
     250             :     {
     251       21368 :       _local_node_coor[4] = EFAPoint(0.5, 0.0, 0.0);
     252       21368 :       _local_node_coor[5] = EFAPoint(0.5, 0.5, 0.0);
     253       21368 :       _local_node_coor[6] = EFAPoint(0.0, 0.5, 0.0);
     254       21368 :       _local_node_coor[7] = EFAPoint(0.0, 0.0, 0.5);
     255       21368 :       _local_node_coor[8] = EFAPoint(0.5, 0.0, 0.5);
     256       21368 :       _local_node_coor[9] = EFAPoint(0.0, 0.5, 0.5);
     257             :     }
     258             : 
     259       21368 :     if (_num_nodes > 10)
     260             :     {
     261       10684 :       _local_node_coor[10] = EFAPoint(1 / 3., 1 / 3., 0.0);
     262       10684 :       _local_node_coor[11] = EFAPoint(1 / 3., 0.0, 1 / 3.);
     263       10684 :       _local_node_coor[12] = EFAPoint(1 / 3., 1 / 3., 1 / 3.);
     264       10684 :       _local_node_coor[13] = EFAPoint(0.0, 1 / 3., 1 / 3.);
     265             :     }
     266             :   }
     267             :   else
     268           0 :     EFAError("EFAElement3D: number of faces should be either 4(TET) or 6(HEX).");
     269       43474 : }
     270             : 
     271             : unsigned int
     272      625456 : EFAElement3D::numFragments() const
     273             : {
     274      625456 :   return _fragments.size();
     275             : }
     276             : 
     277             : bool
     278      867958 : EFAElement3D::isPartial() const
     279             : {
     280      867958 :   if (_fragments.size() > 0)
     281             :   {
     282     2068604 :     for (unsigned int i = 0; i < _num_vertices; ++i)
     283             :     {
     284             :       bool node_in_frag = false;
     285     2764230 :       for (unsigned int j = 0; j < _fragments.size(); ++j)
     286             :       {
     287     1982438 :         if (_fragments[j]->containsNode(_nodes[i]))
     288             :         {
     289             :           node_in_frag = true;
     290             :           break;
     291             :         }
     292             :       } // j
     293             : 
     294     1982438 :       if (!node_in_frag)
     295             :         return true;
     296             :     } // i
     297             :   }
     298             :   return false;
     299             : }
     300             : 
     301             : void
     302        3256 : EFAElement3D::getNonPhysicalNodes(std::set<EFANode *> & non_physical_nodes) const
     303             : {
     304             :   // Any nodes that don't belong to any fragment are non-physical
     305             :   // First add all nodes in the element to the set
     306       37254 :   for (unsigned int i = 0; i < _nodes.size(); ++i)
     307       33998 :     non_physical_nodes.insert(_nodes[i]);
     308             : 
     309             :   // Now delete any nodes that are contained in fragments
     310             :   std::set<EFANode *>::iterator sit;
     311       37254 :   for (sit = non_physical_nodes.begin(); sit != non_physical_nodes.end();)
     312             :   {
     313             :     bool erased = false;
     314       57444 :     for (unsigned int i = 0; i < _fragments.size(); ++i)
     315             :     {
     316       33998 :       if (_fragments[i]->containsNode(*sit))
     317             :       {
     318       10552 :         non_physical_nodes.erase(sit++);
     319             :         erased = true;
     320       10552 :         break;
     321             :       }
     322             :     }
     323       33998 :     if (!erased)
     324             :       ++sit;
     325             :   }
     326        3256 : }
     327             : 
     328             : void
     329      873626 : EFAElement3D::switchNode(EFANode * new_node, EFANode * old_node, bool descend_to_parent)
     330             : {
     331             :   // We are not switching any embedded nodes here; This is an enhanced version
     332    11281916 :   for (unsigned int i = 0; i < _num_nodes; ++i)
     333             :   {
     334    10408290 :     if (_nodes[i] == old_node)
     335       13357 :       _nodes[i] = new_node;
     336             :   }
     337     1417041 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     338      543415 :     _fragments[i]->switchNode(new_node, old_node);
     339             : 
     340     4629910 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     341     3756284 :     _faces[i]->switchNode(new_node, old_node);
     342             : 
     343      873626 :   if (_parent && descend_to_parent)
     344             :   {
     345       11441 :     _parent->switchNode(new_node, old_node, false);
     346      570988 :     for (unsigned int i = 0; i < _parent->numGeneralNeighbors(); ++i)
     347             :     {
     348      559547 :       EFAElement * neigh_elem = _parent->getGeneralNeighbor(i); // generalized neighbor element
     349     1319713 :       for (unsigned int k = 0; k < neigh_elem->numChildren(); ++k)
     350      760166 :         neigh_elem->getChild(k)->switchNode(new_node, old_node, false);
     351             :     }
     352             :   }
     353      873626 : }
     354             : 
     355             : void
     356           0 : EFAElement3D::switchEmbeddedNode(EFANode * new_emb_node, EFANode * old_emb_node)
     357             : {
     358           0 :   for (unsigned int i = 0; i < _num_faces; ++i)
     359           0 :     _faces[i]->switchNode(new_emb_node, old_emb_node);
     360           0 :   for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
     361           0 :     _interior_nodes[i]->switchNode(new_emb_node, old_emb_node);
     362           0 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
     363           0 :     _fragments[i]->switchNode(new_emb_node, old_emb_node);
     364           0 : }
     365             : 
     366             : void
     367        2711 : EFAElement3D::updateFragmentNode()
     368             : {
     369             :   // In EFAElement3D, updateFragmentNode needs to be implemented
     370        2711 : }
     371             : 
     372             : void
     373     2611614 : EFAElement3D::getMasterInfo(EFANode * node,
     374             :                             std::vector<EFANode *> & master_nodes,
     375             :                             std::vector<double> & master_weights) const
     376             : {
     377             :   // Given a EFAnode, return its master nodes and weights
     378     2611614 :   master_nodes.clear();
     379     2611614 :   master_weights.clear();
     380             :   bool masters_found = false;
     381     5571533 :   for (unsigned int i = 0; i < _num_faces; ++i) // check element exterior faces
     382             :   {
     383     5571533 :     if (_faces[i]->containsNode(node))
     384             :     {
     385     2611614 :       masters_found = _faces[i]->getMasterInfo(node, master_nodes, master_weights);
     386     2611614 :       if (masters_found)
     387             :         break;
     388             :       else
     389           0 :         EFAError("In getMasterInfo: cannot find master nodes in element faces");
     390             :     }
     391             :   }
     392             : 
     393             :   if (!masters_found) // check element interior embedded nodes
     394             :   {
     395           0 :     for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
     396             :     {
     397           0 :       if (_interior_nodes[i]->getNode() == node)
     398             :       {
     399           0 :         std::vector<double> xi_3d(3, -100.0);
     400           0 :         for (unsigned int j = 0; j < 3; ++j)
     401           0 :           xi_3d[j] = _interior_nodes[i]->getParametricCoordinates(j);
     402           0 :         for (unsigned int j = 0; j < _num_nodes; ++j)
     403             :         {
     404           0 :           master_nodes.push_back(_nodes[j]);
     405           0 :           double weight = 0.0;
     406           0 :           if (_num_nodes == 8)
     407           0 :             weight = Efa::linearHexShape3D(j, xi_3d);
     408           0 :           else if (_num_nodes == 4)
     409           0 :             weight = Efa::linearTetShape3D(j, xi_3d);
     410             :           else
     411           0 :             EFAError("unknown 3D element");
     412           0 :           master_weights.push_back(weight);
     413             :         }
     414             :         masters_found = true;
     415             :         break;
     416           0 :       }
     417             :     }
     418             :   }
     419             : 
     420     2611614 :   if (!masters_found)
     421           0 :     EFAError("In EFAelement3D::getMasterInfo, cannot find the given EFANode");
     422     2611614 : }
     423             : 
     424             : unsigned int
     425        1657 : EFAElement3D::numInteriorNodes() const
     426             : {
     427        1657 :   return _interior_nodes.size();
     428             : }
     429             : 
     430             : bool
     431      495734 : EFAElement3D::overlaysElement(const EFAElement3D * other_elem) const
     432             : {
     433             :   bool overlays = false;
     434             :   const EFAElement3D * other3d = dynamic_cast<const EFAElement3D *>(other_elem);
     435      495734 :   if (!other3d)
     436           0 :     EFAError("failed to dynamic cast to other3d");
     437             : 
     438             :   // Find indices of common nodes
     439      495734 :   const auto & common_face_curr = getCommonFaceID(other3d);
     440      495734 :   if (common_face_curr.size() == 1)
     441             :   {
     442      158940 :     unsigned int curr_face_id = common_face_curr[0];
     443      158940 :     EFAFace * curr_face = _faces[curr_face_id];
     444      158940 :     unsigned int other_face_id = other3d->getFaceID(curr_face);
     445      158940 :     EFAFace * other_face = other3d->_faces[other_face_id];
     446      158940 :     if (curr_face->hasSameOrientation(other_face))
     447             :       overlays = true;
     448             :   }
     449      336794 :   else if (common_face_curr.size() > 1)
     450             :   {
     451             :     // TODO: We probably need more error checking here.
     452             :     overlays = true;
     453             :   }
     454      495734 :   return overlays;
     455      495734 : }
     456             : 
     457             : unsigned int
     458      176107 : EFAElement3D::getNeighborIndex(const EFAElement * neighbor_elem) const
     459             : {
     460      544178 :   for (unsigned int i = 0; i < _num_faces; ++i)
     461      812917 :     for (unsigned int j = 0; j < _face_neighbors[i].size(); ++j)
     462      444846 :       if (_face_neighbors[i][j] == neighbor_elem)
     463      176107 :         return i;
     464           0 :   EFAError("in getNeighborIndex() element ", _id, " does not have neighbor ", neighbor_elem->id());
     465             : }
     466             : 
     467             : void
     468       37900 : EFAElement3D::getNeighborEdgeIndex(const EFAElement3D * neighbor_elem,
     469             :                                    unsigned int face_id,
     470             :                                    unsigned int edge_id,
     471             :                                    unsigned int & neigh_face_id,
     472             :                                    unsigned int & neigh_edge_id) const
     473             : {
     474       37900 :   EFAEdge * edge = this->getFace(face_id)->getEdge(edge_id);
     475       78514 :   for (unsigned int i = 0; i < neighbor_elem->numFaces(); ++i)
     476             :   {
     477      258642 :     for (unsigned int j = 0; j < neighbor_elem->getFace(i)->numEdges(); ++j)
     478             :     {
     479      218028 :       EFAEdge * neigh_edge = neighbor_elem->getFace(i)->getEdge(j);
     480      218028 :       if (neigh_edge->equivalent(*edge))
     481             :       {
     482       37900 :         neigh_face_id = i;
     483       37900 :         neigh_edge_id = j;
     484       37900 :         return;
     485             :       }
     486             :     }
     487             :   }
     488           0 :   EFAError("in getNeighborEdgeIndex() element ",
     489             :            _id,
     490             :            " does not share a common edge with element",
     491             :            neighbor_elem->id());
     492             : }
     493             : 
     494             : void
     495       41021 : EFAElement3D::clearNeighbors()
     496             : {
     497       41021 :   _general_neighbors.clear();
     498      246971 :   for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
     499             :   {
     500      205950 :     _face_neighbors[face_iter].clear();
     501      949398 :     for (unsigned int edge_iter = 0; edge_iter < _faces[face_iter]->numEdges(); ++edge_iter)
     502      743448 :       _face_edge_neighbors[face_iter][edge_iter].clear();
     503             :   }
     504       41021 : }
     505             : 
     506             : void
     507       41021 : EFAElement3D::setupNeighbors(std::map<EFANode *, std::set<EFAElement *>> & inverse_connectivity_map)
     508             : {
     509       41021 :   findGeneralNeighbors(inverse_connectivity_map);
     510             :   std::vector<std::pair<unsigned int, unsigned int>> common_ids;
     511     1546163 :   for (unsigned int eit2 = 0; eit2 < _general_neighbors.size(); ++eit2)
     512             :   {
     513     1505142 :     EFAElement3D * neigh_elem = dynamic_cast<EFAElement3D *>(_general_neighbors[eit2]);
     514     1505142 :     if (!neigh_elem)
     515           0 :       EFAError("neighbor_elem is not of EFAelement3D type");
     516             : 
     517     1505142 :     const auto & common_face_id = getCommonFaceID(neigh_elem);
     518     1841936 :     if (common_face_id.empty() && getCommonEdgeID(neigh_elem, common_ids) &&
     519      336794 :         !overlaysElement(neigh_elem))
     520             :     {
     521             :       bool is_edge_neighbor = false;
     522             : 
     523             :       // Fragments must match up.
     524      336794 :       if ((_fragments.size() > 1) || (neigh_elem->numFragments() > 1))
     525           0 :         EFAError("in updateFaceNeighbors: Cannot have more than 1 fragment");
     526             : 
     527      336794 :       if ((_fragments.size() == 1) && (neigh_elem->numFragments() == 1))
     528             :       {
     529       30676 :         if (_fragments[0]->isEdgeConnected(neigh_elem->getFragment(0)))
     530             :           is_edge_neighbor = true;
     531             :       }
     532             :       else // If there are no fragments to match up, consider them edge neighbors
     533             :         is_edge_neighbor = true;
     534             : 
     535             :       if (is_edge_neighbor)
     536     1001840 :         for (const auto & [face_id, edge_id] : common_ids)
     537      667980 :           _face_edge_neighbors[face_id][edge_id].push_back(neigh_elem);
     538             :     }
     539             : 
     540     1505142 :     if (common_face_id.size() == 1 && !overlaysElement(neigh_elem))
     541             :     {
     542      157196 :       unsigned int face_id = common_face_id[0];
     543             :       bool is_face_neighbor = false;
     544             : 
     545             :       // Fragments must match up.
     546      157196 :       if ((_fragments.size() > 1) || (neigh_elem->numFragments() > 1))
     547           0 :         EFAError("in updateFaceNeighbors: Cannot have more than 1 fragment");
     548             : 
     549      157196 :       if ((_fragments.size() == 1) && (neigh_elem->numFragments() == 1))
     550             :       {
     551       16960 :         if (_fragments[0]->isConnected(neigh_elem->getFragment(0)))
     552             :           is_face_neighbor = true;
     553             :       }
     554             :       else // If there are no fragments to match up, consider them neighbors
     555             :         is_face_neighbor = true;
     556             : 
     557             :       if (is_face_neighbor)
     558             :       {
     559      157052 :         if (_face_neighbors[face_id].size() > 1)
     560           0 :           EFAError("Element ",
     561             :                    _id,
     562             :                    " already has 2 face neighbors: ",
     563             :                    _face_neighbors[face_id][0]->id(),
     564             :                    " ",
     565             :                    _face_neighbors[face_id][1]->id());
     566      157052 :         _face_neighbors[face_id].push_back(neigh_elem);
     567             :       }
     568             :     }
     569     1505142 :   }
     570       41021 : }
     571             : 
     572             : void
     573       41021 : EFAElement3D::neighborSanityCheck() const
     574             : {
     575      246971 :   for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
     576             :   {
     577      363002 :     for (unsigned int en_iter = 0; en_iter < _face_neighbors[face_iter].size(); ++en_iter)
     578             :     {
     579      157052 :       EFAElement3D * neigh_elem = _face_neighbors[face_iter][en_iter];
     580      157052 :       if (neigh_elem != nullptr)
     581             :       {
     582             :         bool found_neighbor = false;
     583      953932 :         for (unsigned int face_iter2 = 0; face_iter2 < neigh_elem->numFaces(); ++face_iter2)
     584             :         {
     585     1266552 :           for (unsigned int en_iter2 = 0; en_iter2 < neigh_elem->numFaceNeighbors(face_iter2);
     586             :                ++en_iter2)
     587             :           {
     588      626724 :             if (neigh_elem->getFaceNeighbor(face_iter2, en_iter2) == this)
     589             :             {
     590      157052 :               if ((en_iter2 > 1) && (en_iter > 1))
     591           0 :                 EFAError(
     592             :                     "Element and neighbor element cannot both have >1 neighbors on a common face");
     593             :               found_neighbor = true;
     594             :               break;
     595             :             }
     596             :           }
     597             :         }
     598      157052 :         if (!found_neighbor)
     599           0 :           EFAError("Neighbor element doesn't recognize current element as neighbor");
     600             :       }
     601             :     }
     602             :   }
     603       41021 : }
     604             : 
     605             : void
     606       40844 : EFAElement3D::initCrackTip(std::set<EFAElement *> & CrackTipElements)
     607             : {
     608       40844 :   if (isCrackTipElement())
     609             :   {
     610         477 :     CrackTipElements.insert(this);
     611        3051 :     for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
     612             :     {
     613        2574 :       if ((_face_neighbors[face_iter].size() == 2) && (_faces[face_iter]->hasIntersection()))
     614             :       {
     615             :         // Neither neighbor overlays current element.  We are on the uncut element ahead of the tip.
     616             :         // Flag neighbors as crack tip split elements and add this element as their crack tip
     617             :         // neighbor.
     618         976 :         if (_face_neighbors[face_iter][0]->overlaysElement(this) ||
     619         488 :             _face_neighbors[face_iter][1]->overlaysElement(this))
     620           0 :           EFAError("Element has a neighbor that overlays itself");
     621             : 
     622             :         // Make sure the current elment hasn't been flagged as a tip element
     623         488 :         if (_crack_tip_split_element)
     624           0 :           EFAError("crack_tip_split_element already flagged.  In elem: ",
     625             :                    _id,
     626             :                    " flags: ",
     627             :                    _crack_tip_split_element,
     628             :                    " ",
     629             :                    _face_neighbors[face_iter][0]->isCrackTipSplit(),
     630             :                    " ",
     631             :                    _face_neighbors[face_iter][1]->isCrackTipSplit());
     632             : 
     633         488 :         _face_neighbors[face_iter][0]->setCrackTipSplit();
     634         488 :         _face_neighbors[face_iter][1]->setCrackTipSplit();
     635             : 
     636         488 :         _face_neighbors[face_iter][0]->addCrackTipNeighbor(this);
     637         488 :         _face_neighbors[face_iter][1]->addCrackTipNeighbor(this);
     638             :       }
     639             :     } // face_iter
     640             :   }
     641       40844 : }
     642             : 
     643             : bool
     644       28261 : EFAElement3D::shouldDuplicateForCrackTip(const std::set<EFAElement *> & CrackTipElements)
     645             : {
     646             :   // This method is called in createChildElements()
     647             :   // Only duplicate when
     648             :   // 1) currElem will be a NEW crack tip element
     649             :   // 2) currElem is a crack tip split element at last time step and the tip will extend
     650             :   // 3) currElem is the neighbor of a to-be-second-split element which has another neighbor
     651             :   //    sharing a phantom node with currElem
     652             :   bool should_duplicate = false;
     653       28261 :   if (_fragments.size() == 1)
     654             :   {
     655             :     std::set<EFAElement *>::iterator sit;
     656        6343 :     sit = CrackTipElements.find(this);
     657        6343 :     if (sit == CrackTipElements.end() && isCrackTipElement())
     658             :       should_duplicate = true;
     659        3832 :     else if (shouldDuplicateCrackTipSplitElement(CrackTipElements))
     660             :       should_duplicate = true;
     661        3256 :     else if (shouldDuplicateForPhantomCorner())
     662             :       should_duplicate = true;
     663             :   }
     664       28261 :   return should_duplicate;
     665             : }
     666             : 
     667             : bool
     668        3832 : EFAElement3D::shouldDuplicateCrackTipSplitElement(const std::set<EFAElement *> & CrackTipElements)
     669             : {
     670             :   // Determine whether element at crack tip should be duplicated.  It should be duplicated
     671             :   // if the crack will extend into the next element, or if it has a non-physical node
     672             :   // connected to a face where a crack terminates, but will extend.
     673             : 
     674             :   bool should_duplicate = false;
     675        3832 :   if (_fragments.size() == 1)
     676             :   {
     677             :     std::vector<unsigned int> split_neighbors;
     678        3832 :     if (willCrackTipExtend(split_neighbors))
     679             :       should_duplicate = true;
     680             :     else
     681             :     {
     682             :       // The element may not be at the crack tip, but could have a non-physical node
     683             :       // connected to a crack tip face (on a neighbor element) that will be split.  We need to
     684             :       // duplicate in that case as well.
     685             :       std::set<EFANode *> non_physical_nodes;
     686        3256 :       getNonPhysicalNodes(non_physical_nodes);
     687             : 
     688      125888 :       for (unsigned int eit = 0; eit < _general_neighbors.size(); ++eit)
     689             :       {
     690      122632 :         EFAElement3D * neigh_elem = dynamic_cast<EFAElement3D *>(_general_neighbors[eit]);
     691      122632 :         if (!neigh_elem)
     692           0 :           EFAError("general elem is not of type EFAelement3D");
     693             : 
     694             :         // check if a general neighbor is an old crack tip element and will be split
     695             :         std::set<EFAElement *>::iterator sit;
     696      122632 :         sit = CrackTipElements.find(neigh_elem);
     697      122632 :         if (sit != CrackTipElements.end() && neigh_elem->numFragments() > 1)
     698             :         {
     699           0 :           for (unsigned int i = 0; i < neigh_elem->numFaces(); ++i)
     700             :           {
     701           0 :             std::set<EFANode *> neigh_face_nodes = neigh_elem->getFaceNodes(i);
     702           0 :             if (neigh_elem->numFaceNeighbors(i) == 2 &&
     703           0 :                 Efa::numCommonElems(neigh_face_nodes, non_physical_nodes) > 0)
     704             :             {
     705             :               should_duplicate = true;
     706             :               break;
     707             :             }
     708             :           } // i
     709             :         }
     710             :         if (should_duplicate)
     711             :           break;
     712             :       } // eit
     713             :     }
     714        3832 :   } // IF only one fragment
     715        3832 :   return should_duplicate;
     716             : }
     717             : 
     718             : bool
     719        3256 : EFAElement3D::shouldDuplicateForPhantomCorner()
     720             : {
     721             :   // if a partial element will be split for a second time and it has two neighbor elements
     722             :   // sharing one phantom node with the aforementioned partial element, then the two neighbor
     723             :   // elements should be duplicated
     724             :   bool should_duplicate = false;
     725        3256 :   if (_fragments.size() == 1 && (!_crack_tip_split_element))
     726             :   {
     727       17158 :     for (unsigned int i = 0; i < _num_faces; ++i)
     728             :     {
     729       14284 :       std::set<EFANode *> phantom_nodes = getPhantomNodeOnFace(i);
     730       14284 :       if (phantom_nodes.size() > 0 && numFaceNeighbors(i) == 1)
     731             :       {
     732        7240 :         EFAElement3D * neighbor_elem = _face_neighbors[i][0];
     733        7240 :         if (neighbor_elem->numFragments() > 1) // neighbor will be split
     734             :         {
     735           0 :           for (unsigned int j = 0; j < neighbor_elem->numFaces(); ++j)
     736             :           {
     737           0 :             if (!neighbor_elem->getFace(j)->equivalent(_faces[i]) &&
     738           0 :                 neighbor_elem->numFaceNeighbors(j) > 0)
     739             :             {
     740           0 :               std::set<EFANode *> neigh_phantom_nodes = neighbor_elem->getPhantomNodeOnFace(j);
     741           0 :               if (Efa::numCommonElems(phantom_nodes, neigh_phantom_nodes) > 0)
     742             :               {
     743             :                 should_duplicate = true;
     744             :                 break;
     745             :               }
     746             :             }
     747             :           } // j
     748             :         }
     749             :       }
     750             :       if (should_duplicate)
     751             :         break;
     752             :     } // i
     753             :   }
     754        3256 :   return should_duplicate;
     755             : }
     756             : 
     757             : bool
     758        3832 : EFAElement3D::willCrackTipExtend(std::vector<unsigned int> & split_neighbors) const
     759             : {
     760             :   // Determine whether the current element is a crack tip element for which the crack will
     761             :   // extend into the next element.
     762             :   // N.B. this is called at the beginning of createChildElements
     763             :   bool will_extend = false;
     764        3832 :   if (_fragments.size() == 1 && _crack_tip_split_element)
     765             :   {
     766        1988 :     for (unsigned int i = 0; i < _crack_tip_neighbors.size(); ++i)
     767             :     {
     768        1030 :       unsigned int neigh_idx = _crack_tip_neighbors[i]; // essentially a face_id
     769        1030 :       if (numFaceNeighbors(neigh_idx) != 1)
     770           0 :         EFAError("in will_crack_tip_extend() element ",
     771             :                  _id,
     772             :                  " has ",
     773             :                  _face_neighbors[neigh_idx].size(),
     774             :                  " neighbors on face ",
     775             :                  neigh_idx);
     776             : 
     777        1030 :       EFAElement3D * neighbor_elem = _face_neighbors[neigh_idx][0];
     778        1030 :       if (neighbor_elem->numFragments() > 2)
     779             :       {
     780           0 :         EFAError("in will_crack_tip_extend() element ",
     781             :                  neighbor_elem->id(),
     782             :                  " has ",
     783             :                  neighbor_elem->numFragments(),
     784             :                  " fragments");
     785             :       }
     786        1030 :       else if (neighbor_elem->numFragments() == 2)
     787             :       {
     788         576 :         EFAFragment3D * neigh_frag1 = neighbor_elem->getFragment(0);
     789         576 :         EFAFragment3D * neigh_frag2 = neighbor_elem->getFragment(1);
     790         576 :         std::vector<EFANode *> neigh_cut_nodes = neigh_frag1->getCommonNodes(neigh_frag2);
     791             :         unsigned int counter = 0; // counter how many common nodes are contained by current face
     792        2880 :         for (unsigned int j = 0; j < neigh_cut_nodes.size(); ++j)
     793             :         {
     794        2304 :           if (_faces[neigh_idx]->containsNode(neigh_cut_nodes[j]))
     795        1152 :             counter += 1;
     796             :         }
     797         576 :         if (counter == 2)
     798             :         {
     799         576 :           split_neighbors.push_back(neigh_idx);
     800             :           will_extend = true;
     801             :         }
     802         576 :       }
     803             :     } // i
     804             :   }
     805        3832 :   return will_extend;
     806             : }
     807             : 
     808             : bool
     809       49676 : EFAElement3D::isCrackTipElement() const
     810             : {
     811       49676 :   return fragmentHasTipFaces();
     812             : }
     813             : 
     814             : unsigned int
     815        5980 : EFAElement3D::getNumCuts() const
     816             : {
     817             :   unsigned int num_cut_faces = 0;
     818       36100 :   for (unsigned int i = 0; i < _num_faces; ++i)
     819       30120 :     if (_faces[i]->hasIntersection())
     820           0 :       num_cut_faces += 1;
     821        5980 :   return num_cut_faces;
     822             : }
     823             : 
     824             : bool
     825       20706 : EFAElement3D::isFinalCut() const
     826             : {
     827             :   // if an element has been cut third times its fragment must have 3 interior faces
     828             :   // and at this point, we do not want it to be further cut
     829             :   bool cut_third = false;
     830       20706 :   if (_fragments.size() > 0)
     831             :   {
     832             :     unsigned int num_interior_faces = 0;
     833       16822 :     for (unsigned int i = 0; i < _fragments[0]->numFaces(); ++i)
     834             :     {
     835       14190 :       if (_fragments[0]->isFaceInterior(i))
     836        2434 :         num_interior_faces += 1;
     837             :     }
     838        2632 :     if (num_interior_faces == 3)
     839             :       cut_third = true;
     840             :   }
     841       20706 :   return cut_third;
     842             : }
     843             : 
     844             : void
     845       26673 : EFAElement3D::updateFragments(const std::set<EFAElement *> & CrackTipElements,
     846             :                               std::map<unsigned int, EFANode *> & EmbeddedNodes)
     847             : {
     848             :   // combine the crack-tip faces in a fragment to a single intersected face
     849             :   std::set<EFAElement *>::iterator sit;
     850       26673 :   sit = CrackTipElements.find(this);
     851       26673 :   if (sit != CrackTipElements.end()) // curr_elem is a crack tip element
     852             :   {
     853         254 :     if (_fragments.size() == 1)
     854         254 :       _fragments[0]->combine_tip_faces();
     855             :     else
     856           0 :       EFAError("crack tip elem ", _id, " must have 1 fragment");
     857             :   }
     858             : 
     859             :   // remove the inappropriate embedded nodes on interior faces
     860             :   // (MUST DO THIS AFTER combine_tip_faces())
     861       26673 :   if (_fragments.size() == 1)
     862        3352 :     _fragments[0]->removeInvalidEmbeddedNodes(EmbeddedNodes);
     863             : 
     864             :   // for an element with no fragment, create one fragment identical to the element
     865       26673 :   if (_fragments.size() == 0)
     866       23321 :     _fragments.push_back(new EFAFragment3D(this, true, this));
     867       26673 :   if (_fragments.size() != 1)
     868           0 :     EFAError("Element ", _id, " must have 1 fragment at this point");
     869             : 
     870             :   // count fragment's cut faces
     871       26673 :   unsigned int num_cut_frag_faces = _fragments[0]->getNumCuts();
     872       26673 :   unsigned int num_frag_faces = _fragments[0]->numFaces();
     873       26673 :   if (num_cut_frag_faces > _fragments[0]->numFaces())
     874           0 :     EFAError("In element ", _id, " there are too many cut fragment faces");
     875             : 
     876             :   // leave the uncut frag as it is
     877       26673 :   if (num_cut_frag_faces == 0)
     878             :   {
     879       25016 :     if (!isPartial()) // delete the temp frag for an uncut elem
     880             :     {
     881       21918 :       delete _fragments[0];
     882       21918 :       _fragments.clear();
     883             :     }
     884       25016 :     return;
     885             :   }
     886             : 
     887             :   // split one fragment into one or two new fragments
     888        1657 :   std::vector<EFAFragment3D *> new_frags = _fragments[0]->split();
     889        1657 :   if (new_frags.size() == 1 || new_frags.size() == 2)
     890             :   {
     891        1657 :     delete _fragments[0]; // delete the old fragment
     892        1657 :     _fragments.clear();
     893        4526 :     for (unsigned int i = 0; i < new_frags.size(); ++i)
     894        2869 :       _fragments.push_back(new_frags[i]);
     895             :   }
     896             :   else
     897           0 :     EFAError("Number of fragments must be 1 or 2 at this point");
     898             : 
     899        1657 :   fragmentSanityCheck(num_frag_faces, num_cut_frag_faces);
     900        1657 : }
     901             : 
     902             : void
     903        1657 : EFAElement3D::fragmentSanityCheck(unsigned int n_old_frag_faces, unsigned int n_old_frag_cuts) const
     904             : {
     905        1657 :   unsigned int n_interior_nodes = numInteriorNodes();
     906        1657 :   if (n_interior_nodes > 0 && n_interior_nodes != 1)
     907           0 :     EFAError("After update_fragments this element has ", n_interior_nodes, " interior nodes");
     908             : 
     909        1657 :   if (n_old_frag_cuts == 0)
     910             :   {
     911           0 :     if (_fragments.size() != 1 || _fragments[0]->numFaces() != n_old_frag_faces)
     912           0 :       EFAError("Incorrect link size for element with 0 cuts");
     913             :   }
     914        1657 :   else if (fragmentHasTipFaces()) // crack tip case
     915             :   {
     916         445 :     if (_fragments.size() != 1 || _fragments[0]->numFaces() != n_old_frag_faces + n_old_frag_cuts)
     917           0 :       EFAError("Incorrect link size for element with crack-tip faces");
     918             :   }
     919             :   else // frag is thoroughly cut
     920             :   {
     921        1212 :     if (_fragments.size() != 2 || (_fragments[0]->numFaces() + _fragments[1]->numFaces()) !=
     922        1212 :                                       n_old_frag_faces + n_old_frag_cuts + 2)
     923           0 :       EFAError("Incorrect link size for element that has been completely cut");
     924             :   }
     925        1657 : }
     926             : 
     927             : void
     928        5980 : EFAElement3D::restoreFragment(const EFAElement * const from_elem)
     929             : {
     930        5980 :   const EFAElement3D * from_elem3d = dynamic_cast<const EFAElement3D *>(from_elem);
     931        5980 :   if (!from_elem3d)
     932           0 :     EFAError("from_elem is not of EFAelement3D type");
     933             : 
     934             :   // restore fragments
     935        5980 :   if (_fragments.size() != 0)
     936           0 :     EFAError("in restoreFragmentInfo elements must not have any pre-existing fragments");
     937       11960 :   for (unsigned int i = 0; i < from_elem3d->numFragments(); ++i)
     938        5980 :     _fragments.push_back(new EFAFragment3D(this, true, from_elem3d, i));
     939             : 
     940             :   // restore interior nodes
     941        5980 :   if (_interior_nodes.size() != 0)
     942           0 :     EFAError("in restoreFragmentInfo elements must not have any pre-exsiting interior nodes");
     943        5980 :   for (unsigned int i = 0; i < from_elem3d->_interior_nodes.size(); ++i)
     944           0 :     _interior_nodes.push_back(new EFAVolumeNode(*from_elem3d->_interior_nodes[i]));
     945             : 
     946             :   // restore face intersections
     947        5980 :   if (getNumCuts() != 0)
     948           0 :     EFAError("In restoreEdgeIntersection: edge cuts already exist in element ", _id);
     949       36100 :   for (unsigned int i = 0; i < _num_faces; ++i)
     950       30120 :     _faces[i]->copyIntersection(*from_elem3d->_faces[i]);
     951             : 
     952             :   // replace all local nodes with global nodes
     953       68130 :   for (unsigned int i = 0; i < from_elem3d->numNodes(); ++i)
     954             :   {
     955       62150 :     if (from_elem3d->_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
     956       62150 :       switchNode(
     957             :           _nodes[i], from_elem3d->_nodes[i], false); // EFAelement is not a child of any parent
     958             :     else
     959           0 :       EFAError("In restoreFragmentInfo all of from_elem's nodes must be local");
     960             :   }
     961        5980 : }
     962             : 
     963             : void
     964       26673 : EFAElement3D::createChild(const std::set<EFAElement *> & CrackTipElements,
     965             :                           std::map<unsigned int, EFAElement *> & Elements,
     966             :                           std::map<unsigned int, EFAElement *> & newChildElements,
     967             :                           std::vector<EFAElement *> & ChildElements,
     968             :                           std::vector<EFAElement *> & ParentElements,
     969             :                           std::map<unsigned int, EFANode *> & TempNodes)
     970             : {
     971       26673 :   if (_children.size() != 0)
     972           0 :     EFAError("Element cannot have existing children in createChildElements");
     973             : 
     974       26673 :   if (_fragments.size() > 1 || shouldDuplicateForCrackTip(CrackTipElements))
     975             :   {
     976        1499 :     if (_fragments.size() > 2)
     977           0 :       EFAError("More than 2 fragments not yet supported");
     978             : 
     979             :     // set up the children
     980        1499 :     ParentElements.push_back(this);
     981        4210 :     for (unsigned int ichild = 0; ichild < _fragments.size(); ++ichild)
     982             :     {
     983             :       unsigned int new_elem_id;
     984        2711 :       if (newChildElements.size() == 0)
     985         138 :         new_elem_id = Efa::getNewID(Elements);
     986             :       else
     987        2573 :         new_elem_id = Efa::getNewID(newChildElements);
     988             : 
     989        2711 :       EFAElement3D * childElem = new EFAElement3D(new_elem_id, this->numNodes(), this->numFaces());
     990        2711 :       newChildElements.insert(std::make_pair(new_elem_id, childElem));
     991             : 
     992        2711 :       ChildElements.push_back(childElem);
     993        2711 :       childElem->setParent(this);
     994        2711 :       _children.push_back(childElem);
     995             : 
     996             :       std::vector<std::vector<EFANode *>> cut_plane_nodes;
     997       17396 :       for (unsigned int i = 0; i < this->getFragment(ichild)->numFaces(); ++i)
     998             :       {
     999       14685 :         if (this->getFragment(ichild)->isFaceInterior(i))
    1000             :         {
    1001        2488 :           EFAFace * face = this->getFragment(ichild)->getFace(i);
    1002             :           std::vector<EFANode *> node_line;
    1003       11496 :           for (unsigned int j = 0; j < face->numNodes(); ++j)
    1004        9008 :             node_line.push_back(face->getNode(j));
    1005        2488 :           cut_plane_nodes.push_back(node_line);
    1006        2488 :         }
    1007             :       }
    1008             : 
    1009             :       std::vector<EFAPoint> cut_plane_points;
    1010             : 
    1011        2711 :       EFAPoint normal(0.0, 0.0, 0.0);
    1012        2711 :       EFAPoint orig(0.0, 0.0, 0.0);
    1013             : 
    1014        2711 :       if (cut_plane_nodes.size())
    1015             :       {
    1016       11496 :         for (unsigned int i = 0; i < cut_plane_nodes[0].size(); ++i)
    1017             :         {
    1018             :           std::vector<EFANode *> master_nodes;
    1019             :           std::vector<double> master_weights;
    1020             : 
    1021        9008 :           this->getMasterInfo(cut_plane_nodes[0][i], master_nodes, master_weights);
    1022        9008 :           EFAPoint coor(0.0, 0.0, 0.0);
    1023       27024 :           for (unsigned int i = 0; i < master_nodes.size(); ++i)
    1024             :           {
    1025       18016 :             EFANode * local = this->createLocalNodeFromGlobalNode(master_nodes[i]);
    1026       18016 :             coor += _local_node_coor[local->id()] * master_weights[i];
    1027       18016 :             delete local;
    1028             :           }
    1029        9008 :           cut_plane_points.push_back(coor);
    1030        9008 :         }
    1031       11496 :         for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
    1032        9008 :           orig += cut_plane_points[i];
    1033        2488 :         orig /= cut_plane_points.size();
    1034             : 
    1035        2488 :         EFAPoint center(0.0, 0.0, 0.0);
    1036       11496 :         for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
    1037        9008 :           center += cut_plane_points[i];
    1038        2488 :         center /= cut_plane_points.size();
    1039             : 
    1040       11496 :         for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
    1041             :         {
    1042        9008 :           unsigned int iplus1 = i < cut_plane_points.size() - 1 ? i + 1 : 0;
    1043        9008 :           EFAPoint ray1 = cut_plane_points[i] - center;
    1044        9008 :           EFAPoint ray2 = cut_plane_points[iplus1] - center;
    1045        9008 :           normal += ray1.cross(ray2);
    1046             :         }
    1047        2488 :         normal /= cut_plane_points.size();
    1048        2488 :         Xfem::normalizePoint(normal);
    1049             :       }
    1050             : 
    1051             :       // get child element's nodes
    1052       30759 :       for (unsigned int j = 0; j < _num_nodes; ++j)
    1053             :       {
    1054       28048 :         EFAPoint p(0.0, 0.0, 0.0);
    1055       28048 :         p = _local_node_coor[j];
    1056       28048 :         EFAPoint origin_to_point = p - orig;
    1057       28048 :         if (_fragments.size() == 1 && !shouldDuplicateForCrackTip(CrackTipElements))
    1058           0 :           childElem->setNode(j, _nodes[j]); // inherit parent's node
    1059       28048 :         else if (origin_to_point * normal < Xfem::tol)
    1060       15168 :           childElem->setNode(j, _nodes[j]); // inherit parent's node
    1061             :         else                                // parent element's node is not in fragment
    1062             :         {
    1063       12880 :           unsigned int new_node_id = Efa::getNewID(TempNodes);
    1064       12880 :           EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
    1065       12880 :           TempNodes.insert(std::make_pair(new_node_id, newNode));
    1066       12880 :           childElem->setNode(j, newNode); // be a temp node
    1067             :         }
    1068             :       }
    1069             : 
    1070             :       // get child element's fragments
    1071        2711 :       EFAFragment3D * new_frag = new EFAFragment3D(childElem, true, this, ichild);
    1072        2711 :       childElem->_fragments.push_back(new_frag);
    1073             : 
    1074             :       // get child element's faces and set up adjacent faces
    1075        2711 :       childElem->createFaces();
    1076       16417 :       for (unsigned int j = 0; j < _num_faces; ++j)
    1077       13706 :         childElem->_faces[j]->copyIntersection(*_faces[j]);
    1078        2711 :       childElem->removePhantomEmbeddedNode(); // IMPORTANT
    1079             : 
    1080             :       // inherit old interior nodes
    1081        2711 :       for (unsigned int j = 0; j < _interior_nodes.size(); ++j)
    1082           0 :         childElem->_interior_nodes.push_back(new EFAVolumeNode(*_interior_nodes[j]));
    1083        2711 :     }
    1084             :   }
    1085             :   else // num_links == 1 || num_links == 0
    1086             :   {
    1087             :     // child is itself - but don't insert into the list of ChildElements!!!
    1088       25174 :     _children.push_back(this);
    1089             :   }
    1090       26673 : }
    1091             : 
    1092             : void
    1093        2711 : EFAElement3D::removePhantomEmbeddedNode()
    1094             : {
    1095             :   // remove the embedded nodes on faces that are outside the real domain
    1096        2711 :   if (_fragments.size() > 0)
    1097             :   {
    1098       16417 :     for (unsigned int i = 0; i < _num_faces; ++i)
    1099             :     {
    1100             :       // get emb nodes to be removed on edges
    1101             :       std::vector<EFANode *> nodes_to_delete;
    1102       63410 :       for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
    1103             :       {
    1104             :         EFAEdge * edge = _faces[i]->getEdge(j);
    1105       68636 :         for (unsigned int k = 0; k < edge->numEmbeddedNodes(); ++k)
    1106             :         {
    1107       18932 :           if (!_fragments[0]->containsNode(edge->getEmbeddedNode(k)))
    1108           0 :             nodes_to_delete.push_back(edge->getEmbeddedNode(k));
    1109             :         } // k
    1110             :       }   // j
    1111             : 
    1112             :       // get emb nodes to be removed in the face interior
    1113       13706 :       for (unsigned int j = 0; j < _faces[i]->numInteriorNodes(); ++j)
    1114             :       {
    1115           0 :         EFANode * face_node = _faces[i]->getInteriorNode(j)->getNode();
    1116           0 :         if (!_fragments[0]->containsNode(face_node))
    1117           0 :           nodes_to_delete.push_back(face_node);
    1118             :       } // j
    1119             : 
    1120             :       // remove all invalid embedded nodes
    1121       13706 :       for (unsigned int j = 0; j < nodes_to_delete.size(); ++j)
    1122           0 :         _faces[i]->removeEmbeddedNode(nodes_to_delete[j]);
    1123       13706 :     } // i
    1124             :   }
    1125        2711 : }
    1126             : 
    1127             : void
    1128        2711 : EFAElement3D::connectNeighbors(std::map<unsigned int, EFANode *> & PermanentNodes,
    1129             :                                std::map<unsigned int, EFANode *> & TempNodes,
    1130             :                                std::map<EFANode *, std::set<EFAElement *>> & InverseConnectivityMap,
    1131             :                                bool merge_phantom_faces)
    1132             : {
    1133             :   // N.B. "this" must point to a child element that was just created
    1134        2711 :   if (!_parent)
    1135           0 :     EFAError("no parent element for child element ", _id, " in connect_neighbors");
    1136        2711 :   EFAElement3D * parent3d = dynamic_cast<EFAElement3D *>(_parent);
    1137        2711 :   if (!parent3d)
    1138           0 :     EFAError("cannot dynamic cast to parent3d in connect_neighbors");
    1139             : 
    1140             :   // First loop through edges and merge nodes with neighbors as appropriate
    1141       16417 :   for (unsigned int j = 0; j < _num_faces; ++j)
    1142             :   {
    1143       24673 :     for (unsigned int k = 0; k < parent3d->numFaceNeighbors(j); ++k)
    1144             :     {
    1145       10967 :       EFAElement3D * NeighborElem = parent3d->getFaceNeighbor(j, k);
    1146       10967 :       unsigned int neighbor_face_id = NeighborElem->getNeighborIndex(parent3d);
    1147             : 
    1148       10967 :       if (_faces[j]->hasIntersection())
    1149             :       {
    1150       20235 :         for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
    1151             :         {
    1152             :           EFAElement3D * childOfNeighborElem =
    1153       13252 :               dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
    1154       13252 :           if (!childOfNeighborElem)
    1155           0 :             EFAError("dynamic cast childOfNeighborElem fails");
    1156             : 
    1157             :           // Check to see if the nodes are already merged.  There's nothing else to do in that case.
    1158       13252 :           EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
    1159       13252 :           if (_faces[j]->equivalent(neighborChildFace))
    1160        3935 :             continue;
    1161             : 
    1162        9317 :           if (_fragments[0]->isConnected(childOfNeighborElem->getFragment(0)))
    1163             :           {
    1164       14681 :             for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
    1165             :             {
    1166             :               unsigned int childNodeIndex = i;
    1167             :               unsigned int neighborChildNodeIndex =
    1168       11436 :                   parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
    1169             : 
    1170       11436 :               EFANode * childNode = _faces[j]->getNode(childNodeIndex);
    1171       11436 :               EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
    1172       11436 :               mergeNodes(
    1173             :                   childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
    1174             :             } // i
    1175             : 
    1176        9081 :             for (unsigned int m = 0; m < _num_interior_face_nodes; ++m)
    1177             :             {
    1178             :               unsigned int childNodeIndex = m;
    1179             :               unsigned int neighborChildNodeIndex =
    1180        5836 :                   parent3d->getNeighborFaceInteriorNodeID(j, childNodeIndex, NeighborElem);
    1181             : 
    1182        5836 :               EFANode * childNode = _faces[j]->getInteriorFaceNode(childNodeIndex);
    1183             :               EFANode * childOfNeighborNode =
    1184        5836 :                   neighborChildFace->getInteriorFaceNode(neighborChildNodeIndex);
    1185        5836 :               mergeNodes(
    1186             :                   childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
    1187             :             } // m
    1188             :           }
    1189             :         } // l, loop over NeighborElem's children
    1190             :       }
    1191             :       else // No edge intersection -- optionally merge non-material nodes if they share a common
    1192             :            // parent
    1193             :       {
    1194        3984 :         if (merge_phantom_faces)
    1195             :         {
    1196        7968 :           for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
    1197             :           {
    1198             :             EFAElement3D * childOfNeighborElem =
    1199        3984 :                 dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
    1200        3984 :             if (!childOfNeighborElem)
    1201           0 :               EFAError("dynamic cast childOfNeighborElem fails");
    1202             : 
    1203        3984 :             EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
    1204        3984 :             if (!neighborChildFace
    1205        3984 :                      ->hasIntersection()) // neighbor face must NOT have intersection either
    1206             :             {
    1207             :               // Check to see if the nodes are already merged.  There's nothing else to do in that
    1208             :               // case.
    1209        3984 :               if (_faces[j]->equivalent(neighborChildFace))
    1210        2404 :                 continue;
    1211             : 
    1212        7452 :               for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
    1213             :               {
    1214             :                 unsigned int childNodeIndex = i;
    1215             :                 unsigned int neighborChildNodeIndex =
    1216        5872 :                     parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
    1217             : 
    1218        5872 :                 EFANode * childNode = _faces[j]->getNode(childNodeIndex);
    1219        5872 :                 EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
    1220             : 
    1221       11193 :                 if (childNode->parent() != nullptr &&
    1222        5321 :                     childNode->parent() ==
    1223             :                         childOfNeighborNode
    1224        5321 :                             ->parent()) // non-material node and both come from same parent
    1225           0 :                   mergeNodes(childNode,
    1226             :                              childOfNeighborNode,
    1227             :                              childOfNeighborElem,
    1228             :                              PermanentNodes,
    1229             :                              TempNodes);
    1230             :               } // i
    1231             :             }
    1232             :           } // loop over NeighborElem's children
    1233             :         }   // if (merge_phantom_edges)
    1234             :       }     // IF edge-j has_intersection()
    1235             :     }       // k, loop over neighbors on edge j
    1236             :   }         // j, loop over all faces
    1237             : 
    1238             :   // Now do a second loop through faces and convert remaining nodes to permanent nodes.
    1239             :   // If there is no neighbor on that face, also duplicate the embedded node if it exists
    1240       30759 :   for (unsigned int j = 0; j < _num_nodes; ++j)
    1241             :   {
    1242       28048 :     EFANode * childNode = _nodes[j];
    1243       28048 :     if (childNode->category() == EFANode::N_CATEGORY_TEMP)
    1244             :     {
    1245             :       // if current child element does not have siblings, and if current temp node is a lone one
    1246             :       // this temp node should be merged back to its parent permanent node. Otherwise we would have
    1247             :       // permanent nodes that are not connected to any element
    1248        1588 :       std::set<EFAElement *> patch_elems = InverseConnectivityMap[childNode->parent()];
    1249        1588 :       if (parent3d->numFragments() == 1 && patch_elems.size() == 1)
    1250           0 :         switchNode(childNode->parent(), childNode, false);
    1251             :       else
    1252             :       {
    1253        1588 :         unsigned int new_node_id = Efa::getNewID(PermanentNodes);
    1254             :         EFANode * newNode =
    1255        1588 :             new EFANode(new_node_id, EFANode::N_CATEGORY_PERMANENT, childNode->parent());
    1256        1588 :         PermanentNodes.insert(std::make_pair(new_node_id, newNode));
    1257        1588 :         switchNode(newNode, childNode, false);
    1258             :       }
    1259        1588 :       if (!Efa::deleteFromMap(TempNodes, childNode))
    1260           0 :         EFAError(
    1261             :             "Attempted to delete node: ", childNode->id(), " from TempNodes, but couldn't find it");
    1262             :     }
    1263             :   }
    1264        2711 : }
    1265             : 
    1266             : void
    1267           0 : EFAElement3D::printElement(std::ostream & ostream) const
    1268             : {
    1269             :   // first line: all elem faces
    1270             :   ostream << std::setw(5);
    1271           0 :   ostream << _id << "| ";
    1272           0 :   for (unsigned int j = 0; j < _num_faces; ++j)
    1273             :   {
    1274           0 :     for (unsigned int k = 0; k < _faces[j]->numNodes(); ++k)
    1275           0 :       ostream << std::setw(5) << _faces[j]->getNode(k)->idCatString();
    1276           0 :     ostream << " | ";
    1277             :   }
    1278             :   ostream << std::endl;
    1279             : 
    1280             :   // second line: emb nodes in all faces + neighbor of each face
    1281             :   ostream << std::setw(5);
    1282             :   ostream << "embed"
    1283           0 :           << "| ";
    1284           0 :   for (unsigned int j = 0; j < _num_faces; ++j)
    1285             :   {
    1286           0 :     for (unsigned int k = 0; k < _faces[j]->numEdges(); ++k)
    1287             :     {
    1288             :       ostream << std::setw(4);
    1289           0 :       if (_faces[j]->getEdge(k)->hasIntersection())
    1290             :       {
    1291           0 :         if (_faces[j]->getEdge(k)->numEmbeddedNodes() > 1)
    1292             :         {
    1293           0 :           ostream << "[";
    1294           0 :           for (unsigned int l = 0; l < _faces[j]->getEdge(k)->numEmbeddedNodes(); ++l)
    1295             :           {
    1296           0 :             ostream << _faces[j]->getEdge(k)->getEmbeddedNode(l)->id() << " ";
    1297           0 :             if (l == _faces[j]->getEdge(k)->numEmbeddedNodes() - 1)
    1298           0 :               ostream << "]";
    1299             :             else
    1300           0 :               ostream << " ";
    1301             :           } // l
    1302             :         }
    1303             :         else
    1304           0 :           ostream << _faces[j]->getEdge(k)->getEmbeddedNode(0)->id() << " ";
    1305             :       }
    1306             :       else
    1307           0 :         ostream << "  -- ";
    1308             :     } // k
    1309           0 :     ostream << " | ";
    1310             :   } // j
    1311             :   ostream << std::endl;
    1312             : 
    1313             :   // third line: neighbors
    1314             :   ostream << std::setw(5);
    1315             :   ostream << "neigh"
    1316           0 :           << "| ";
    1317           0 :   for (unsigned int j = 0; j < _num_faces; ++j)
    1318             :   {
    1319             :     ostream << std::setw(4);
    1320           0 :     if (numFaceNeighbors(j) > 1)
    1321             :     {
    1322           0 :       ostream << "[";
    1323           0 :       for (unsigned int k = 0; k < numFaceNeighbors(j); ++k)
    1324             :       {
    1325           0 :         ostream << getFaceNeighbor(j, k)->id();
    1326           0 :         if (k == numFaceNeighbors(j) - 1)
    1327           0 :           ostream << "]";
    1328             :         else
    1329           0 :           ostream << " ";
    1330             :       }
    1331             :     }
    1332             :     else
    1333             :     {
    1334           0 :       if (numFaceNeighbors(j) == 1)
    1335           0 :         ostream << getFaceNeighbor(j, 0)->id() << " ";
    1336             :       else
    1337           0 :         ostream << "  -- ";
    1338             :     }
    1339             :   }
    1340             :   ostream << std::endl;
    1341             : 
    1342             :   // fourth line: fragments
    1343           0 :   for (unsigned int j = 0; j < _fragments.size(); ++j)
    1344             :   {
    1345             :     ostream << std::setw(4);
    1346           0 :     ostream << "frag" << j << "| ";
    1347           0 :     for (unsigned int k = 0; k < _fragments[j]->numFaces(); ++k)
    1348             :     {
    1349           0 :       for (unsigned int l = 0; l < _fragments[j]->getFace(k)->numNodes(); ++l)
    1350           0 :         ostream << std::setw(5) << _fragments[j]->getFace(k)->getNode(l)->idCatString();
    1351           0 :       ostream << " | ";
    1352             :     }
    1353             :     ostream << std::endl;
    1354             :   }
    1355             :   ostream << std::endl;
    1356           0 : }
    1357             : 
    1358             : EFAFragment3D *
    1359    11540970 : EFAElement3D::getFragment(unsigned int frag_id) const
    1360             : {
    1361    11540970 :   if (frag_id < _fragments.size())
    1362    11540970 :     return _fragments[frag_id];
    1363             :   else
    1364           0 :     EFAError("frag_id out of bounds");
    1365             : }
    1366             : 
    1367             : std::set<EFANode *>
    1368           0 : EFAElement3D::getFaceNodes(unsigned int face_id) const
    1369             : {
    1370             :   std::set<EFANode *> face_nodes;
    1371           0 :   for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i)
    1372           0 :     face_nodes.insert(_faces[face_id]->getNode(i));
    1373           0 :   return face_nodes;
    1374             : }
    1375             : 
    1376             : bool
    1377           0 : EFAElement3D::getFaceNodeParametricCoordinates(EFANode * node, std::vector<double> & xi_3d) const
    1378             : {
    1379             :   // get the parametric coords of a node in an element face
    1380             :   unsigned int face_id = std::numeric_limits<unsigned int>::max();
    1381             :   bool face_found = false;
    1382           0 :   for (unsigned int i = 0; i < _num_faces; ++i)
    1383             :   {
    1384           0 :     if (_faces[i]->containsNode(node))
    1385             :     {
    1386             :       face_id = i;
    1387             :       face_found = true;
    1388             :       break;
    1389             :     }
    1390             :   }
    1391           0 :   if (face_found)
    1392             :   {
    1393           0 :     std::vector<double> xi_2d(2, 0.0);
    1394           0 :     if (_faces[face_id]->getFaceNodeParametricCoords(node, xi_2d))
    1395           0 :       mapParametricCoordinateFrom2DTo3D(face_id, xi_2d, xi_3d);
    1396             :     else
    1397           0 :       EFAError("failed to get the 2D para coords on the face");
    1398           0 :   }
    1399           0 :   return face_found;
    1400             : }
    1401             : 
    1402             : EFAVolumeNode *
    1403           0 : EFAElement3D::getInteriorNode(unsigned int interior_node_id) const
    1404             : {
    1405           0 :   if (interior_node_id < _interior_nodes.size())
    1406           0 :     return _interior_nodes[interior_node_id];
    1407             :   else
    1408           0 :     EFAError("interior_node_id out of bounds");
    1409             : }
    1410             : 
    1411             : void
    1412           0 : EFAElement3D::removeEmbeddedNode(EFANode * emb_node, bool remove_for_neighbor)
    1413             : {
    1414           0 :   for (unsigned int i = 0; i < _fragments.size(); ++i)
    1415           0 :     _fragments[i]->removeEmbeddedNode(emb_node);
    1416             : 
    1417           0 :   for (unsigned int i = 0; i < _faces.size(); ++i)
    1418           0 :     _faces[i]->removeEmbeddedNode(emb_node);
    1419             : 
    1420           0 :   if (remove_for_neighbor)
    1421             :   {
    1422           0 :     for (unsigned int i = 0; i < numFaces(); ++i)
    1423           0 :       for (unsigned int j = 0; j < numFaceNeighbors(i); ++j)
    1424           0 :         getFaceNeighbor(i, j)->removeEmbeddedNode(emb_node, false);
    1425             :   }
    1426           0 : }
    1427             : 
    1428             : unsigned int
    1429    18829009 : EFAElement3D::numFaces() const
    1430             : {
    1431    18829009 :   return _faces.size();
    1432             : }
    1433             : 
    1434             : void
    1435           0 : EFAElement3D::setFace(unsigned int face_id, EFAFace * face)
    1436             : {
    1437           0 :   _faces[face_id] = face;
    1438           0 : }
    1439             : 
    1440             : void
    1441       43474 : EFAElement3D::createFaces()
    1442             : {
    1443             :   // create element faces based on existing element nodes
    1444       43474 :   int hex_local_node_indices[6][4] = {
    1445             :       {0, 3, 2, 1}, {0, 1, 5, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}};
    1446       43474 :   int tet_local_node_indices[4][3] = {{0, 2, 1}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}};
    1447             : 
    1448       43474 :   int hex_interior_face_node_indices[6][5] = {{8, 9, 10, 11, 20},
    1449             :                                               {8, 13, 16, 12, 21},
    1450             :                                               {9, 14, 17, 13, 22},
    1451             :                                               {10, 14, 18, 15, 23},
    1452             :                                               {11, 15, 19, 12, 24},
    1453             :                                               {16, 17, 18, 19, 25}};
    1454       43474 :   int tet_interior_face_node_indices[4][4] = {
    1455             :       {4, 5, 6, 10}, {4, 7, 8, 11}, {5, 8, 9, 12}, {6, 7, 9, 13}};
    1456             : 
    1457       43474 :   _faces = std::vector<EFAFace *>(_num_faces, nullptr);
    1458       43474 :   if (_num_nodes == 8 || _num_nodes == 20 || _num_nodes == 27)
    1459             :   {
    1460       22106 :     if (_num_faces != 6)
    1461           0 :       EFAError("num_faces of hexes must be 6");
    1462      154742 :     for (unsigned int i = 0; i < _num_faces; ++i)
    1463             :     {
    1464      132636 :       _faces[i] = new EFAFace(4, _num_interior_face_nodes);
    1465      663180 :       for (unsigned int j = 0; j < 4; ++j)
    1466      530544 :         _faces[i]->setNode(j, _nodes[hex_local_node_indices[i][j]]);
    1467      132636 :       _faces[i]->createEdges();
    1468      153588 :       for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
    1469       20952 :         _faces[i]->setInteriorFaceNode(k, _nodes[hex_interior_face_node_indices[i][k]]);
    1470             :     }
    1471             :   }
    1472             :   else if (_num_nodes == 4 || _num_nodes == 10 || _num_nodes == 14)
    1473             :   {
    1474       21368 :     if (_num_faces != 4)
    1475           0 :       EFAError("num_faces of tets must be 4");
    1476      106840 :     for (unsigned int i = 0; i < _num_faces; ++i)
    1477             :     {
    1478       85472 :       _faces[i] = new EFAFace(3, _num_interior_face_nodes);
    1479      341888 :       for (unsigned int j = 0; j < 3; ++j)
    1480      256416 :         _faces[i]->setNode(j, _nodes[tet_local_node_indices[i][j]]);
    1481       85472 :       _faces[i]->createEdges();
    1482      384624 :       for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
    1483      299152 :         _faces[i]->setInteriorFaceNode(k, _nodes[tet_interior_face_node_indices[i][k]]);
    1484             :     }
    1485             :   }
    1486             :   else
    1487           0 :     EFAError("unknown 3D element type in createFaces()");
    1488             : 
    1489      261582 :   for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
    1490             :   {
    1491      218108 :     _face_edge_neighbors[face_iter].resize(_faces[face_iter]->numEdges());
    1492     1005068 :     for (unsigned int edge_iter = 0; edge_iter < _faces[face_iter]->numEdges(); ++edge_iter)
    1493      786960 :       _face_edge_neighbors[face_iter][edge_iter].clear();
    1494             :   }
    1495             : 
    1496             :   // create element face connectivity array
    1497       43474 :   findFacesAdjacentToFaces(); // IMPORTANT
    1498       43474 : }
    1499             : 
    1500             : EFAFace *
    1501    17543635 : EFAElement3D::getFace(unsigned int face_id) const
    1502             : {
    1503    17543635 :   return _faces[face_id];
    1504             : }
    1505             : 
    1506             : unsigned int
    1507      258333 : EFAElement3D::getFaceID(EFAFace * face) const
    1508             : {
    1509             :   bool found_face_id = false;
    1510             :   unsigned int face_id;
    1511      828467 :   for (unsigned int iface = 0; iface < _num_faces; ++iface)
    1512             :   {
    1513      828467 :     if (_faces[iface]->equivalent(face))
    1514             :     {
    1515             :       face_id = iface;
    1516             :       found_face_id = true;
    1517             :       break;
    1518             :     }
    1519             :   }
    1520      258333 :   if (!found_face_id)
    1521           0 :     EFAError("input face not found in get_face_id()");
    1522      258333 :   return face_id;
    1523             : }
    1524             : 
    1525             : std::vector<unsigned int>
    1526     2000876 : EFAElement3D::getCommonFaceID(const EFAElement3D * other_elem) const
    1527             : {
    1528             :   std::vector<unsigned int> face_id;
    1529    10897268 :   for (unsigned int i = 0; i < _num_faces; ++i)
    1530    48895602 :     for (unsigned int j = 0; j < other_elem->_num_faces; ++j)
    1531    40316538 :       if (_faces[i]->equivalent(other_elem->_faces[j]))
    1532             :       {
    1533      317328 :         face_id.push_back(i);
    1534             :         break;
    1535             :       }
    1536             : 
    1537     2000876 :   return face_id;
    1538           0 : }
    1539             : 
    1540             : bool
    1541     1347038 : EFAElement3D::getCommonEdgeID(const EFAElement3D * other_elem,
    1542             :                               std::vector<std::pair<unsigned int, unsigned int>> & common_ids) const
    1543             : {
    1544             :   // all edges of the other element
    1545             :   std::set<std::pair<EFANode *, EFANode *>> other_edges;
    1546     7060010 :   for (const auto k : index_range(other_elem->_faces))
    1547             :   {
    1548     5712972 :     const auto & face = *other_elem->_faces[k];
    1549    23826348 :     for (const auto l : make_range(other_elem->_faces[k]->numEdges()))
    1550             :     {
    1551             :       const auto & edge = *face.getEdge(l);
    1552    18113376 :       other_edges.insert(edge.getSortedNodes());
    1553             :     }
    1554             :   }
    1555             : 
    1556             :   // loop over all edges of this element
    1557     1347038 :   common_ids.clear();
    1558     7060010 :   for (const auto i : index_range(_faces))
    1559    23826348 :     for (const auto j : make_range(_faces[i]->numEdges()))
    1560             :     {
    1561    18113376 :       const auto & edge = *_faces[i]->getEdge(j);
    1562    18113376 :       const auto edge_nodes = edge.getSortedNodes();
    1563             : 
    1564             :       // is this edge contained in the other element?
    1565    18113376 :       if (edge.isEmbeddedPermanent() || other_edges.count(edge_nodes) == 0)
    1566    17439528 :         continue;
    1567             : 
    1568      673848 :       common_ids.emplace_back(i, j);
    1569             :     }
    1570             : 
    1571     1347038 :   return common_ids.size() > 0;
    1572             : }
    1573             : 
    1574             : unsigned int
    1575       17308 : EFAElement3D::getNeighborFaceNodeID(unsigned int face_id,
    1576             :                                     unsigned int node_id,
    1577             :                                     EFAElement3D * neighbor_elem) const
    1578             : {
    1579             :   // get the corresponding node_id on the corresponding face of neighbor_elem
    1580             :   bool found_id = false;
    1581             :   unsigned int neigh_face_node_id;
    1582       17308 :   unsigned int common_face_id = getNeighborIndex(neighbor_elem);
    1583       17308 :   if (common_face_id == face_id)
    1584             :   {
    1585       17308 :     unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
    1586       17308 :     EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
    1587       40282 :     for (unsigned int i = 0; i < neigh_face->numNodes(); ++i)
    1588             :     {
    1589       40282 :       if (_faces[face_id]->getNode(node_id) == neigh_face->getNode(i))
    1590             :       {
    1591             :         neigh_face_node_id = i;
    1592             :         found_id = true;
    1593             :         break;
    1594             :       }
    1595             :     }
    1596             :   }
    1597             :   else
    1598           0 :     EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
    1599       17308 :   if (!found_id)
    1600           0 :     EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
    1601       17308 :   return neigh_face_node_id;
    1602             : }
    1603             : 
    1604             : unsigned int
    1605        5836 : EFAElement3D::getNeighborFaceInteriorNodeID(unsigned int face_id,
    1606             :                                             unsigned int node_id,
    1607             :                                             EFAElement3D * neighbor_elem) const
    1608             : {
    1609             :   // get the corresponding node_id on the corresponding face of neighbor_elem
    1610             :   bool found_id = false;
    1611             :   unsigned int neigh_face_node_id;
    1612        5836 :   unsigned int common_face_id = getNeighborIndex(neighbor_elem);
    1613        5836 :   if (common_face_id == face_id)
    1614             :   {
    1615        5836 :     unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
    1616        5836 :     EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
    1617             : 
    1618       13552 :     for (unsigned int i = 0; i < _num_interior_face_nodes; ++i)
    1619             :     {
    1620       13552 :       if (_faces[face_id]->getInteriorFaceNode(node_id) == neigh_face->getInteriorFaceNode(i))
    1621             :       {
    1622             :         neigh_face_node_id = i;
    1623             :         found_id = true;
    1624             :         break;
    1625             :       }
    1626             :     }
    1627             :   }
    1628             :   else
    1629           0 :     EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
    1630        5836 :   if (!found_id)
    1631           0 :     EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
    1632        5836 :   return neigh_face_node_id;
    1633             : }
    1634             : 
    1635             : unsigned int
    1636       39292 : EFAElement3D::getNeighborFaceEdgeID(unsigned int face_id,
    1637             :                                     unsigned int edge_id,
    1638             :                                     EFAElement3D * neighbor_elem) const
    1639             : {
    1640             :   // get the corresponding edge_id on the corresponding face of neighbor_elem
    1641             :   bool found_id = false;
    1642             :   unsigned int neigh_face_edge_id;
    1643       39292 :   unsigned int common_face_id = getNeighborIndex(neighbor_elem);
    1644       39292 :   if (common_face_id == face_id)
    1645             :   {
    1646       39292 :     unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
    1647       39292 :     EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
    1648       83108 :     for (unsigned int i = 0; i < neigh_face->numEdges(); ++i)
    1649             :     {
    1650       83108 :       if (_faces[face_id]->getEdge(edge_id)->equivalent(*neigh_face->getEdge(i)))
    1651             :       {
    1652             :         neigh_face_edge_id = i;
    1653             :         found_id = true;
    1654             :         break;
    1655             :       }
    1656             :     }
    1657             :   }
    1658             :   else
    1659           0 :     EFAError("getNeighborFaceEdgeID: neighbor_elem is not a neighbor on face_id");
    1660       39292 :   if (!found_id)
    1661           0 :     EFAError("getNeighborFaceEdgeID: could not find neighbor face edge id");
    1662       39292 :   return neigh_face_edge_id;
    1663             : }
    1664             : 
    1665             : void
    1666       46034 : EFAElement3D::findFacesAdjacentToFaces()
    1667             : {
    1668       46034 :   _faces_adjacent_to_faces.clear();
    1669      276942 :   for (unsigned int i = 0; i < _faces.size(); ++i)
    1670             :   {
    1671      230908 :     std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr);
    1672     1435172 :     for (unsigned int j = 0; j < _faces.size(); ++j)
    1673             :     {
    1674     1204264 :       if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j]))
    1675             :       {
    1676      833040 :         unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]);
    1677      833040 :         face_adjacents[adj_edge] = _faces[j];
    1678             :       }
    1679             :     }
    1680      230908 :     _faces_adjacent_to_faces.push_back(face_adjacents);
    1681      230908 :   }
    1682       46034 : }
    1683             : 
    1684             : EFAFace *
    1685       99393 : EFAElement3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
    1686             : {
    1687       99393 :   return _faces_adjacent_to_faces[face_id][edge_id];
    1688             : }
    1689             : 
    1690             : EFAFace *
    1691      129073 : EFAElement3D::getFragmentFace(unsigned int frag_id, unsigned int face_id) const
    1692             : {
    1693      129073 :   if (frag_id < _fragments.size())
    1694      129073 :     return _fragments[frag_id]->getFace(face_id);
    1695             :   else
    1696           0 :     EFAError("frag_id out of bounds in getFragmentFace");
    1697             : }
    1698             : 
    1699             : std::set<EFANode *>
    1700       14284 : EFAElement3D::getPhantomNodeOnFace(unsigned int face_id) const
    1701             : {
    1702             :   std::set<EFANode *> phantom_nodes;
    1703       14284 :   if (_fragments.size() > 0)
    1704             :   {
    1705       65500 :     for (unsigned int j = 0; j < _faces[face_id]->numNodes(); ++j) // loop ove 2 edge nodes
    1706             :     {
    1707             :       bool node_in_frag = false;
    1708       74640 :       for (unsigned int k = 0; k < _fragments.size(); ++k)
    1709             :       {
    1710       51216 :         if (_fragments[k]->containsNode(_faces[face_id]->getNode(j)))
    1711             :         {
    1712             :           node_in_frag = true;
    1713             :           break;
    1714             :         }
    1715             :       }
    1716       51216 :       if (!node_in_frag)
    1717       23424 :         phantom_nodes.insert(_faces[face_id]->getNode(j));
    1718             :     }
    1719             :   }
    1720       14284 :   return phantom_nodes;
    1721             : }
    1722             : 
    1723             : bool
    1724       19484 : EFAElement3D::getFragmentFaceID(unsigned int elem_face_id, unsigned int & frag_face_id) const
    1725             : {
    1726             :   // find the fragment face that is contained by given element edge
    1727             :   // N.B. if the elem edge contains two frag edges, this method will only return
    1728             :   // the first frag edge ID
    1729             :   bool frag_face_found = false;
    1730       19484 :   frag_face_id = std::numeric_limits<unsigned int>::max();
    1731       19484 :   if (_fragments.size() == 1)
    1732             :   {
    1733        1344 :     for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
    1734             :     {
    1735        1344 :       if (_faces[elem_face_id]->containsFace(_fragments[0]->getFace(j)))
    1736             :       {
    1737         384 :         frag_face_id = j;
    1738             :         frag_face_found = true;
    1739         384 :         break;
    1740             :       }
    1741             :     }
    1742             :   }
    1743       19484 :   return frag_face_found;
    1744             : }
    1745             : 
    1746             : bool
    1747        9806 : EFAElement3D::getFragmentFaceEdgeID(unsigned int ElemFaceID,
    1748             :                                     unsigned int ElemFaceEdgeID,
    1749             :                                     unsigned int & FragFaceID,
    1750             :                                     unsigned int & FragFaceEdgeID) const
    1751             : {
    1752             :   // Purpose: given an edge of an elem face, find which frag face's edge it contains
    1753             :   bool frag_edge_found = false;
    1754        9806 :   FragFaceID = FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
    1755        9806 :   if (getFragmentFaceID(ElemFaceID, FragFaceID))
    1756             :   {
    1757         256 :     EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
    1758         256 :     EFAFace * frag_face = getFragmentFace(0, FragFaceID);
    1759         640 :     for (unsigned int i = 0; i < frag_face->numEdges(); ++i)
    1760             :     {
    1761         640 :       if (elem_edge->containsEdge(*frag_face->getEdge(i)))
    1762             :       {
    1763         256 :         FragFaceEdgeID = i;
    1764             :         frag_edge_found = true;
    1765         256 :         break;
    1766             :       }
    1767             :     }
    1768             :   }
    1769        9806 :   return frag_edge_found;
    1770             : }
    1771             : 
    1772             : bool
    1773        9678 : EFAElement3D::isPhysicalEdgeCut(unsigned int ElemFaceID,
    1774             :                                 unsigned int ElemFaceEdgeID,
    1775             :                                 double position) const
    1776             : {
    1777        9678 :   unsigned int FragFaceID, FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
    1778             :   bool is_in_real = false;
    1779        9678 :   if (_fragments.size() == 0)
    1780             :   {
    1781             :     is_in_real = true;
    1782             :   }
    1783         128 :   else if (getFragmentFaceEdgeID(ElemFaceID, ElemFaceEdgeID, FragFaceID, FragFaceEdgeID))
    1784             :   {
    1785         128 :     EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
    1786         128 :     EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
    1787             :     double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
    1788         128 :     xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
    1789         128 :     xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
    1790         128 :     if ((position - xi[0]) * (position - xi[1]) <
    1791             :         0.0) // the cut to be added is within the real part of the edge
    1792             :       is_in_real = true;
    1793             :   }
    1794        9678 :   return is_in_real;
    1795             : }
    1796             : 
    1797             : bool
    1798       15746 : EFAElement3D::isFacePhantom(unsigned int face_id) const
    1799             : {
    1800             :   bool is_phantom = false;
    1801       15746 :   if (_fragments.size() > 0)
    1802             :   {
    1803             :     bool contains_frag_face = false;
    1804       11550 :     for (unsigned int i = 0; i < _fragments.size(); ++i)
    1805             :     {
    1806       31474 :       for (unsigned int j = 0; j < _fragments[i]->numFaces(); ++j)
    1807             :       {
    1808       31474 :         if (_faces[face_id]->containsFace(_fragments[i]->getFace(j)))
    1809             :         {
    1810             :           contains_frag_face = true;
    1811             :           break;
    1812             :         }
    1813             :       }
    1814       11550 :       if (contains_frag_face)
    1815             :         break;
    1816             :     }
    1817       11550 :     if (!contains_frag_face)
    1818             :       is_phantom = true;
    1819             :   }
    1820       15746 :   return is_phantom;
    1821             : }
    1822             : 
    1823             : unsigned int
    1824     1395897 : EFAElement3D::numFaceNeighbors(unsigned int face_id) const
    1825             : {
    1826     1395897 :   return _face_neighbors[face_id].size();
    1827             : }
    1828             : 
    1829             : unsigned int
    1830       69794 : EFAElement3D::numEdgeNeighbors(unsigned int face_id, unsigned int edge_id) const
    1831             : {
    1832       69794 :   return _face_edge_neighbors[face_id][edge_id].size();
    1833             : }
    1834             : 
    1835             : EFAElement3D *
    1836      677687 : EFAElement3D::getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
    1837             : {
    1838      677687 :   if (_face_neighbors[face_id][0] != nullptr && neighbor_id < _face_neighbors[face_id].size())
    1839      677687 :     return _face_neighbors[face_id][neighbor_id];
    1840             :   else
    1841           0 :     EFAError("edge neighbor does not exist");
    1842             : }
    1843             : 
    1844             : EFAElement3D *
    1845       37900 : EFAElement3D::getEdgeNeighbor(unsigned int face_id,
    1846             :                               unsigned int edge_id,
    1847             :                               unsigned int neighbor_id) const
    1848             : {
    1849       37900 :   if (neighbor_id < _face_edge_neighbors[face_id][edge_id].size())
    1850       37900 :     return _face_edge_neighbors[face_id][edge_id][neighbor_id];
    1851             :   else
    1852           0 :     EFAError("edge neighbor does not exist");
    1853             : }
    1854             : 
    1855             : bool
    1856       51333 : EFAElement3D::fragmentHasTipFaces() const
    1857             : {
    1858             :   bool has_tip_faces = false;
    1859       51333 :   if (_fragments.size() == 1)
    1860             :   {
    1861       82970 :     for (unsigned int i = 0; i < _num_faces; ++i)
    1862             :     {
    1863             :       unsigned int num_frag_faces = 0; // count how many fragment edges this element edge contains
    1864       71206 :       if (_faces[i]->hasIntersection())
    1865             :       {
    1866      303040 :         for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
    1867             :         {
    1868      256536 :           if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
    1869       50160 :             num_frag_faces += 1;
    1870             :         } // j
    1871       46504 :         if (num_frag_faces == 2)
    1872             :         {
    1873             :           has_tip_faces = true;
    1874             :           break;
    1875             :         }
    1876             :       }
    1877             :     } // i
    1878             :   }
    1879       51333 :   return has_tip_faces;
    1880             : }
    1881             : 
    1882             : std::vector<unsigned int>
    1883           0 : EFAElement3D::getTipFaceIDs() const
    1884             : {
    1885             :   // if this element is a crack tip element, returns the crack tip faces' ID
    1886             :   std::vector<unsigned int> tip_face_id;
    1887           0 :   if (_fragments.size() == 1) // crack tip element with a partial fragment saved
    1888             :   {
    1889           0 :     for (unsigned int i = 0; i < _num_faces; ++i)
    1890             :     {
    1891             :       unsigned int num_frag_faces = 0; // count how many fragment faces this element edge contains
    1892           0 :       if (_faces[i]->hasIntersection())
    1893             :       {
    1894           0 :         for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
    1895             :         {
    1896           0 :           if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
    1897           0 :             num_frag_faces += 1;
    1898             :         }                        // j
    1899           0 :         if (num_frag_faces == 2) // element face contains two fragment edges
    1900           0 :           tip_face_id.push_back(i);
    1901             :       }
    1902             :     } // i
    1903             :   }
    1904           0 :   return tip_face_id;
    1905           0 : }
    1906             : 
    1907             : std::set<EFANode *>
    1908           0 : EFAElement3D::getTipEmbeddedNodes() const
    1909             : {
    1910             :   // if this element is a crack tip element, returns the crack tip edge's ID
    1911             :   std::set<EFANode *> tip_emb;
    1912           0 :   if (_fragments.size() == 1) // crack tip element with a partial fragment saved
    1913             :   {
    1914           0 :     for (unsigned int i = 0; i < _num_faces; ++i)
    1915             :     {
    1916             :       std::vector<EFAFace *> frag_faces; // count how many fragment edges this element edge contains
    1917           0 :       if (_faces[i]->hasIntersection())
    1918             :       {
    1919           0 :         for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
    1920             :         {
    1921           0 :           if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
    1922           0 :             frag_faces.push_back(_fragments[0]->getFace(j));
    1923             :         }                           // j
    1924           0 :         if (frag_faces.size() == 2) // element edge contains two fragment edges
    1925             :         {
    1926           0 :           unsigned int edge_id = frag_faces[0]->adjacentCommonEdge(frag_faces[1]);
    1927           0 :           tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(0));
    1928           0 :           tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(1));
    1929             :         }
    1930             :       }
    1931           0 :     } // i
    1932             :   }
    1933           0 :   return tip_emb;
    1934             : }
    1935             : 
    1936             : bool
    1937        9678 : EFAElement3D::faceContainsTip(unsigned int face_id) const
    1938             : {
    1939             :   bool contain_tip = false;
    1940        9678 :   if (_fragments.size() == 1)
    1941             :   {
    1942             :     unsigned int num_frag_faces = 0; // count how many fragment faces this element face contains
    1943         128 :     if (_faces[face_id]->hasIntersection())
    1944             :     {
    1945           0 :       for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
    1946             :       {
    1947           0 :         if (_faces[face_id]->containsFace(_fragments[0]->getFace(j)))
    1948           0 :           num_frag_faces += 1;
    1949             :       } // j
    1950           0 :       if (num_frag_faces == 2)
    1951             :         contain_tip = true;
    1952             :     }
    1953             :   }
    1954        9678 :   return contain_tip;
    1955             : }
    1956             : 
    1957             : bool
    1958        9678 : EFAElement3D::fragmentFaceAlreadyCut(unsigned int ElemFaceID) const
    1959             : {
    1960             :   // when marking cuts, check if the corresponding frag face already has been cut
    1961             :   bool has_cut = false;
    1962        9678 :   if (faceContainsTip(ElemFaceID))
    1963             :     has_cut = true;
    1964             :   else
    1965             :   {
    1966        9678 :     unsigned int FragFaceID = std::numeric_limits<unsigned int>::max();
    1967        9678 :     if (getFragmentFaceID(ElemFaceID, FragFaceID))
    1968             :     {
    1969         128 :       EFAFace * frag_face = getFragmentFace(0, FragFaceID);
    1970         128 :       if (frag_face->hasIntersection())
    1971             :         has_cut = true;
    1972             :     }
    1973             :   }
    1974        9678 :   return has_cut;
    1975             : }
    1976             : 
    1977             : void
    1978       99393 : EFAElement3D::addFaceEdgeCut(unsigned int face_id,
    1979             :                              unsigned int edge_id,
    1980             :                              double position,
    1981             :                              EFANode * embedded_node,
    1982             :                              std::map<unsigned int, EFANode *> & EmbeddedNodes,
    1983             :                              bool add_to_neighbor,
    1984             :                              bool add_to_adjacent)
    1985             : {
    1986             :   // Purpose: add intersection on Edge edge_id of Face face_id
    1987       99393 :   EFANode * local_embedded = nullptr;
    1988       99393 :   EFAEdge * cut_edge = _faces[face_id]->getEdge(edge_id);
    1989       99393 :   EFANode * edge_node1 = cut_edge->getNode(0);
    1990       99393 :   if (embedded_node) // use the existing embedded node if it was passed in
    1991       67499 :     local_embedded = embedded_node;
    1992             : 
    1993             :   // get adjacent face info
    1994       99393 :   EFAFace * adj_face = getAdjacentFace(face_id, edge_id);
    1995       99393 :   unsigned int adj_face_id = getFaceID(adj_face);
    1996       99393 :   unsigned int adj_edge_id = adj_face->adjacentCommonEdge(_faces[face_id]);
    1997             : 
    1998             :   // check if cut has already been added to this face edge
    1999             :   bool cut_exist = false;
    2000             : 
    2001       99393 :   if (cut_edge->hasIntersectionAtPosition(position, edge_node1))
    2002             :   {
    2003       89715 :     unsigned int emb_id = cut_edge->getEmbeddedNodeIndex(position, edge_node1);
    2004       89715 :     EFANode * old_emb = cut_edge->getEmbeddedNode(emb_id);
    2005       89715 :     if (embedded_node && embedded_node != old_emb)
    2006           0 :       EFAError("Attempting to add edge intersection when one already exists with different node.",
    2007             :                " elem: ",
    2008             :                _id,
    2009             :                " edge: ",
    2010             :                edge_id,
    2011             :                " position: ",
    2012             :                position);
    2013       89715 :     local_embedded = old_emb;
    2014             :     cut_exist = true;
    2015             :   }
    2016             : 
    2017       19356 :   if (!cut_exist && !fragmentFaceAlreadyCut(face_id) &&
    2018        9678 :       isPhysicalEdgeCut(face_id, edge_id, position))
    2019             :   {
    2020             :     // check if cut has already been added to the neighbor edges
    2021        9678 :     checkNeighborFaceCut(face_id, edge_id, position, edge_node1, embedded_node, local_embedded);
    2022        9678 :     checkNeighborFaceCut(
    2023             :         adj_face_id, adj_edge_id, position, edge_node1, embedded_node, local_embedded);
    2024             : 
    2025        9678 :     if (!local_embedded) // need to create new embedded node
    2026             :     {
    2027        1766 :       unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
    2028        1766 :       local_embedded = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
    2029        1766 :       EmbeddedNodes.insert(std::make_pair(new_node_id, local_embedded));
    2030             :     }
    2031             : 
    2032             :     // add to elem face edge
    2033        9678 :     cut_edge->addIntersection(position, local_embedded, edge_node1);
    2034        9678 :     if (cut_edge->numEmbeddedNodes() > 2)
    2035           0 :       EFAError("element edge can't have >2 embedded nodes");
    2036             : 
    2037             :     // cut fragment faces, which is an essential addition to other code in this method that cuts
    2038             :     // element faces
    2039             :     unsigned int FragFaceID;
    2040             :     unsigned int FragFaceEdgeID;
    2041        9678 :     if (getFragmentFaceEdgeID(face_id, edge_id, FragFaceID, FragFaceEdgeID))
    2042             :     {
    2043         128 :       EFAEdge * elem_edge = _faces[face_id]->getEdge(edge_id);
    2044         128 :       EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
    2045             :       double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
    2046         128 :       xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
    2047         128 :       xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
    2048         128 :       double frag_pos = (position - xi[0]) / (xi[1] - xi[0]);
    2049         128 :       EFANode * frag_edge_node1 = frag_edge->getNode(0);
    2050             : 
    2051         128 :       if (!frag_edge->hasIntersection())
    2052         128 :         frag_edge->addIntersection(frag_pos, local_embedded, frag_edge_node1);
    2053             :     }
    2054             : 
    2055             :     // add to adjacent face edge
    2056        9678 :     if (add_to_adjacent)
    2057             :     {
    2058        4839 :       double adj_pos = 1.0 - position;
    2059        4839 :       addFaceEdgeCut(
    2060             :           adj_face_id, adj_edge_id, adj_pos, local_embedded, EmbeddedNodes, false, false);
    2061             :     }
    2062             :   }
    2063             : 
    2064             :   // add cut to neighbor face edge
    2065       99393 :   if (add_to_neighbor)
    2066             :   {
    2067       56654 :     for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
    2068             :     {
    2069       24760 :       EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
    2070       24760 :       unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
    2071       24760 :       unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
    2072       24760 :       double neigh_pos = 1.0 - position; // get emb node's postion on neighbor edge
    2073       24760 :       face_neighbor->addFaceEdgeCut(
    2074             :           neigh_face_id, neigh_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false, true);
    2075             :     }
    2076             : 
    2077       69794 :     for (unsigned int en_iter = 0; en_iter < numEdgeNeighbors(face_id, edge_id); ++en_iter)
    2078             :     {
    2079       37900 :       EFAElement3D * edge_neighbor = getEdgeNeighbor(face_id, edge_id, en_iter);
    2080             :       unsigned int neigh_face_id, neigh_edge_id;
    2081       37900 :       getNeighborEdgeIndex(edge_neighbor, face_id, edge_id, neigh_face_id, neigh_edge_id);
    2082             : 
    2083             :       // Check the ordering of the node and the assign the position
    2084             :       double neigh_pos;
    2085       75800 :       if (_faces[face_id]->getEdge(edge_id)->getNode(0) ==
    2086       37900 :           edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
    2087             :         neigh_pos = position;
    2088       37818 :       else if (_faces[face_id]->getEdge(edge_id)->getNode(1) ==
    2089       18909 :                edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
    2090       18909 :         neigh_pos = 1.0 - position;
    2091             :       else
    2092           0 :         EFAError("The EFANodes on commaon edge are not matched.");
    2093             : 
    2094       37900 :       edge_neighbor->addFaceEdgeCut(
    2095             :           neigh_face_id, neigh_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false, true);
    2096             :     }
    2097             :   } // If add_to_neighbor required
    2098       99393 : }
    2099             : 
    2100             : void
    2101           0 : EFAElement3D::addFragFaceEdgeCut(unsigned int /*frag_face_id*/,
    2102             :                                  unsigned int /*frag_edge_id*/,
    2103             :                                  double /*position*/,
    2104             :                                  std::map<unsigned int, EFANode *> & /*EmbeddedNodes*/,
    2105             :                                  bool /*add_to_neighbor*/,
    2106             :                                  bool /*add_to_adjacent*/)
    2107             : {
    2108             :   // TODO: mark frag face edges
    2109             :   // also need to check if cut has been added to this frag face edge or neighbor edge of adjacent
    2110             :   // face
    2111           0 : }
    2112             : 
    2113             : void
    2114       19356 : EFAElement3D::checkNeighborFaceCut(unsigned int face_id,
    2115             :                                    unsigned int edge_id,
    2116             :                                    double position,
    2117             :                                    EFANode * from_node,
    2118             :                                    EFANode * embedded_node,
    2119             :                                    EFANode *& local_embedded)
    2120             : {
    2121             :   // N.B. this is important. We are checking if the corresponding edge of the neighbor face or of
    2122             :   // the adjacent
    2123             :   // face's neighbor face has a cut at the same position. If so, use the existing embedded node as
    2124             :   // local_embedded
    2125       33888 :   for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
    2126             :   {
    2127       14532 :     EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
    2128       14532 :     unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
    2129       14532 :     unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
    2130       14532 :     EFAEdge * neigh_edge = face_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id);
    2131             : 
    2132       14532 :     if (neigh_edge->hasIntersectionAtPosition(position, from_node))
    2133             :     {
    2134        7332 :       unsigned int emb_id = neigh_edge->getEmbeddedNodeIndex(position, from_node);
    2135        7332 :       EFANode * old_emb = neigh_edge->getEmbeddedNode(emb_id);
    2136             : 
    2137        7332 :       if (embedded_node && embedded_node != old_emb)
    2138           0 :         EFAError(
    2139             :             "attempting to add edge intersection when one already exists with different node.");
    2140        7332 :       if (local_embedded && local_embedded != old_emb)
    2141           0 :         EFAError("attempting to assign contradictory pointer to local_embedded.");
    2142             : 
    2143        7332 :       local_embedded = old_emb;
    2144             :     }
    2145             :   } // en_iter
    2146       19356 : }
    2147             : 
    2148             : void
    2149           0 : EFAElement3D::mapParametricCoordinateFrom2DTo3D(unsigned int face_id,
    2150             :                                                 std::vector<double> & xi_2d,
    2151             :                                                 std::vector<double> & xi_3d) const
    2152             : {
    2153             :   // given the coords of a point in a 2D face, translate it to 3D parametric coords
    2154           0 :   xi_3d.resize(3, 0.0);
    2155           0 :   if (_num_faces == 6)
    2156             :   {
    2157             :     if (face_id == 0)
    2158             :     {
    2159           0 :       xi_3d[0] = xi_2d[1];
    2160           0 :       xi_3d[1] = xi_2d[0];
    2161           0 :       xi_3d[2] = -1.0;
    2162             :     }
    2163             :     else if (face_id == 1)
    2164             :     {
    2165           0 :       xi_3d[0] = xi_2d[0];
    2166           0 :       xi_3d[1] = -1.0;
    2167           0 :       xi_3d[2] = xi_2d[1];
    2168             :     }
    2169             :     else if (face_id == 2)
    2170             :     {
    2171           0 :       xi_3d[0] = 1.0;
    2172           0 :       xi_3d[1] = xi_2d[0];
    2173           0 :       xi_3d[2] = xi_2d[1];
    2174             :     }
    2175             :     else if (face_id == 3)
    2176             :     {
    2177           0 :       xi_3d[0] = -xi_2d[0];
    2178           0 :       xi_3d[1] = 1.0;
    2179           0 :       xi_3d[2] = xi_2d[1];
    2180             :     }
    2181             :     else if (face_id == 4)
    2182             :     {
    2183           0 :       xi_3d[0] = -1.0;
    2184           0 :       xi_3d[1] = -xi_2d[0];
    2185           0 :       xi_3d[2] = xi_2d[1];
    2186             :     }
    2187             :     else if (face_id == 5)
    2188             :     {
    2189           0 :       xi_3d[0] = xi_2d[0];
    2190           0 :       xi_3d[1] = xi_2d[1];
    2191           0 :       xi_3d[2] = 1.0;
    2192             :     }
    2193             :     else
    2194           0 :       EFAError("face_id out of bounds");
    2195             :   }
    2196           0 :   else if (_num_faces == 4)
    2197             :   {
    2198           0 :     if (face_id == 0)
    2199             :     {
    2200           0 :       xi_3d[0] = xi_2d[0];
    2201           0 :       xi_3d[1] = xi_2d[1];
    2202           0 :       xi_3d[2] = 0.0;
    2203             :     }
    2204           0 :     else if (face_id == 1)
    2205             :     {
    2206           0 :       xi_3d[0] = 0.0;
    2207           0 :       xi_3d[1] = xi_2d[0];
    2208           0 :       xi_3d[2] = xi_2d[1];
    2209             :     }
    2210           0 :     else if (face_id == 2)
    2211             :     {
    2212           0 :       xi_3d[0] = xi_2d[1];
    2213           0 :       xi_3d[1] = 0.0;
    2214           0 :       xi_3d[2] = xi_2d[0];
    2215             :     }
    2216           0 :     else if (face_id == 3)
    2217             :     {
    2218           0 :       xi_3d[0] = xi_2d[0];
    2219           0 :       xi_3d[1] = xi_2d[2];
    2220           0 :       xi_3d[2] = xi_2d[1];
    2221             :     }
    2222             :     else
    2223           0 :       EFAError("face_id out of bounds");
    2224             :   }
    2225             :   else
    2226           0 :     EFAError("unknown element for 3D");
    2227           0 : }
    2228             : 
    2229             : std::vector<EFANode *>
    2230           0 : EFAElement3D::getCommonNodes(const EFAElement3D * other_elem) const
    2231             : {
    2232             :   std::set<EFANode *> e1nodes(_nodes.begin(),
    2233           0 :                               _nodes.begin() + _num_vertices); // only account for corner nodes
    2234             :   std::set<EFANode *> e2nodes(other_elem->_nodes.begin(),
    2235           0 :                               other_elem->_nodes.begin() + _num_vertices);
    2236           0 :   std::vector<EFANode *> common_nodes = Efa::getCommonElems(e1nodes, e2nodes);
    2237           0 :   return common_nodes;
    2238             : }

Generated by: LCOV version 1.14