libMesh
mesh_refinement_smoothing.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/libmesh_config.h"
22 
23 // only compile these functions if the user requests AMR support
24 #ifdef LIBMESH_ENABLE_AMR
25 
26 #include "libmesh/elem.h"
27 #include "libmesh/mesh_base.h"
28 #include "libmesh/mesh_refinement.h"
29 #include "libmesh/parallel.h"
30 #include "libmesh/remote_elem.h"
31 
32 namespace libMesh
33 {
34 
35 
36 
37 //-----------------------------------------------------------------
38 // Mesh refinement methods
39 bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch)
40 {
41  // This function must be run on all processors at once
42  parallel_object_only();
43 
44  bool flags_changed = false;
45 
46 
47  // Vector holding the maximum element level that touches a node.
48  std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0);
49  std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0);
50 
51  // Loop over all the active elements & fill the vector
52  for (auto & elem : _mesh.active_element_ptr_range())
53  {
54  const unsigned char elem_level =
55  cast_int<unsigned char>(elem->level() +
56  ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
57  const unsigned char elem_p_level =
58  cast_int<unsigned char>(elem->p_level() +
59  ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
60 
61  // Set the max_level at each node
62  for (const Node & node : elem->node_ref_range())
63  {
64  const dof_id_type node_number = node.id();
65 
66  libmesh_assert_less (node_number, max_level_at_node.size());
67 
68  max_level_at_node[node_number] =
69  std::max (max_level_at_node[node_number], elem_level);
70  max_p_level_at_node[node_number] =
71  std::max (max_p_level_at_node[node_number], elem_p_level);
72  }
73  }
74 
75 
76  // Now loop over the active elements and flag the elements
77  // who violate the requested level mismatch. Alternatively, if
78  // _enforce_mismatch_limit_prior_to_refinement is true, swap refinement flags
79  // accordingly.
80  for (auto & elem : _mesh.active_element_ptr_range())
81  {
82  const unsigned int elem_level = elem->level();
83  const unsigned int elem_p_level = elem->p_level();
84 
85  // Skip the element if it is already fully flagged
86  // unless we are enforcing mismatch prior to refinement and may need to
87  // remove the refinement flag(s)
88  if (elem->refinement_flag() == Elem::REFINE &&
89  elem->p_refinement_flag() == Elem::REFINE
91  continue;
92 
93  // Loop over the nodes, check for possible mismatch
94  for (const Node & node : elem->node_ref_range())
95  {
96  const dof_id_type node_number = node.id();
97 
98  // Flag the element for refinement if it violates
99  // the requested level mismatch
100  if ((elem_level + max_mismatch) < max_level_at_node[node_number]
101  && elem->refinement_flag() != Elem::REFINE)
102  {
103  elem->set_refinement_flag (Elem::REFINE);
104  flags_changed = true;
105  }
106  if ((elem_p_level + max_mismatch) < max_p_level_at_node[node_number]
107  && elem->p_refinement_flag() != Elem::REFINE)
108  {
109  elem->set_p_refinement_flag (Elem::REFINE);
110  flags_changed = true;
111  }
112 
113  // Possibly enforce limit mismatch prior to refinement
114  flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, POINT, max_mismatch);
115  }
116  }
117 
118  // If flags changed on any processor then they changed globally
119  this->comm().max(flags_changed);
120 
121  return flags_changed;
122 }
123 
124 
125 
126 bool MeshRefinement::limit_level_mismatch_at_edge (const unsigned int max_mismatch)
127 {
128  // This function must be run on all processors at once
129  parallel_object_only();
130 
131  bool flags_changed = false;
132 
133 
134  // Maps holding the maximum element level that touches an edge
135  std::map<std::pair<unsigned int, unsigned int>, unsigned char>
136  max_level_at_edge;
137  std::map<std::pair<unsigned int, unsigned int>, unsigned char>
138  max_p_level_at_edge;
139 
140  // Loop over all the active elements & fill the maps
141  for (auto & elem : _mesh.active_element_ptr_range())
142  {
143  const unsigned char elem_level =
144  cast_int<unsigned char>(elem->level() +
145  ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
146  const unsigned char elem_p_level =
147  cast_int<unsigned char>(elem->p_level() +
148  ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
149 
150  // Set the max_level at each edge
151  for (auto n : elem->edge_index_range())
152  {
153  std::unique_ptr<const Elem> edge = elem->build_edge_ptr(n);
154  dof_id_type childnode0 = edge->node_id(0);
155  dof_id_type childnode1 = edge->node_id(1);
156  if (childnode1 < childnode0)
157  std::swap(childnode0, childnode1);
158 
159  for (const Elem * p = elem; p != nullptr; p = p->parent())
160  {
161  std::unique_ptr<const Elem> pedge = p->build_edge_ptr(n);
162  dof_id_type node0 = pedge->node_id(0);
163  dof_id_type node1 = pedge->node_id(1);
164 
165  if (node1 < node0)
166  std::swap(node0, node1);
167 
168  // If elem does not share this edge with its ancestor
169  // p, refinement levels of elements sharing p's edge
170  // are not restricted by refinement levels of elem.
171  // Furthermore, elem will not share this edge with any
172  // of p's ancestors, so we can safely break out of the
173  // for loop early.
174  if (node0 != childnode0 && node1 != childnode1)
175  break;
176 
177  childnode0 = node0;
178  childnode1 = node1;
179 
180  std::pair<unsigned int, unsigned int> edge_key =
181  std::make_pair(node0, node1);
182 
183  if (max_level_at_edge.find(edge_key) ==
184  max_level_at_edge.end())
185  {
186  max_level_at_edge[edge_key] = elem_level;
187  max_p_level_at_edge[edge_key] = elem_p_level;
188  }
189  else
190  {
191  max_level_at_edge[edge_key] =
192  std::max (max_level_at_edge[edge_key], elem_level);
193  max_p_level_at_edge[edge_key] =
194  std::max (max_p_level_at_edge[edge_key], elem_p_level);
195  }
196  }
197  }
198  }
199 
200 
201  // Now loop over the active elements and flag the elements
202  // who violate the requested level mismatch
203  for (auto & elem : _mesh.active_element_ptr_range())
204  {
205  const unsigned int elem_level = elem->level();
206  const unsigned int elem_p_level = elem->p_level();
207 
208  // Skip the element if it is already fully flagged
209  if (elem->refinement_flag() == Elem::REFINE &&
210  elem->p_refinement_flag() == Elem::REFINE
212  continue;
213 
214  // Loop over the nodes, check for possible mismatch
215  for (auto n : elem->edge_index_range())
216  {
217  std::unique_ptr<Elem> edge = elem->build_edge_ptr(n);
218  dof_id_type node0 = edge->node_id(0);
219  dof_id_type node1 = edge->node_id(1);
220  if (node1 < node0)
221  std::swap(node0, node1);
222 
223  std::pair<dof_id_type, dof_id_type> edge_key =
224  std::make_pair(node0, node1);
225 
226  // Flag the element for refinement if it violates
227  // the requested level mismatch
228  if ((elem_level + max_mismatch) < max_level_at_edge[edge_key]
229  && elem->refinement_flag() != Elem::REFINE)
230  {
231  elem->set_refinement_flag (Elem::REFINE);
232  flags_changed = true;
233  }
234 
235  if ((elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key]
236  && elem->p_refinement_flag() != Elem::REFINE)
237  {
238  elem->set_p_refinement_flag (Elem::REFINE);
239  flags_changed = true;
240  }
241 
242  // Possibly enforce limit mismatch prior to refinement
243  flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, EDGE, max_mismatch);
244  } // loop over edges
245  } // loop over active elements
246 
247  // If flags changed on any processor then they changed globally
248  this->comm().max(flags_changed);
249 
250  return flags_changed;
251 }
252 
253 
254 
255 bool MeshRefinement::limit_overrefined_boundary(const signed char max_mismatch)
256 {
257  // This function must be run on all processors at once
258  parallel_object_only();
259 
260  bool flags_changed = false;
261 
262  // Loop over all the active elements & look for mismatches to fix.
263  for (auto & elem : _mesh.active_element_ptr_range())
264  {
265  // If we don't have an interior_parent then there's nothing to
266  // be mismatched with.
267  if ((elem->dim() >= LIBMESH_DIM) ||
268  !elem->interior_parent())
269  continue;
270 
271  const unsigned char elem_level =
272  cast_int<unsigned char>(elem->level() +
273  ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
274  const unsigned char elem_p_level =
275  cast_int<unsigned char>(elem->p_level() +
276  ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
277 
278  // get all relevant interior elements
279  std::set<Elem *> neighbor_set;
280  elem->find_interior_neighbors(neighbor_set);
281 
282  for (auto & neighbor : neighbor_set)
283  if (max_mismatch >= 0)
284  {
285  if ((elem_level > neighbor->level() + max_mismatch) &&
286  (neighbor->refinement_flag() != Elem::REFINE))
287  {
288  neighbor->set_refinement_flag(Elem::REFINE);
289  flags_changed = true;
290  }
291 
292  if ((elem_p_level > neighbor->p_level() + max_mismatch) &&
293  (neighbor->p_refinement_flag() != Elem::REFINE))
294  {
295  neighbor->set_p_refinement_flag(Elem::REFINE);
296  flags_changed = true;
297  }
298  }
299  }
300 
301  // If flags changed on any processor then they changed globally
302  this->comm().max(flags_changed);
303 
304  return flags_changed;
305 }
306 
307 
308 
309 bool MeshRefinement::limit_underrefined_boundary(const signed char max_mismatch)
310 {
311  // This function must be run on all processors at once
312  parallel_object_only();
313 
314  bool flags_changed = false;
315 
316  // Loop over all the active elements & look for mismatches to fix.
317  for (auto & elem : _mesh.active_element_ptr_range())
318  {
319  // If we don't have an interior_parent then there's nothing to
320  // be mismatched with.
321  if ((elem->dim() >= LIBMESH_DIM) ||
322  !elem->interior_parent())
323  continue;
324 
325  // get all relevant interior elements
326  std::set<const Elem *> neighbor_set;
327  elem->find_interior_neighbors(neighbor_set);
328 
329  for (const Elem * neighbor : neighbor_set)
330  {
331  const unsigned char neighbor_level =
332  cast_int<unsigned char>(neighbor->level() +
333  ((neighbor->refinement_flag() == Elem::REFINE) ? 1 : 0));
334 
335  const unsigned char neighbor_p_level =
336  cast_int<unsigned char>(neighbor->p_level() +
337  ((neighbor->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
338 
339  if (max_mismatch >= 0)
340  {
341  if ((neighbor_level >
342  elem->level() + max_mismatch) &&
343  (elem->refinement_flag() != Elem::REFINE))
344  {
345  elem->set_refinement_flag(Elem::REFINE);
346  flags_changed = true;
347  }
348 
349  if ((neighbor_p_level >
350  elem->p_level() + max_mismatch) &&
351  (elem->p_refinement_flag() != Elem::REFINE))
352  {
353  elem->set_p_refinement_flag(Elem::REFINE);
354  flags_changed = true;
355  }
356  }
357  } // loop over interior neighbors
358  }
359 
360  // If flags changed on any processor then they changed globally
361  this->comm().max(flags_changed);
362 
363  return flags_changed;
364 }
365 
366 
367 
369 {
370  // This function must be run on all processors at once
371  parallel_object_only();
372 
373  bool flags_changed = false;
374 
375  // Note: we *cannot* use a reference to the real pointer here, since
376  // the pointer may be reseated below and we don't want to reseat
377  // pointers held by the Mesh.
378  for (Elem * elem : _mesh.active_element_ptr_range())
379  {
380  // First, see if there's any possibility we might have to flag
381  // this element for h and p refinement - do we have any visible
382  // neighbors? Next we'll check to see if any of those neighbors
383  // are as coarse or coarser than us.
384  bool h_flag_me = false,
385  p_flag_me = false;
386  for (auto neighbor : elem->neighbor_ptr_range())
387  {
388  // Quit if the element is not a local boundary
389  if (neighbor != nullptr && neighbor != remote_elem)
390  {
391  h_flag_me = true;
392  p_flag_me = true;
393  break;
394  }
395  }
396 
397  // Skip the element if it is already fully flagged for refinement
398  if (elem->p_refinement_flag() == Elem::REFINE)
399  p_flag_me = false;
400  if (elem->refinement_flag() == Elem::REFINE)
401  {
402  h_flag_me = false;
403  if (!p_flag_me)
404  continue;
405  }
406  // Test the parent if that is already flagged for coarsening
407  else if (elem->refinement_flag() == Elem::COARSEN)
408  {
409  libmesh_assert(elem->parent());
410  elem = elem->parent();
411  // FIXME - this doesn't seem right - RHS
412  if (elem->refinement_flag() != Elem::COARSEN_INACTIVE)
413  continue;
414  p_flag_me = false;
415  }
416 
417  const unsigned int my_level = elem->level();
418  int my_p_adjustment = 0;
419  if (elem->p_refinement_flag() == Elem::REFINE)
420  my_p_adjustment = 1;
421  else if (elem->p_refinement_flag() == Elem::COARSEN)
422  {
423  libmesh_assert_greater (elem->p_level(), 0);
424  my_p_adjustment = -1;
425  }
426  const unsigned int my_new_p_level = elem->p_level() +
427  my_p_adjustment;
428 
429  // Check all the element neighbors
430  for (auto neighbor : elem->neighbor_ptr_range())
431  {
432  // Quit if the element is on a local boundary
433  if (neighbor == nullptr || neighbor == remote_elem)
434  {
435  h_flag_me = false;
436  p_flag_me = false;
437  break;
438  }
439  // if the neighbor will be equally or less refined than
440  // we are, then we will not become an unrefined island.
441  // So if we are still considering h refinement:
442  if (h_flag_me &&
443  // If our neighbor is already at a lower level,
444  // it can't end up at a higher level even if it
445  // is flagged for refinement once
446  ((neighbor->level() < my_level) ||
447  // If our neighbor is at the same level but isn't
448  // flagged for refinement, it won't end up at a
449  // higher level
450  ((neighbor->active()) &&
451  (neighbor->refinement_flag() != Elem::REFINE)) ||
452  // If our neighbor is currently more refined but is
453  // a parent flagged for coarsening, it will end up
454  // at the same level.
455  (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE)))
456  {
457  // We've proven we won't become an unrefined island,
458  // so don't h refine to avoid that.
459  h_flag_me = false;
460 
461  // If we've also proven we don't need to p refine,
462  // we don't need to check more neighbors
463  if (!p_flag_me)
464  break;
465  }
466  if (p_flag_me)
467  {
468  // if active neighbors will have a p level
469  // equal to or lower than ours, then we do not need to p
470  // refine ourselves.
471  if (neighbor->active())
472  {
473  int p_adjustment = 0;
474  if (neighbor->p_refinement_flag() == Elem::REFINE)
475  p_adjustment = 1;
476  else if (neighbor->p_refinement_flag() == Elem::COARSEN)
477  {
478  libmesh_assert_greater (neighbor->p_level(), 0);
479  p_adjustment = -1;
480  }
481  if (my_new_p_level >= neighbor->p_level() + p_adjustment)
482  {
483  p_flag_me = false;
484  if (!h_flag_me)
485  break;
486  }
487  }
488  // If we have inactive neighbors, we need to
489  // test all their active descendants which neighbor us
490  else if (neighbor->ancestor())
491  {
492  if (neighbor->min_new_p_level_by_neighbor(elem,
493  my_new_p_level + 2) <= my_new_p_level)
494  {
495  p_flag_me = false;
496  if (!h_flag_me)
497  break;
498  }
499  }
500  }
501  }
502 
503  if (h_flag_me)
504  {
505  // Parents that would create islands should no longer
506  // coarsen
507  if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
508  {
509  for (auto & child : elem->child_ref_range())
510  {
511  libmesh_assert_equal_to (child.refinement_flag(),
512  Elem::COARSEN);
513  child.set_refinement_flag(Elem::DO_NOTHING);
514  }
515  elem->set_refinement_flag(Elem::INACTIVE);
516  }
517  else
518  elem->set_refinement_flag(Elem::REFINE);
519  flags_changed = true;
520  }
521  if (p_flag_me)
522  {
523  if (elem->p_refinement_flag() == Elem::COARSEN)
524  elem->set_p_refinement_flag(Elem::DO_NOTHING);
525  else
526  elem->set_p_refinement_flag(Elem::REFINE);
527  flags_changed = true;
528  }
529  }
530 
531  // If flags changed on any processor then they changed globally
532  this->comm().max(flags_changed);
533 
534  return flags_changed;
535 }
536 
537 
538 
540  NeighborType nt,
541  unsigned max_mismatch)
542 {
543  // Eventual return value
544  bool flags_changed = false;
545 
546  // If we are enforcing the limit prior to refinement then we
547  // need to remove flags from any elements marked for refinement that
548  // would cause a mismatch
550  && elem->refinement_flag() == Elem::REFINE)
551  {
552  // get all the relevant neighbors since we may have to refine
553  // elements off edges or corners as well
554  std::set<const Elem *> neighbor_set;
555 
556  if (nt == POINT)
557  elem->find_point_neighbors(neighbor_set);
558  else if (nt == EDGE)
559  elem->find_edge_neighbors(neighbor_set);
560  else
561  libmesh_error_msg("Unrecognized NeighborType: " << nt);
562 
563  // Loop over the neighbors of element e
564  for (const auto & neighbor : neighbor_set)
565  {
566  if ((elem->level() + 1 - max_mismatch) > neighbor->level())
567  {
569  flags_changed = true;
570  }
571  if ((elem->p_level() + 1 - max_mismatch) > neighbor->p_level())
572  {
574  flags_changed = true;
575  }
576  } // loop over edge/point neighbors
577  } // if _enforce_mismatch_limit_prior_to_refinement
578 
579  return flags_changed;
580 }
581 
582 } // namespace libMesh
583 
584 
585 #endif
libMesh::MeshRefinement::NeighborType
NeighborType
This helper function enforces the desired mismatch limits prior to refinement.
Definition: mesh_refinement.h:858
libMesh::Elem::find_point_neighbors
void find_point_neighbors(const Point &p, std::set< const Elem * > &neighbor_set) const
This function finds all active elements (including this one) which are in the same manifold as this e...
Definition: elem.C:560
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::MeshRefinement::_mesh
MeshBase & _mesh
Reference to the mesh.
Definition: mesh_refinement.h:745
libMesh::Elem::set_p_refinement_flag
void set_p_refinement_flag(const RefinementState pflag)
Sets the value of the p-refinement flag for the element.
Definition: elem.h:2638
libMesh::MeshRefinement::eliminate_unrefined_patches
bool eliminate_unrefined_patches()
This algorithm selects an element for refinement if all of its neighbors are (or will be) refined.
Definition: mesh_refinement_smoothing.C:368
libMesh::Elem::find_edge_neighbors
void find_edge_neighbors(const Point &p1, const Point &p2, std::set< const Elem * > &neighbor_set) const
This function finds all active elements in the same manifold as this element which touch the current ...
Definition: elem.C:646
libMesh::Elem::level
unsigned int level() const
Definition: elem.h:2478
libMesh::Elem::COARSEN
Definition: elem.h:1169
libMesh::MeshBase::active_element_ptr_range
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::Elem::COARSEN_INACTIVE
Definition: elem.h:1175
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::Elem::p_level
unsigned int p_level() const
Definition: elem.h:2512
libMesh::MeshRefinement::limit_overrefined_boundary
bool limit_overrefined_boundary(const signed char max_mismatch)
Definition: mesh_refinement_smoothing.C:255
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::MeshRefinement::limit_underrefined_boundary
bool limit_underrefined_boundary(const signed char max_mismatch)
Definition: mesh_refinement_smoothing.C:309
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::Elem::DO_NOTHING
Definition: elem.h:1170
libMesh::MeshRefinement::enforce_mismatch_limit_prior_to_refinement
bool & enforce_mismatch_limit_prior_to_refinement()
Get/set the _enforce_mismatch_limit_prior_to_refinement flag.
Definition: mesh_refinement.h:954
libMesh::Elem::REFINE
Definition: elem.h:1171
libMesh::Elem::parent
const Elem * parent() const
Definition: elem.h:2434
libMesh::MeshBase::n_nodes
virtual dof_id_type n_nodes() const =0
libMesh::Elem::refinement_flag
RefinementState refinement_flag() const
Definition: elem.h:2614
swap
void swap(Iterator &lhs, Iterator &rhs)
swap, used to implement op=
Definition: variant_filter_iterator.h:478
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::MeshRefinement::limit_level_mismatch_at_edge
bool limit_level_mismatch_at_edge(const unsigned int max_mismatch)
Definition: mesh_refinement_smoothing.C:126
libMesh::Elem::set_refinement_flag
void set_refinement_flag(const RefinementState rflag)
Sets the value of the refinement flag for the element.
Definition: elem.h:2622
libMesh::Elem::INACTIVE
Definition: elem.h:1174
libMesh::MeshRefinement::_enforce_mismatch_limit_prior_to_refinement
bool _enforce_mismatch_limit_prior_to_refinement
This option enforces the mismatch level prior to refinement by checking if refining any element marke...
Definition: mesh_refinement.h:847
libMesh::MeshRefinement::POINT
Definition: mesh_refinement.h:858
libMesh::remote_elem
const RemoteElem * remote_elem
Definition: remote_elem.C:57
libMesh::MeshRefinement::limit_level_mismatch_at_node
bool limit_level_mismatch_at_node(const unsigned int max_mismatch)
This algorithm restricts the maximum level mismatch at any node in the mesh.
Definition: mesh_refinement_smoothing.C:39
libMesh::MeshRefinement::EDGE
Definition: mesh_refinement.h:858