https://mooseframework.inl.gov
Loading...
Searching...
No Matches
EFAElement3D.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "EFAElement3D.h"
11
12#include <iomanip>
13
14#include "EFAFaceNode.h"
15#include "EFAVolumeNode.h"
16#include "EFANode.h"
17#include "EFAEdge.h"
18#include "EFAFace.h"
19#include "EFAFragment3D.h"
20#include "EFAFuncs.h"
21#include "EFAError.h"
22#include "XFEMFuncs.h"
23
24#include "libmesh/int_range.h"
25
26EFAElement3D::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
63EFAElement3D::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)
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
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
140void
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
271unsigned int
273{
274 return _fragments.size();
275}
276
277bool
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
301void
302EFAElement3D::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
328void
329EFAElement3D::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
355void
356EFAElement3D::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
366void
368{
369 // In EFAElement3D, updateFragmentNode needs to be implemented
370}
371
372void
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
424unsigned int
426{
427 return _interior_nodes.size();
428}
429
430bool
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
457unsigned int
458EFAElement3D::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
467void
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
494void
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
506void
507EFAElement3D::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
572void
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
605void
606EFAElement3D::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
643bool
644EFAElement3D::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
667bool
668EFAElement3D::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
718bool
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
757bool
758EFAElement3D::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
808bool
813
814unsigned 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
824bool
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
844void
845EFAElement3D::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
902void
903EFAElement3D::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
927void
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)
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
963void
964EFAElement3D::createChild(const std::set<EFAElement *> & CrackTipElements,
965 std::map<unsigned int, EFAElement *> & Elements,
966 std::map<unsigned int, EFAElement *> & newChildElements,
967 std::vector<EFAElement *> & ChildElements,
968 std::vector<EFAElement *> & ParentElements,
969 std::map<unsigned int, EFANode *> & TempNodes)
970{
971 if (_children.size() != 0)
972 EFAError("Element cannot have existing children in createChildElements");
973
974 if (_fragments.size() > 1 || shouldDuplicateForCrackTip(CrackTipElements))
975 {
976 if (_fragments.size() > 2)
977 EFAError("More than 2 fragments not yet supported");
978
979 // set up the children
980 ParentElements.push_back(this);
981 for (unsigned int ichild = 0; ichild < _fragments.size(); ++ichild)
982 {
983 unsigned int new_elem_id;
984 if (newChildElements.size() == 0)
985 new_elem_id = Efa::getNewID(Elements);
986 else
987 new_elem_id = Efa::getNewID(newChildElements);
988
989 EFAElement3D * childElem = new EFAElement3D(new_elem_id, this->numNodes(), this->numFaces());
990 newChildElements.insert(std::make_pair(new_elem_id, childElem));
991
992 ChildElements.push_back(childElem);
993 childElem->setParent(this);
994 _children.push_back(childElem);
995
996 std::vector<std::vector<EFANode *>> cut_plane_nodes;
997 for (unsigned int i = 0; i < this->getFragment(ichild)->numFaces(); ++i)
998 {
999 if (this->getFragment(ichild)->isFaceInterior(i))
1000 {
1001 EFAFace * face = this->getFragment(ichild)->getFace(i);
1002 std::vector<EFANode *> node_line;
1003 for (unsigned int j = 0; j < face->numNodes(); ++j)
1004 node_line.push_back(face->getNode(j));
1005 cut_plane_nodes.push_back(node_line);
1006 }
1007 }
1008
1009 std::vector<EFAPoint> cut_plane_points;
1010
1011 EFAPoint orig(0.0, 0.0, 0.0);
1012
1013 std::vector<EFAPoint> normal_v;
1014
1015 if (cut_plane_nodes.size())
1016 {
1017 for (unsigned int i = 0; i < cut_plane_nodes[0].size(); ++i)
1018 {
1019 std::vector<EFANode *> master_nodes;
1020 std::vector<double> master_weights;
1021
1022 this->getMasterInfo(cut_plane_nodes[0][i], master_nodes, master_weights);
1023 EFAPoint coor(0.0, 0.0, 0.0);
1024 for (unsigned int i = 0; i < master_nodes.size(); ++i)
1025 {
1026 EFANode * local = this->createLocalNodeFromGlobalNode(master_nodes[i]);
1027 coor += _local_node_coor[local->id()] * master_weights[i];
1028 delete local;
1029 }
1030 cut_plane_points.push_back(coor);
1031 }
1032
1033 for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1034 orig += cut_plane_points[i];
1035 orig /= cut_plane_points.size();
1036
1037 for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1038 {
1039 unsigned int iplus1 = i < cut_plane_points.size() - 1 ? i + 1 : 0;
1040 unsigned int iminus1 = i == 0 ? cut_plane_points.size() - 1 : i - 1;
1041 EFAPoint ray1 = cut_plane_points[iminus1] - cut_plane_points[i];
1042 EFAPoint ray2 = cut_plane_points[i] - cut_plane_points[iplus1];
1043 normal_v.push_back(ray1.cross(ray2));
1044 }
1045
1046 for (unsigned int i = 0; i < normal_v.size(); ++i)
1047 Xfem::normalizePoint(normal_v[i]);
1048 }
1049
1050 // get child element's nodes
1051 for (unsigned int j = 0; j < _num_nodes; ++j)
1052 {
1053 EFAPoint p(0.0, 0.0, 0.0);
1054 p = _local_node_coor[j];
1055 EFAPoint origin_to_point = p - orig;
1056
1057 bool node_outside_fragment = false;
1058 for (unsigned int k = 0; k < normal_v.size(); ++k)
1059 if (origin_to_point * normal_v[k] > Xfem::tol)
1060 {
1061 node_outside_fragment = true;
1062 break;
1063 }
1064
1065 if (_fragments.size() == 1 && !shouldDuplicateForCrackTip(CrackTipElements))
1066 childElem->setNode(j, _nodes[j]); // inherit parent's node
1067 else if (!node_outside_fragment)
1068 childElem->setNode(j, _nodes[j]); // inherit parent's node
1069 else // parent element's node is not in fragment
1070 {
1071 unsigned int new_node_id = Efa::getNewID(TempNodes);
1072 EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
1073 TempNodes.insert(std::make_pair(new_node_id, newNode));
1074 childElem->setNode(j, newNode); // be a temp node
1075 }
1076 }
1077
1078 // get child element's fragments
1079 EFAFragment3D * new_frag = new EFAFragment3D(childElem, true, this, ichild);
1080 childElem->_fragments.push_back(new_frag);
1081
1082 // get child element's faces and set up adjacent faces
1083 childElem->createFaces();
1084 for (unsigned int j = 0; j < _num_faces; ++j)
1085 childElem->_faces[j]->copyIntersection(*_faces[j]);
1086 childElem->removePhantomEmbeddedNode(); // IMPORTANT
1087
1088 // inherit old interior nodes
1089 for (unsigned int j = 0; j < _interior_nodes.size(); ++j)
1090 childElem->_interior_nodes.push_back(new EFAVolumeNode(*_interior_nodes[j]));
1091 }
1092 }
1093 else // num_links == 1 || num_links == 0
1094 {
1095 // child is itself - but don't insert into the list of ChildElements!!!
1096 _children.push_back(this);
1097 }
1098}
1099
1100void
1102{
1103 // remove the embedded nodes on faces that are outside the real domain
1104 if (_fragments.size() > 0)
1105 {
1106 for (unsigned int i = 0; i < _num_faces; ++i)
1107 {
1108 // get emb nodes to be removed on edges
1109 std::vector<EFANode *> nodes_to_delete;
1110 for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
1111 {
1112 EFAEdge * edge = _faces[i]->getEdge(j);
1113 for (unsigned int k = 0; k < edge->numEmbeddedNodes(); ++k)
1114 {
1115 if (!_fragments[0]->containsNode(edge->getEmbeddedNode(k)))
1116 nodes_to_delete.push_back(edge->getEmbeddedNode(k));
1117 } // k
1118 } // j
1119
1120 // get emb nodes to be removed in the face interior
1121 for (unsigned int j = 0; j < _faces[i]->numInteriorNodes(); ++j)
1122 {
1123 EFANode * face_node = _faces[i]->getInteriorNode(j)->getNode();
1124 if (!_fragments[0]->containsNode(face_node))
1125 nodes_to_delete.push_back(face_node);
1126 } // j
1127
1128 // remove all invalid embedded nodes
1129 for (unsigned int j = 0; j < nodes_to_delete.size(); ++j)
1130 _faces[i]->removeEmbeddedNode(nodes_to_delete[j]);
1131 } // i
1132 }
1133}
1134
1135void
1136EFAElement3D::connectNeighbors(std::map<unsigned int, EFANode *> & PermanentNodes,
1137 std::map<unsigned int, EFANode *> & TempNodes,
1138 std::map<EFANode *, std::set<EFAElement *>> & InverseConnectivityMap,
1139 bool merge_phantom_faces)
1140{
1141 // N.B. "this" must point to a child element that was just created
1142 if (!_parent)
1143 EFAError("no parent element for child element ", _id, " in connect_neighbors");
1144 EFAElement3D * parent3d = dynamic_cast<EFAElement3D *>(_parent);
1145 if (!parent3d)
1146 EFAError("cannot dynamic cast to parent3d in connect_neighbors");
1147
1148 // First loop through edges and merge nodes with neighbors as appropriate
1149 for (unsigned int j = 0; j < _num_faces; ++j)
1150 {
1151 for (unsigned int k = 0; k < parent3d->numFaceNeighbors(j); ++k)
1152 {
1153 EFAElement3D * NeighborElem = parent3d->getFaceNeighbor(j, k);
1154 unsigned int neighbor_face_id = NeighborElem->getNeighborIndex(parent3d);
1155
1156 if (_faces[j]->hasIntersection())
1157 {
1158 for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
1159 {
1160 EFAElement3D * childOfNeighborElem =
1161 dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
1162 if (!childOfNeighborElem)
1163 EFAError("dynamic cast childOfNeighborElem fails");
1164
1165 // Check to see if the nodes are already merged. There's nothing else to do in that case.
1166 EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
1167 if (_faces[j]->equivalent(neighborChildFace))
1168 continue;
1169
1170 if (_fragments[0]->isConnected(childOfNeighborElem->getFragment(0)))
1171 {
1172 for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
1173 {
1174 unsigned int childNodeIndex = i;
1175 unsigned int neighborChildNodeIndex =
1176 parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
1177
1178 EFANode * childNode = _faces[j]->getNode(childNodeIndex);
1179 EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
1180 mergeNodes(
1181 childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
1182 } // i
1183
1184 for (unsigned int m = 0; m < _num_interior_face_nodes; ++m)
1185 {
1186 unsigned int childNodeIndex = m;
1187 unsigned int neighborChildNodeIndex =
1188 parent3d->getNeighborFaceInteriorNodeID(j, childNodeIndex, NeighborElem);
1189
1190 EFANode * childNode = _faces[j]->getInteriorFaceNode(childNodeIndex);
1191 EFANode * childOfNeighborNode =
1192 neighborChildFace->getInteriorFaceNode(neighborChildNodeIndex);
1193 mergeNodes(
1194 childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
1195 } // m
1196 }
1197 } // l, loop over NeighborElem's children
1198 }
1199 else // No edge intersection -- optionally merge non-material nodes if they share a common
1200 // parent
1201 {
1202 if (merge_phantom_faces)
1203 {
1204 for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
1205 {
1206 EFAElement3D * childOfNeighborElem =
1207 dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
1208 if (!childOfNeighborElem)
1209 EFAError("dynamic cast childOfNeighborElem fails");
1210
1211 EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
1212 if (!neighborChildFace
1213 ->hasIntersection()) // neighbor face must NOT have intersection either
1214 {
1215 // Check to see if the nodes are already merged. There's nothing else to do in that
1216 // case.
1217 if (_faces[j]->equivalent(neighborChildFace))
1218 continue;
1219
1220 for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
1221 {
1222 unsigned int childNodeIndex = i;
1223 unsigned int neighborChildNodeIndex =
1224 parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
1225
1226 EFANode * childNode = _faces[j]->getNode(childNodeIndex);
1227 EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
1228
1229 if (childNode->parent() != nullptr &&
1230 childNode->parent() ==
1231 childOfNeighborNode
1232 ->parent()) // non-material node and both come from same parent
1233 mergeNodes(childNode,
1234 childOfNeighborNode,
1235 childOfNeighborElem,
1236 PermanentNodes,
1237 TempNodes);
1238 } // i
1239 }
1240 } // loop over NeighborElem's children
1241 } // if (merge_phantom_edges)
1242 } // IF edge-j has_intersection()
1243 } // k, loop over neighbors on edge j
1244 } // j, loop over all faces
1245
1246 // Now do a second loop through faces and convert remaining nodes to permanent nodes.
1247 // If there is no neighbor on that face, also duplicate the embedded node if it exists
1248 for (unsigned int j = 0; j < _num_nodes; ++j)
1249 {
1250 EFANode * childNode = _nodes[j];
1251 if (childNode->category() == EFANode::N_CATEGORY_TEMP)
1252 {
1253 // if current child element does not have siblings, and if current temp node is a lone one
1254 // this temp node should be merged back to its parent permanent node. Otherwise we would have
1255 // permanent nodes that are not connected to any element
1256 std::set<EFAElement *> patch_elems = InverseConnectivityMap[childNode->parent()];
1257 if (parent3d->numFragments() == 1 && patch_elems.size() == 1)
1258 switchNode(childNode->parent(), childNode, false);
1259 else
1260 {
1261 unsigned int new_node_id = Efa::getNewID(PermanentNodes);
1262 EFANode * newNode =
1263 new EFANode(new_node_id, EFANode::N_CATEGORY_PERMANENT, childNode->parent());
1264 PermanentNodes.insert(std::make_pair(new_node_id, newNode));
1265 switchNode(newNode, childNode, false);
1266 }
1267 if (!Efa::deleteFromMap(TempNodes, childNode))
1268 EFAError(
1269 "Attempted to delete node: ", childNode->id(), " from TempNodes, but couldn't find it");
1270 }
1271 }
1272}
1273
1274void
1275EFAElement3D::printElement(std::ostream & ostream) const
1276{
1277 // first line: all elem faces
1278 ostream << std::setw(5);
1279 ostream << _id << "| ";
1280 for (unsigned int j = 0; j < _num_faces; ++j)
1281 {
1282 for (unsigned int k = 0; k < _faces[j]->numNodes(); ++k)
1283 ostream << std::setw(5) << _faces[j]->getNode(k)->idCatString();
1284 ostream << " | ";
1285 }
1286 ostream << std::endl;
1287
1288 // second line: emb nodes in all faces + neighbor of each face
1289 ostream << std::setw(5);
1290 ostream << "embed"
1291 << "| ";
1292 for (unsigned int j = 0; j < _num_faces; ++j)
1293 {
1294 for (unsigned int k = 0; k < _faces[j]->numEdges(); ++k)
1295 {
1296 ostream << std::setw(4);
1297 if (_faces[j]->getEdge(k)->hasIntersection())
1298 {
1299 if (_faces[j]->getEdge(k)->numEmbeddedNodes() > 1)
1300 {
1301 ostream << "[";
1302 for (unsigned int l = 0; l < _faces[j]->getEdge(k)->numEmbeddedNodes(); ++l)
1303 {
1304 ostream << _faces[j]->getEdge(k)->getEmbeddedNode(l)->id() << " ";
1305 if (l == _faces[j]->getEdge(k)->numEmbeddedNodes() - 1)
1306 ostream << "]";
1307 else
1308 ostream << " ";
1309 } // l
1310 }
1311 else
1312 ostream << _faces[j]->getEdge(k)->getEmbeddedNode(0)->id() << " ";
1313 }
1314 else
1315 ostream << " -- ";
1316 } // k
1317 ostream << " | ";
1318 } // j
1319 ostream << std::endl;
1320
1321 // third line: neighbors
1322 ostream << std::setw(5);
1323 ostream << "neigh"
1324 << "| ";
1325 for (unsigned int j = 0; j < _num_faces; ++j)
1326 {
1327 ostream << std::setw(4);
1328 if (numFaceNeighbors(j) > 1)
1329 {
1330 ostream << "[";
1331 for (unsigned int k = 0; k < numFaceNeighbors(j); ++k)
1332 {
1333 ostream << getFaceNeighbor(j, k)->id();
1334 if (k == numFaceNeighbors(j) - 1)
1335 ostream << "]";
1336 else
1337 ostream << " ";
1338 }
1339 }
1340 else
1341 {
1342 if (numFaceNeighbors(j) == 1)
1343 ostream << getFaceNeighbor(j, 0)->id() << " ";
1344 else
1345 ostream << " -- ";
1346 }
1347 }
1348 ostream << std::endl;
1349
1350 // fourth line: fragments
1351 for (unsigned int j = 0; j < _fragments.size(); ++j)
1352 {
1353 ostream << std::setw(4);
1354 ostream << "frag" << j << "| ";
1355 for (unsigned int k = 0; k < _fragments[j]->numFaces(); ++k)
1356 {
1357 for (unsigned int l = 0; l < _fragments[j]->getFace(k)->numNodes(); ++l)
1358 ostream << std::setw(5) << _fragments[j]->getFace(k)->getNode(l)->idCatString();
1359 ostream << " | ";
1360 }
1361 ostream << std::endl;
1362 }
1363 ostream << std::endl;
1364}
1365
1367EFAElement3D::getFragment(unsigned int frag_id) const
1368{
1369 if (frag_id < _fragments.size())
1370 return _fragments[frag_id];
1371 else
1372 EFAError("frag_id out of bounds");
1373}
1374
1375std::set<EFANode *>
1376EFAElement3D::getFaceNodes(unsigned int face_id) const
1377{
1378 std::set<EFANode *> face_nodes;
1379 for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i)
1380 face_nodes.insert(_faces[face_id]->getNode(i));
1381 return face_nodes;
1382}
1383
1384bool
1385EFAElement3D::getFaceNodeParametricCoordinates(EFANode * node, std::vector<double> & xi_3d) const
1386{
1387 // get the parametric coords of a node in an element face
1388 unsigned int face_id = std::numeric_limits<unsigned int>::max();
1389 bool face_found = false;
1390 for (unsigned int i = 0; i < _num_faces; ++i)
1391 {
1392 if (_faces[i]->containsNode(node))
1393 {
1394 face_id = i;
1395 face_found = true;
1396 break;
1397 }
1398 }
1399 if (face_found)
1400 {
1401 std::vector<double> xi_2d(2, 0.0);
1402 if (_faces[face_id]->getFaceNodeParametricCoords(node, xi_2d))
1403 mapParametricCoordinateFrom2DTo3D(face_id, xi_2d, xi_3d);
1404 else
1405 EFAError("failed to get the 2D para coords on the face");
1406 }
1407 return face_found;
1408}
1409
1411EFAElement3D::getInteriorNode(unsigned int interior_node_id) const
1412{
1413 if (interior_node_id < _interior_nodes.size())
1414 return _interior_nodes[interior_node_id];
1415 else
1416 EFAError("interior_node_id out of bounds");
1417}
1418
1419void
1420EFAElement3D::removeEmbeddedNode(EFANode * emb_node, bool remove_for_neighbor)
1421{
1422 for (unsigned int i = 0; i < _fragments.size(); ++i)
1423 _fragments[i]->removeEmbeddedNode(emb_node);
1424
1425 for (unsigned int i = 0; i < _faces.size(); ++i)
1426 _faces[i]->removeEmbeddedNode(emb_node);
1427
1428 if (remove_for_neighbor)
1429 {
1430 for (unsigned int i = 0; i < numFaces(); ++i)
1431 for (unsigned int j = 0; j < numFaceNeighbors(i); ++j)
1432 getFaceNeighbor(i, j)->removeEmbeddedNode(emb_node, false);
1433 }
1434}
1435
1436unsigned int
1438{
1439 return _faces.size();
1440}
1441
1442void
1443EFAElement3D::setFace(unsigned int face_id, EFAFace * face)
1444{
1445 _faces[face_id] = face;
1446}
1447
1448void
1450{
1451 // create element faces based on existing element nodes
1452 int hex_local_node_indices[6][4] = {
1453 {0, 3, 2, 1}, {0, 1, 5, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}};
1454 int tet_local_node_indices[4][3] = {{0, 2, 1}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}};
1455
1456 int hex_interior_face_node_indices[6][5] = {{8, 9, 10, 11, 20},
1457 {8, 13, 16, 12, 21},
1458 {9, 14, 17, 13, 22},
1459 {10, 14, 18, 15, 23},
1460 {11, 15, 19, 12, 24},
1461 {16, 17, 18, 19, 25}};
1462 int tet_interior_face_node_indices[4][4] = {
1463 {4, 5, 6, 10}, {4, 7, 8, 11}, {5, 8, 9, 12}, {6, 7, 9, 13}};
1464
1465 _faces = std::vector<EFAFace *>(_num_faces, nullptr);
1466 if (_num_nodes == 8 || _num_nodes == 20 || _num_nodes == 27)
1467 {
1468 if (_num_faces != 6)
1469 EFAError("num_faces of hexes must be 6");
1470 for (unsigned int i = 0; i < _num_faces; ++i)
1471 {
1473 for (unsigned int j = 0; j < 4; ++j)
1474 _faces[i]->setNode(j, _nodes[hex_local_node_indices[i][j]]);
1475 _faces[i]->createEdges();
1476 for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
1477 _faces[i]->setInteriorFaceNode(k, _nodes[hex_interior_face_node_indices[i][k]]);
1478 }
1479 }
1480 else if (_num_nodes == 4 || _num_nodes == 10 || _num_nodes == 14)
1481 {
1482 if (_num_faces != 4)
1483 EFAError("num_faces of tets must be 4");
1484 for (unsigned int i = 0; i < _num_faces; ++i)
1485 {
1487 for (unsigned int j = 0; j < 3; ++j)
1488 _faces[i]->setNode(j, _nodes[tet_local_node_indices[i][j]]);
1489 _faces[i]->createEdges();
1490 for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
1491 _faces[i]->setInteriorFaceNode(k, _nodes[tet_interior_face_node_indices[i][k]]);
1492 }
1493 }
1494 else
1495 EFAError("unknown 3D element type in createFaces()");
1496
1497 for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
1498 {
1499 _face_edge_neighbors[face_iter].resize(_faces[face_iter]->numEdges());
1500 for (unsigned int edge_iter = 0; edge_iter < _faces[face_iter]->numEdges(); ++edge_iter)
1501 _face_edge_neighbors[face_iter][edge_iter].clear();
1502 }
1503
1504 // create element face connectivity array
1505 findFacesAdjacentToFaces(); // IMPORTANT
1506}
1507
1508EFAFace *
1509EFAElement3D::getFace(unsigned int face_id) const
1510{
1511 return _faces[face_id];
1512}
1513
1514unsigned int
1516{
1517 bool found_face_id = false;
1518 unsigned int face_id;
1519 for (unsigned int iface = 0; iface < _num_faces; ++iface)
1520 {
1521 if (_faces[iface]->equivalent(face))
1522 {
1523 face_id = iface;
1524 found_face_id = true;
1525 break;
1526 }
1527 }
1528 if (!found_face_id)
1529 EFAError("input face not found in get_face_id()");
1530 return face_id;
1531}
1532
1533std::vector<unsigned int>
1535{
1536 std::vector<unsigned int> face_id;
1537 for (unsigned int i = 0; i < _num_faces; ++i)
1538 for (unsigned int j = 0; j < other_elem->_num_faces; ++j)
1539 if (_faces[i]->equivalent(other_elem->_faces[j]))
1540 {
1541 face_id.push_back(i);
1542 break;
1543 }
1544
1545 return face_id;
1546}
1547
1548bool
1550 std::vector<std::pair<unsigned int, unsigned int>> & common_ids) const
1551{
1552 // all edges of the other element
1553 std::set<std::pair<EFANode *, EFANode *>> other_edges;
1554 for (const auto k : index_range(other_elem->_faces))
1555 {
1556 const auto & face = *other_elem->_faces[k];
1557 for (const auto l : make_range(other_elem->_faces[k]->numEdges()))
1558 {
1559 const auto & edge = *face.getEdge(l);
1560 other_edges.insert(edge.getSortedNodes());
1561 }
1562 }
1563
1564 // loop over all edges of this element
1565 common_ids.clear();
1566 for (const auto i : index_range(_faces))
1567 for (const auto j : make_range(_faces[i]->numEdges()))
1568 {
1569 const auto & edge = *_faces[i]->getEdge(j);
1570 const auto edge_nodes = edge.getSortedNodes();
1571
1572 // is this edge contained in the other element?
1573 if (edge.isEmbeddedPermanent() || other_edges.count(edge_nodes) == 0)
1574 continue;
1575
1576 common_ids.emplace_back(i, j);
1577 }
1578
1579 return common_ids.size() > 0;
1580}
1581
1582unsigned int
1584 unsigned int node_id,
1585 EFAElement3D * neighbor_elem) const
1586{
1587 // get the corresponding node_id on the corresponding face of neighbor_elem
1588 bool found_id = false;
1589 unsigned int neigh_face_node_id;
1590 unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1591 if (common_face_id == face_id)
1592 {
1593 unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1594 EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1595 for (unsigned int i = 0; i < neigh_face->numNodes(); ++i)
1596 {
1597 if (_faces[face_id]->getNode(node_id) == neigh_face->getNode(i))
1598 {
1599 neigh_face_node_id = i;
1600 found_id = true;
1601 break;
1602 }
1603 }
1604 }
1605 else
1606 EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
1607 if (!found_id)
1608 EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
1609 return neigh_face_node_id;
1610}
1611
1612unsigned int
1614 unsigned int node_id,
1615 EFAElement3D * neighbor_elem) const
1616{
1617 // get the corresponding node_id on the corresponding face of neighbor_elem
1618 bool found_id = false;
1619 unsigned int neigh_face_node_id;
1620 unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1621 if (common_face_id == face_id)
1622 {
1623 unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1624 EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1625
1626 for (unsigned int i = 0; i < _num_interior_face_nodes; ++i)
1627 {
1628 if (_faces[face_id]->getInteriorFaceNode(node_id) == neigh_face->getInteriorFaceNode(i))
1629 {
1630 neigh_face_node_id = i;
1631 found_id = true;
1632 break;
1633 }
1634 }
1635 }
1636 else
1637 EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
1638 if (!found_id)
1639 EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
1640 return neigh_face_node_id;
1641}
1642
1643unsigned int
1645 unsigned int edge_id,
1646 EFAElement3D * neighbor_elem) const
1647{
1648 // get the corresponding edge_id on the corresponding face of neighbor_elem
1649 bool found_id = false;
1650 unsigned int neigh_face_edge_id;
1651 unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1652 if (common_face_id == face_id)
1653 {
1654 unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1655 EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1656 for (unsigned int i = 0; i < neigh_face->numEdges(); ++i)
1657 {
1658 if (_faces[face_id]->getEdge(edge_id)->equivalent(*neigh_face->getEdge(i)))
1659 {
1660 neigh_face_edge_id = i;
1661 found_id = true;
1662 break;
1663 }
1664 }
1665 }
1666 else
1667 EFAError("getNeighborFaceEdgeID: neighbor_elem is not a neighbor on face_id");
1668 if (!found_id)
1669 EFAError("getNeighborFaceEdgeID: could not find neighbor face edge id");
1670 return neigh_face_edge_id;
1671}
1672
1673void
1675{
1677 for (unsigned int i = 0; i < _faces.size(); ++i)
1678 {
1679 std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr);
1680 for (unsigned int j = 0; j < _faces.size(); ++j)
1681 {
1682 if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j]))
1683 {
1684 unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]);
1685 face_adjacents[adj_edge] = _faces[j];
1686 }
1687 }
1688 _faces_adjacent_to_faces.push_back(face_adjacents);
1689 }
1690}
1691
1692EFAFace *
1693EFAElement3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
1694{
1695 return _faces_adjacent_to_faces[face_id][edge_id];
1696}
1697
1698EFAFace *
1699EFAElement3D::getFragmentFace(unsigned int frag_id, unsigned int face_id) const
1700{
1701 if (frag_id < _fragments.size())
1702 return _fragments[frag_id]->getFace(face_id);
1703 else
1704 EFAError("frag_id out of bounds in getFragmentFace");
1705}
1706
1707std::set<EFANode *>
1708EFAElement3D::getPhantomNodeOnFace(unsigned int face_id) const
1709{
1710 std::set<EFANode *> phantom_nodes;
1711 if (_fragments.size() > 0)
1712 {
1713 for (unsigned int j = 0; j < _faces[face_id]->numNodes(); ++j) // loop ove 2 edge nodes
1714 {
1715 bool node_in_frag = false;
1716 for (unsigned int k = 0; k < _fragments.size(); ++k)
1717 {
1718 if (_fragments[k]->containsNode(_faces[face_id]->getNode(j)))
1719 {
1720 node_in_frag = true;
1721 break;
1722 }
1723 }
1724 if (!node_in_frag)
1725 phantom_nodes.insert(_faces[face_id]->getNode(j));
1726 }
1727 }
1728 return phantom_nodes;
1729}
1730
1731bool
1732EFAElement3D::getFragmentFaceID(unsigned int elem_face_id, unsigned int & frag_face_id) const
1733{
1734 // find the fragment face that is contained by given element edge
1735 // N.B. if the elem edge contains two frag edges, this method will only return
1736 // the first frag edge ID
1737 bool frag_face_found = false;
1738 frag_face_id = std::numeric_limits<unsigned int>::max();
1739 if (_fragments.size() == 1)
1740 {
1741 for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1742 {
1743 if (_faces[elem_face_id]->containsFace(_fragments[0]->getFace(j)))
1744 {
1745 frag_face_id = j;
1746 frag_face_found = true;
1747 break;
1748 }
1749 }
1750 }
1751 return frag_face_found;
1752}
1753
1754bool
1756 unsigned int ElemFaceEdgeID,
1757 unsigned int & FragFaceID,
1758 unsigned int & FragFaceEdgeID) const
1759{
1760 // Purpose: given an edge of an elem face, find which frag face's edge it contains
1761 bool frag_edge_found = false;
1762 FragFaceID = FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
1763 if (getFragmentFaceID(ElemFaceID, FragFaceID))
1764 {
1765 EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
1766 EFAFace * frag_face = getFragmentFace(0, FragFaceID);
1767 for (unsigned int i = 0; i < frag_face->numEdges(); ++i)
1768 {
1769 if (elem_edge->containsEdge(*frag_face->getEdge(i)))
1770 {
1771 FragFaceEdgeID = i;
1772 frag_edge_found = true;
1773 break;
1774 }
1775 }
1776 }
1777 return frag_edge_found;
1778}
1779
1780bool
1781EFAElement3D::isPhysicalEdgeCut(unsigned int ElemFaceID,
1782 unsigned int ElemFaceEdgeID,
1783 double position) const
1784{
1785 unsigned int FragFaceID, FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
1786 bool is_in_real = false;
1787 if (_fragments.size() == 0)
1788 {
1789 is_in_real = true;
1790 }
1791 else if (getFragmentFaceEdgeID(ElemFaceID, ElemFaceEdgeID, FragFaceID, FragFaceEdgeID))
1792 {
1793 EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
1794 EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
1795 double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
1796 xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
1797 xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
1798 if ((position - xi[0]) * (position - xi[1]) <
1799 0.0) // the cut to be added is within the real part of the edge
1800 is_in_real = true;
1801 }
1802 return is_in_real;
1803}
1804
1805bool
1806EFAElement3D::isFacePhantom(unsigned int face_id) const
1807{
1808 bool is_phantom = false;
1809 if (_fragments.size() > 0)
1810 {
1811 bool contains_frag_face = false;
1812 for (unsigned int i = 0; i < _fragments.size(); ++i)
1813 {
1814 for (unsigned int j = 0; j < _fragments[i]->numFaces(); ++j)
1815 {
1816 if (_faces[face_id]->containsFace(_fragments[i]->getFace(j)))
1817 {
1818 contains_frag_face = true;
1819 break;
1820 }
1821 }
1822 if (contains_frag_face)
1823 break;
1824 }
1825 if (!contains_frag_face)
1826 is_phantom = true;
1827 }
1828 return is_phantom;
1829}
1830
1831unsigned int
1832EFAElement3D::numFaceNeighbors(unsigned int face_id) const
1833{
1834 return _face_neighbors[face_id].size();
1835}
1836
1837unsigned int
1838EFAElement3D::numEdgeNeighbors(unsigned int face_id, unsigned int edge_id) const
1839{
1840 return _face_edge_neighbors[face_id][edge_id].size();
1841}
1842
1844EFAElement3D::getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
1845{
1846 if (_face_neighbors[face_id][0] != nullptr && neighbor_id < _face_neighbors[face_id].size())
1847 return _face_neighbors[face_id][neighbor_id];
1848 else
1849 EFAError("edge neighbor does not exist");
1850}
1851
1854 unsigned int edge_id,
1855 unsigned int neighbor_id) const
1856{
1857 if (neighbor_id < _face_edge_neighbors[face_id][edge_id].size())
1858 return _face_edge_neighbors[face_id][edge_id][neighbor_id];
1859 else
1860 EFAError("edge neighbor does not exist");
1861}
1862
1863bool
1865{
1866 bool has_tip_faces = false;
1867 if (_fragments.size() == 1)
1868 {
1869 for (unsigned int i = 0; i < _num_faces; ++i)
1870 {
1871 unsigned int num_frag_faces = 0; // count how many fragment edges this element edge contains
1872 if (_faces[i]->hasIntersection())
1873 {
1874 for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1875 {
1876 if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1877 num_frag_faces += 1;
1878 } // j
1879 if (num_frag_faces == 2)
1880 {
1881 has_tip_faces = true;
1882 break;
1883 }
1884 }
1885 } // i
1886 }
1887 return has_tip_faces;
1888}
1889
1890std::vector<unsigned int>
1892{
1893 // if this element is a crack tip element, returns the crack tip faces' ID
1894 std::vector<unsigned int> tip_face_id;
1895 if (_fragments.size() == 1) // crack tip element with a partial fragment saved
1896 {
1897 for (unsigned int i = 0; i < _num_faces; ++i)
1898 {
1899 unsigned int num_frag_faces = 0; // count how many fragment faces this element edge contains
1900 if (_faces[i]->hasIntersection())
1901 {
1902 for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1903 {
1904 if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1905 num_frag_faces += 1;
1906 } // j
1907 if (num_frag_faces == 2) // element face contains two fragment edges
1908 tip_face_id.push_back(i);
1909 }
1910 } // i
1911 }
1912 return tip_face_id;
1913}
1914
1915std::set<EFANode *>
1917{
1918 // if this element is a crack tip element, returns the crack tip edge's ID
1919 std::set<EFANode *> tip_emb;
1920 if (_fragments.size() == 1) // crack tip element with a partial fragment saved
1921 {
1922 for (unsigned int i = 0; i < _num_faces; ++i)
1923 {
1924 std::vector<EFAFace *> frag_faces; // count how many fragment edges this element edge contains
1925 if (_faces[i]->hasIntersection())
1926 {
1927 for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1928 {
1929 if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1930 frag_faces.push_back(_fragments[0]->getFace(j));
1931 } // j
1932 if (frag_faces.size() == 2) // element edge contains two fragment edges
1933 {
1934 unsigned int edge_id = frag_faces[0]->adjacentCommonEdge(frag_faces[1]);
1935 tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(0));
1936 tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(1));
1937 }
1938 }
1939 } // i
1940 }
1941 return tip_emb;
1942}
1943
1944bool
1945EFAElement3D::faceContainsTip(unsigned int face_id) const
1946{
1947 bool contain_tip = false;
1948 if (_fragments.size() == 1)
1949 {
1950 unsigned int num_frag_faces = 0; // count how many fragment faces this element face contains
1951 if (_faces[face_id]->hasIntersection())
1952 {
1953 for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1954 {
1955 if (_faces[face_id]->containsFace(_fragments[0]->getFace(j)))
1956 num_frag_faces += 1;
1957 } // j
1958 if (num_frag_faces == 2)
1959 contain_tip = true;
1960 }
1961 }
1962 return contain_tip;
1963}
1964
1965bool
1966EFAElement3D::fragmentFaceAlreadyCut(unsigned int ElemFaceID) const
1967{
1968 // when marking cuts, check if the corresponding frag face already has been cut
1969 bool has_cut = false;
1970 if (faceContainsTip(ElemFaceID))
1971 has_cut = true;
1972 else
1973 {
1974 unsigned int FragFaceID = std::numeric_limits<unsigned int>::max();
1975 if (getFragmentFaceID(ElemFaceID, FragFaceID))
1976 {
1977 EFAFace * frag_face = getFragmentFace(0, FragFaceID);
1978 if (frag_face->hasIntersection())
1979 has_cut = true;
1980 }
1981 }
1982 return has_cut;
1983}
1984
1985void
1986EFAElement3D::addFaceEdgeCut(unsigned int face_id,
1987 unsigned int edge_id,
1988 double position,
1989 EFANode * embedded_node,
1990 std::map<unsigned int, EFANode *> & EmbeddedNodes,
1991 bool add_to_neighbor,
1992 bool add_to_adjacent)
1993{
1994 // Purpose: add intersection on Edge edge_id of Face face_id
1995 EFANode * local_embedded = nullptr;
1996 EFAEdge * cut_edge = _faces[face_id]->getEdge(edge_id);
1997 EFANode * edge_node1 = cut_edge->getNode(0);
1998 if (embedded_node) // use the existing embedded node if it was passed in
1999 local_embedded = embedded_node;
2000
2001 // get adjacent face info
2002 EFAFace * adj_face = getAdjacentFace(face_id, edge_id);
2003 unsigned int adj_face_id = getFaceID(adj_face);
2004 unsigned int adj_edge_id = adj_face->adjacentCommonEdge(_faces[face_id]);
2005
2006 // check if cut has already been added to this face edge
2007 bool cut_exist = false;
2008
2009 if (cut_edge->hasIntersectionAtPosition(position, edge_node1))
2010 {
2011 unsigned int emb_id = cut_edge->getEmbeddedNodeIndex(position, edge_node1);
2012 EFANode * old_emb = cut_edge->getEmbeddedNode(emb_id);
2013 if (embedded_node && embedded_node != old_emb)
2014 EFAError("Attempting to add edge intersection when one already exists with different node.",
2015 " elem: ",
2016 _id,
2017 " edge: ",
2018 edge_id,
2019 " position: ",
2020 position);
2021 local_embedded = old_emb;
2022 cut_exist = true;
2023 }
2024
2025 if (!cut_exist && !fragmentFaceAlreadyCut(face_id) &&
2026 isPhysicalEdgeCut(face_id, edge_id, position))
2027 {
2028 // check if cut has already been added to the neighbor edges
2029 checkNeighborFaceCut(face_id, edge_id, position, edge_node1, embedded_node, local_embedded);
2031 adj_face_id, adj_edge_id, position, edge_node1, embedded_node, local_embedded);
2032
2033 if (!local_embedded) // need to create new embedded node
2034 {
2035 unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
2036 local_embedded = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
2037 EmbeddedNodes.insert(std::make_pair(new_node_id, local_embedded));
2038 }
2039
2040 // add to elem face edge
2041 cut_edge->addIntersection(position, local_embedded, edge_node1);
2042 if (cut_edge->numEmbeddedNodes() > 2)
2043 EFAError("element edge can't have >2 embedded nodes");
2044
2045 // cut fragment faces, which is an essential addition to other code in this method that cuts
2046 // element faces
2047 unsigned int FragFaceID;
2048 unsigned int FragFaceEdgeID;
2049 if (getFragmentFaceEdgeID(face_id, edge_id, FragFaceID, FragFaceEdgeID))
2050 {
2051 EFAEdge * elem_edge = _faces[face_id]->getEdge(edge_id);
2052 EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
2053 double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
2054 xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
2055 xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
2056 double frag_pos = (position - xi[0]) / (xi[1] - xi[0]);
2057 EFANode * frag_edge_node1 = frag_edge->getNode(0);
2058
2059 if (!frag_edge->hasIntersection())
2060 frag_edge->addIntersection(frag_pos, local_embedded, frag_edge_node1);
2061 }
2062
2063 // add to adjacent face edge
2064 if (add_to_adjacent)
2065 {
2066 double adj_pos = 1.0 - position;
2068 adj_face_id, adj_edge_id, adj_pos, local_embedded, EmbeddedNodes, false, false);
2069 }
2070 }
2071
2072 // add cut to neighbor face edge
2073 if (add_to_neighbor)
2074 {
2075 for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
2076 {
2077 EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
2078 unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
2079 unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
2080 double neigh_pos = 1.0 - position; // get emb node's postion on neighbor edge
2081 face_neighbor->addFaceEdgeCut(
2082 neigh_face_id, neigh_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false, true);
2083 }
2084
2085 for (unsigned int en_iter = 0; en_iter < numEdgeNeighbors(face_id, edge_id); ++en_iter)
2086 {
2087 EFAElement3D * edge_neighbor = getEdgeNeighbor(face_id, edge_id, en_iter);
2088 unsigned int neigh_face_id, neigh_edge_id;
2089 getNeighborEdgeIndex(edge_neighbor, face_id, edge_id, neigh_face_id, neigh_edge_id);
2090
2091 // Check the ordering of the node and the assign the position
2092 double neigh_pos;
2093 if (_faces[face_id]->getEdge(edge_id)->getNode(0) ==
2094 edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
2095 neigh_pos = position;
2096 else if (_faces[face_id]->getEdge(edge_id)->getNode(1) ==
2097 edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
2098 neigh_pos = 1.0 - position;
2099 else
2100 EFAError("The EFANodes on commaon edge are not matched.");
2101
2102 edge_neighbor->addFaceEdgeCut(
2103 neigh_face_id, neigh_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false, true);
2104 }
2105 } // If add_to_neighbor required
2106}
2107
2108void
2109EFAElement3D::addFragFaceEdgeCut(unsigned int /*frag_face_id*/,
2110 unsigned int /*frag_edge_id*/,
2111 double /*position*/,
2112 std::map<unsigned int, EFANode *> & /*EmbeddedNodes*/,
2113 bool /*add_to_neighbor*/,
2114 bool /*add_to_adjacent*/)
2115{
2116 // TODO: mark frag face edges
2117 // also need to check if cut has been added to this frag face edge or neighbor edge of adjacent
2118 // face
2119}
2120
2121void
2123 unsigned int edge_id,
2124 double position,
2125 EFANode * from_node,
2126 EFANode * embedded_node,
2127 EFANode *& local_embedded)
2128{
2129 // N.B. this is important. We are checking if the corresponding edge of the neighbor face or of
2130 // the adjacent
2131 // face's neighbor face has a cut at the same position. If so, use the existing embedded node as
2132 // local_embedded
2133 for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
2134 {
2135 EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
2136 unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
2137 unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
2138 EFAEdge * neigh_edge = face_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id);
2139
2140 if (neigh_edge->hasIntersectionAtPosition(position, from_node))
2141 {
2142 unsigned int emb_id = neigh_edge->getEmbeddedNodeIndex(position, from_node);
2143 EFANode * old_emb = neigh_edge->getEmbeddedNode(emb_id);
2144
2145 if (embedded_node && embedded_node != old_emb)
2146 EFAError(
2147 "attempting to add edge intersection when one already exists with different node.");
2148 if (local_embedded && local_embedded != old_emb)
2149 EFAError("attempting to assign contradictory pointer to local_embedded.");
2150
2151 local_embedded = old_emb;
2152 }
2153 } // en_iter
2154}
2155
2156void
2158 std::vector<double> & xi_2d,
2159 std::vector<double> & xi_3d) const
2160{
2161 // given the coords of a point in a 2D face, translate it to 3D parametric coords
2162 xi_3d.resize(3, 0.0);
2163 if (_num_faces == 6)
2164 {
2165 if (face_id == 0)
2166 {
2167 xi_3d[0] = xi_2d[1];
2168 xi_3d[1] = xi_2d[0];
2169 xi_3d[2] = -1.0;
2170 }
2171 else if (face_id == 1)
2172 {
2173 xi_3d[0] = xi_2d[0];
2174 xi_3d[1] = -1.0;
2175 xi_3d[2] = xi_2d[1];
2176 }
2177 else if (face_id == 2)
2178 {
2179 xi_3d[0] = 1.0;
2180 xi_3d[1] = xi_2d[0];
2181 xi_3d[2] = xi_2d[1];
2182 }
2183 else if (face_id == 3)
2184 {
2185 xi_3d[0] = -xi_2d[0];
2186 xi_3d[1] = 1.0;
2187 xi_3d[2] = xi_2d[1];
2188 }
2189 else if (face_id == 4)
2190 {
2191 xi_3d[0] = -1.0;
2192 xi_3d[1] = -xi_2d[0];
2193 xi_3d[2] = xi_2d[1];
2194 }
2195 else if (face_id == 5)
2196 {
2197 xi_3d[0] = xi_2d[0];
2198 xi_3d[1] = xi_2d[1];
2199 xi_3d[2] = 1.0;
2200 }
2201 else
2202 EFAError("face_id out of bounds");
2203 }
2204 else if (_num_faces == 4)
2205 {
2206 if (face_id == 0)
2207 {
2208 xi_3d[0] = xi_2d[0];
2209 xi_3d[1] = xi_2d[1];
2210 xi_3d[2] = 0.0;
2211 }
2212 else if (face_id == 1)
2213 {
2214 xi_3d[0] = 0.0;
2215 xi_3d[1] = xi_2d[0];
2216 xi_3d[2] = xi_2d[1];
2217 }
2218 else if (face_id == 2)
2219 {
2220 xi_3d[0] = xi_2d[1];
2221 xi_3d[1] = 0.0;
2222 xi_3d[2] = xi_2d[0];
2223 }
2224 else if (face_id == 3)
2225 {
2226 xi_3d[0] = xi_2d[0];
2227 xi_3d[1] = xi_2d[2];
2228 xi_3d[2] = xi_2d[1];
2229 }
2230 else
2231 EFAError("face_id out of bounds");
2232 }
2233 else
2234 EFAError("unknown element for 3D");
2235}
2236
2237std::vector<EFANode *>
2239{
2240 std::set<EFANode *> e1nodes(_nodes.begin(),
2241 _nodes.begin() + _num_vertices); // only account for corner nodes
2242 std::set<EFANode *> e2nodes(other_elem->_nodes.begin(),
2243 other_elem->_nodes.begin() + _num_vertices);
2244 std::vector<EFANode *> common_nodes = Efa::getCommonElems(e1nodes, e2nodes);
2245 return common_nodes;
2246}
const Real p
Point xi
sideset clear()
unsigned int numEmbeddedNodes() const
Definition EFAEdge.C:341
bool hasIntersectionAtPosition(double position, EFANode *from_node) const
Definition EFAEdge.C:213
EFANode * getNode(unsigned int index) const
Definition EFAEdge.C:181
EFANode * getEmbeddedNode(unsigned int index) const
Definition EFAEdge.C:332
bool equivalent(const EFAEdge &other) const
Definition EFAEdge.C:38
double distanceFromNode1(EFANode *node) const
Definition EFAEdge.C:250
unsigned int getEmbeddedNodeIndex(EFANode *node) const
Definition EFAEdge.C:283
void addIntersection(double position, EFANode *embedded_node_tmp, EFANode *from_node)
Definition EFAEdge.C:132
bool containsEdge(const EFAEdge &other) const
Definition EFAEdge.C:65
bool hasIntersection() const
Definition EFAEdge.C:200
virtual void restoreFragment(const EFAElement *const from_elem)
std::vector< unsigned int > getCommonFaceID(const EFAElement3D *other_elem) const
virtual bool shouldDuplicateCrackTipSplitElement(const std::set< EFAElement * > &CrackTipElements)
void checkNeighborFaceCut(unsigned int face_id, unsigned int edge_id, double position, EFANode *from_node, EFANode *embedded_node, EFANode *&local_embedded)
std::vector< unsigned int > getTipFaceIDs() const
virtual void initCrackTip(std::set< EFAElement * > &CrackTipElements)
bool overlaysElement(const EFAElement3D *other_elem) const
virtual void switchEmbeddedNode(EFANode *new_node, EFANode *old_node)
virtual unsigned int numInteriorNodes() const
void setLocalCoordinates()
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
EFAElement3D(unsigned int eid, unsigned int n_nodes, unsigned int n_faces)
bool getCommonEdgeID(const EFAElement3D *other_elem, std::vector< std::pair< unsigned int, unsigned int > > &common_ids) const
EFAElement3D * getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
std::vector< std::vector< std::vector< EFAElement3D * > > > _face_edge_neighbors
virtual void switchNode(EFANode *new_node, EFANode *old_node, bool descend_to_parent)
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< EFAFragment3D * > _fragments
std::set< EFANode * > getFaceNodes(unsigned int face_id) const
bool getFragmentFaceEdgeID(unsigned int ElemFaceID, unsigned int ElemFaceEdgeID, unsigned int &FragFaceID, unsigned int &FragFaceEdgeID) const
unsigned int numEdgeNeighbors(unsigned int face_id, unsigned int edge_id) const
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)
std::vector< std::vector< EFAElement3D * > > _face_neighbors
unsigned int numFaces() const
virtual bool shouldDuplicateForPhantomCorner()
unsigned int getFaceID(EFAFace *face) const
virtual unsigned int numFragments() const
virtual unsigned int getNeighborIndex(const EFAElement *neighbor_elem) const
virtual unsigned int getNumCuts() const
EFAElement3D * getEdgeNeighbor(unsigned int face_id, unsigned int edge_id, unsigned int neighbor_id) const
void setFace(unsigned int face_id, EFAFace *face)
EFAFragment3D * getFragment(unsigned int frag_id) const
unsigned int _num_vertices
unsigned int getNeighborFaceEdgeID(unsigned int face_id, unsigned int edg_id, EFAElement3D *neighbor_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)
bool fragmentHasTipFaces() const
virtual void getMasterInfo(EFANode *node, std::vector< EFANode * > &master_nodes, std::vector< double > &master_weights) const
void findFacesAdjacentToFaces()
std::vector< EFAPoint > _local_node_coor
std::set< EFANode * > getTipEmbeddedNodes() const
void removeEmbeddedNode(EFANode *emb_node, bool remove_for_neighbor)
void mapParametricCoordinateFrom2DTo3D(unsigned int face_id, std::vector< double > &xi_2d, std::vector< double > &xi_3d) const
bool getFaceNodeParametricCoordinates(EFANode *node, std::vector< double > &xi_3d) const
EFAFace * getFace(unsigned int face_id) const
virtual void setupNeighbors(std::map< EFANode *, std::set< EFAElement * > > &InverseConnectivityMap)
virtual bool isFinalCut() const
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
EFAVolumeNode * getInteriorNode(unsigned int interior_node_id) const
virtual bool isPartial() const
virtual void updateFragmentNode()
virtual bool shouldDuplicateForCrackTip(const std::set< EFAElement * > &CrackTipElements)
bool isPhysicalEdgeCut(unsigned int ElemFaceID, unsigned int ElemFaceEdgeID, double position) const
bool getFragmentFaceID(unsigned int elem_face_id, unsigned int &frag_face_id) const
std::vector< EFAFace * > _faces
unsigned int _num_interior_face_nodes
bool isFacePhantom(unsigned int face_id) const
virtual bool willCrackTipExtend(std::vector< unsigned int > &split_neighbors) const
virtual void neighborSanityCheck() const
std::vector< EFANode * > getCommonNodes(const EFAElement3D *other_elem) const
unsigned int _num_faces
virtual void clearNeighbors()
unsigned int getNeighborFaceInteriorNodeID(unsigned int face_id, unsigned int node_id, EFAElement3D *neighbor_elem) const
virtual void getNonPhysicalNodes(std::set< EFANode * > &non_physical_nodes) const
virtual void removePhantomEmbeddedNode()
unsigned int getNeighborFaceNodeID(unsigned int face_id, unsigned int node_id, EFAElement3D *neighbor_elem) const
bool fragmentFaceAlreadyCut(unsigned int ElemFaceID) const
std::vector< EFAVolumeNode * > _interior_nodes
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)
virtual bool isCrackTipElement() const
virtual void fragmentSanityCheck(unsigned int n_old_frag_faces, unsigned int n_old_frag_cuts) const
virtual void updateFragments(const std::set< EFAElement * > &CrackTipElements, std::map< unsigned int, EFANode * > &EmbeddedNodes)
unsigned int numFaceNeighbors(unsigned int face_id) const
bool faceContainsTip(unsigned int face_id) const
EFAFace * getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
std::set< EFANode * > getPhantomNodeOnFace(unsigned int face_id) const
virtual void printElement(std::ostream &ostream) const
std::vector< std::vector< EFAFace * > > _faces_adjacent_to_faces
EFAElement * getGeneralNeighbor(unsigned int index) const
Definition EFAElement.C:230
unsigned int numGeneralNeighbors() const
Definition EFAElement.C:236
std::vector< EFANode * > _nodes
Definition EFAElement.h:29
unsigned int _num_nodes
Definition EFAElement.h:28
unsigned int numNodes() const
Definition EFAElement.C:34
EFAElement * _parent
Definition EFAElement.h:31
void mergeNodes(EFANode *&childNode, EFANode *&childOfNeighborNode, EFAElement *childOfNeighborElem, std::map< unsigned int, EFANode * > &PermanentNodes, std::map< unsigned int, EFANode * > &TempNodes)
Definition EFAElement.C:242
std::vector< EFAElement * > _general_neighbors
Definition EFAElement.h:36
EFANode * getNode(unsigned int node_id) const
Definition EFAElement.C:46
bool containsNode(EFANode *node) const
Definition EFAElement.C:52
EFAElement * getChild(unsigned int child_id) const
Definition EFAElement.C:174
bool isCrackTipSplit() const
Definition EFAElement.C:128
void setNode(unsigned int node_id, EFANode *node)
Definition EFAElement.C:40
unsigned int _id
Definition EFAElement.h:27
bool _crack_tip_split_element
Definition EFAElement.h:33
void setParent(EFAElement *parent)
Definition EFAElement.C:183
std::vector< unsigned int > _crack_tip_neighbors
Definition EFAElement.h:34
void findGeneralNeighbors(const std::map< EFANode *, std::set< EFAElement * > > &InverseConnectivity)
Definition EFAElement.C:208
EFANode * createLocalNodeFromGlobalNode(const EFANode *global_node) const
Definition EFAElement.C:70
virtual void switchNode(EFANode *new_node, EFANode *old_node, bool descend_to_parent)=0
unsigned int numChildren() const
Definition EFAElement.C:189
std::vector< EFANode * > _local_nodes
Definition EFAElement.h:30
unsigned int id() const
Definition EFAElement.C:28
std::vector< EFAElement * > _children
Definition EFAElement.h:32
unsigned int numEdges() const
Definition EFAFace.h:49
bool hasSameOrientation(const EFAFace *other_face) const
Definition EFAFace.C:615
bool hasIntersection() const
Definition EFAFace.C:568
unsigned int adjacentCommonEdge(const EFAFace *other_face) const
Definition EFAFace.C:603
EFAEdge * getEdge(unsigned int edge_id) const
Definition EFAFace.h:50
bool equivalent(const EFAFace *other_face) const
Definition EFAFace.C:355
EFANode * getInteriorFaceNode(unsigned int i) const
Definition EFAFace.h:58
unsigned int numNodes() const
Definition EFAFace.C:87
EFANode * getNode(unsigned int node_id) const
Definition EFAFace.C:99
bool isFaceInterior(unsigned int face_id) const
unsigned int numFaces() const
EFAFace * getFace(unsigned int face_id) const
std::vector< EFANode * > getCommonNodes(EFAFragment *other) const
Definition EFAFragment.C:20
EFANode * parent() const
Definition EFANode.C:48
@ N_CATEGORY_EMBEDDED
Definition EFANode.h:21
@ N_CATEGORY_TEMP
Definition EFANode.h:20
@ N_CATEGORY_PERMANENT
Definition EFANode.h:19
@ N_CATEGORY_LOCAL_INDEX
Definition EFANode.h:23
unsigned int id() const
Definition EFANode.C:36
N_CATEGORY category() const
Definition EFANode.C:42
EFAPoint cross(const EFAPoint &point)
Definition EFAPoint.C:98
std::vector< T > getCommonElems(std::set< T > &v1, std::set< T > &v2)
Definition EFAFuncs.h:69
bool deleteFromMap(std::map< unsigned int, T * > &theMap, T *elemToDelete, bool delete_elem=true)
Definition EFAFuncs.h:22
double linearHexShape3D(unsigned int node_id, std::vector< double > &xi_3d)
Definition EFAFuncs.C:33
double linearTetShape3D(unsigned int node_id, std::vector< double > &xi_3d)
Definition EFAFuncs.C:48
unsigned int getNewID(std::map< unsigned int, T * > &theMap)
Definition EFAFuncs.h:38
unsigned int numCommonElems(std::set< T > &v1, std::set< T > &v2)
Definition EFAFuncs.h:49
void normalizePoint(Point &p)
Definition XFEMFuncs.C:621
static const double tol
Definition XFEMFuncs.h:21
const dof_id_type n_nodes