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