www.mooseframework.org
EFAElement3D.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 normal(0.0, 0.0, 0.0);
1012  EFAPoint orig(0.0, 0.0, 0.0);
1013 
1014  if (cut_plane_nodes.size())
1015  {
1016  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  this->getMasterInfo(cut_plane_nodes[0][i], master_nodes, master_weights);
1022  EFAPoint coor(0.0, 0.0, 0.0);
1023  for (unsigned int i = 0; i < master_nodes.size(); ++i)
1024  {
1025  EFANode * local = this->createLocalNodeFromGlobalNode(master_nodes[i]);
1026  coor += _local_node_coor[local->id()] * master_weights[i];
1027  delete local;
1028  }
1029  cut_plane_points.push_back(coor);
1030  }
1031  for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1032  orig += cut_plane_points[i];
1033  orig /= cut_plane_points.size();
1034 
1035  EFAPoint center(0.0, 0.0, 0.0);
1036  for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1037  center += cut_plane_points[i];
1038  center /= cut_plane_points.size();
1039 
1040  for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1041  {
1042  unsigned int iplus1 = i < cut_plane_points.size() - 1 ? i + 1 : 0;
1043  EFAPoint ray1 = cut_plane_points[i] - center;
1044  EFAPoint ray2 = cut_plane_points[iplus1] - center;
1045  normal += ray1.cross(ray2);
1046  }
1047  normal /= cut_plane_points.size();
1048  Xfem::normalizePoint(normal);
1049  }
1050 
1051  // get child element's nodes
1052  for (unsigned int j = 0; j < _num_nodes; ++j)
1053  {
1054  EFAPoint p(0.0, 0.0, 0.0);
1055  p = _local_node_coor[j];
1056  EFAPoint origin_to_point = p - orig;
1057  if (_fragments.size() == 1 && !shouldDuplicateForCrackTip(CrackTipElements))
1058  childElem->setNode(j, _nodes[j]); // inherit parent's node
1059  else if (origin_to_point * normal < Xfem::tol)
1060  childElem->setNode(j, _nodes[j]); // inherit parent's node
1061  else // parent element's node is not in fragment
1062  {
1063  unsigned int new_node_id = Efa::getNewID(TempNodes);
1064  EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
1065  TempNodes.insert(std::make_pair(new_node_id, newNode));
1066  childElem->setNode(j, newNode); // be a temp node
1067  }
1068  }
1069 
1070  // get child element's fragments
1071  EFAFragment3D * new_frag = new EFAFragment3D(childElem, true, this, ichild);
1072  childElem->_fragments.push_back(new_frag);
1073 
1074  // get child element's faces and set up adjacent faces
1075  childElem->createFaces();
1076  for (unsigned int j = 0; j < _num_faces; ++j)
1077  childElem->_faces[j]->copyIntersection(*_faces[j]);
1078  childElem->removePhantomEmbeddedNode(); // IMPORTANT
1079 
1080  // inherit old interior nodes
1081  for (unsigned int j = 0; j < _interior_nodes.size(); ++j)
1082  childElem->_interior_nodes.push_back(new EFAVolumeNode(*_interior_nodes[j]));
1083  }
1084  }
1085  else // num_links == 1 || num_links == 0
1086  {
1087  // child is itself - but don't insert into the list of ChildElements!!!
1088  _children.push_back(this);
1089  }
1090 }
1091 
1092 void
1094 {
1095  // remove the embedded nodes on faces that are outside the real domain
1096  if (_fragments.size() > 0)
1097  {
1098  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  for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
1103  {
1104  EFAEdge * edge = _faces[i]->getEdge(j);
1105  for (unsigned int k = 0; k < edge->numEmbeddedNodes(); ++k)
1106  {
1107  if (!_fragments[0]->containsNode(edge->getEmbeddedNode(k)))
1108  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  for (unsigned int j = 0; j < _faces[i]->numInteriorNodes(); ++j)
1114  {
1115  EFANode * face_node = _faces[i]->getInteriorNode(j)->getNode();
1116  if (!_fragments[0]->containsNode(face_node))
1117  nodes_to_delete.push_back(face_node);
1118  } // j
1119 
1120  // remove all invalid embedded nodes
1121  for (unsigned int j = 0; j < nodes_to_delete.size(); ++j)
1122  _faces[i]->removeEmbeddedNode(nodes_to_delete[j]);
1123  } // i
1124  }
1125 }
1126 
1127 void
1128 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  if (!_parent)
1135  EFAError("no parent element for child element ", _id, " in connect_neighbors");
1136  EFAElement3D * parent3d = dynamic_cast<EFAElement3D *>(_parent);
1137  if (!parent3d)
1138  EFAError("cannot dynamic cast to parent3d in connect_neighbors");
1139 
1140  // First loop through edges and merge nodes with neighbors as appropriate
1141  for (unsigned int j = 0; j < _num_faces; ++j)
1142  {
1143  for (unsigned int k = 0; k < parent3d->numFaceNeighbors(j); ++k)
1144  {
1145  EFAElement3D * NeighborElem = parent3d->getFaceNeighbor(j, k);
1146  unsigned int neighbor_face_id = NeighborElem->getNeighborIndex(parent3d);
1147 
1148  if (_faces[j]->hasIntersection())
1149  {
1150  for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
1151  {
1152  EFAElement3D * childOfNeighborElem =
1153  dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
1154  if (!childOfNeighborElem)
1155  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  EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
1159  if (_faces[j]->equivalent(neighborChildFace))
1160  continue;
1161 
1162  if (_fragments[0]->isConnected(childOfNeighborElem->getFragment(0)))
1163  {
1164  for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
1165  {
1166  unsigned int childNodeIndex = i;
1167  unsigned int neighborChildNodeIndex =
1168  parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
1169 
1170  EFANode * childNode = _faces[j]->getNode(childNodeIndex);
1171  EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
1172  mergeNodes(
1173  childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
1174  } // i
1175 
1176  for (unsigned int m = 0; m < _num_interior_face_nodes; ++m)
1177  {
1178  unsigned int childNodeIndex = m;
1179  unsigned int neighborChildNodeIndex =
1180  parent3d->getNeighborFaceInteriorNodeID(j, childNodeIndex, NeighborElem);
1181 
1182  EFANode * childNode = _faces[j]->getInteriorFaceNode(childNodeIndex);
1183  EFANode * childOfNeighborNode =
1184  neighborChildFace->getInteriorFaceNode(neighborChildNodeIndex);
1185  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  if (merge_phantom_faces)
1195  {
1196  for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
1197  {
1198  EFAElement3D * childOfNeighborElem =
1199  dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
1200  if (!childOfNeighborElem)
1201  EFAError("dynamic cast childOfNeighborElem fails");
1202 
1203  EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
1204  if (!neighborChildFace
1205  ->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  if (_faces[j]->equivalent(neighborChildFace))
1210  continue;
1211 
1212  for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
1213  {
1214  unsigned int childNodeIndex = i;
1215  unsigned int neighborChildNodeIndex =
1216  parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
1217 
1218  EFANode * childNode = _faces[j]->getNode(childNodeIndex);
1219  EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
1220 
1221  if (childNode->parent() != nullptr &&
1222  childNode->parent() ==
1223  childOfNeighborNode
1224  ->parent()) // non-material node and both come from same parent
1225  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  for (unsigned int j = 0; j < _num_nodes; ++j)
1241  {
1242  EFANode * childNode = _nodes[j];
1243  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  std::set<EFAElement *> patch_elems = InverseConnectivityMap[childNode->parent()];
1249  if (parent3d->numFragments() == 1 && patch_elems.size() == 1)
1250  switchNode(childNode->parent(), childNode, false);
1251  else
1252  {
1253  unsigned int new_node_id = Efa::getNewID(PermanentNodes);
1254  EFANode * newNode =
1255  new EFANode(new_node_id, EFANode::N_CATEGORY_PERMANENT, childNode->parent());
1256  PermanentNodes.insert(std::make_pair(new_node_id, newNode));
1257  switchNode(newNode, childNode, false);
1258  }
1259  if (!Efa::deleteFromMap(TempNodes, childNode))
1260  EFAError(
1261  "Attempted to delete node: ", childNode->id(), " from TempNodes, but couldn't find it");
1262  }
1263  }
1264 }
1265 
1266 void
1267 EFAElement3D::printElement(std::ostream & ostream) const
1268 {
1269  // first line: all elem faces
1270  ostream << std::setw(5);
1271  ostream << _id << "| ";
1272  for (unsigned int j = 0; j < _num_faces; ++j)
1273  {
1274  for (unsigned int k = 0; k < _faces[j]->numNodes(); ++k)
1275  ostream << std::setw(5) << _faces[j]->getNode(k)->idCatString();
1276  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  << "| ";
1284  for (unsigned int j = 0; j < _num_faces; ++j)
1285  {
1286  for (unsigned int k = 0; k < _faces[j]->numEdges(); ++k)
1287  {
1288  ostream << std::setw(4);
1289  if (_faces[j]->getEdge(k)->hasIntersection())
1290  {
1291  if (_faces[j]->getEdge(k)->numEmbeddedNodes() > 1)
1292  {
1293  ostream << "[";
1294  for (unsigned int l = 0; l < _faces[j]->getEdge(k)->numEmbeddedNodes(); ++l)
1295  {
1296  ostream << _faces[j]->getEdge(k)->getEmbeddedNode(l)->id() << " ";
1297  if (l == _faces[j]->getEdge(k)->numEmbeddedNodes() - 1)
1298  ostream << "]";
1299  else
1300  ostream << " ";
1301  } // l
1302  }
1303  else
1304  ostream << _faces[j]->getEdge(k)->getEmbeddedNode(0)->id() << " ";
1305  }
1306  else
1307  ostream << " -- ";
1308  } // k
1309  ostream << " | ";
1310  } // j
1311  ostream << std::endl;
1312 
1313  // third line: neighbors
1314  ostream << std::setw(5);
1315  ostream << "neigh"
1316  << "| ";
1317  for (unsigned int j = 0; j < _num_faces; ++j)
1318  {
1319  ostream << std::setw(4);
1320  if (numFaceNeighbors(j) > 1)
1321  {
1322  ostream << "[";
1323  for (unsigned int k = 0; k < numFaceNeighbors(j); ++k)
1324  {
1325  ostream << getFaceNeighbor(j, k)->id();
1326  if (k == numFaceNeighbors(j) - 1)
1327  ostream << "]";
1328  else
1329  ostream << " ";
1330  }
1331  }
1332  else
1333  {
1334  if (numFaceNeighbors(j) == 1)
1335  ostream << getFaceNeighbor(j, 0)->id() << " ";
1336  else
1337  ostream << " -- ";
1338  }
1339  }
1340  ostream << std::endl;
1341 
1342  // fourth line: fragments
1343  for (unsigned int j = 0; j < _fragments.size(); ++j)
1344  {
1345  ostream << std::setw(4);
1346  ostream << "frag" << j << "| ";
1347  for (unsigned int k = 0; k < _fragments[j]->numFaces(); ++k)
1348  {
1349  for (unsigned int l = 0; l < _fragments[j]->getFace(k)->numNodes(); ++l)
1350  ostream << std::setw(5) << _fragments[j]->getFace(k)->getNode(l)->idCatString();
1351  ostream << " | ";
1352  }
1353  ostream << std::endl;
1354  }
1355  ostream << std::endl;
1356 }
1357 
1358 EFAFragment3D *
1359 EFAElement3D::getFragment(unsigned int frag_id) const
1360 {
1361  if (frag_id < _fragments.size())
1362  return _fragments[frag_id];
1363  else
1364  EFAError("frag_id out of bounds");
1365 }
1366 
1367 std::set<EFANode *>
1368 EFAElement3D::getFaceNodes(unsigned int face_id) const
1369 {
1370  std::set<EFANode *> face_nodes;
1371  for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i)
1372  face_nodes.insert(_faces[face_id]->getNode(i));
1373  return face_nodes;
1374 }
1375 
1376 bool
1377 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  for (unsigned int i = 0; i < _num_faces; ++i)
1383  {
1384  if (_faces[i]->containsNode(node))
1385  {
1386  face_id = i;
1387  face_found = true;
1388  break;
1389  }
1390  }
1391  if (face_found)
1392  {
1393  std::vector<double> xi_2d(2, 0.0);
1394  if (_faces[face_id]->getFaceNodeParametricCoords(node, xi_2d))
1395  mapParametricCoordinateFrom2DTo3D(face_id, xi_2d, xi_3d);
1396  else
1397  EFAError("failed to get the 2D para coords on the face");
1398  }
1399  return face_found;
1400 }
1401 
1402 EFAVolumeNode *
1403 EFAElement3D::getInteriorNode(unsigned int interior_node_id) const
1404 {
1405  if (interior_node_id < _interior_nodes.size())
1406  return _interior_nodes[interior_node_id];
1407  else
1408  EFAError("interior_node_id out of bounds");
1409 }
1410 
1411 void
1412 EFAElement3D::removeEmbeddedNode(EFANode * emb_node, bool remove_for_neighbor)
1413 {
1414  for (unsigned int i = 0; i < _fragments.size(); ++i)
1415  _fragments[i]->removeEmbeddedNode(emb_node);
1416 
1417  for (unsigned int i = 0; i < _faces.size(); ++i)
1418  _faces[i]->removeEmbeddedNode(emb_node);
1419 
1420  if (remove_for_neighbor)
1421  {
1422  for (unsigned int i = 0; i < numFaces(); ++i)
1423  for (unsigned int j = 0; j < numFaceNeighbors(i); ++j)
1424  getFaceNeighbor(i, j)->removeEmbeddedNode(emb_node, false);
1425  }
1426 }
1427 
1428 unsigned int
1430 {
1431  return _faces.size();
1432 }
1433 
1434 void
1435 EFAElement3D::setFace(unsigned int face_id, EFAFace * face)
1436 {
1437  _faces[face_id] = face;
1438 }
1439 
1440 void
1442 {
1443  // create element faces based on existing element nodes
1444  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  int tet_local_node_indices[4][3] = {{0, 2, 1}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}};
1447 
1448  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  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  _faces = std::vector<EFAFace *>(_num_faces, nullptr);
1458  if (_num_nodes == 8 || _num_nodes == 20 || _num_nodes == 27)
1459  {
1460  if (_num_faces != 6)
1461  EFAError("num_faces of hexes must be 6");
1462  for (unsigned int i = 0; i < _num_faces; ++i)
1463  {
1465  for (unsigned int j = 0; j < 4; ++j)
1466  _faces[i]->setNode(j, _nodes[hex_local_node_indices[i][j]]);
1467  _faces[i]->createEdges();
1468  for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
1469  _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  if (_num_faces != 4)
1475  EFAError("num_faces of tets must be 4");
1476  for (unsigned int i = 0; i < _num_faces; ++i)
1477  {
1479  for (unsigned int j = 0; j < 3; ++j)
1480  _faces[i]->setNode(j, _nodes[tet_local_node_indices[i][j]]);
1481  _faces[i]->createEdges();
1482  for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
1483  _faces[i]->setInteriorFaceNode(k, _nodes[tet_interior_face_node_indices[i][k]]);
1484  }
1485  }
1486  else
1487  EFAError("unknown 3D element type in createFaces()");
1488 
1489  for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
1490  {
1491  _face_edge_neighbors[face_iter].resize(_faces[face_iter]->numEdges());
1492  for (unsigned int edge_iter = 0; edge_iter < _faces[face_iter]->numEdges(); ++edge_iter)
1493  _face_edge_neighbors[face_iter][edge_iter].clear();
1494  }
1495 
1496  // create element face connectivity array
1497  findFacesAdjacentToFaces(); // IMPORTANT
1498 }
1499 
1500 EFAFace *
1501 EFAElement3D::getFace(unsigned int face_id) const
1502 {
1503  return _faces[face_id];
1504 }
1505 
1506 unsigned int
1508 {
1509  bool found_face_id = false;
1510  unsigned int face_id;
1511  for (unsigned int iface = 0; iface < _num_faces; ++iface)
1512  {
1513  if (_faces[iface]->equivalent(face))
1514  {
1515  face_id = iface;
1516  found_face_id = true;
1517  break;
1518  }
1519  }
1520  if (!found_face_id)
1521  EFAError("input face not found in get_face_id()");
1522  return face_id;
1523 }
1524 
1525 std::vector<unsigned int>
1527 {
1528  std::vector<unsigned int> face_id;
1529  for (unsigned int i = 0; i < _num_faces; ++i)
1530  for (unsigned int j = 0; j < other_elem->_num_faces; ++j)
1531  if (_faces[i]->equivalent(other_elem->_faces[j]))
1532  {
1533  face_id.push_back(i);
1534  break;
1535  }
1536 
1537  return face_id;
1538 }
1539 
1540 bool
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  for (const auto k : index_range(other_elem->_faces))
1547  {
1548  const auto & face = *other_elem->_faces[k];
1549  for (const auto l : make_range(other_elem->_faces[k]->numEdges()))
1550  {
1551  const auto & edge = *face.getEdge(l);
1552  other_edges.insert(edge.getSortedNodes());
1553  }
1554  }
1555 
1556  // loop over all edges of this element
1557  common_ids.clear();
1558  for (const auto i : index_range(_faces))
1559  for (const auto j : make_range(_faces[i]->numEdges()))
1560  {
1561  const auto & edge = *_faces[i]->getEdge(j);
1562  const auto edge_nodes = edge.getSortedNodes();
1563 
1564  // is this edge contained in the other element?
1565  if (edge.isEmbeddedPermanent() || other_edges.count(edge_nodes) == 0)
1566  continue;
1567 
1568  common_ids.emplace_back(i, j);
1569  }
1570 
1571  return common_ids.size() > 0;
1572 }
1573 
1574 unsigned int
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  unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1583  if (common_face_id == face_id)
1584  {
1585  unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1586  EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1587  for (unsigned int i = 0; i < neigh_face->numNodes(); ++i)
1588  {
1589  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  EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
1599  if (!found_id)
1600  EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
1601  return neigh_face_node_id;
1602 }
1603 
1604 unsigned int
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  unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1613  if (common_face_id == face_id)
1614  {
1615  unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1616  EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1617 
1618  for (unsigned int i = 0; i < _num_interior_face_nodes; ++i)
1619  {
1620  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  EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
1630  if (!found_id)
1631  EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
1632  return neigh_face_node_id;
1633 }
1634 
1635 unsigned int
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  unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1644  if (common_face_id == face_id)
1645  {
1646  unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1647  EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1648  for (unsigned int i = 0; i < neigh_face->numEdges(); ++i)
1649  {
1650  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  EFAError("getNeighborFaceEdgeID: neighbor_elem is not a neighbor on face_id");
1660  if (!found_id)
1661  EFAError("getNeighborFaceEdgeID: could not find neighbor face edge id");
1662  return neigh_face_edge_id;
1663 }
1664 
1665 void
1667 {
1668  _faces_adjacent_to_faces.clear();
1669  for (unsigned int i = 0; i < _faces.size(); ++i)
1670  {
1671  std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr);
1672  for (unsigned int j = 0; j < _faces.size(); ++j)
1673  {
1674  if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j]))
1675  {
1676  unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]);
1677  face_adjacents[adj_edge] = _faces[j];
1678  }
1679  }
1680  _faces_adjacent_to_faces.push_back(face_adjacents);
1681  }
1682 }
1683 
1684 EFAFace *
1685 EFAElement3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
1686 {
1687  return _faces_adjacent_to_faces[face_id][edge_id];
1688 }
1689 
1690 EFAFace *
1691 EFAElement3D::getFragmentFace(unsigned int frag_id, unsigned int face_id) const
1692 {
1693  if (frag_id < _fragments.size())
1694  return _fragments[frag_id]->getFace(face_id);
1695  else
1696  EFAError("frag_id out of bounds in getFragmentFace");
1697 }
1698 
1699 std::set<EFANode *>
1700 EFAElement3D::getPhantomNodeOnFace(unsigned int face_id) const
1701 {
1702  std::set<EFANode *> phantom_nodes;
1703  if (_fragments.size() > 0)
1704  {
1705  for (unsigned int j = 0; j < _faces[face_id]->numNodes(); ++j) // loop ove 2 edge nodes
1706  {
1707  bool node_in_frag = false;
1708  for (unsigned int k = 0; k < _fragments.size(); ++k)
1709  {
1710  if (_fragments[k]->containsNode(_faces[face_id]->getNode(j)))
1711  {
1712  node_in_frag = true;
1713  break;
1714  }
1715  }
1716  if (!node_in_frag)
1717  phantom_nodes.insert(_faces[face_id]->getNode(j));
1718  }
1719  }
1720  return phantom_nodes;
1721 }
1722 
1723 bool
1724 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  frag_face_id = std::numeric_limits<unsigned int>::max();
1731  if (_fragments.size() == 1)
1732  {
1733  for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1734  {
1735  if (_faces[elem_face_id]->containsFace(_fragments[0]->getFace(j)))
1736  {
1737  frag_face_id = j;
1738  frag_face_found = true;
1739  break;
1740  }
1741  }
1742  }
1743  return frag_face_found;
1744 }
1745 
1746 bool
1747 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  FragFaceID = FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
1755  if (getFragmentFaceID(ElemFaceID, FragFaceID))
1756  {
1757  EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
1758  EFAFace * frag_face = getFragmentFace(0, FragFaceID);
1759  for (unsigned int i = 0; i < frag_face->numEdges(); ++i)
1760  {
1761  if (elem_edge->containsEdge(*frag_face->getEdge(i)))
1762  {
1763  FragFaceEdgeID = i;
1764  frag_edge_found = true;
1765  break;
1766  }
1767  }
1768  }
1769  return frag_edge_found;
1770 }
1771 
1772 bool
1773 EFAElement3D::isPhysicalEdgeCut(unsigned int ElemFaceID,
1774  unsigned int ElemFaceEdgeID,
1775  double position) const
1776 {
1777  unsigned int FragFaceID, FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
1778  bool is_in_real = false;
1779  if (_fragments.size() == 0)
1780  {
1781  is_in_real = true;
1782  }
1783  else if (getFragmentFaceEdgeID(ElemFaceID, ElemFaceEdgeID, FragFaceID, FragFaceEdgeID))
1784  {
1785  EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
1786  EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
1787  double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
1788  xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
1789  xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
1790  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  return is_in_real;
1795 }
1796 
1797 bool
1798 EFAElement3D::isFacePhantom(unsigned int face_id) const
1799 {
1800  bool is_phantom = false;
1801  if (_fragments.size() > 0)
1802  {
1803  bool contains_frag_face = false;
1804  for (unsigned int i = 0; i < _fragments.size(); ++i)
1805  {
1806  for (unsigned int j = 0; j < _fragments[i]->numFaces(); ++j)
1807  {
1808  if (_faces[face_id]->containsFace(_fragments[i]->getFace(j)))
1809  {
1810  contains_frag_face = true;
1811  break;
1812  }
1813  }
1814  if (contains_frag_face)
1815  break;
1816  }
1817  if (!contains_frag_face)
1818  is_phantom = true;
1819  }
1820  return is_phantom;
1821 }
1822 
1823 unsigned int
1824 EFAElement3D::numFaceNeighbors(unsigned int face_id) const
1825 {
1826  return _face_neighbors[face_id].size();
1827 }
1828 
1829 unsigned int
1830 EFAElement3D::numEdgeNeighbors(unsigned int face_id, unsigned int edge_id) const
1831 {
1832  return _face_edge_neighbors[face_id][edge_id].size();
1833 }
1834 
1835 EFAElement3D *
1836 EFAElement3D::getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
1837 {
1838  if (_face_neighbors[face_id][0] != nullptr && neighbor_id < _face_neighbors[face_id].size())
1839  return _face_neighbors[face_id][neighbor_id];
1840  else
1841  EFAError("edge neighbor does not exist");
1842 }
1843 
1844 EFAElement3D *
1845 EFAElement3D::getEdgeNeighbor(unsigned int face_id,
1846  unsigned int edge_id,
1847  unsigned int neighbor_id) const
1848 {
1849  if (neighbor_id < _face_edge_neighbors[face_id][edge_id].size())
1850  return _face_edge_neighbors[face_id][edge_id][neighbor_id];
1851  else
1852  EFAError("edge neighbor does not exist");
1853 }
1854 
1855 bool
1857 {
1858  bool has_tip_faces = false;
1859  if (_fragments.size() == 1)
1860  {
1861  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  if (_faces[i]->hasIntersection())
1865  {
1866  for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1867  {
1868  if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1869  num_frag_faces += 1;
1870  } // j
1871  if (num_frag_faces == 2)
1872  {
1873  has_tip_faces = true;
1874  break;
1875  }
1876  }
1877  } // i
1878  }
1879  return has_tip_faces;
1880 }
1881 
1882 std::vector<unsigned int>
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  if (_fragments.size() == 1) // crack tip element with a partial fragment saved
1888  {
1889  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  if (_faces[i]->hasIntersection())
1893  {
1894  for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1895  {
1896  if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1897  num_frag_faces += 1;
1898  } // j
1899  if (num_frag_faces == 2) // element face contains two fragment edges
1900  tip_face_id.push_back(i);
1901  }
1902  } // i
1903  }
1904  return tip_face_id;
1905 }
1906 
1907 std::set<EFANode *>
1909 {
1910  // if this element is a crack tip element, returns the crack tip edge's ID
1911  std::set<EFANode *> tip_emb;
1912  if (_fragments.size() == 1) // crack tip element with a partial fragment saved
1913  {
1914  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  if (_faces[i]->hasIntersection())
1918  {
1919  for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1920  {
1921  if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1922  frag_faces.push_back(_fragments[0]->getFace(j));
1923  } // j
1924  if (frag_faces.size() == 2) // element edge contains two fragment edges
1925  {
1926  unsigned int edge_id = frag_faces[0]->adjacentCommonEdge(frag_faces[1]);
1927  tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(0));
1928  tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(1));
1929  }
1930  }
1931  } // i
1932  }
1933  return tip_emb;
1934 }
1935 
1936 bool
1937 EFAElement3D::faceContainsTip(unsigned int face_id) const
1938 {
1939  bool contain_tip = false;
1940  if (_fragments.size() == 1)
1941  {
1942  unsigned int num_frag_faces = 0; // count how many fragment faces this element face contains
1943  if (_faces[face_id]->hasIntersection())
1944  {
1945  for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1946  {
1947  if (_faces[face_id]->containsFace(_fragments[0]->getFace(j)))
1948  num_frag_faces += 1;
1949  } // j
1950  if (num_frag_faces == 2)
1951  contain_tip = true;
1952  }
1953  }
1954  return contain_tip;
1955 }
1956 
1957 bool
1958 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  if (faceContainsTip(ElemFaceID))
1963  has_cut = true;
1964  else
1965  {
1966  unsigned int FragFaceID = std::numeric_limits<unsigned int>::max();
1967  if (getFragmentFaceID(ElemFaceID, FragFaceID))
1968  {
1969  EFAFace * frag_face = getFragmentFace(0, FragFaceID);
1970  if (frag_face->hasIntersection())
1971  has_cut = true;
1972  }
1973  }
1974  return has_cut;
1975 }
1976 
1977 void
1978 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  EFANode * local_embedded = nullptr;
1988  EFAEdge * cut_edge = _faces[face_id]->getEdge(edge_id);
1989  EFANode * edge_node1 = cut_edge->getNode(0);
1990  if (embedded_node) // use the existing embedded node if it was passed in
1991  local_embedded = embedded_node;
1992 
1993  // get adjacent face info
1994  EFAFace * adj_face = getAdjacentFace(face_id, edge_id);
1995  unsigned int adj_face_id = getFaceID(adj_face);
1996  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  if (cut_edge->hasIntersectionAtPosition(position, edge_node1))
2002  {
2003  unsigned int emb_id = cut_edge->getEmbeddedNodeIndex(position, edge_node1);
2004  EFANode * old_emb = cut_edge->getEmbeddedNode(emb_id);
2005  if (embedded_node && embedded_node != old_emb)
2006  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  local_embedded = old_emb;
2014  cut_exist = true;
2015  }
2016 
2017  if (!cut_exist && !fragmentFaceAlreadyCut(face_id) &&
2018  isPhysicalEdgeCut(face_id, edge_id, position))
2019  {
2020  // check if cut has already been added to the neighbor edges
2021  checkNeighborFaceCut(face_id, edge_id, position, edge_node1, embedded_node, local_embedded);
2023  adj_face_id, adj_edge_id, position, edge_node1, embedded_node, local_embedded);
2024 
2025  if (!local_embedded) // need to create new embedded node
2026  {
2027  unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
2028  local_embedded = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
2029  EmbeddedNodes.insert(std::make_pair(new_node_id, local_embedded));
2030  }
2031 
2032  // add to elem face edge
2033  cut_edge->addIntersection(position, local_embedded, edge_node1);
2034  if (cut_edge->numEmbeddedNodes() > 2)
2035  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  if (getFragmentFaceEdgeID(face_id, edge_id, FragFaceID, FragFaceEdgeID))
2042  {
2043  EFAEdge * elem_edge = _faces[face_id]->getEdge(edge_id);
2044  EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
2045  double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
2046  xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
2047  xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
2048  double frag_pos = (position - xi[0]) / (xi[1] - xi[0]);
2049  EFANode * frag_edge_node1 = frag_edge->getNode(0);
2050 
2051  if (!frag_edge->hasIntersection())
2052  frag_edge->addIntersection(frag_pos, local_embedded, frag_edge_node1);
2053  }
2054 
2055  // add to adjacent face edge
2056  if (add_to_adjacent)
2057  {
2058  double adj_pos = 1.0 - position;
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  if (add_to_neighbor)
2066  {
2067  for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
2068  {
2069  EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
2070  unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
2071  unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
2072  double neigh_pos = 1.0 - position; // get emb node's postion on neighbor edge
2073  face_neighbor->addFaceEdgeCut(
2074  neigh_face_id, neigh_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false, true);
2075  }
2076 
2077  for (unsigned int en_iter = 0; en_iter < numEdgeNeighbors(face_id, edge_id); ++en_iter)
2078  {
2079  EFAElement3D * edge_neighbor = getEdgeNeighbor(face_id, edge_id, en_iter);
2080  unsigned int neigh_face_id, neigh_edge_id;
2081  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  if (_faces[face_id]->getEdge(edge_id)->getNode(0) ==
2086  edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
2087  neigh_pos = position;
2088  else if (_faces[face_id]->getEdge(edge_id)->getNode(1) ==
2089  edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
2090  neigh_pos = 1.0 - position;
2091  else
2092  EFAError("The EFANodes on commaon edge are not matched.");
2093 
2094  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 }
2099 
2100 void
2101 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 }
2112 
2113 void
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  for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
2126  {
2127  EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
2128  unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
2129  unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
2130  EFAEdge * neigh_edge = face_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id);
2131 
2132  if (neigh_edge->hasIntersectionAtPosition(position, from_node))
2133  {
2134  unsigned int emb_id = neigh_edge->getEmbeddedNodeIndex(position, from_node);
2135  EFANode * old_emb = neigh_edge->getEmbeddedNode(emb_id);
2136 
2137  if (embedded_node && embedded_node != old_emb)
2138  EFAError(
2139  "attempting to add edge intersection when one already exists with different node.");
2140  if (local_embedded && local_embedded != old_emb)
2141  EFAError("attempting to assign contradictory pointer to local_embedded.");
2142 
2143  local_embedded = old_emb;
2144  }
2145  } // en_iter
2146 }
2147 
2148 void
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  xi_3d.resize(3, 0.0);
2155  if (_num_faces == 6)
2156  {
2157  if (face_id == 0)
2158  {
2159  xi_3d[0] = xi_2d[1];
2160  xi_3d[1] = xi_2d[0];
2161  xi_3d[2] = -1.0;
2162  }
2163  else if (face_id == 1)
2164  {
2165  xi_3d[0] = xi_2d[0];
2166  xi_3d[1] = -1.0;
2167  xi_3d[2] = xi_2d[1];
2168  }
2169  else if (face_id == 2)
2170  {
2171  xi_3d[0] = 1.0;
2172  xi_3d[1] = xi_2d[0];
2173  xi_3d[2] = xi_2d[1];
2174  }
2175  else if (face_id == 3)
2176  {
2177  xi_3d[0] = -xi_2d[0];
2178  xi_3d[1] = 1.0;
2179  xi_3d[2] = xi_2d[1];
2180  }
2181  else if (face_id == 4)
2182  {
2183  xi_3d[0] = -1.0;
2184  xi_3d[1] = -xi_2d[0];
2185  xi_3d[2] = xi_2d[1];
2186  }
2187  else if (face_id == 5)
2188  {
2189  xi_3d[0] = xi_2d[0];
2190  xi_3d[1] = xi_2d[1];
2191  xi_3d[2] = 1.0;
2192  }
2193  else
2194  EFAError("face_id out of bounds");
2195  }
2196  else if (_num_faces == 4)
2197  {
2198  if (face_id == 0)
2199  {
2200  xi_3d[0] = xi_2d[0];
2201  xi_3d[1] = xi_2d[1];
2202  xi_3d[2] = 0.0;
2203  }
2204  else if (face_id == 1)
2205  {
2206  xi_3d[0] = 0.0;
2207  xi_3d[1] = xi_2d[0];
2208  xi_3d[2] = xi_2d[1];
2209  }
2210  else if (face_id == 2)
2211  {
2212  xi_3d[0] = xi_2d[1];
2213  xi_3d[1] = 0.0;
2214  xi_3d[2] = xi_2d[0];
2215  }
2216  else if (face_id == 3)
2217  {
2218  xi_3d[0] = xi_2d[0];
2219  xi_3d[1] = xi_2d[2];
2220  xi_3d[2] = xi_2d[1];
2221  }
2222  else
2223  EFAError("face_id out of bounds");
2224  }
2225  else
2226  EFAError("unknown element for 3D");
2227 }
2228 
2229 std::vector<EFANode *>
2231 {
2232  std::set<EFANode *> e1nodes(_nodes.begin(),
2233  _nodes.begin() + _num_vertices); // only account for corner nodes
2234  std::set<EFANode *> e2nodes(other_elem->_nodes.begin(),
2235  other_elem->_nodes.begin() + _num_vertices);
2236  std::vector<EFANode *> common_nodes = Efa::getCommonElems(e1nodes, e2nodes);
2237  return common_nodes;
2238 }
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
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:124
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
static const std::string center
Definition: NS.h:28
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