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