https://mooseframework.inl.gov
EFAFragment2D.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 "EFAElement2D.h"
11 
12 #include "EFANode.h"
13 #include "EFAEdge.h"
14 #include "EFAFace.h"
15 #include "EFAFragment2D.h"
16 
17 #include "EFAFaceNode.h"
18 #include "EFAFuncs.h"
19 #include "EFAError.h"
20 
22  bool create_boundary_edges,
23  const EFAElement2D * from_host,
24  unsigned int frag_id)
25  : EFAFragment(), _host_elem(host)
26 {
27  if (create_boundary_edges)
28  {
29  if (!from_host)
30  EFAError("EFAfragment2D constructor must have a from_host to copy from");
31  if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself
32  {
33  for (unsigned int i = 0; i < from_host->numEdges(); ++i)
34  _boundary_edges.push_back(new EFAEdge(*from_host->getEdge(i)));
35  }
36  else
37  {
38  if (frag_id > from_host->numFragments() - 1)
39  EFAError("In EFAfragment2D constructor fragment_copy_index out of bounds");
40  for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numEdges(); ++i)
41  _boundary_edges.push_back(new EFAEdge(*from_host->getFragmentEdge(frag_id, i)));
42  }
43  }
44 }
45 
47  : EFAFragment(), _host_elem(host)
48 {
49  for (unsigned int i = 0; i < from_face->numEdges(); ++i)
50  _boundary_edges.push_back(new EFAEdge(*from_face->getEdge(i)));
51 }
52 
54 {
55  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
56  {
57  if (_boundary_edges[i])
58  {
59  delete _boundary_edges[i];
60  _boundary_edges[i] = nullptr;
61  }
62  }
63 }
64 
65 void
66 EFAFragment2D::switchNode(EFANode * new_node, EFANode * old_node)
67 {
68  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
69  _boundary_edges[i]->switchNode(new_node, old_node);
70 }
71 
72 bool
74 {
75  bool contains = false;
76  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
77  {
78  if (_boundary_edges[i]->containsNode(node))
79  {
80  contains = true;
81  break;
82  }
83  }
84  return contains;
85 }
86 
87 unsigned int
89 {
90  unsigned int num_cut_edges = 0;
91  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
92  {
93  if (_boundary_edges[i]->hasIntersection())
94  num_cut_edges += _boundary_edges[i]->numEmbeddedNodes();
95  }
96  return num_cut_edges;
97 }
98 
99 unsigned int
101 {
102  unsigned int num_cut_nodes = 0;
103  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
104  if (_boundary_edges[i]->getNode(0)->category() == EFANode::N_CATEGORY_EMBEDDED_PERMANENT)
105  num_cut_nodes++;
106  return num_cut_nodes;
107 }
108 
109 std::set<EFANode *>
111 {
112  std::set<EFANode *> nodes;
113  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
114  {
115  nodes.insert(_boundary_edges[i]->getNode(0));
116  nodes.insert(_boundary_edges[i]->getNode(1));
117  }
118  return nodes;
119 }
120 
121 bool
123 {
124  bool is_connected = false;
125  EFAFragment2D * other_frag2d = dynamic_cast<EFAFragment2D *>(other_fragment);
126  if (!other_frag2d)
127  EFAError("in isConnected other_fragment is not of type EFAfragement2D");
128 
129  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
130  {
131  for (unsigned int j = 0; j < other_frag2d->numEdges(); ++j)
132  {
133  if (_boundary_edges[i]->equivalent(*other_frag2d->getEdge(j)))
134  {
135  is_connected = true;
136  break;
137  }
138  }
139  if (is_connected)
140  break;
141  } // i
142  return is_connected;
143 }
144 
145 void
146 EFAFragment2D::removeInvalidEmbeddedNodes(std::map<unsigned int, EFANode *> & EmbeddedNodes)
147 {
148  // if a fragment only has 1 intersection which is in an interior edge
149  // remove this embedded node (MUST DO THIS AFTER combine_tip_edges())
150  if (getNumCuts() == 1)
151  {
152  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
153  {
154  if (isEdgeInterior(i) && _boundary_edges[i]->hasIntersection())
155  {
156  if (_host_elem->numInteriorNodes() != 1)
157  EFAError("host element must have 1 interior node at this point");
158  Efa::deleteFromMap(EmbeddedNodes, _boundary_edges[i]->getEmbeddedNode(0));
159  _boundary_edges[i]->removeEmbeddedNodes();
161  break;
162  }
163  } // i
164  }
165 }
166 
167 void
169 {
170  // combine the tip edges in a crack tip fragment
171  // N.B. the host elem can only have one elem_tip_edge, otherwise it should have already been
172  // completely split
173  if (!_host_elem)
174  EFAError("In combine_tip_edges() the frag must have host_elem");
175 
176  bool has_tip_edges = false;
177  unsigned int elem_tip_edge_id = std::numeric_limits<unsigned int>::max();
178  std::vector<unsigned int> frag_tip_edge_id;
179  for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
180  {
181  frag_tip_edge_id.clear();
183  {
184  for (unsigned int j = 0; j < _boundary_edges.size(); ++j)
185  {
187  frag_tip_edge_id.push_back(j);
188  } // j
189  if (frag_tip_edge_id.size() == 2) // combine the two frag edges on this elem edge
190  {
191  has_tip_edges = true;
192  elem_tip_edge_id = i;
193  break;
194  }
195  }
196  } // i
197  if (has_tip_edges)
198  {
199  // frag_tip_edge_id[0] must precede frag_tip_edge_id[1]
200  unsigned int edge0_next(frag_tip_edge_id[0] < (numEdges() - 1) ? frag_tip_edge_id[0] + 1 : 0);
201  if (edge0_next != frag_tip_edge_id[1])
202  EFAError("frag_tip_edge_id[1] must be the next edge of frag_tip_edge_id[0]");
203 
204  // get the two end nodes of the new edge
205  EFANode * node1 = _boundary_edges[frag_tip_edge_id[0]]->getNode(0);
206  EFANode * emb_node = _boundary_edges[frag_tip_edge_id[0]]->getNode(1);
207  EFANode * node2 = _boundary_edges[frag_tip_edge_id[1]]->getNode(1);
208  if (emb_node != _boundary_edges[frag_tip_edge_id[1]]->getNode(0))
209  EFAError("fragment edges are not correctly set up");
210 
211  // get the new edge with one intersection
212  EFAEdge * elem_edge = _host_elem->getEdge(elem_tip_edge_id);
213  double xi_node1 = elem_edge->distanceFromNode1(node1);
214  double xi_node2 = elem_edge->distanceFromNode1(node2);
215  double xi_emb = elem_edge->distanceFromNode1(emb_node);
216  double position = (xi_emb - xi_node1) / (xi_node2 - xi_node1);
217  EFAEdge * full_edge = new EFAEdge(node1, node2);
218  full_edge->addIntersection(position, emb_node, node1);
219 
220  // combine the two original fragment edges
221  delete _boundary_edges[frag_tip_edge_id[0]];
222  delete _boundary_edges[frag_tip_edge_id[1]];
223  _boundary_edges[frag_tip_edge_id[0]] = full_edge;
224  _boundary_edges.erase(_boundary_edges.begin() + frag_tip_edge_id[1]);
225  }
226 }
227 
228 /*
229 std::vector<EFAnode*>
230 EFAfragment::commonNodesWithEdge(EFAEdge & other_edge)
231 {
232  std::vector<EFAnode*> common_nodes;
233  for (unsigned int i = 0; i < 2; ++i)
234  {
235  EFAnode* edge_node = other_edge.node_ptr(i);
236  if (containsNode(edge_node))
237  common_nodes.push_back(edge_node);
238  }
239  return common_nodes;
240 }
241 */
242 
243 bool
244 EFAFragment2D::isEdgeInterior(unsigned int edge_id) const
245 {
246  if (!_host_elem)
247  EFAError("in isEdgeInterior fragment must have host elem");
248 
249  bool edge_in_elem_edge = false;
250 
251  for (unsigned int i = 0; i < _host_elem->numEdges(); ++i)
252  {
253  if (_host_elem->getEdge(i)->containsEdge(*_boundary_edges[edge_id]))
254  {
255  edge_in_elem_edge = true;
256  break;
257  }
258  }
259  if (!edge_in_elem_edge)
260  return true; // yes, is interior
261  else
262  return false;
263 }
264 
265 std::vector<unsigned int>
267 {
268  std::vector<unsigned int> interior_edge_id;
269  for (unsigned int i = 0; i < _boundary_edges.size(); ++i)
270  {
271  if (isEdgeInterior(i))
272  interior_edge_id.push_back(i);
273  }
274  return interior_edge_id;
275 }
276 
277 bool
278 EFAFragment2D::isSecondaryInteriorEdge(unsigned int edge_id) const
279 {
280  bool is_second_cut = false;
281  if (!_host_elem)
282  EFAError("in isSecondaryInteriorEdge fragment must have host elem");
283 
284  for (unsigned int i = 0; i < _host_elem->numInteriorNodes(); ++i)
285  {
287  {
288  is_second_cut = true;
289  break;
290  }
291  }
292  return is_second_cut;
293 }
294 
295 unsigned int
297 {
298  return _boundary_edges.size();
299 }
300 
301 EFAEdge *
302 EFAFragment2D::getEdge(unsigned int edge_id) const
303 {
304  if (edge_id > _boundary_edges.size() - 1)
305  EFAError("in EFAfragment2D::get_edge, index out of bounds");
306  return _boundary_edges[edge_id];
307 }
308 
309 void
311 {
312  _boundary_edges.push_back(new_edge);
313 }
314 
315 std::set<EFANode *>
316 EFAFragment2D::getEdgeNodes(unsigned int edge_id) const
317 {
318  std::set<EFANode *> edge_nodes;
319  edge_nodes.insert(_boundary_edges[edge_id]->getNode(0));
320  edge_nodes.insert(_boundary_edges[edge_id]->getNode(1));
321  return edge_nodes;
322 }
323 
324 EFAElement2D *
326 {
327  return _host_elem;
328 }
329 
330 std::vector<EFAFragment2D *>
332 {
333  // This method will split one existing fragment into one or two
334  // new fragments and return them.
335  // N.B. each boundary each can only have 1 cut at most
336  std::vector<EFAFragment2D *> new_fragments;
337  std::vector<std::vector<EFANode *>> fragment_nodes(
338  2); // vectors of EFA nodes in the two fragments
339  unsigned int frag_number = 0; // Index of the current fragment that we are assmbling nodes into
340  unsigned int edge_cut_count = 0;
341  unsigned int node_cut_count = 0;
342  for (unsigned int iedge = 0; iedge < _boundary_edges.size(); ++iedge)
343  {
344  fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getNode(0));
345 
346  if (_boundary_edges[iedge]->getNode(0)->category() ==
347  EFANode::N_CATEGORY_EMBEDDED_PERMANENT) // if current node has been cut change fragment
348  {
349  ++node_cut_count;
350  frag_number = 1 - frag_number; // Toggle between 0 and 1
351  fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getNode(0));
352  }
353 
354  if (_boundary_edges[iedge]->numEmbeddedNodes() > 1)
355  EFAError("A fragment boundary edge can't have more than 1 cuts");
356  if (_boundary_edges[iedge]->hasIntersection()) // if current edge is cut add cut intersection //
357  // node to both fragments and and change fragment
358  {
359  fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
360  ++edge_cut_count;
361  frag_number = 1 - frag_number; // Toggle between 0 and 1
362  fragment_nodes[frag_number].push_back(_boundary_edges[iedge]->getEmbeddedNode(0));
363  }
364  }
365 
366  if ((edge_cut_count + node_cut_count) > 1) // any two cuts case
367  {
368  for (unsigned int frag_idx = 0; frag_idx < 2; ++frag_idx) // Create 2 fragments
369  {
370  auto & this_frag_nodes = fragment_nodes[frag_idx];
371  // check to make sure an edge wasn't cut
372  if (this_frag_nodes.size() >= 3)
373  {
374  EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
375  for (unsigned int inode = 0; inode < this_frag_nodes.size() - 1; inode++)
376  new_frag->addEdge(new EFAEdge(this_frag_nodes[inode], this_frag_nodes[inode + 1]));
377 
378  new_frag->addEdge(
379  new EFAEdge(this_frag_nodes[this_frag_nodes.size() - 1], this_frag_nodes[0]));
380 
381  new_fragments.push_back(new_frag);
382  }
383  }
384  }
385  else if (edge_cut_count == 1) // single edge cut case
386  {
387  EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
388  for (unsigned int inode = 0; inode < fragment_nodes[0].size() - 1;
389  inode++) // assemble fragment part 1
390  new_frag->addEdge(new EFAEdge(fragment_nodes[0][inode], fragment_nodes[0][inode + 1]));
391 
392  for (unsigned int inode = 0; inode < fragment_nodes[1].size() - 1;
393  inode++) // assemble fragment part 2
394  new_frag->addEdge(new EFAEdge(fragment_nodes[1][inode], fragment_nodes[1][inode + 1]));
395 
396  new_frag->addEdge(
397  new EFAEdge(fragment_nodes[1][fragment_nodes[1].size() - 1], fragment_nodes[0][0]));
398 
399  new_fragments.push_back(new_frag);
400  }
401  else if (node_cut_count == 1) // single node cut case
402  {
403  EFAFragment2D * new_frag = new EFAFragment2D(_host_elem, false, nullptr);
404  for (unsigned int iedge = 0; iedge < _boundary_edges.size(); ++iedge)
405  {
406  EFANode * first_node_on_edge = _boundary_edges[iedge]->getNode(0);
407  EFANode * second_node_on_edge = _boundary_edges[iedge]->getNode(1);
408  new_frag->addEdge(new EFAEdge(first_node_on_edge, second_node_on_edge));
409  }
410 
411  new_fragments.push_back(new_frag);
412  }
413 
414  return new_fragments;
415 }
virtual unsigned int getNumCuts() const
Definition: EFAFragment2D.C:88
unsigned int numEdges() const
Definition: EFAFace.h:49
void combineTipEdges()
EFAElement2D * getHostElement() const
bool isSecondaryInteriorEdge(unsigned int edge_id) const
virtual unsigned int numInteriorNodes() const
Definition: EFAElement2D.C:358
std::set< EFANode * > getEdgeNodes(unsigned int edge_id) const
unsigned int numEdges() const
EFAEdge * getEdge(unsigned int edge_id) const
EFAFaceNode * getInteriorNode(unsigned int interior_node_id) const
void addEdge(EFAEdge *new_edge)
bool hasIntersection() const
Definition: EFAEdge.C:200
bool deleteFromMap(std::map< unsigned int, T *> &theMap, T *elemToDelete, bool delete_elem=true)
Definition: EFAFuncs.h:22
bool isEdgeInterior(unsigned int edge_id) const
std::vector< unsigned int > getInteriorEdgeID() const
std::vector< EFAFragment2D * > split()
unsigned int numEdges() const
virtual unsigned int numFragments() const
Definition: EFAElement2D.C:207
virtual std::set< EFANode * > getAllNodes() const
double distanceFromNode1(EFANode *node) const
Definition: EFAEdge.C:250
virtual unsigned int getNumCutNodes() const
virtual bool isConnected(EFAFragment *other_fragment) const
EFAFragment2D * getFragment(unsigned int frag_id) const
std::vector< EFAEdge * > _boundary_edges
Definition: EFAFragment2D.h:32
bool containsEdge(const EFAEdge &other) const
Definition: EFAEdge.C:65
EFAEdge * getEdge(unsigned int edge_id) const
Definition: EFAFace.h:50
EFANode * getNode()
Definition: EFAFaceNode.C:25
virtual void removeInvalidEmbeddedNodes(std::map< unsigned int, EFANode *> &EmbeddedNodes)
virtual void switchNode(EFANode *new_node, EFANode *old_node)
Definition: EFAFragment2D.C:66
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
void addIntersection(double position, EFANode *embedded_node_tmp, EFANode *from_node)
Definition: EFAEdge.C:132
EFAEdge * getEdge(unsigned int edge_id) const
void deleteInteriorNodes()
EFAFragment2D(EFAElement2D *host, bool create_boundary_edges, const EFAElement2D *from_host, unsigned int frag_id=std::numeric_limits< unsigned int >::max())
Definition: EFAFragment2D.C:21
EFAElement2D * _host_elem
Definition: EFAFragment2D.h:31
virtual bool containsNode(EFANode *node) const
Definition: EFAFragment2D.C:73
EFAEdge * getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const