Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "EFAElement3D.h"
11 :
12 : #include <iomanip>
13 :
14 : #include "EFAFaceNode.h"
15 : #include "EFAVolumeNode.h"
16 : #include "EFANode.h"
17 : #include "EFAEdge.h"
18 : #include "EFAFace.h"
19 : #include "EFAFragment3D.h"
20 : #include "EFAFuncs.h"
21 : #include "EFAError.h"
22 : #include "XFEMFuncs.h"
23 :
24 : #include "libmesh/int_range.h"
25 :
26 47798 : EFAElement3D::EFAElement3D(unsigned int eid, unsigned int n_nodes, unsigned int n_faces)
27 : : EFAElement(eid, n_nodes),
28 47798 : _num_faces(n_faces),
29 47798 : _faces(_num_faces, nullptr),
30 47798 : _face_neighbors(_num_faces),
31 95596 : _face_edge_neighbors(_num_faces)
32 : {
33 47798 : if (_num_faces == 4)
34 : {
35 21368 : _num_vertices = 4;
36 21368 : if (_num_nodes == 14)
37 10684 : _num_interior_face_nodes = 4;
38 10684 : else if (_num_nodes == 10)
39 10684 : _num_interior_face_nodes = 3;
40 0 : else if (_num_nodes == 4)
41 0 : _num_interior_face_nodes = 0;
42 : else
43 0 : EFAError("In EFAelement3D the supported TET element types are TET4, TET10 and TET14");
44 : }
45 26430 : else if (_num_faces == 6)
46 : {
47 26430 : _num_vertices = 8;
48 26430 : if (_num_nodes == 27)
49 388 : _num_interior_face_nodes = 5;
50 26042 : else if (_num_nodes == 20)
51 388 : _num_interior_face_nodes = 4;
52 25654 : else if (_num_nodes == 8)
53 25654 : _num_interior_face_nodes = 0;
54 : else
55 0 : EFAError("In EFAelement3D the supported HEX element types are HEX8, HEX20 and HEX27");
56 : }
57 : else
58 0 : EFAError("In EFAelement3D the supported element types are TET4, TET10, TET14, HEX8, HEX20 and "
59 : "HEX27");
60 47798 : setLocalCoordinates();
61 47798 : }
62 :
63 2680 : EFAElement3D::EFAElement3D(const EFAElement3D * from_elem, bool convert_to_local)
64 2680 : : EFAElement(from_elem->_id, from_elem->_num_nodes),
65 2680 : _num_faces(from_elem->_num_faces),
66 2680 : _faces(_num_faces, nullptr),
67 2680 : _face_neighbors(_num_faces),
68 5360 : _face_edge_neighbors(_num_faces)
69 : {
70 2680 : if (convert_to_local)
71 : {
72 : // build local nodes from global nodes
73 30480 : for (unsigned int i = 0; i < _num_nodes; ++i)
74 : {
75 27800 : if (from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_PERMANENT ||
76 0 : from_elem->_nodes[i]->category() == EFANode::N_CATEGORY_TEMP)
77 : {
78 27800 : _nodes[i] = from_elem->createLocalNodeFromGlobalNode(from_elem->_nodes[i]);
79 27800 : _local_nodes.push_back(_nodes[i]); // convenient to delete local nodes
80 : }
81 : else
82 0 : EFAError("In EFAelement3D ",
83 : from_elem->id(),
84 : " the copy constructor must have from_elem w/ global nodes. node: ",
85 : i,
86 : " category: ",
87 : from_elem->_nodes[i]->category());
88 : }
89 :
90 : // copy faces, fragments and interior nodes from from_elem
91 16200 : for (unsigned int i = 0; i < _num_faces; ++i)
92 13520 : _faces[i] = new EFAFace(*from_elem->_faces[i]);
93 5360 : for (unsigned int i = 0; i < from_elem->_fragments.size(); ++i)
94 2680 : _fragments.push_back(new EFAFragment3D(this, true, from_elem, i));
95 2680 : for (unsigned int i = 0; i < from_elem->_interior_nodes.size(); ++i)
96 0 : _interior_nodes.push_back(new EFAVolumeNode(*from_elem->_interior_nodes[i]));
97 :
98 : // replace all global nodes with local nodes
99 30480 : for (unsigned int i = 0; i < _num_nodes; ++i)
100 : {
101 27800 : if (_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
102 27800 : switchNode(
103 : _nodes[i],
104 : from_elem->_nodes[i],
105 : false); // when save to _cut_elem_map, the EFAelement is not a child of any parent
106 : else
107 0 : EFAError("In EFAelement3D copy constructor this elem's nodes must be local");
108 : }
109 :
110 : // create element face connectivity array (IMPORTANT)
111 2680 : findFacesAdjacentToFaces();
112 :
113 2680 : _local_node_coor = from_elem->_local_node_coor;
114 2680 : _num_interior_face_nodes = from_elem->_num_interior_face_nodes;
115 2680 : _num_vertices = from_elem->_num_vertices;
116 : }
117 : else
118 0 : EFAError("this EFAelement3D constructor only converts global nodes to local nodes");
119 2680 : }
120 :
121 98276 : EFAElement3D::~EFAElement3D()
122 : {
123 65428 : for (unsigned int i = 0; i < _fragments.size(); ++i)
124 14950 : if (_fragments[i])
125 14950 : delete _fragments[i];
126 :
127 308050 : for (unsigned int i = 0; i < _faces.size(); ++i)
128 257572 : if (_faces[i])
129 257572 : delete _faces[i];
130 :
131 50478 : for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
132 0 : if (_interior_nodes[i])
133 0 : delete _interior_nodes[i];
134 :
135 78278 : for (unsigned int i = 0; i < _local_nodes.size(); ++i)
136 27800 : if (_local_nodes[i])
137 27800 : delete _local_nodes[i];
138 98276 : }
139 :
140 : void
141 47798 : EFAElement3D::setLocalCoordinates()
142 : {
143 47798 : if (_num_faces == 6)
144 : {
145 : /*
146 : HEX27(HEX20): 7 18 6
147 : o--------------o--------------o
148 : /: / /|
149 : / : / / |
150 : / : / / |
151 : 19/ : 25/ 17/ |
152 : o--------------o--------------o |
153 : / : / /| |
154 : / 15o / 23o / | 14o
155 : / : / / | /|
156 : 4/ : 16/ 5/ | / |
157 : o--------------o--------------o | / |
158 : | : | 26 | |/ |
159 : | 24o : | o | 22o |
160 : | : | 10 | /| |
161 : | 3o....|.........o....|../.|....o
162 : | . | | / | / 2
163 : | . 21| 13|/ | /
164 : 12 o--------------o--------------o | /
165 : | . | | |/
166 : | 11o | 20o | o
167 : | . | | / 9
168 : | . | | /
169 : | . | | /
170 : |. | |/
171 : o--------------o--------------o
172 : 0 8 1
173 :
174 : */
175 26430 : _local_node_coor.resize(_num_nodes);
176 26430 : _local_node_coor[0] = EFAPoint(0.0, 0.0, 0.0);
177 26430 : _local_node_coor[1] = EFAPoint(1.0, 0.0, 0.0);
178 26430 : _local_node_coor[2] = EFAPoint(1.0, 1.0, 0.0);
179 26430 : _local_node_coor[3] = EFAPoint(0.0, 1.0, 0.0);
180 26430 : _local_node_coor[4] = EFAPoint(0.0, 0.0, 1.0);
181 26430 : _local_node_coor[5] = EFAPoint(1.0, 0.0, 1.0);
182 26430 : _local_node_coor[6] = EFAPoint(1.0, 1.0, 1.0);
183 26430 : _local_node_coor[7] = EFAPoint(0.0, 1.0, 1.0);
184 :
185 26430 : if (_num_nodes > 8)
186 : {
187 776 : _local_node_coor[8] = EFAPoint(0.5, 0.0, 0.0);
188 776 : _local_node_coor[9] = EFAPoint(1.0, 0.5, 0.0);
189 776 : _local_node_coor[10] = EFAPoint(0.5, 1.0, 0.0);
190 776 : _local_node_coor[11] = EFAPoint(0.0, 0.5, 0.0);
191 776 : _local_node_coor[12] = EFAPoint(0.0, 0.0, 0.5);
192 776 : _local_node_coor[13] = EFAPoint(1.0, 0.0, 0.5);
193 776 : _local_node_coor[14] = EFAPoint(1.0, 1.0, 0.5);
194 776 : _local_node_coor[15] = EFAPoint(0.0, 1.0, 0.5);
195 776 : _local_node_coor[16] = EFAPoint(0.5, 0.0, 1.0);
196 776 : _local_node_coor[17] = EFAPoint(1.0, 0.5, 1.0);
197 776 : _local_node_coor[18] = EFAPoint(0.5, 1.0, 1.0);
198 776 : _local_node_coor[19] = EFAPoint(0.0, 0.5, 1.0);
199 : }
200 :
201 26430 : if (_num_nodes > 20)
202 : {
203 388 : _local_node_coor[20] = EFAPoint(0.5, 0.5, 0.0);
204 388 : _local_node_coor[21] = EFAPoint(0.5, 0.0, 0.5);
205 388 : _local_node_coor[22] = EFAPoint(1.0, 0.5, 0.5);
206 388 : _local_node_coor[23] = EFAPoint(0.5, 1.0, 0.5);
207 388 : _local_node_coor[24] = EFAPoint(0.0, 0.5, 0.5);
208 388 : _local_node_coor[25] = EFAPoint(0.5, 0.5, 1.0);
209 388 : _local_node_coor[26] = EFAPoint(0.5, 0.5, 0.5);
210 : }
211 : }
212 21368 : else if (_num_faces == 4)
213 : {
214 : /*
215 : 3
216 : TET10: o
217 : /|\
218 : / | \
219 : 7 / | \9
220 : o | o
221 : / |8 \
222 : / o \
223 : / 6 | \
224 : 0 o.....o.|.......o 2
225 : \ | /
226 : \ | /
227 : \ | /
228 : 4 o | o 5
229 : \ | /
230 : \ | /
231 : \|/
232 : o
233 : 1
234 :
235 : */
236 : /*
237 : TET14 elements also include four face nodes:
238 : Node 10, centroid on side 0, arithmetic mean of 0/1/2 or 4/5/6
239 : Node 11, centroid on side 1, arithmetic mean of 0/1/3 or 4/7/8
240 : Node 12, centroid on side 2, arithmetic mean of 1/2/3 or 5/8/9
241 : Node 13, centroid on side 3, arithmetic mean of 0/2/3 or 6/7/9
242 : */
243 21368 : _local_node_coor.resize(_num_nodes);
244 21368 : _local_node_coor[0] = EFAPoint(0.0, 0.0, 0.0);
245 21368 : _local_node_coor[1] = EFAPoint(1.0, 0.0, 0.0);
246 21368 : _local_node_coor[2] = EFAPoint(0.0, 1.0, 0.0);
247 21368 : _local_node_coor[3] = EFAPoint(0.0, 0.0, 1.0);
248 :
249 21368 : if (_num_nodes > 4)
250 : {
251 21368 : _local_node_coor[4] = EFAPoint(0.5, 0.0, 0.0);
252 21368 : _local_node_coor[5] = EFAPoint(0.5, 0.5, 0.0);
253 21368 : _local_node_coor[6] = EFAPoint(0.0, 0.5, 0.0);
254 21368 : _local_node_coor[7] = EFAPoint(0.0, 0.0, 0.5);
255 21368 : _local_node_coor[8] = EFAPoint(0.5, 0.0, 0.5);
256 21368 : _local_node_coor[9] = EFAPoint(0.0, 0.5, 0.5);
257 : }
258 :
259 21368 : if (_num_nodes > 10)
260 : {
261 10684 : _local_node_coor[10] = EFAPoint(1 / 3., 1 / 3., 0.0);
262 10684 : _local_node_coor[11] = EFAPoint(1 / 3., 0.0, 1 / 3.);
263 10684 : _local_node_coor[12] = EFAPoint(1 / 3., 1 / 3., 1 / 3.);
264 10684 : _local_node_coor[13] = EFAPoint(0.0, 1 / 3., 1 / 3.);
265 : }
266 : }
267 : else
268 0 : EFAError("EFAElement3D: number of faces should be either 4(TET) or 6(HEX).");
269 47798 : }
270 :
271 : unsigned int
272 682182 : EFAElement3D::numFragments() const
273 : {
274 682182 : return _fragments.size();
275 : }
276 :
277 : bool
278 952090 : EFAElement3D::isPartial() const
279 : {
280 952090 : if (_fragments.size() > 0)
281 : {
282 2364923 : for (unsigned int i = 0; i < _num_vertices; ++i)
283 : {
284 : bool node_in_frag = false;
285 3108429 : for (unsigned int j = 0; j < _fragments.size(); ++j)
286 : {
287 2260631 : if (_fragments[j]->containsNode(_nodes[i]))
288 : {
289 : node_in_frag = true;
290 : break;
291 : }
292 : } // j
293 :
294 2260631 : if (!node_in_frag)
295 : return true;
296 : } // i
297 : }
298 : return false;
299 : }
300 :
301 : void
302 3828 : EFAElement3D::getNonPhysicalNodes(std::set<EFANode *> & non_physical_nodes) const
303 : {
304 : // Any nodes that don't belong to any fragment are non-physical
305 : // First add all nodes in the element to the set
306 42402 : for (unsigned int i = 0; i < _nodes.size(); ++i)
307 38574 : non_physical_nodes.insert(_nodes[i]);
308 :
309 : // Now delete any nodes that are contained in fragments
310 : std::set<EFANode *>::iterator sit;
311 42402 : for (sit = non_physical_nodes.begin(); sit != non_physical_nodes.end();)
312 : {
313 : bool erased = false;
314 63876 : for (unsigned int i = 0; i < _fragments.size(); ++i)
315 : {
316 38574 : if (_fragments[i]->containsNode(*sit))
317 : {
318 13272 : non_physical_nodes.erase(sit++);
319 : erased = true;
320 13272 : break;
321 : }
322 : }
323 38574 : if (!erased)
324 : ++sit;
325 : }
326 3828 : }
327 :
328 : void
329 887706 : EFAElement3D::switchNode(EFANode * new_node, EFANode * old_node, bool descend_to_parent)
330 : {
331 : // We are not switching any embedded nodes here; This is an enhanced version
332 11408636 : for (unsigned int i = 0; i < _num_nodes; ++i)
333 : {
334 10520930 : if (_nodes[i] == old_node)
335 13741 : _nodes[i] = new_node;
336 : }
337 1441777 : for (unsigned int i = 0; i < _fragments.size(); ++i)
338 554071 : _fragments[i]->switchNode(new_node, old_node);
339 :
340 4728470 : for (unsigned int i = 0; i < _faces.size(); ++i)
341 3840764 : _faces[i]->switchNode(new_node, old_node);
342 :
343 887706 : if (_parent && descend_to_parent)
344 : {
345 11793 : _parent->switchNode(new_node, old_node, false);
346 576876 : for (unsigned int i = 0; i < _parent->numGeneralNeighbors(); ++i)
347 : {
348 565083 : EFAElement * neigh_elem = _parent->getGeneralNeighbor(i); // generalized neighbor element
349 1331649 : for (unsigned int k = 0; k < neigh_elem->numChildren(); ++k)
350 766566 : neigh_elem->getChild(k)->switchNode(new_node, old_node, false);
351 : }
352 : }
353 887706 : }
354 :
355 : void
356 0 : EFAElement3D::switchEmbeddedNode(EFANode * new_emb_node, EFANode * old_emb_node)
357 : {
358 0 : for (unsigned int i = 0; i < _num_faces; ++i)
359 0 : _faces[i]->switchNode(new_emb_node, old_emb_node);
360 0 : for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
361 0 : _interior_nodes[i]->switchNode(new_emb_node, old_emb_node);
362 0 : for (unsigned int i = 0; i < _fragments.size(); ++i)
363 0 : _fragments[i]->switchNode(new_emb_node, old_emb_node);
364 0 : }
365 :
366 : void
367 2831 : EFAElement3D::updateFragmentNode()
368 : {
369 : // In EFAElement3D, updateFragmentNode needs to be implemented
370 2831 : }
371 :
372 : void
373 3181742 : EFAElement3D::getMasterInfo(EFANode * node,
374 : std::vector<EFANode *> & master_nodes,
375 : std::vector<double> & master_weights) const
376 : {
377 : // Given a EFAnode, return its master nodes and weights
378 3181742 : master_nodes.clear();
379 3181742 : master_weights.clear();
380 : bool masters_found = false;
381 6998975 : for (unsigned int i = 0; i < _num_faces; ++i) // check element exterior faces
382 : {
383 6998975 : if (_faces[i]->containsNode(node))
384 : {
385 3181742 : masters_found = _faces[i]->getMasterInfo(node, master_nodes, master_weights);
386 3181742 : if (masters_found)
387 : break;
388 : else
389 0 : EFAError("In getMasterInfo: cannot find master nodes in element faces");
390 : }
391 : }
392 :
393 : if (!masters_found) // check element interior embedded nodes
394 : {
395 0 : for (unsigned int i = 0; i < _interior_nodes.size(); ++i)
396 : {
397 0 : if (_interior_nodes[i]->getNode() == node)
398 : {
399 0 : std::vector<double> xi_3d(3, -100.0);
400 0 : for (unsigned int j = 0; j < 3; ++j)
401 0 : xi_3d[j] = _interior_nodes[i]->getParametricCoordinates(j);
402 0 : for (unsigned int j = 0; j < _num_nodes; ++j)
403 : {
404 0 : master_nodes.push_back(_nodes[j]);
405 0 : double weight = 0.0;
406 0 : if (_num_nodes == 8)
407 0 : weight = Efa::linearHexShape3D(j, xi_3d);
408 0 : else if (_num_nodes == 4)
409 0 : weight = Efa::linearTetShape3D(j, xi_3d);
410 : else
411 0 : EFAError("unknown 3D element");
412 0 : master_weights.push_back(weight);
413 : }
414 : masters_found = true;
415 : break;
416 0 : }
417 : }
418 : }
419 :
420 3181742 : if (!masters_found)
421 0 : EFAError("In EFAelement3D::getMasterInfo, cannot find the given EFANode");
422 3181742 : }
423 :
424 : unsigned int
425 1829 : EFAElement3D::numInteriorNodes() const
426 : {
427 1829 : return _interior_nodes.size();
428 : }
429 :
430 : bool
431 538058 : EFAElement3D::overlaysElement(const EFAElement3D * other_elem) const
432 : {
433 : bool overlays = false;
434 : const EFAElement3D * other3d = dynamic_cast<const EFAElement3D *>(other_elem);
435 538058 : if (!other3d)
436 0 : EFAError("failed to dynamic cast to other3d");
437 :
438 : // Find indices of common nodes
439 538058 : const auto & common_face_curr = getCommonFaceID(other3d);
440 538058 : if (common_face_curr.size() == 1)
441 : {
442 176792 : unsigned int curr_face_id = common_face_curr[0];
443 176792 : EFAFace * curr_face = _faces[curr_face_id];
444 176792 : unsigned int other_face_id = other3d->getFaceID(curr_face);
445 176792 : EFAFace * other_face = other3d->_faces[other_face_id];
446 176792 : if (curr_face->hasSameOrientation(other_face))
447 : overlays = true;
448 : }
449 361266 : else if (common_face_curr.size() > 1)
450 : {
451 : // TODO: We probably need more error checking here.
452 : overlays = true;
453 : }
454 538058 : return overlays;
455 538058 : }
456 :
457 : unsigned int
458 189763 : EFAElement3D::getNeighborIndex(const EFAElement * neighbor_elem) const
459 : {
460 595566 : for (unsigned int i = 0; i < _num_faces; ++i)
461 890153 : for (unsigned int j = 0; j < _face_neighbors[i].size(); ++j)
462 484350 : if (_face_neighbors[i][j] == neighbor_elem)
463 189763 : return i;
464 0 : EFAError("in getNeighborIndex() element ", _id, " does not have neighbor ", neighbor_elem->id());
465 : }
466 :
467 : void
468 40204 : EFAElement3D::getNeighborEdgeIndex(const EFAElement3D * neighbor_elem,
469 : unsigned int face_id,
470 : unsigned int edge_id,
471 : unsigned int & neigh_face_id,
472 : unsigned int & neigh_edge_id) const
473 : {
474 40204 : EFAEdge * edge = this->getFace(face_id)->getEdge(edge_id);
475 84162 : for (unsigned int i = 0; i < neighbor_elem->numFaces(); ++i)
476 : {
477 281234 : for (unsigned int j = 0; j < neighbor_elem->getFace(i)->numEdges(); ++j)
478 : {
479 237276 : EFAEdge * neigh_edge = neighbor_elem->getFace(i)->getEdge(j);
480 237276 : if (neigh_edge->equivalent(*edge))
481 : {
482 40204 : neigh_face_id = i;
483 40204 : neigh_edge_id = j;
484 40204 : return;
485 : }
486 : }
487 : }
488 0 : EFAError("in getNeighborEdgeIndex() element ",
489 : _id,
490 : " does not share a common edge with element",
491 : neighbor_elem->id());
492 : }
493 :
494 : void
495 45225 : EFAElement3D::clearNeighbors()
496 : {
497 45225 : _general_neighbors.clear();
498 276399 : for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
499 : {
500 231174 : _face_neighbors[face_iter].clear();
501 1075518 : for (unsigned int edge_iter = 0; edge_iter < _faces[face_iter]->numEdges(); ++edge_iter)
502 844344 : _face_edge_neighbors[face_iter][edge_iter].clear();
503 : }
504 45225 : }
505 :
506 : void
507 45225 : EFAElement3D::setupNeighbors(std::map<EFANode *, std::set<EFAElement *>> & inverse_connectivity_map)
508 : {
509 45225 : findGeneralNeighbors(inverse_connectivity_map);
510 : std::vector<std::pair<unsigned int, unsigned int>> common_ids;
511 1603515 : for (unsigned int eit2 = 0; eit2 < _general_neighbors.size(); ++eit2)
512 : {
513 1558290 : EFAElement3D * neigh_elem = dynamic_cast<EFAElement3D *>(_general_neighbors[eit2]);
514 1558290 : if (!neigh_elem)
515 0 : EFAError("neighbor_elem is not of EFAelement3D type");
516 :
517 1558290 : const auto & common_face_id = getCommonFaceID(neigh_elem);
518 1919556 : if (common_face_id.empty() && getCommonEdgeID(neigh_elem, common_ids) &&
519 361266 : !overlaysElement(neigh_elem))
520 : {
521 : bool is_edge_neighbor = false;
522 :
523 : // Fragments must match up.
524 361266 : if ((_fragments.size() > 1) || (neigh_elem->numFragments() > 1))
525 0 : EFAError("in updateFaceNeighbors: Cannot have more than 1 fragment");
526 :
527 361266 : if ((_fragments.size() == 1) && (neigh_elem->numFragments() == 1))
528 : {
529 32172 : 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 1075256 : for (const auto & [face_id, edge_id] : common_ids)
537 716924 : _face_edge_neighbors[face_id][edge_id].push_back(neigh_elem);
538 : }
539 :
540 1558290 : if (common_face_id.size() == 1 && !overlaysElement(neigh_elem))
541 : {
542 174488 : unsigned int face_id = common_face_id[0];
543 : bool is_face_neighbor = false;
544 :
545 : // Fragments must match up.
546 174488 : if ((_fragments.size() > 1) || (neigh_elem->numFragments() > 1))
547 0 : EFAError("in updateFaceNeighbors: Cannot have more than 1 fragment");
548 :
549 174488 : if ((_fragments.size() == 1) && (neigh_elem->numFragments() == 1))
550 : {
551 18924 : 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 174344 : if (_face_neighbors[face_id].size() > 1)
560 0 : EFAError("Element ",
561 : _id,
562 : " already has 2 face neighbors: ",
563 : _face_neighbors[face_id][0]->id(),
564 : " ",
565 : _face_neighbors[face_id][1]->id());
566 174344 : _face_neighbors[face_id].push_back(neigh_elem);
567 : }
568 : }
569 1558290 : }
570 45225 : }
571 :
572 : void
573 45225 : EFAElement3D::neighborSanityCheck() const
574 : {
575 276399 : for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
576 : {
577 405518 : for (unsigned int en_iter = 0; en_iter < _face_neighbors[face_iter].size(); ++en_iter)
578 : {
579 174344 : EFAElement3D * neigh_elem = _face_neighbors[face_iter][en_iter];
580 174344 : if (neigh_elem != nullptr)
581 : {
582 : bool found_neighbor = false;
583 1074976 : for (unsigned int face_iter2 = 0; face_iter2 < neigh_elem->numFaces(); ++face_iter2)
584 : {
585 1426492 : for (unsigned int en_iter2 = 0; en_iter2 < neigh_elem->numFaceNeighbors(face_iter2);
586 : ++en_iter2)
587 : {
588 700204 : if (neigh_elem->getFaceNeighbor(face_iter2, en_iter2) == this)
589 : {
590 174344 : if ((en_iter2 > 1) && (en_iter > 1))
591 0 : EFAError(
592 : "Element and neighbor element cannot both have >1 neighbors on a common face");
593 : found_neighbor = true;
594 : break;
595 : }
596 : }
597 : }
598 174344 : if (!found_neighbor)
599 0 : EFAError("Neighbor element doesn't recognize current element as neighbor");
600 : }
601 : }
602 : }
603 45225 : }
604 :
605 : void
606 45048 : EFAElement3D::initCrackTip(std::set<EFAElement *> & CrackTipElements)
607 : {
608 45048 : if (isCrackTipElement())
609 : {
610 617 : CrackTipElements.insert(this);
611 4031 : for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
612 : {
613 3414 : 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 1256 : if (_face_neighbors[face_iter][0]->overlaysElement(this) ||
619 628 : _face_neighbors[face_iter][1]->overlaysElement(this))
620 0 : EFAError("Element has a neighbor that overlays itself");
621 :
622 : // Make sure the current elment hasn't been flagged as a tip element
623 628 : if (_crack_tip_split_element)
624 0 : EFAError("crack_tip_split_element already flagged. In elem: ",
625 : _id,
626 : " flags: ",
627 : _crack_tip_split_element,
628 : " ",
629 : _face_neighbors[face_iter][0]->isCrackTipSplit(),
630 : " ",
631 : _face_neighbors[face_iter][1]->isCrackTipSplit());
632 :
633 628 : _face_neighbors[face_iter][0]->setCrackTipSplit();
634 628 : _face_neighbors[face_iter][1]->setCrackTipSplit();
635 :
636 628 : _face_neighbors[face_iter][0]->addCrackTipNeighbor(this);
637 628 : _face_neighbors[face_iter][1]->addCrackTipNeighbor(this);
638 : }
639 : } // face_iter
640 : }
641 45048 : }
642 :
643 : bool
644 32081 : EFAElement3D::shouldDuplicateForCrackTip(const std::set<EFAElement *> & CrackTipElements)
645 : {
646 : // This method is called in createChildElements()
647 : // Only duplicate when
648 : // 1) currElem will be a NEW crack tip element
649 : // 2) currElem is a crack tip split element at last time step and the tip will extend
650 : // 3) currElem is the neighbor of a to-be-second-split element which has another neighbor
651 : // sharing a phantom node with currElem
652 : bool should_duplicate = false;
653 32081 : if (_fragments.size() == 1)
654 : {
655 : std::set<EFAElement *>::iterator sit;
656 7275 : sit = CrackTipElements.find(this);
657 7275 : if (sit == CrackTipElements.end() && isCrackTipElement())
658 : should_duplicate = true;
659 4548 : else if (shouldDuplicateCrackTipSplitElement(CrackTipElements))
660 : should_duplicate = true;
661 3828 : else if (shouldDuplicateForPhantomCorner())
662 : should_duplicate = true;
663 : }
664 32081 : return should_duplicate;
665 : }
666 :
667 : bool
668 4548 : EFAElement3D::shouldDuplicateCrackTipSplitElement(const std::set<EFAElement *> & CrackTipElements)
669 : {
670 : // Determine whether element at crack tip should be duplicated. It should be duplicated
671 : // if the crack will extend into the next element, or if it has a non-physical node
672 : // connected to a face where a crack terminates, but will extend.
673 :
674 : bool should_duplicate = false;
675 4548 : if (_fragments.size() == 1)
676 : {
677 : std::vector<unsigned int> split_neighbors;
678 4548 : 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 3828 : getNonPhysicalNodes(non_physical_nodes);
687 :
688 133984 : for (unsigned int eit = 0; eit < _general_neighbors.size(); ++eit)
689 : {
690 130156 : EFAElement3D * neigh_elem = dynamic_cast<EFAElement3D *>(_general_neighbors[eit]);
691 130156 : if (!neigh_elem)
692 0 : EFAError("general elem is not of type EFAelement3D");
693 :
694 : // check if a general neighbor is an old crack tip element and will be split
695 : std::set<EFAElement *>::iterator sit;
696 130156 : sit = CrackTipElements.find(neigh_elem);
697 130156 : if (sit != CrackTipElements.end() && neigh_elem->numFragments() > 1)
698 : {
699 0 : for (unsigned int i = 0; i < neigh_elem->numFaces(); ++i)
700 : {
701 0 : std::set<EFANode *> neigh_face_nodes = neigh_elem->getFaceNodes(i);
702 0 : if (neigh_elem->numFaceNeighbors(i) == 2 &&
703 0 : Efa::numCommonElems(neigh_face_nodes, non_physical_nodes) > 0)
704 : {
705 : should_duplicate = true;
706 : break;
707 : }
708 : } // i
709 : }
710 : if (should_duplicate)
711 : break;
712 : } // eit
713 : }
714 4548 : } // IF only one fragment
715 4548 : return should_duplicate;
716 : }
717 :
718 : bool
719 3828 : EFAElement3D::shouldDuplicateForPhantomCorner()
720 : {
721 : // if a partial element will be split for a second time and it has two neighbor elements
722 : // sharing one phantom node with the aforementioned partial element, then the two neighbor
723 : // elements should be duplicated
724 : bool should_duplicate = false;
725 3828 : if (_fragments.size() == 1 && (!_crack_tip_split_element))
726 : {
727 19650 : for (unsigned int i = 0; i < _num_faces; ++i)
728 : {
729 16420 : std::set<EFANode *> phantom_nodes = getPhantomNodeOnFace(i);
730 16420 : if (phantom_nodes.size() > 0 && numFaceNeighbors(i) == 1)
731 : {
732 7752 : EFAElement3D * neighbor_elem = _face_neighbors[i][0];
733 7752 : if (neighbor_elem->numFragments() > 1) // neighbor will be split
734 : {
735 0 : for (unsigned int j = 0; j < neighbor_elem->numFaces(); ++j)
736 : {
737 0 : if (!neighbor_elem->getFace(j)->equivalent(_faces[i]) &&
738 0 : neighbor_elem->numFaceNeighbors(j) > 0)
739 : {
740 0 : std::set<EFANode *> neigh_phantom_nodes = neighbor_elem->getPhantomNodeOnFace(j);
741 0 : if (Efa::numCommonElems(phantom_nodes, neigh_phantom_nodes) > 0)
742 : {
743 : should_duplicate = true;
744 : break;
745 : }
746 : }
747 : } // j
748 : }
749 : }
750 : if (should_duplicate)
751 : break;
752 : } // i
753 : }
754 3828 : return should_duplicate;
755 : }
756 :
757 : bool
758 4548 : EFAElement3D::willCrackTipExtend(std::vector<unsigned int> & split_neighbors) const
759 : {
760 : // Determine whether the current element is a crack tip element for which the crack will
761 : // extend into the next element.
762 : // N.B. this is called at the beginning of createChildElements
763 : bool will_extend = false;
764 4548 : if (_fragments.size() == 1 && _crack_tip_split_element)
765 : {
766 2708 : for (unsigned int i = 0; i < _crack_tip_neighbors.size(); ++i)
767 : {
768 1390 : unsigned int neigh_idx = _crack_tip_neighbors[i]; // essentially a face_id
769 1390 : if (numFaceNeighbors(neigh_idx) != 1)
770 0 : EFAError("in will_crack_tip_extend() element ",
771 : _id,
772 : " has ",
773 : _face_neighbors[neigh_idx].size(),
774 : " neighbors on face ",
775 : neigh_idx);
776 :
777 1390 : EFAElement3D * neighbor_elem = _face_neighbors[neigh_idx][0];
778 1390 : if (neighbor_elem->numFragments() > 2)
779 : {
780 0 : EFAError("in will_crack_tip_extend() element ",
781 : neighbor_elem->id(),
782 : " has ",
783 : neighbor_elem->numFragments(),
784 : " fragments");
785 : }
786 1390 : else if (neighbor_elem->numFragments() == 2)
787 : {
788 720 : EFAFragment3D * neigh_frag1 = neighbor_elem->getFragment(0);
789 720 : EFAFragment3D * neigh_frag2 = neighbor_elem->getFragment(1);
790 720 : 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 3600 : for (unsigned int j = 0; j < neigh_cut_nodes.size(); ++j)
793 : {
794 2880 : if (_faces[neigh_idx]->containsNode(neigh_cut_nodes[j]))
795 1440 : counter += 1;
796 : }
797 720 : if (counter == 2)
798 : {
799 720 : split_neighbors.push_back(neigh_idx);
800 : will_extend = true;
801 : }
802 720 : }
803 : } // i
804 : }
805 4548 : return will_extend;
806 : }
807 :
808 : bool
809 54824 : EFAElement3D::isCrackTipElement() const
810 : {
811 54824 : return fragmentHasTipFaces();
812 : }
813 :
814 : unsigned int
815 6728 : EFAElement3D::getNumCuts() const
816 : {
817 : unsigned int num_cut_faces = 0;
818 41336 : for (unsigned int i = 0; i < _num_faces; ++i)
819 34608 : if (_faces[i]->hasIntersection())
820 0 : num_cut_faces += 1;
821 6728 : return num_cut_faces;
822 : }
823 :
824 : bool
825 23388 : EFAElement3D::isFinalCut() const
826 : {
827 : // if an element has been cut third times its fragment must have 3 interior faces
828 : // and at this point, we do not want it to be further cut
829 : bool cut_third = false;
830 23388 : if (_fragments.size() > 0)
831 : {
832 : unsigned int num_interior_faces = 0;
833 20074 : for (unsigned int i = 0; i < _fragments[0]->numFaces(); ++i)
834 : {
835 16990 : if (_fragments[0]->isFaceInterior(i))
836 2798 : num_interior_faces += 1;
837 : }
838 3084 : if (num_interior_faces == 3)
839 : cut_third = true;
840 : }
841 23388 : return cut_third;
842 : }
843 :
844 : void
845 30213 : EFAElement3D::updateFragments(const std::set<EFAElement *> & CrackTipElements,
846 : std::map<unsigned int, EFANode *> & EmbeddedNodes)
847 : {
848 : // combine the crack-tip faces in a fragment to a single intersected face
849 : std::set<EFAElement *>::iterator sit;
850 30213 : sit = CrackTipElements.find(this);
851 30213 : if (sit != CrackTipElements.end()) // curr_elem is a crack tip element
852 : {
853 370 : if (_fragments.size() == 1)
854 370 : _fragments[0]->combine_tip_faces();
855 : else
856 0 : EFAError("crack tip elem ", _id, " must have 1 fragment");
857 : }
858 :
859 : // remove the inappropriate embedded nodes on interior faces
860 : // (MUST DO THIS AFTER combine_tip_faces())
861 30213 : if (_fragments.size() == 1)
862 3948 : _fragments[0]->removeInvalidEmbeddedNodes(EmbeddedNodes);
863 :
864 : // for an element with no fragment, create one fragment identical to the element
865 30213 : if (_fragments.size() == 0)
866 26265 : _fragments.push_back(new EFAFragment3D(this, true, this));
867 30213 : if (_fragments.size() != 1)
868 0 : EFAError("Element ", _id, " must have 1 fragment at this point");
869 :
870 : // count fragment's cut faces
871 30213 : unsigned int num_cut_frag_faces = _fragments[0]->getNumCuts();
872 30213 : unsigned int num_frag_faces = _fragments[0]->numFaces();
873 30213 : if (num_cut_frag_faces > _fragments[0]->numFaces())
874 0 : EFAError("In element ", _id, " there are too many cut fragment faces");
875 :
876 : // leave the uncut frag as it is
877 30213 : if (num_cut_frag_faces == 0)
878 : {
879 28384 : if (!isPartial()) // delete the temp frag for an uncut elem
880 : {
881 24806 : delete _fragments[0];
882 24806 : _fragments.clear();
883 : }
884 28384 : return;
885 : }
886 :
887 : // split one fragment into one or two new fragments
888 1829 : std::vector<EFAFragment3D *> new_frags = _fragments[0]->split();
889 1829 : if (new_frags.size() == 1 || new_frags.size() == 2)
890 : {
891 1829 : delete _fragments[0]; // delete the old fragment
892 1829 : _fragments.clear();
893 4910 : for (unsigned int i = 0; i < new_frags.size(); ++i)
894 3081 : _fragments.push_back(new_frags[i]);
895 : }
896 : else
897 0 : EFAError("Number of fragments must be 1 or 2 at this point");
898 :
899 1829 : fragmentSanityCheck(num_frag_faces, num_cut_frag_faces);
900 1829 : }
901 :
902 : void
903 1829 : EFAElement3D::fragmentSanityCheck(unsigned int n_old_frag_faces, unsigned int n_old_frag_cuts) const
904 : {
905 1829 : unsigned int n_interior_nodes = numInteriorNodes();
906 1829 : if (n_interior_nodes > 0 && n_interior_nodes != 1)
907 0 : EFAError("After update_fragments this element has ", n_interior_nodes, " interior nodes");
908 :
909 1829 : if (n_old_frag_cuts == 0)
910 : {
911 0 : if (_fragments.size() != 1 || _fragments[0]->numFaces() != n_old_frag_faces)
912 0 : EFAError("Incorrect link size for element with 0 cuts");
913 : }
914 1829 : else if (fragmentHasTipFaces()) // crack tip case
915 : {
916 577 : if (_fragments.size() != 1 || _fragments[0]->numFaces() != n_old_frag_faces + n_old_frag_cuts)
917 0 : EFAError("Incorrect link size for element with crack-tip faces");
918 : }
919 : else // frag is thoroughly cut
920 : {
921 1252 : if (_fragments.size() != 2 || (_fragments[0]->numFaces() + _fragments[1]->numFaces()) !=
922 1252 : n_old_frag_faces + n_old_frag_cuts + 2)
923 0 : EFAError("Incorrect link size for element that has been completely cut");
924 : }
925 1829 : }
926 :
927 : void
928 6728 : EFAElement3D::restoreFragment(const EFAElement * const from_elem)
929 : {
930 6728 : const EFAElement3D * from_elem3d = dynamic_cast<const EFAElement3D *>(from_elem);
931 6728 : if (!from_elem3d)
932 0 : EFAError("from_elem is not of EFAelement3D type");
933 :
934 : // restore fragments
935 6728 : if (_fragments.size() != 0)
936 0 : EFAError("in restoreFragmentInfo elements must not have any pre-existing fragments");
937 13456 : for (unsigned int i = 0; i < from_elem3d->numFragments(); ++i)
938 6728 : _fragments.push_back(new EFAFragment3D(this, true, from_elem3d, i));
939 :
940 : // restore interior nodes
941 6728 : if (_interior_nodes.size() != 0)
942 0 : EFAError("in restoreFragmentInfo elements must not have any pre-exsiting interior nodes");
943 6728 : for (unsigned int i = 0; i < from_elem3d->_interior_nodes.size(); ++i)
944 0 : _interior_nodes.push_back(new EFAVolumeNode(*from_elem3d->_interior_nodes[i]));
945 :
946 : // restore face intersections
947 6728 : if (getNumCuts() != 0)
948 0 : EFAError("In restoreEdgeIntersection: edge cuts already exist in element ", _id);
949 41336 : for (unsigned int i = 0; i < _num_faces; ++i)
950 34608 : _faces[i]->copyIntersection(*from_elem3d->_faces[i]);
951 :
952 : // replace all local nodes with global nodes
953 74862 : for (unsigned int i = 0; i < from_elem3d->numNodes(); ++i)
954 : {
955 68134 : if (from_elem3d->_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
956 68134 : switchNode(
957 : _nodes[i], from_elem3d->_nodes[i], false); // EFAelement is not a child of any parent
958 : else
959 0 : EFAError("In restoreFragmentInfo all of from_elem's nodes must be local");
960 : }
961 6728 : }
962 :
963 : void
964 30213 : EFAElement3D::createChild(const std::set<EFAElement *> & CrackTipElements,
965 : std::map<unsigned int, EFAElement *> & Elements,
966 : std::map<unsigned int, EFAElement *> & newChildElements,
967 : std::vector<EFAElement *> & ChildElements,
968 : std::vector<EFAElement *> & ParentElements,
969 : std::map<unsigned int, EFANode *> & TempNodes)
970 : {
971 30213 : if (_children.size() != 0)
972 0 : EFAError("Element cannot have existing children in createChildElements");
973 :
974 30213 : if (_fragments.size() > 1 || shouldDuplicateForCrackTip(CrackTipElements))
975 : {
976 1579 : if (_fragments.size() > 2)
977 0 : EFAError("More than 2 fragments not yet supported");
978 :
979 : // set up the children
980 1579 : ParentElements.push_back(this);
981 4410 : for (unsigned int ichild = 0; ichild < _fragments.size(); ++ichild)
982 : {
983 : unsigned int new_elem_id;
984 2831 : if (newChildElements.size() == 0)
985 150 : new_elem_id = Efa::getNewID(Elements);
986 : else
987 2681 : new_elem_id = Efa::getNewID(newChildElements);
988 :
989 2831 : EFAElement3D * childElem = new EFAElement3D(new_elem_id, this->numNodes(), this->numFaces());
990 2831 : newChildElements.insert(std::make_pair(new_elem_id, childElem));
991 :
992 2831 : ChildElements.push_back(childElem);
993 2831 : childElem->setParent(this);
994 2831 : _children.push_back(childElem);
995 :
996 : std::vector<std::vector<EFANode *>> cut_plane_nodes;
997 18260 : for (unsigned int i = 0; i < this->getFragment(ichild)->numFaces(); ++i)
998 : {
999 15429 : if (this->getFragment(ichild)->isFaceInterior(i))
1000 : {
1001 2584 : EFAFace * face = this->getFragment(ichild)->getFace(i);
1002 : std::vector<EFANode *> node_line;
1003 11976 : for (unsigned int j = 0; j < face->numNodes(); ++j)
1004 9392 : node_line.push_back(face->getNode(j));
1005 2584 : cut_plane_nodes.push_back(node_line);
1006 2584 : }
1007 : }
1008 :
1009 : std::vector<EFAPoint> cut_plane_points;
1010 :
1011 2831 : EFAPoint orig(0.0, 0.0, 0.0);
1012 :
1013 : std::vector<EFAPoint> normal_v;
1014 :
1015 2831 : if (cut_plane_nodes.size())
1016 : {
1017 11976 : 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 9392 : this->getMasterInfo(cut_plane_nodes[0][i], master_nodes, master_weights);
1023 9392 : EFAPoint coor(0.0, 0.0, 0.0);
1024 28176 : for (unsigned int i = 0; i < master_nodes.size(); ++i)
1025 : {
1026 18784 : EFANode * local = this->createLocalNodeFromGlobalNode(master_nodes[i]);
1027 18784 : coor += _local_node_coor[local->id()] * master_weights[i];
1028 18784 : delete local;
1029 : }
1030 9392 : cut_plane_points.push_back(coor);
1031 9392 : }
1032 :
1033 11976 : for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1034 9392 : orig += cut_plane_points[i];
1035 2584 : orig /= cut_plane_points.size();
1036 :
1037 11976 : for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
1038 : {
1039 9392 : unsigned int iplus1 = i < cut_plane_points.size() - 1 ? i + 1 : 0;
1040 9392 : unsigned int iminus1 = i == 0 ? cut_plane_points.size() - 1 : i - 1;
1041 9392 : EFAPoint ray1 = cut_plane_points[iminus1] - cut_plane_points[i];
1042 9392 : EFAPoint ray2 = cut_plane_points[i] - cut_plane_points[iplus1];
1043 18784 : normal_v.push_back(ray1.cross(ray2));
1044 : }
1045 :
1046 11976 : for (unsigned int i = 0; i < normal_v.size(); ++i)
1047 9392 : Xfem::normalizePoint(normal_v[i]);
1048 : }
1049 :
1050 : // get child element's nodes
1051 31839 : for (unsigned int j = 0; j < _num_nodes; ++j)
1052 : {
1053 29008 : EFAPoint p(0.0, 0.0, 0.0);
1054 29008 : p = _local_node_coor[j];
1055 29008 : EFAPoint origin_to_point = p - orig;
1056 :
1057 : bool node_outside_fragment = false;
1058 76432 : for (unsigned int k = 0; k < normal_v.size(); ++k)
1059 60688 : if (origin_to_point * normal_v[k] > Xfem::tol)
1060 : {
1061 : node_outside_fragment = true;
1062 : break;
1063 : }
1064 :
1065 29008 : if (_fragments.size() == 1 && !shouldDuplicateForCrackTip(CrackTipElements))
1066 0 : childElem->setNode(j, _nodes[j]); // inherit parent's node
1067 29008 : else if (!node_outside_fragment)
1068 15744 : childElem->setNode(j, _nodes[j]); // inherit parent's node
1069 : else // parent element's node is not in fragment
1070 : {
1071 13264 : unsigned int new_node_id = Efa::getNewID(TempNodes);
1072 13264 : EFANode * newNode = new EFANode(new_node_id, EFANode::N_CATEGORY_TEMP, _nodes[j]);
1073 13264 : TempNodes.insert(std::make_pair(new_node_id, newNode));
1074 13264 : childElem->setNode(j, newNode); // be a temp node
1075 : }
1076 : }
1077 :
1078 : // get child element's fragments
1079 2831 : EFAFragment3D * new_frag = new EFAFragment3D(childElem, true, this, ichild);
1080 2831 : childElem->_fragments.push_back(new_frag);
1081 :
1082 : // get child element's faces and set up adjacent faces
1083 2831 : childElem->createFaces();
1084 17257 : for (unsigned int j = 0; j < _num_faces; ++j)
1085 14426 : childElem->_faces[j]->copyIntersection(*_faces[j]);
1086 2831 : childElem->removePhantomEmbeddedNode(); // IMPORTANT
1087 :
1088 : // inherit old interior nodes
1089 2831 : for (unsigned int j = 0; j < _interior_nodes.size(); ++j)
1090 0 : childElem->_interior_nodes.push_back(new EFAVolumeNode(*_interior_nodes[j]));
1091 2831 : }
1092 : }
1093 : else // num_links == 1 || num_links == 0
1094 : {
1095 : // child is itself - but don't insert into the list of ChildElements!!!
1096 28634 : _children.push_back(this);
1097 : }
1098 30213 : }
1099 :
1100 : void
1101 2831 : EFAElement3D::removePhantomEmbeddedNode()
1102 : {
1103 : // remove the embedded nodes on faces that are outside the real domain
1104 2831 : if (_fragments.size() > 0)
1105 : {
1106 17257 : 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 67010 : for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
1111 : {
1112 : EFAEdge * edge = _faces[i]->getEdge(j);
1113 72380 : for (unsigned int k = 0; k < edge->numEmbeddedNodes(); ++k)
1114 : {
1115 19796 : if (!_fragments[0]->containsNode(edge->getEmbeddedNode(k)))
1116 0 : 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 14426 : for (unsigned int j = 0; j < _faces[i]->numInteriorNodes(); ++j)
1122 : {
1123 0 : EFANode * face_node = _faces[i]->getInteriorNode(j)->getNode();
1124 0 : if (!_fragments[0]->containsNode(face_node))
1125 0 : nodes_to_delete.push_back(face_node);
1126 : } // j
1127 :
1128 : // remove all invalid embedded nodes
1129 14426 : for (unsigned int j = 0; j < nodes_to_delete.size(); ++j)
1130 0 : _faces[i]->removeEmbeddedNode(nodes_to_delete[j]);
1131 14426 : } // i
1132 : }
1133 2831 : }
1134 :
1135 : void
1136 2831 : EFAElement3D::connectNeighbors(std::map<unsigned int, EFANode *> & PermanentNodes,
1137 : std::map<unsigned int, EFANode *> & TempNodes,
1138 : std::map<EFANode *, std::set<EFAElement *>> & InverseConnectivityMap,
1139 : bool merge_phantom_faces)
1140 : {
1141 : // N.B. "this" must point to a child element that was just created
1142 2831 : if (!_parent)
1143 0 : EFAError("no parent element for child element ", _id, " in connect_neighbors");
1144 2831 : EFAElement3D * parent3d = dynamic_cast<EFAElement3D *>(_parent);
1145 2831 : if (!parent3d)
1146 0 : EFAError("cannot dynamic cast to parent3d in connect_neighbors");
1147 :
1148 : // First loop through edges and merge nodes with neighbors as appropriate
1149 17257 : for (unsigned int j = 0; j < _num_faces; ++j)
1150 : {
1151 25953 : for (unsigned int k = 0; k < parent3d->numFaceNeighbors(j); ++k)
1152 : {
1153 11527 : EFAElement3D * NeighborElem = parent3d->getFaceNeighbor(j, k);
1154 11527 : unsigned int neighbor_face_id = NeighborElem->getNeighborIndex(parent3d);
1155 :
1156 11527 : if (_faces[j]->hasIntersection())
1157 : {
1158 21011 : for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
1159 : {
1160 : EFAElement3D * childOfNeighborElem =
1161 13732 : dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
1162 13732 : if (!childOfNeighborElem)
1163 0 : 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 13732 : EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
1167 13732 : if (_faces[j]->equivalent(neighborChildFace))
1168 4079 : continue;
1169 :
1170 9653 : if (_fragments[0]->isConnected(childOfNeighborElem->getFragment(0)))
1171 : {
1172 15481 : for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
1173 : {
1174 : unsigned int childNodeIndex = i;
1175 : unsigned int neighborChildNodeIndex =
1176 12076 : parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
1177 :
1178 12076 : EFANode * childNode = _faces[j]->getNode(childNodeIndex);
1179 12076 : EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
1180 12076 : mergeNodes(
1181 : childNode, childOfNeighborNode, childOfNeighborElem, PermanentNodes, TempNodes);
1182 : } // i
1183 :
1184 9241 : for (unsigned int m = 0; m < _num_interior_face_nodes; ++m)
1185 : {
1186 : unsigned int childNodeIndex = m;
1187 : unsigned int neighborChildNodeIndex =
1188 5836 : parent3d->getNeighborFaceInteriorNodeID(j, childNodeIndex, NeighborElem);
1189 :
1190 5836 : EFANode * childNode = _faces[j]->getInteriorFaceNode(childNodeIndex);
1191 : EFANode * childOfNeighborNode =
1192 5836 : neighborChildFace->getInteriorFaceNode(neighborChildNodeIndex);
1193 5836 : 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 4248 : if (merge_phantom_faces)
1203 : {
1204 8496 : for (unsigned int l = 0; l < NeighborElem->numChildren(); ++l)
1205 : {
1206 : EFAElement3D * childOfNeighborElem =
1207 4248 : dynamic_cast<EFAElement3D *>(NeighborElem->getChild(l));
1208 4248 : if (!childOfNeighborElem)
1209 0 : EFAError("dynamic cast childOfNeighborElem fails");
1210 :
1211 4248 : EFAFace * neighborChildFace = childOfNeighborElem->getFace(neighbor_face_id);
1212 4248 : if (!neighborChildFace
1213 4248 : ->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 4248 : if (_faces[j]->equivalent(neighborChildFace))
1218 2588 : continue;
1219 :
1220 7852 : for (unsigned int i = 0; i < _faces[j]->numNodes(); ++i)
1221 : {
1222 : unsigned int childNodeIndex = i;
1223 : unsigned int neighborChildNodeIndex =
1224 6192 : parent3d->getNeighborFaceNodeID(j, childNodeIndex, NeighborElem);
1225 :
1226 6192 : EFANode * childNode = _faces[j]->getNode(childNodeIndex);
1227 6192 : EFANode * childOfNeighborNode = neighborChildFace->getNode(neighborChildNodeIndex);
1228 :
1229 11761 : if (childNode->parent() != nullptr &&
1230 5569 : childNode->parent() ==
1231 : childOfNeighborNode
1232 5569 : ->parent()) // non-material node and both come from same parent
1233 0 : 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 31839 : for (unsigned int j = 0; j < _num_nodes; ++j)
1249 : {
1250 29008 : EFANode * childNode = _nodes[j];
1251 29008 : 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 1620 : std::set<EFAElement *> patch_elems = InverseConnectivityMap[childNode->parent()];
1257 1620 : if (parent3d->numFragments() == 1 && patch_elems.size() == 1)
1258 0 : switchNode(childNode->parent(), childNode, false);
1259 : else
1260 : {
1261 1620 : unsigned int new_node_id = Efa::getNewID(PermanentNodes);
1262 : EFANode * newNode =
1263 1620 : new EFANode(new_node_id, EFANode::N_CATEGORY_PERMANENT, childNode->parent());
1264 1620 : PermanentNodes.insert(std::make_pair(new_node_id, newNode));
1265 1620 : switchNode(newNode, childNode, false);
1266 : }
1267 1620 : if (!Efa::deleteFromMap(TempNodes, childNode))
1268 0 : EFAError(
1269 : "Attempted to delete node: ", childNode->id(), " from TempNodes, but couldn't find it");
1270 : }
1271 : }
1272 2831 : }
1273 :
1274 : void
1275 0 : EFAElement3D::printElement(std::ostream & ostream) const
1276 : {
1277 : // first line: all elem faces
1278 : ostream << std::setw(5);
1279 0 : ostream << _id << "| ";
1280 0 : for (unsigned int j = 0; j < _num_faces; ++j)
1281 : {
1282 0 : for (unsigned int k = 0; k < _faces[j]->numNodes(); ++k)
1283 0 : ostream << std::setw(5) << _faces[j]->getNode(k)->idCatString();
1284 0 : 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 0 : << "| ";
1292 0 : for (unsigned int j = 0; j < _num_faces; ++j)
1293 : {
1294 0 : for (unsigned int k = 0; k < _faces[j]->numEdges(); ++k)
1295 : {
1296 : ostream << std::setw(4);
1297 0 : if (_faces[j]->getEdge(k)->hasIntersection())
1298 : {
1299 0 : if (_faces[j]->getEdge(k)->numEmbeddedNodes() > 1)
1300 : {
1301 0 : ostream << "[";
1302 0 : for (unsigned int l = 0; l < _faces[j]->getEdge(k)->numEmbeddedNodes(); ++l)
1303 : {
1304 0 : ostream << _faces[j]->getEdge(k)->getEmbeddedNode(l)->id() << " ";
1305 0 : if (l == _faces[j]->getEdge(k)->numEmbeddedNodes() - 1)
1306 0 : ostream << "]";
1307 : else
1308 0 : ostream << " ";
1309 : } // l
1310 : }
1311 : else
1312 0 : ostream << _faces[j]->getEdge(k)->getEmbeddedNode(0)->id() << " ";
1313 : }
1314 : else
1315 0 : ostream << " -- ";
1316 : } // k
1317 0 : ostream << " | ";
1318 : } // j
1319 : ostream << std::endl;
1320 :
1321 : // third line: neighbors
1322 : ostream << std::setw(5);
1323 : ostream << "neigh"
1324 0 : << "| ";
1325 0 : for (unsigned int j = 0; j < _num_faces; ++j)
1326 : {
1327 : ostream << std::setw(4);
1328 0 : if (numFaceNeighbors(j) > 1)
1329 : {
1330 0 : ostream << "[";
1331 0 : for (unsigned int k = 0; k < numFaceNeighbors(j); ++k)
1332 : {
1333 0 : ostream << getFaceNeighbor(j, k)->id();
1334 0 : if (k == numFaceNeighbors(j) - 1)
1335 0 : ostream << "]";
1336 : else
1337 0 : ostream << " ";
1338 : }
1339 : }
1340 : else
1341 : {
1342 0 : if (numFaceNeighbors(j) == 1)
1343 0 : ostream << getFaceNeighbor(j, 0)->id() << " ";
1344 : else
1345 0 : ostream << " -- ";
1346 : }
1347 : }
1348 : ostream << std::endl;
1349 :
1350 : // fourth line: fragments
1351 0 : for (unsigned int j = 0; j < _fragments.size(); ++j)
1352 : {
1353 : ostream << std::setw(4);
1354 0 : ostream << "frag" << j << "| ";
1355 0 : for (unsigned int k = 0; k < _fragments[j]->numFaces(); ++k)
1356 : {
1357 0 : for (unsigned int l = 0; l < _fragments[j]->getFace(k)->numNodes(); ++l)
1358 0 : ostream << std::setw(5) << _fragments[j]->getFace(k)->getNode(l)->idCatString();
1359 0 : ostream << " | ";
1360 : }
1361 : ostream << std::endl;
1362 : }
1363 : ostream << std::endl;
1364 0 : }
1365 :
1366 : EFAFragment3D *
1367 13669912 : EFAElement3D::getFragment(unsigned int frag_id) const
1368 : {
1369 13669912 : if (frag_id < _fragments.size())
1370 13669912 : return _fragments[frag_id];
1371 : else
1372 0 : EFAError("frag_id out of bounds");
1373 : }
1374 :
1375 : std::set<EFANode *>
1376 0 : EFAElement3D::getFaceNodes(unsigned int face_id) const
1377 : {
1378 : std::set<EFANode *> face_nodes;
1379 0 : for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i)
1380 0 : face_nodes.insert(_faces[face_id]->getNode(i));
1381 0 : return face_nodes;
1382 : }
1383 :
1384 : bool
1385 0 : EFAElement3D::getFaceNodeParametricCoordinates(EFANode * node, std::vector<double> & xi_3d) const
1386 : {
1387 : // get the parametric coords of a node in an element face
1388 : unsigned int face_id = std::numeric_limits<unsigned int>::max();
1389 : bool face_found = false;
1390 0 : for (unsigned int i = 0; i < _num_faces; ++i)
1391 : {
1392 0 : if (_faces[i]->containsNode(node))
1393 : {
1394 : face_id = i;
1395 : face_found = true;
1396 : break;
1397 : }
1398 : }
1399 0 : if (face_found)
1400 : {
1401 0 : std::vector<double> xi_2d(2, 0.0);
1402 0 : if (_faces[face_id]->getFaceNodeParametricCoords(node, xi_2d))
1403 0 : mapParametricCoordinateFrom2DTo3D(face_id, xi_2d, xi_3d);
1404 : else
1405 0 : EFAError("failed to get the 2D para coords on the face");
1406 0 : }
1407 0 : return face_found;
1408 : }
1409 :
1410 : EFAVolumeNode *
1411 0 : EFAElement3D::getInteriorNode(unsigned int interior_node_id) const
1412 : {
1413 0 : if (interior_node_id < _interior_nodes.size())
1414 0 : return _interior_nodes[interior_node_id];
1415 : else
1416 0 : EFAError("interior_node_id out of bounds");
1417 : }
1418 :
1419 : void
1420 0 : EFAElement3D::removeEmbeddedNode(EFANode * emb_node, bool remove_for_neighbor)
1421 : {
1422 0 : for (unsigned int i = 0; i < _fragments.size(); ++i)
1423 0 : _fragments[i]->removeEmbeddedNode(emb_node);
1424 :
1425 0 : for (unsigned int i = 0; i < _faces.size(); ++i)
1426 0 : _faces[i]->removeEmbeddedNode(emb_node);
1427 :
1428 0 : if (remove_for_neighbor)
1429 : {
1430 0 : for (unsigned int i = 0; i < numFaces(); ++i)
1431 0 : for (unsigned int j = 0; j < numFaceNeighbors(i); ++j)
1432 0 : getFaceNeighbor(i, j)->removeEmbeddedNode(emb_node, false);
1433 : }
1434 0 : }
1435 :
1436 : unsigned int
1437 22767201 : EFAElement3D::numFaces() const
1438 : {
1439 22767201 : return _faces.size();
1440 : }
1441 :
1442 : void
1443 0 : EFAElement3D::setFace(unsigned int face_id, EFAFace * face)
1444 : {
1445 0 : _faces[face_id] = face;
1446 0 : }
1447 :
1448 : void
1449 47798 : EFAElement3D::createFaces()
1450 : {
1451 : // create element faces based on existing element nodes
1452 47798 : 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 47798 : int tet_local_node_indices[4][3] = {{0, 2, 1}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}};
1455 :
1456 47798 : 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 47798 : 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 47798 : _faces = std::vector<EFAFace *>(_num_faces, nullptr);
1466 47798 : if (_num_nodes == 8 || _num_nodes == 20 || _num_nodes == 27)
1467 : {
1468 26430 : if (_num_faces != 6)
1469 0 : EFAError("num_faces of hexes must be 6");
1470 185010 : for (unsigned int i = 0; i < _num_faces; ++i)
1471 : {
1472 158580 : _faces[i] = new EFAFace(4, _num_interior_face_nodes);
1473 792900 : for (unsigned int j = 0; j < 4; ++j)
1474 634320 : _faces[i]->setNode(j, _nodes[hex_local_node_indices[i][j]]);
1475 158580 : _faces[i]->createEdges();
1476 179532 : for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
1477 20952 : _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 21368 : if (_num_faces != 4)
1483 0 : EFAError("num_faces of tets must be 4");
1484 106840 : for (unsigned int i = 0; i < _num_faces; ++i)
1485 : {
1486 85472 : _faces[i] = new EFAFace(3, _num_interior_face_nodes);
1487 341888 : for (unsigned int j = 0; j < 3; ++j)
1488 256416 : _faces[i]->setNode(j, _nodes[tet_local_node_indices[i][j]]);
1489 85472 : _faces[i]->createEdges();
1490 384624 : for (unsigned int k = 0; k < _num_interior_face_nodes; ++k)
1491 299152 : _faces[i]->setInteriorFaceNode(k, _nodes[tet_interior_face_node_indices[i][k]]);
1492 : }
1493 : }
1494 : else
1495 0 : EFAError("unknown 3D element type in createFaces()");
1496 :
1497 291850 : for (unsigned int face_iter = 0; face_iter < _num_faces; ++face_iter)
1498 : {
1499 244052 : _face_edge_neighbors[face_iter].resize(_faces[face_iter]->numEdges());
1500 1134788 : for (unsigned int edge_iter = 0; edge_iter < _faces[face_iter]->numEdges(); ++edge_iter)
1501 890736 : _face_edge_neighbors[face_iter][edge_iter].clear();
1502 : }
1503 :
1504 : // create element face connectivity array
1505 47798 : findFacesAdjacentToFaces(); // IMPORTANT
1506 47798 : }
1507 :
1508 : EFAFace *
1509 21258453 : EFAElement3D::getFace(unsigned int face_id) const
1510 : {
1511 21258453 : return _faces[face_id];
1512 : }
1513 :
1514 : unsigned int
1515 286225 : EFAElement3D::getFaceID(EFAFace * face) const
1516 : {
1517 : bool found_face_id = false;
1518 : unsigned int face_id;
1519 931687 : for (unsigned int iface = 0; iface < _num_faces; ++iface)
1520 : {
1521 931687 : if (_faces[iface]->equivalent(face))
1522 : {
1523 : face_id = iface;
1524 : found_face_id = true;
1525 : break;
1526 : }
1527 : }
1528 286225 : if (!found_face_id)
1529 0 : EFAError("input face not found in get_face_id()");
1530 286225 : return face_id;
1531 : }
1532 :
1533 : std::vector<unsigned int>
1534 2096348 : EFAElement3D::getCommonFaceID(const EFAElement3D * other_elem) const
1535 : {
1536 : std::vector<unsigned int> face_id;
1537 11565572 : for (unsigned int i = 0; i < _num_faces; ++i)
1538 52782190 : for (unsigned int j = 0; j < other_elem->_num_faces; ++j)
1539 43665718 : if (_faces[i]->equivalent(other_elem->_faces[j]))
1540 : {
1541 352752 : face_id.push_back(i);
1542 : break;
1543 : }
1544 :
1545 2096348 : return face_id;
1546 0 : }
1547 :
1548 : bool
1549 1382614 : EFAElement3D::getCommonEdgeID(const EFAElement3D * other_elem,
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 7309042 : for (const auto k : index_range(other_elem->_faces))
1555 : {
1556 5926428 : const auto & face = *other_elem->_faces[k];
1557 24893628 : for (const auto l : make_range(other_elem->_faces[k]->numEdges()))
1558 : {
1559 : const auto & edge = *face.getEdge(l);
1560 18967200 : other_edges.insert(edge.getSortedNodes());
1561 : }
1562 : }
1563 :
1564 : // loop over all edges of this element
1565 1382614 : common_ids.clear();
1566 7309042 : for (const auto i : index_range(_faces))
1567 24893628 : for (const auto j : make_range(_faces[i]->numEdges()))
1568 : {
1569 18967200 : const auto & edge = *_faces[i]->getEdge(j);
1570 18967200 : const auto edge_nodes = edge.getSortedNodes();
1571 :
1572 : // is this edge contained in the other element?
1573 18967200 : if (edge.isEmbeddedPermanent() || other_edges.count(edge_nodes) == 0)
1574 18244408 : continue;
1575 :
1576 722792 : common_ids.emplace_back(i, j);
1577 : }
1578 :
1579 1382614 : return common_ids.size() > 0;
1580 : }
1581 :
1582 : unsigned int
1583 18268 : EFAElement3D::getNeighborFaceNodeID(unsigned int face_id,
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 18268 : unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1591 18268 : if (common_face_id == face_id)
1592 : {
1593 18268 : unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1594 18268 : EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1595 42682 : for (unsigned int i = 0; i < neigh_face->numNodes(); ++i)
1596 : {
1597 42682 : 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 0 : EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
1607 18268 : if (!found_id)
1608 0 : EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
1609 18268 : return neigh_face_node_id;
1610 : }
1611 :
1612 : unsigned int
1613 5836 : EFAElement3D::getNeighborFaceInteriorNodeID(unsigned int face_id,
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 5836 : unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1621 5836 : if (common_face_id == face_id)
1622 : {
1623 5836 : unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1624 5836 : EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1625 :
1626 13552 : for (unsigned int i = 0; i < _num_interior_face_nodes; ++i)
1627 : {
1628 13552 : 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 0 : EFAError("getNeighborFaceNodeID: neighbor_elem is not a neighbor on face_id");
1638 5836 : if (!found_id)
1639 0 : EFAError("getNeighborFaceNodeID: could not find neighbor face node id");
1640 5836 : return neigh_face_node_id;
1641 : }
1642 :
1643 : unsigned int
1644 42924 : EFAElement3D::getNeighborFaceEdgeID(unsigned int face_id,
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 42924 : unsigned int common_face_id = getNeighborIndex(neighbor_elem);
1652 42924 : if (common_face_id == face_id)
1653 : {
1654 42924 : unsigned int neigh_face_id = neighbor_elem->getNeighborIndex(this);
1655 42924 : EFAFace * neigh_face = neighbor_elem->getFace(neigh_face_id);
1656 90988 : for (unsigned int i = 0; i < neigh_face->numEdges(); ++i)
1657 : {
1658 90988 : 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 0 : EFAError("getNeighborFaceEdgeID: neighbor_elem is not a neighbor on face_id");
1668 42924 : if (!found_id)
1669 0 : EFAError("getNeighborFaceEdgeID: could not find neighbor face edge id");
1670 42924 : return neigh_face_edge_id;
1671 : }
1672 :
1673 : void
1674 50478 : EFAElement3D::findFacesAdjacentToFaces()
1675 : {
1676 50478 : _faces_adjacent_to_faces.clear();
1677 308050 : for (unsigned int i = 0; i < _faces.size(); ++i)
1678 : {
1679 257572 : std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr);
1680 1621820 : for (unsigned int j = 0; j < _faces.size(); ++j)
1681 : {
1682 1364248 : if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j]))
1683 : {
1684 939696 : unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]);
1685 939696 : face_adjacents[adj_edge] = _faces[j];
1686 : }
1687 : }
1688 257572 : _faces_adjacent_to_faces.push_back(face_adjacents);
1689 257572 : }
1690 50478 : }
1691 :
1692 : EFAFace *
1693 109433 : EFAElement3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
1694 : {
1695 109433 : return _faces_adjacent_to_faces[face_id][edge_id];
1696 : }
1697 :
1698 : EFAFace *
1699 149525 : EFAElement3D::getFragmentFace(unsigned int frag_id, unsigned int face_id) const
1700 : {
1701 149525 : if (frag_id < _fragments.size())
1702 149525 : return _fragments[frag_id]->getFace(face_id);
1703 : else
1704 0 : EFAError("frag_id out of bounds in getFragmentFace");
1705 : }
1706 :
1707 : std::set<EFANode *>
1708 16420 : EFAElement3D::getPhantomNodeOnFace(unsigned int face_id) const
1709 : {
1710 : std::set<EFANode *> phantom_nodes;
1711 16420 : if (_fragments.size() > 0)
1712 : {
1713 76180 : for (unsigned int j = 0; j < _faces[face_id]->numNodes(); ++j) // loop ove 2 edge nodes
1714 : {
1715 : bool node_in_frag = false;
1716 86160 : for (unsigned int k = 0; k < _fragments.size(); ++k)
1717 : {
1718 59760 : if (_fragments[k]->containsNode(_faces[face_id]->getNode(j)))
1719 : {
1720 : node_in_frag = true;
1721 : break;
1722 : }
1723 : }
1724 59760 : if (!node_in_frag)
1725 26400 : phantom_nodes.insert(_faces[face_id]->getNode(j));
1726 : }
1727 : }
1728 16420 : return phantom_nodes;
1729 : }
1730 :
1731 : bool
1732 20284 : EFAElement3D::getFragmentFaceID(unsigned int elem_face_id, unsigned int & frag_face_id) const
1733 : {
1734 : // find the fragment face that is contained by given element edge
1735 : // N.B. if the elem edge contains two frag edges, this method will only return
1736 : // the first frag edge ID
1737 : bool frag_face_found = false;
1738 20284 : frag_face_id = std::numeric_limits<unsigned int>::max();
1739 20284 : if (_fragments.size() == 1)
1740 : {
1741 1680 : for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1742 : {
1743 1680 : if (_faces[elem_face_id]->containsFace(_fragments[0]->getFace(j)))
1744 : {
1745 480 : frag_face_id = j;
1746 : frag_face_found = true;
1747 480 : break;
1748 : }
1749 : }
1750 : }
1751 20284 : return frag_face_found;
1752 : }
1753 :
1754 : bool
1755 10222 : EFAElement3D::getFragmentFaceEdgeID(unsigned int ElemFaceID,
1756 : unsigned int ElemFaceEdgeID,
1757 : unsigned int & FragFaceID,
1758 : unsigned int & FragFaceEdgeID) const
1759 : {
1760 : // Purpose: given an edge of an elem face, find which frag face's edge it contains
1761 : bool frag_edge_found = false;
1762 10222 : FragFaceID = FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
1763 10222 : if (getFragmentFaceID(ElemFaceID, FragFaceID))
1764 : {
1765 320 : EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
1766 320 : EFAFace * frag_face = getFragmentFace(0, FragFaceID);
1767 800 : for (unsigned int i = 0; i < frag_face->numEdges(); ++i)
1768 : {
1769 800 : if (elem_edge->containsEdge(*frag_face->getEdge(i)))
1770 : {
1771 320 : FragFaceEdgeID = i;
1772 : frag_edge_found = true;
1773 320 : break;
1774 : }
1775 : }
1776 : }
1777 10222 : return frag_edge_found;
1778 : }
1779 :
1780 : bool
1781 10062 : EFAElement3D::isPhysicalEdgeCut(unsigned int ElemFaceID,
1782 : unsigned int ElemFaceEdgeID,
1783 : double position) const
1784 : {
1785 10062 : unsigned int FragFaceID, FragFaceEdgeID = std::numeric_limits<unsigned int>::max();
1786 : bool is_in_real = false;
1787 10062 : if (_fragments.size() == 0)
1788 : {
1789 : is_in_real = true;
1790 : }
1791 160 : else if (getFragmentFaceEdgeID(ElemFaceID, ElemFaceEdgeID, FragFaceID, FragFaceEdgeID))
1792 : {
1793 160 : EFAEdge * elem_edge = _faces[ElemFaceID]->getEdge(ElemFaceEdgeID);
1794 160 : EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
1795 : double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
1796 160 : xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
1797 160 : xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
1798 160 : 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 10062 : return is_in_real;
1803 : }
1804 :
1805 : bool
1806 17958 : EFAElement3D::isFacePhantom(unsigned int face_id) const
1807 : {
1808 : bool is_phantom = false;
1809 17958 : if (_fragments.size() > 0)
1810 : {
1811 : bool contains_frag_face = false;
1812 13610 : for (unsigned int i = 0; i < _fragments.size(); ++i)
1813 : {
1814 38142 : for (unsigned int j = 0; j < _fragments[i]->numFaces(); ++j)
1815 : {
1816 38142 : if (_faces[face_id]->containsFace(_fragments[i]->getFace(j)))
1817 : {
1818 : contains_frag_face = true;
1819 : break;
1820 : }
1821 : }
1822 13610 : if (contains_frag_face)
1823 : break;
1824 : }
1825 13610 : if (!contains_frag_face)
1826 : is_phantom = true;
1827 : }
1828 17958 : return is_phantom;
1829 : }
1830 :
1831 : unsigned int
1832 1567541 : EFAElement3D::numFaceNeighbors(unsigned int face_id) const
1833 : {
1834 1567541 : return _face_neighbors[face_id].size();
1835 : }
1836 :
1837 : unsigned int
1838 76522 : EFAElement3D::numEdgeNeighbors(unsigned int face_id, unsigned int edge_id) const
1839 : {
1840 76522 : return _face_edge_neighbors[face_id][edge_id].size();
1841 : }
1842 :
1843 : EFAElement3D *
1844 755359 : EFAElement3D::getFaceNeighbor(unsigned int face_id, unsigned int neighbor_id) const
1845 : {
1846 755359 : if (_face_neighbors[face_id][0] != nullptr && neighbor_id < _face_neighbors[face_id].size())
1847 755359 : return _face_neighbors[face_id][neighbor_id];
1848 : else
1849 0 : EFAError("edge neighbor does not exist");
1850 : }
1851 :
1852 : EFAElement3D *
1853 40204 : EFAElement3D::getEdgeNeighbor(unsigned int face_id,
1854 : unsigned int edge_id,
1855 : unsigned int neighbor_id) const
1856 : {
1857 40204 : if (neighbor_id < _face_edge_neighbors[face_id][edge_id].size())
1858 40204 : return _face_edge_neighbors[face_id][edge_id][neighbor_id];
1859 : else
1860 0 : EFAError("edge neighbor does not exist");
1861 : }
1862 :
1863 : bool
1864 56653 : EFAElement3D::fragmentHasTipFaces() const
1865 : {
1866 : bool has_tip_faces = false;
1867 56653 : if (_fragments.size() == 1)
1868 : {
1869 94714 : 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 81638 : if (_faces[i]->hasIntersection())
1873 : {
1874 343872 : for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1875 : {
1876 291608 : if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1877 56432 : num_frag_faces += 1;
1878 : } // j
1879 52264 : if (num_frag_faces == 2)
1880 : {
1881 : has_tip_faces = true;
1882 : break;
1883 : }
1884 : }
1885 : } // i
1886 : }
1887 56653 : return has_tip_faces;
1888 : }
1889 :
1890 : std::vector<unsigned int>
1891 0 : EFAElement3D::getTipFaceIDs() const
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 0 : if (_fragments.size() == 1) // crack tip element with a partial fragment saved
1896 : {
1897 0 : 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 0 : if (_faces[i]->hasIntersection())
1901 : {
1902 0 : for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1903 : {
1904 0 : if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1905 0 : num_frag_faces += 1;
1906 : } // j
1907 0 : if (num_frag_faces == 2) // element face contains two fragment edges
1908 0 : tip_face_id.push_back(i);
1909 : }
1910 : } // i
1911 : }
1912 0 : return tip_face_id;
1913 0 : }
1914 :
1915 : std::set<EFANode *>
1916 0 : EFAElement3D::getTipEmbeddedNodes() const
1917 : {
1918 : // if this element is a crack tip element, returns the crack tip edge's ID
1919 : std::set<EFANode *> tip_emb;
1920 0 : if (_fragments.size() == 1) // crack tip element with a partial fragment saved
1921 : {
1922 0 : 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 0 : if (_faces[i]->hasIntersection())
1926 : {
1927 0 : for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1928 : {
1929 0 : if (_faces[i]->containsFace(_fragments[0]->getFace(j)))
1930 0 : frag_faces.push_back(_fragments[0]->getFace(j));
1931 : } // j
1932 0 : if (frag_faces.size() == 2) // element edge contains two fragment edges
1933 : {
1934 0 : unsigned int edge_id = frag_faces[0]->adjacentCommonEdge(frag_faces[1]);
1935 0 : tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(0));
1936 0 : tip_emb.insert(frag_faces[0]->getEdge(edge_id)->getNode(1));
1937 : }
1938 : }
1939 0 : } // i
1940 : }
1941 0 : return tip_emb;
1942 : }
1943 :
1944 : bool
1945 10062 : EFAElement3D::faceContainsTip(unsigned int face_id) const
1946 : {
1947 : bool contain_tip = false;
1948 10062 : if (_fragments.size() == 1)
1949 : {
1950 : unsigned int num_frag_faces = 0; // count how many fragment faces this element face contains
1951 160 : if (_faces[face_id]->hasIntersection())
1952 : {
1953 0 : for (unsigned int j = 0; j < _fragments[0]->numFaces(); ++j)
1954 : {
1955 0 : if (_faces[face_id]->containsFace(_fragments[0]->getFace(j)))
1956 0 : num_frag_faces += 1;
1957 : } // j
1958 0 : if (num_frag_faces == 2)
1959 : contain_tip = true;
1960 : }
1961 : }
1962 10062 : return contain_tip;
1963 : }
1964 :
1965 : bool
1966 10062 : EFAElement3D::fragmentFaceAlreadyCut(unsigned int ElemFaceID) const
1967 : {
1968 : // when marking cuts, check if the corresponding frag face already has been cut
1969 : bool has_cut = false;
1970 10062 : if (faceContainsTip(ElemFaceID))
1971 : has_cut = true;
1972 : else
1973 : {
1974 10062 : unsigned int FragFaceID = std::numeric_limits<unsigned int>::max();
1975 10062 : if (getFragmentFaceID(ElemFaceID, FragFaceID))
1976 : {
1977 160 : EFAFace * frag_face = getFragmentFace(0, FragFaceID);
1978 160 : if (frag_face->hasIntersection())
1979 : has_cut = true;
1980 : }
1981 : }
1982 10062 : return has_cut;
1983 : }
1984 :
1985 : void
1986 109433 : EFAElement3D::addFaceEdgeCut(unsigned int face_id,
1987 : unsigned int edge_id,
1988 : double position,
1989 : EFANode * embedded_node,
1990 : std::map<unsigned int, EFANode *> & EmbeddedNodes,
1991 : bool add_to_neighbor,
1992 : bool add_to_adjacent)
1993 : {
1994 : // Purpose: add intersection on Edge edge_id of Face face_id
1995 109433 : EFANode * local_embedded = nullptr;
1996 109433 : EFAEdge * cut_edge = _faces[face_id]->getEdge(edge_id);
1997 109433 : EFANode * edge_node1 = cut_edge->getNode(0);
1998 109433 : if (embedded_node) // use the existing embedded node if it was passed in
1999 73115 : local_embedded = embedded_node;
2000 :
2001 : // get adjacent face info
2002 109433 : EFAFace * adj_face = getAdjacentFace(face_id, edge_id);
2003 109433 : unsigned int adj_face_id = getFaceID(adj_face);
2004 109433 : 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 109433 : if (cut_edge->hasIntersectionAtPosition(position, edge_node1))
2010 : {
2011 99371 : unsigned int emb_id = cut_edge->getEmbeddedNodeIndex(position, edge_node1);
2012 99371 : EFANode * old_emb = cut_edge->getEmbeddedNode(emb_id);
2013 99371 : if (embedded_node && embedded_node != old_emb)
2014 0 : 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 99371 : local_embedded = old_emb;
2022 : cut_exist = true;
2023 : }
2024 :
2025 20124 : if (!cut_exist && !fragmentFaceAlreadyCut(face_id) &&
2026 10062 : isPhysicalEdgeCut(face_id, edge_id, position))
2027 : {
2028 : // check if cut has already been added to the neighbor edges
2029 10062 : checkNeighborFaceCut(face_id, edge_id, position, edge_node1, embedded_node, local_embedded);
2030 10062 : checkNeighborFaceCut(
2031 : adj_face_id, adj_edge_id, position, edge_node1, embedded_node, local_embedded);
2032 :
2033 10062 : if (!local_embedded) // need to create new embedded node
2034 : {
2035 1850 : unsigned int new_node_id = Efa::getNewID(EmbeddedNodes);
2036 1850 : local_embedded = new EFANode(new_node_id, EFANode::N_CATEGORY_EMBEDDED);
2037 1850 : EmbeddedNodes.insert(std::make_pair(new_node_id, local_embedded));
2038 : }
2039 :
2040 : // add to elem face edge
2041 10062 : cut_edge->addIntersection(position, local_embedded, edge_node1);
2042 10062 : if (cut_edge->numEmbeddedNodes() > 2)
2043 0 : 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 10062 : if (getFragmentFaceEdgeID(face_id, edge_id, FragFaceID, FragFaceEdgeID))
2050 : {
2051 160 : EFAEdge * elem_edge = _faces[face_id]->getEdge(edge_id);
2052 160 : EFAEdge * frag_edge = getFragmentFace(0, FragFaceID)->getEdge(FragFaceEdgeID);
2053 : double xi[2] = {-1.0, -1.0}; // relative coords of two frag edge nodes
2054 160 : xi[0] = elem_edge->distanceFromNode1(frag_edge->getNode(0));
2055 160 : xi[1] = elem_edge->distanceFromNode1(frag_edge->getNode(1));
2056 160 : double frag_pos = (position - xi[0]) / (xi[1] - xi[0]);
2057 160 : EFANode * frag_edge_node1 = frag_edge->getNode(0);
2058 :
2059 160 : if (!frag_edge->hasIntersection())
2060 160 : frag_edge->addIntersection(frag_pos, local_embedded, frag_edge_node1);
2061 : }
2062 :
2063 : // add to adjacent face edge
2064 10062 : if (add_to_adjacent)
2065 : {
2066 5031 : double adj_pos = 1.0 - position;
2067 5031 : addFaceEdgeCut(
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 109433 : if (add_to_neighbor)
2074 : {
2075 64198 : for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
2076 : {
2077 27880 : EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
2078 27880 : unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
2079 27880 : unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
2080 27880 : double neigh_pos = 1.0 - position; // get emb node's postion on neighbor edge
2081 27880 : face_neighbor->addFaceEdgeCut(
2082 : neigh_face_id, neigh_edge_id, neigh_pos, local_embedded, EmbeddedNodes, false, true);
2083 : }
2084 :
2085 76522 : for (unsigned int en_iter = 0; en_iter < numEdgeNeighbors(face_id, edge_id); ++en_iter)
2086 : {
2087 40204 : EFAElement3D * edge_neighbor = getEdgeNeighbor(face_id, edge_id, en_iter);
2088 : unsigned int neigh_face_id, neigh_edge_id;
2089 40204 : 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 80408 : if (_faces[face_id]->getEdge(edge_id)->getNode(0) ==
2094 40204 : edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
2095 : neigh_pos = position;
2096 40122 : else if (_faces[face_id]->getEdge(edge_id)->getNode(1) ==
2097 20061 : edge_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id)->getNode(0))
2098 20061 : neigh_pos = 1.0 - position;
2099 : else
2100 0 : EFAError("The EFANodes on commaon edge are not matched.");
2101 :
2102 40204 : 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 109433 : }
2107 :
2108 : void
2109 0 : EFAElement3D::addFragFaceEdgeCut(unsigned int /*frag_face_id*/,
2110 : unsigned int /*frag_edge_id*/,
2111 : double /*position*/,
2112 : std::map<unsigned int, EFANode *> & /*EmbeddedNodes*/,
2113 : bool /*add_to_neighbor*/,
2114 : bool /*add_to_adjacent*/)
2115 : {
2116 : // TODO: mark frag face edges
2117 : // also need to check if cut has been added to this frag face edge or neighbor edge of adjacent
2118 : // face
2119 0 : }
2120 :
2121 : void
2122 20124 : EFAElement3D::checkNeighborFaceCut(unsigned int face_id,
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 35168 : for (unsigned int en_iter = 0; en_iter < numFaceNeighbors(face_id); ++en_iter)
2134 : {
2135 15044 : EFAElement3D * face_neighbor = getFaceNeighbor(face_id, en_iter);
2136 15044 : unsigned int neigh_face_id = face_neighbor->getNeighborIndex(this);
2137 15044 : unsigned neigh_edge_id = getNeighborFaceEdgeID(face_id, edge_id, face_neighbor);
2138 15044 : EFAEdge * neigh_edge = face_neighbor->getFace(neigh_face_id)->getEdge(neigh_edge_id);
2139 :
2140 15044 : if (neigh_edge->hasIntersectionAtPosition(position, from_node))
2141 : {
2142 7588 : unsigned int emb_id = neigh_edge->getEmbeddedNodeIndex(position, from_node);
2143 7588 : EFANode * old_emb = neigh_edge->getEmbeddedNode(emb_id);
2144 :
2145 7588 : if (embedded_node && embedded_node != old_emb)
2146 0 : EFAError(
2147 : "attempting to add edge intersection when one already exists with different node.");
2148 7588 : if (local_embedded && local_embedded != old_emb)
2149 0 : EFAError("attempting to assign contradictory pointer to local_embedded.");
2150 :
2151 7588 : local_embedded = old_emb;
2152 : }
2153 : } // en_iter
2154 20124 : }
2155 :
2156 : void
2157 0 : EFAElement3D::mapParametricCoordinateFrom2DTo3D(unsigned int face_id,
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 0 : xi_3d.resize(3, 0.0);
2163 0 : if (_num_faces == 6)
2164 : {
2165 : if (face_id == 0)
2166 : {
2167 0 : xi_3d[0] = xi_2d[1];
2168 0 : xi_3d[1] = xi_2d[0];
2169 0 : xi_3d[2] = -1.0;
2170 : }
2171 : else if (face_id == 1)
2172 : {
2173 0 : xi_3d[0] = xi_2d[0];
2174 0 : xi_3d[1] = -1.0;
2175 0 : xi_3d[2] = xi_2d[1];
2176 : }
2177 : else if (face_id == 2)
2178 : {
2179 0 : xi_3d[0] = 1.0;
2180 0 : xi_3d[1] = xi_2d[0];
2181 0 : xi_3d[2] = xi_2d[1];
2182 : }
2183 : else if (face_id == 3)
2184 : {
2185 0 : xi_3d[0] = -xi_2d[0];
2186 0 : xi_3d[1] = 1.0;
2187 0 : xi_3d[2] = xi_2d[1];
2188 : }
2189 : else if (face_id == 4)
2190 : {
2191 0 : xi_3d[0] = -1.0;
2192 0 : xi_3d[1] = -xi_2d[0];
2193 0 : xi_3d[2] = xi_2d[1];
2194 : }
2195 : else if (face_id == 5)
2196 : {
2197 0 : xi_3d[0] = xi_2d[0];
2198 0 : xi_3d[1] = xi_2d[1];
2199 0 : xi_3d[2] = 1.0;
2200 : }
2201 : else
2202 0 : EFAError("face_id out of bounds");
2203 : }
2204 0 : else if (_num_faces == 4)
2205 : {
2206 0 : if (face_id == 0)
2207 : {
2208 0 : xi_3d[0] = xi_2d[0];
2209 0 : xi_3d[1] = xi_2d[1];
2210 0 : xi_3d[2] = 0.0;
2211 : }
2212 0 : else if (face_id == 1)
2213 : {
2214 0 : xi_3d[0] = 0.0;
2215 0 : xi_3d[1] = xi_2d[0];
2216 0 : xi_3d[2] = xi_2d[1];
2217 : }
2218 0 : else if (face_id == 2)
2219 : {
2220 0 : xi_3d[0] = xi_2d[1];
2221 0 : xi_3d[1] = 0.0;
2222 0 : xi_3d[2] = xi_2d[0];
2223 : }
2224 0 : else if (face_id == 3)
2225 : {
2226 0 : xi_3d[0] = xi_2d[0];
2227 0 : xi_3d[1] = xi_2d[2];
2228 0 : xi_3d[2] = xi_2d[1];
2229 : }
2230 : else
2231 0 : EFAError("face_id out of bounds");
2232 : }
2233 : else
2234 0 : EFAError("unknown element for 3D");
2235 0 : }
2236 :
2237 : std::vector<EFANode *>
2238 0 : EFAElement3D::getCommonNodes(const EFAElement3D * other_elem) const
2239 : {
2240 : std::set<EFANode *> e1nodes(_nodes.begin(),
2241 0 : _nodes.begin() + _num_vertices); // only account for corner nodes
2242 : std::set<EFANode *> e2nodes(other_elem->_nodes.begin(),
2243 0 : other_elem->_nodes.begin() + _num_vertices);
2244 0 : std::vector<EFANode *> common_nodes = Efa::getCommonElems(e1nodes, e2nodes);
2245 0 : return common_nodes;
2246 : }
|