www.mooseframework.org
EFAFragment3D.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "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 
58 void
59 EFAFragment3D::switchNode(EFANode * new_node, EFANode * old_node)
60 {
61  for (unsigned int i = 0; i < _faces.size(); ++i)
62  _faces[i]->switchNode(new_node, old_node);
63 }
64 
65 bool
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 
80 unsigned 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 
90 unsigned int
92 {
93  mooseError("Not implemented yet for 3D.");
94 }
95 
96 std::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 
106 bool
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 
121 bool
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 
138 void
139 EFAFragment3D::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 
186 void
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 
205 bool
206 EFAFragment3D::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 
223 std::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 
234 bool
235 EFAFragment3D::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)
241  if (_faces[face_id]->containsNode(_host_elem->getInteriorNode(i)->getNode()))
242  return true;
243 
244  return false;
245 }
246 
247 unsigned int
249 {
250  return _faces.size();
251 }
252 
253 EFAFace *
254 EFAFragment3D::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 
261 unsigned 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 
270 void
272 {
273  _faces.push_back(new_face);
274 }
275 
276 std::set<EFANode *>
277 EFAFragment3D::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 
285 EFAElement3D *
287 {
288  return _host_elem;
289 }
290 
291 std::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 
337 void
339 {
340  _faces_adjacent_to_faces.clear();
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 
355 EFAFace *
356 EFAFragment3D::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 
361 void
363 {
364  for (unsigned int i = 0; i < _faces.size(); ++i)
365  _faces[i]->removeEmbeddedNode(emb_node);
366 }
367 
368 bool
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 
378 void
379 EFAFragment3D::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 
470 EFAEdge *
471 EFAFragment3D::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 
480 void
481 EFAFragment3D::combine_two_faces(unsigned int face_id1,
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 }
EFAFragment3D * getFragment(unsigned int frag_id) const
virtual bool containsNode(EFANode *node) const
Definition: EFAFragment3D.C:66
EFAFace * getFace(unsigned int face_id) const
void removeEmbeddedNode(EFANode *emb_node)
void setEdge(unsigned int edge_id, EFAEdge *new_edge)
Definition: EFAFace.C:254
virtual unsigned int getNumCuts() const
Definition: EFAFragment3D.C:81
void findFacesAdjacentToFaces()
virtual unsigned int numInteriorNodes() const
Definition: EFAElement3D.C:425
void mooseError(Args &&... args)
EFAElement3D * getHostElement() const
std::vector< EFAFragment3D * > split()
void resetEdgeIntersection(const EFAFace *ref_face)
Definition: EFAFace.C:513
unsigned int getFaceID(EFAFace *face) const
EFAEdge * loneEdgeOnFace(unsigned int face_id) const
void combine_tip_faces()
bool deleteFromMap(std::map< unsigned int, T *> &theMap, T *elemToDelete, bool delete_elem=true)
Definition: EFAFuncs.h:22
virtual unsigned int numFragments() const
Definition: EFAElement3D.C:272
std::vector< std::vector< EFAFace * > > _faces_adjacent_to_faces
Definition: EFAFragment3D.h:32
void combineTwoEdges(unsigned int edge_id1, unsigned int edge_id2)
Definition: EFAFace.C:276
unsigned int numFaces() const
EFAFragment3D(EFAElement3D *host, bool create_faces, const EFAElement3D *from_host, unsigned int frag_id=std::numeric_limits< unsigned int >::max())
Definition: EFAFragment3D.C:20
bool isFaceInterior(unsigned int face_id) const
void getNodeInfo(std::vector< std::vector< unsigned int >> &face_node_indices, std::vector< EFANode *> &nodes) const
bool containsFace(const EFAFace *other_face) const
Definition: EFAFace.C:376
EFAFragment3D * connectSubfaces(EFAFace *start_face, unsigned int startOldFaceID, std::vector< std::vector< EFAFace *>> &subfaces)
EFAFace * getFace(unsigned int face_id) const
void sortEdges()
Definition: EFAFace.C:317
virtual bool isConnected(EFAFragment *other_fragment) const
EFAElement3D * _host_elem
Definition: EFAFragment3D.h:30
EFAFace * getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
virtual unsigned int getNumCutNodes() const
Definition: EFAFragment3D.C:91
bool isThirdInteriorFace(unsigned int face_id) const
virtual bool isEdgeConnected(EFAFragment *other_fragment) const
EFANode * getNode()
Definition: EFAVolumeNode.C:31
void removeEmbeddedNode(EFANode *emb_node, bool remove_for_neighbor)
void addFace(EFAFace *new_face)
bool hasFaceWithOneCut() const
std::vector< unsigned int > get_interior_face_id() const
std::vector< T > getCommonElems(std::set< T > &v1, std::set< T > &v2)
Definition: EFAFuncs.h:69
virtual void removeInvalidEmbeddedNodes(std::map< unsigned int, EFANode *> &EmbeddedNodes)
void reverseEdges()
Definition: EFAFace.C:337
std::set< EFANode * > getFaceNodes(unsigned int face_id) const
void createNodes()
Definition: EFAFace.C:242
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
unsigned int adjacentCommonEdge(const EFAFace *other_face) const
Definition: EFAFace.C:603
void combine_two_faces(unsigned int face_id1, unsigned int face_id2, const EFAFace *elem_face)
EFAFace * getFragmentFace(unsigned int frag_id, unsigned int face_id) const
virtual void switchNode(EFANode *new_node, EFANode *old_node)
Definition: EFAFragment3D.C:59
std::vector< EFAFace * > _faces
Definition: EFAFragment3D.h:31
static const std::string k
Definition: NS.h:124
EFAVolumeNode * getInteriorNode(unsigned int interior_node_id) const
unsigned int numFaces() const
virtual std::set< EFANode * > getAllNodes() const
Definition: EFAFragment3D.C:97