https://mooseframework.inl.gov
Loading...
Searching...
No Matches
EFAFragment3D.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 "EFAFragment3D.h"
11
12#include "EFAVolumeNode.h"
13#include "EFANode.h"
14#include "EFAEdge.h"
15#include "EFAFace.h"
16#include "EFAFuncs.h"
17#include "EFAElement3D.h"
18#include "EFAError.h"
19
21 bool create_faces,
22 const EFAElement3D * from_host,
23 unsigned int frag_id)
24 : EFAFragment(), _host_elem(host)
25{
26 if (create_faces)
27 {
28 if (!from_host)
29 EFAError("EFAfragment3D constructor must have a from_host to copy from");
30 if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself
31 {
32 for (unsigned int i = 0; i < from_host->numFaces(); ++i)
33 _faces.push_back(new EFAFace(*from_host->getFace(i)));
34 }
35 else
36 {
37 if (frag_id > from_host->numFragments() - 1)
38 EFAError("In EFAfragment3D constructor fragment_copy_index out of bounds");
39 for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numFaces(); ++i)
40 _faces.push_back(new EFAFace(*from_host->getFragmentFace(frag_id, i)));
41 }
42 findFacesAdjacentToFaces(); // IMPORTANT
43 }
44}
45
47{
48 for (unsigned int i = 0; i < _faces.size(); ++i)
49 {
50 if (_faces[i])
51 {
52 delete _faces[i];
53 _faces[i] = nullptr;
54 }
55 }
56}
57
58void
60{
61 for (unsigned int i = 0; i < _faces.size(); ++i)
62 _faces[i]->switchNode(new_node, old_node);
63}
64
65bool
67{
68 bool contains = false;
69 for (unsigned int i = 0; i < _faces.size(); ++i)
70 {
71 if (_faces[i]->containsNode(node))
72 {
73 contains = true;
74 break;
75 }
76 }
77 return contains;
78}
79
80unsigned int
82{
83 unsigned int num_cut_faces = 0;
84 for (unsigned int i = 0; i < _faces.size(); ++i)
85 if (_faces[i]->hasIntersection())
86 num_cut_faces += 1;
87 return num_cut_faces;
88}
89
90unsigned int
92{
93 mooseError("Not implemented yet for 3D.");
94}
95
96std::set<EFANode *>
98{
99 std::set<EFANode *> all_nodes;
100 for (unsigned int i = 0; i < _faces.size(); ++i)
101 for (unsigned int j = 0; j < _faces[i]->numNodes(); ++j)
102 all_nodes.insert(_faces[i]->getNode(j));
103 return all_nodes;
104}
105
106bool
108{
109 EFAFragment3D * other_frag3d = dynamic_cast<EFAFragment3D *>(other_fragment);
110 if (!other_frag3d)
111 EFAError("in isConnected other_fragment is not of type EFAfragement3D");
112
113 for (unsigned int i = 0; i < _faces.size(); ++i)
114 for (unsigned int j = 0; j < other_frag3d->numFaces(); ++j)
115 if (_faces[i]->equivalent(other_frag3d->_faces[j]))
116 return true;
117
118 return false;
119}
120
121bool
123{
124 EFAFragment3D * other_frag3d = dynamic_cast<EFAFragment3D *>(other_fragment);
125 if (!other_frag3d)
126 EFAError("in isEdgeConnected other_fragment is not of type EFAfragement3D");
127
128 for (unsigned int i = 0; i < _faces.size(); ++i)
129 for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
130 for (unsigned int k = 0; k < other_frag3d->numFaces(); ++k)
131 for (unsigned int l = 0; l < other_frag3d->_faces[k]->numEdges(); ++l)
132 if (_faces[i]->getEdge(j)->equivalent(*(other_frag3d->_faces[k]->getEdge(l))))
133 return true;
134
135 return false;
136}
137
138void
139EFAFragment3D::removeInvalidEmbeddedNodes(std::map<unsigned int, EFANode *> & EmbeddedNodes)
140{
141 // N.B. this method is only called before we update fragments
142 // N.B. an embedded node is valid IF at least one of its host faces is exterior and has more than
143 // 1 cuts
144 // TODO: the invalid cases are generalized from 2D. The method may need improvements in 3D
145 if (hasFaceWithOneCut())
146 {
147 // build a local inverse map for all emb cut nodes in this fragment
148 std::map<EFANode *, std::vector<EFAFace *>> emb_inverse_map;
149 for (unsigned int i = 0; i < _faces.size(); ++i)
150 for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
151 if (_faces[i]->getEdge(j)->hasIntersection())
152 {
153 EFANode * emb_node = _faces[i]->getEdge(j)->getEmbeddedNode(0);
154 emb_inverse_map[emb_node].push_back(_faces[i]);
155 }
156
157 // find all invalid embedded nodes
158 std::vector<EFANode *> invalid_emb;
159 std::map<EFANode *, std::vector<EFAFace *>>::iterator it;
160 for (it = emb_inverse_map.begin(); it != emb_inverse_map.end(); ++it)
161 {
162 EFANode * emb_node = it->first;
163 std::vector<EFAFace *> & emb_faces = it->second;
164 if (emb_faces.size() != 2)
165 EFAError("one embedded node must be owned by 2 faces");
166 unsigned int counter = 0;
167 for (unsigned int i = 0; i < emb_faces.size(); ++i)
168 {
169 unsigned int face_id = getFaceID(emb_faces[i]);
170 if (!isFaceInterior(face_id) && emb_faces[i]->hasIntersection())
171 counter += 1; // count the appropriate emb's faces
172 }
173 if (counter == 0)
174 invalid_emb.push_back(emb_node);
175 }
176
177 // delete all invalid emb nodes
178 for (unsigned int i = 0; i < invalid_emb.size(); ++i)
179 {
180 Efa::deleteFromMap(EmbeddedNodes, invalid_emb[i]);
181 _host_elem->removeEmbeddedNode(invalid_emb[i], true); // also remove from neighbors
182 } // i
183 }
184}
185
186void
188{
189 if (!_host_elem)
190 EFAError("In combine_tip_faces() the frag must have host_elem");
191
192 for (unsigned int i = 0; i < _host_elem->numFaces(); ++i)
193 {
194 std::vector<unsigned int> frag_tip_face_id;
195 for (unsigned int j = 0; j < _faces.size(); ++j)
197 frag_tip_face_id.push_back(j);
198
199 if (frag_tip_face_id.size() == 2) // combine the two frag faces on this elem face
200 combine_two_faces(frag_tip_face_id[0], frag_tip_face_id[1], _host_elem->getFace(i));
201 }
202 // TODO: may need to combine other frag faces that have tip edges
203}
204
205bool
206EFAFragment3D::isFaceInterior(unsigned int face_id) const
207{
208 if (!_host_elem)
209 EFAError("in isFaceInterior() fragment must have host elem");
210
211 bool face_in_elem_face = false;
212 for (unsigned int i = 0; i < _host_elem->numFaces(); ++i)
213 if (_host_elem->getFace(i)->containsFace(_faces[face_id]))
214 {
215 face_in_elem_face = true;
216 break;
217 }
218
219 // the face is interior if it does not coincide with an element face
220 return !face_in_elem_face;
221}
222
223std::vector<unsigned int>
225{
226 std::vector<unsigned int> interior_face_id;
227 for (unsigned int i = 0; i < _faces.size(); ++i)
228 if (isFaceInterior(i))
229 interior_face_id.push_back(i);
230
231 return interior_face_id;
232}
233
234bool
235EFAFragment3D::isThirdInteriorFace(unsigned int face_id) const
236{
237 if (!_host_elem)
238 EFAError("in isThirdInteriorFace fragment must have host elem");
239
240 for (unsigned int i = 0; i < _host_elem->numInteriorNodes(); ++i)
242 return true;
243
244 return false;
245}
246
247unsigned int
249{
250 return _faces.size();
251}
252
253EFAFace *
254EFAFragment3D::getFace(unsigned int face_id) const
255{
256 if (face_id > _faces.size() - 1)
257 EFAError("in EFAfragment3D::get_face, index out of bounds");
258 return _faces[face_id];
259}
260
261unsigned int
263{
264 for (unsigned int i = 0; i < _faces.size(); ++i)
265 if (_faces[i] == face)
266 return i;
267 EFAError("face not found in get_face_id()");
268}
269
270void
272{
273 _faces.push_back(new_face);
274}
275
276std::set<EFANode *>
277EFAFragment3D::getFaceNodes(unsigned int face_id) const
278{
279 std::set<EFANode *> face_nodes;
280 for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i)
281 face_nodes.insert(_faces[face_id]->getNode(i));
282 return face_nodes;
283}
284
287{
288 return _host_elem;
289}
290
291std::vector<EFAFragment3D *>
293{
294 // This method will split one existing fragment into one or two new fragments
295 std::vector<EFAFragment3D *> new_fragments;
296 std::vector<std::vector<EFAFace *>> all_subfaces;
297 for (unsigned int i = 0; i < _faces.size(); ++i)
298 {
299 std::vector<EFAFace *> subfaces = _faces[i]->split();
300 all_subfaces.push_back(subfaces);
301 }
302
303 // build new frags
304 if (hasFaceWithOneCut()) // "fakely" cut fragment
305 {
306 EFAFragment3D * new_frag = new EFAFragment3D(_host_elem, false, nullptr);
307 for (unsigned int i = 0; i < all_subfaces.size(); ++i)
308 for (unsigned int j = 0; j < all_subfaces[i].size(); ++j)
309 new_frag->addFace(all_subfaces[i][j]);
310 new_frag->findFacesAdjacentToFaces();
311 new_fragments.push_back(new_frag);
312 }
313 else // thoroughly cut fragment
314 {
315 // find the first face with 2 sub-faces
316 EFAFace * start_face1 = nullptr;
317 EFAFace * start_face2 = nullptr;
318 unsigned int startOldFaceID = 0;
319 for (unsigned int i = 0; i < _faces.size(); ++i)
320 {
321 if (all_subfaces[i].size() == 2)
322 {
323 start_face1 = all_subfaces[i][0];
324 start_face2 = all_subfaces[i][1];
325 startOldFaceID = i;
326 break;
327 }
328 } // i
329 EFAFragment3D * new_frag1 = connectSubfaces(start_face1, startOldFaceID, all_subfaces);
330 EFAFragment3D * new_frag2 = connectSubfaces(start_face2, startOldFaceID, all_subfaces);
331 new_fragments.push_back(new_frag1);
332 new_fragments.push_back(new_frag2);
333 }
334 return new_fragments;
335}
336
337void
339{
341 for (unsigned int i = 0; i < _faces.size(); ++i)
342 {
343 std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr);
344 for (unsigned int j = 0; j < _faces.size(); ++j)
345 if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j]))
346 {
347 unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]);
348 face_adjacents[adj_edge] = _faces[j];
349 }
350
351 _faces_adjacent_to_faces.push_back(face_adjacents);
352 } // i
353}
354
355EFAFace *
356EFAFragment3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
357{
358 return _faces_adjacent_to_faces[face_id][edge_id]; // possibly NULL
359}
360
361void
363{
364 for (unsigned int i = 0; i < _faces.size(); ++i)
365 _faces[i]->removeEmbeddedNode(emb_node);
366}
367
368bool
370{
371 // N.B. this method can only be implemented when the fragment has just been marked
372 for (unsigned int i = 0; i < _faces.size(); ++i)
373 if (_faces[i]->getNumCuts() == 1)
374 return true;
375 return false;
376}
377
378void
379EFAFragment3D::getNodeInfo(std::vector<std::vector<unsigned int>> & face_node_indices,
380 std::vector<EFANode *> & nodes) const
381{
382 // get all nodes' pointers - a vector
383 std::set<EFANode *> all_node_set = getAllNodes();
384 nodes.resize(all_node_set.size());
385 std::copy(all_node_set.begin(), all_node_set.end(), nodes.begin());
386
387 // get face connectivity
388 face_node_indices.clear();
389 for (unsigned int i = 0; i < _faces.size(); ++i)
390 {
391 std::vector<unsigned int> line_face_indices;
392 for (unsigned int j = 0; j < _faces[i]->numNodes(); ++j)
393 {
394 EFANode * node = _faces[i]->getNode(j);
395 unsigned int vec_index = std::find(nodes.begin(), nodes.end(), node) - nodes.begin();
396 line_face_indices.push_back(vec_index);
397 }
398 face_node_indices.push_back(line_face_indices);
399 }
400}
401
404 unsigned int startOldFaceID,
405 std::vector<std::vector<EFAFace *>> & subfaces)
406{
407 // this method is only called in EFAfragment3D::split()
408 std::vector<bool> contributed(subfaces.size(), false);
409 contributed[startOldFaceID] = true;
410 unsigned int num_contrib_faces = 1;
411 unsigned int old_num_contrib = 1;
412 std::vector<EFAFace *> frag_faces(1, start_face);
413
414 // collect all subfaces connected to start_face
415 do
416 {
417 old_num_contrib = num_contrib_faces;
418 for (unsigned int i = 0; i < subfaces.size(); ++i)
419 {
420 if (!contributed[i]) // old face not contributed to new fragment yet
421 {
422 bool adjacent_found = false;
423 for (unsigned int j = 0; j < subfaces[i].size(); ++j)
424 {
425 for (unsigned int k = 0; k < frag_faces.size(); ++k)
426 {
427 if (subfaces[i][j]->isAdjacent(frag_faces[k]))
428 {
429 adjacent_found = true;
430 contributed[i] = true;
431 frag_faces.push_back(subfaces[i][j]);
432 num_contrib_faces += 1;
433 break;
434 }
435 } // k
436 if (adjacent_found)
437 break;
438 } // j
439 }
440 } // i, loop over all old faces
441 } while (num_contrib_faces != old_num_contrib);
442
443 // get the cut plane face
444 std::vector<EFAEdge *> cut_plane_edges;
445 EFAFragment3D * new_frag = new EFAFragment3D(_host_elem, false, nullptr);
446 for (unsigned int i = 0; i < frag_faces.size(); ++i)
447 new_frag->addFace(frag_faces[i]);
448 new_frag->findFacesAdjacentToFaces();
449
450 for (unsigned int i = 0; i < new_frag->numFaces(); ++i)
451 {
452 EFAEdge * lone_edge = new_frag->loneEdgeOnFace(i);
453 if (lone_edge != nullptr) // valid edge
454 cut_plane_edges.push_back(new EFAEdge(*lone_edge));
455 }
456
457 EFAFace * cut_face = new EFAFace(cut_plane_edges.size());
458 for (unsigned int i = 0; i < cut_plane_edges.size(); ++i)
459 cut_face->setEdge(i, cut_plane_edges[i]);
460 cut_face->sortEdges();
461 cut_face->reverseEdges();
462 cut_face->createNodes();
463
464 // finalize the new fragment
465 new_frag->addFace(cut_face);
466 new_frag->findFacesAdjacentToFaces();
467 return new_frag;
468}
469
470EFAEdge *
471EFAFragment3D::loneEdgeOnFace(unsigned int face_id) const
472{
473 // if any face edge is not shared by any other face, we call it a lone edge
474 for (unsigned int i = 0; i < _faces[face_id]->numEdges(); ++i)
475 if (_faces_adjacent_to_faces[face_id][i] == nullptr)
476 return _faces[face_id]->getEdge(i);
477 return nullptr;
478}
479
480void
482 unsigned int face_id2,
483 const EFAFace * elem_face)
484{
485 // get the new full face
486 EFAFace * full_face = _faces[face_id1]->combineWithFace(_faces[face_id2]);
487 full_face->resetEdgeIntersection(elem_face); // IMPORTANT
488
489 // take care of the common adjacent faces (combine their tip edges)
490 std::set<EFAFace *> face1_neigh;
491 face1_neigh.insert(_faces_adjacent_to_faces[face_id1].begin(),
492 _faces_adjacent_to_faces[face_id1].end());
493 std::set<EFAFace *> face2_neigh;
494 face2_neigh.insert(_faces_adjacent_to_faces[face_id2].begin(),
495 _faces_adjacent_to_faces[face_id2].end());
496 std::vector<EFAFace *> common_adjacent_faces = Efa::getCommonElems(face1_neigh, face2_neigh);
497
498 for (unsigned int i = 0; i < common_adjacent_faces.size(); ++i)
499 {
500 EFAFace * comm_face = common_adjacent_faces[i];
501 if (comm_face != nullptr)
502 {
503 unsigned int edge_id1 = comm_face->adjacentCommonEdge(_faces[face_id1]);
504 unsigned int edge_id2 = comm_face->adjacentCommonEdge(_faces[face_id2]);
505 comm_face->combineTwoEdges(edge_id1, edge_id2);
506 comm_face->resetEdgeIntersection(elem_face); // IMPORTANT
507 }
508 }
509
510 // delete old faces and update private members of EFAfragment3D
511 delete _faces[face_id1];
512 delete _faces[face_id2];
513 _faces[face_id1] = full_face;
514 _faces.erase(_faces.begin() + face_id2);
515 findFacesAdjacentToFaces(); // rebuild _adjacent_face_ix: IMPORTANT
516}
void mooseError(Args &&... args)
virtual unsigned int numInteriorNodes() const
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
unsigned int numFaces() const
virtual unsigned int numFragments() const
EFAFragment3D * getFragment(unsigned int frag_id) const
void removeEmbeddedNode(EFANode *emb_node, bool remove_for_neighbor)
EFAFace * getFace(unsigned int face_id) const
EFAVolumeNode * getInteriorNode(unsigned int interior_node_id) const
void sortEdges()
Definition EFAFace.C:317
void resetEdgeIntersection(const EFAFace *ref_face)
Definition EFAFace.C:513
EFAFace * combineWithFace(const EFAFace *other_face) const
Definition EFAFace.C:449
void createNodes()
Definition EFAFace.C:242
unsigned int adjacentCommonEdge(const EFAFace *other_face) const
Definition EFAFace.C:603
bool containsFace(const EFAFace *other_face) const
Definition EFAFace.C:376
void setEdge(unsigned int edge_id, EFAEdge *new_edge)
Definition EFAFace.C:254
void reverseEdges()
Definition EFAFace.C:337
void combineTwoEdges(unsigned int edge_id1, unsigned int edge_id2)
Definition EFAFace.C:276
virtual void removeInvalidEmbeddedNodes(std::map< unsigned int, EFANode * > &EmbeddedNodes)
std::vector< EFAFace * > _faces
virtual unsigned int getNumCuts() const
bool isFaceInterior(unsigned int face_id) const
virtual bool containsNode(EFANode *node) const
EFAEdge * loneEdgeOnFace(unsigned int face_id) const
unsigned int numFaces() const
void getNodeInfo(std::vector< std::vector< unsigned int > > &face_node_indices, std::vector< EFANode * > &nodes) const
virtual std::set< EFANode * > getAllNodes() const
EFAElement3D * getHostElement() const
void addFace(EFAFace *new_face)
EFAFragment3D(EFAElement3D *host, bool create_faces, const EFAElement3D *from_host, unsigned int frag_id=std::numeric_limits< unsigned int >::max())
bool hasFaceWithOneCut() const
void combine_two_faces(unsigned int face_id1, unsigned int face_id2, const EFAFace *elem_face)
EFAElement3D * _host_elem
bool isThirdInteriorFace(unsigned int face_id) const
unsigned int getFaceID(EFAFace *face) const
void removeEmbeddedNode(EFANode *emb_node)
EFAFragment3D * connectSubfaces(EFAFace *start_face, unsigned int startOldFaceID, std::vector< std::vector< EFAFace * > > &subfaces)
virtual void switchNode(EFANode *new_node, EFANode *old_node)
std::vector< std::vector< EFAFace * > > _faces_adjacent_to_faces
EFAFace * getFace(unsigned int face_id) const
virtual bool isConnected(EFAFragment *other_fragment) const
virtual unsigned int getNumCutNodes() const
EFAFace * getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
void findFacesAdjacentToFaces()
std::vector< unsigned int > get_interior_face_id() const
std::set< EFANode * > getFaceNodes(unsigned int face_id) const
std::vector< EFAFragment3D * > split()
void combine_tip_faces()
virtual bool isEdgeConnected(EFAFragment *other_fragment) const
EFANode * getNode()
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