libMesh
Loading...
Searching...
No Matches
mesh_refinement_smoothing.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
32namespace libMesh
33{
34
35
36
37//-----------------------------------------------------------------
38// Mesh refinement methods
39bool 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
126bool 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 std::unique_ptr<const Elem> edge, pedge;
141 // Loop over all the active elements & fill the maps
142 for (auto & elem : _mesh.active_element_ptr_range())
143 {
144 const unsigned char elem_level =
145 cast_int<unsigned char>(elem->level() +
146 ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
147 const unsigned char elem_p_level =
148 cast_int<unsigned char>(elem->p_level() +
149 ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
150
151 // Set the max_level at each edge
152 for (auto n : elem->edge_index_range())
153 {
154 elem->build_edge_ptr(edge, n);
155 dof_id_type childnode0 = edge->node_id(0);
156 dof_id_type childnode1 = edge->node_id(1);
157 if (childnode1 < childnode0)
158 std::swap(childnode0, childnode1);
159
160 for (const Elem * p = elem; p != nullptr; p = p->parent())
161 {
162 p->build_edge_ptr(pedge, n);
163 dof_id_type node0 = pedge->node_id(0);
164 dof_id_type node1 = pedge->node_id(1);
165
166 if (node1 < node0)
167 std::swap(node0, node1);
168
169 // If elem does not share this edge with its ancestor
170 // p, refinement levels of elements sharing p's edge
171 // are not restricted by refinement levels of elem.
172 // Furthermore, elem will not share this edge with any
173 // of p's ancestors, so we can safely break out of the
174 // for loop early.
175 if (node0 != childnode0 && node1 != childnode1)
176 break;
177
178 childnode0 = node0;
179 childnode1 = node1;
180
181 std::pair<unsigned int, unsigned int> edge_key =
182 std::make_pair(node0, node1);
183
184 // Try emplacing (edge_key, elem_level) into max_level_at_edge map.
185 // If emplacing fails, it means the edge_key already existed, so
186 // we need to take the max of the previous and current values.
187 if (auto [it, emplaced] = max_level_at_edge.emplace(edge_key, elem_level);
188 !emplaced)
189 it->second = std::max(it->second, elem_level);
190
191 // Same thing for p_level
192 if (auto [it, emplaced] = max_p_level_at_edge.emplace(edge_key, elem_p_level);
193 !emplaced)
194 it->second = std::max(it->second, elem_p_level);
195 }
196 }
197 }
198
199
200 // Now loop over the active elements and flag the elements
201 // who violate the requested level mismatch
202 for (auto & elem : _mesh.active_element_ptr_range())
203 {
204 const unsigned int elem_level = elem->level();
205 const unsigned int elem_p_level = elem->p_level();
206
207 // Skip the element if it is already fully flagged
208 if (elem->refinement_flag() == Elem::REFINE &&
209 elem->p_refinement_flag() == Elem::REFINE
211 continue;
212
213 // Loop over the nodes, check for possible mismatch
214 for (auto n : elem->edge_index_range())
215 {
216 elem->build_edge_ptr(edge, n);
217 dof_id_type node0 = edge->node_id(0);
218 dof_id_type node1 = edge->node_id(1);
219 if (node1 < node0)
220 std::swap(node0, node1);
221
222 std::pair<dof_id_type, dof_id_type> edge_key =
223 std::make_pair(node0, node1);
224
225 // Flag the element for refinement if it violates
226 // the requested level mismatch
227 if ((elem_level + max_mismatch) < max_level_at_edge[edge_key]
228 && elem->refinement_flag() != Elem::REFINE)
229 {
230 elem->set_refinement_flag (Elem::REFINE);
231 flags_changed = true;
232 }
233
234 if ((elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key]
235 && elem->p_refinement_flag() != Elem::REFINE)
236 {
237 elem->set_p_refinement_flag (Elem::REFINE);
238 flags_changed = true;
239 }
240
241 // Possibly enforce limit mismatch prior to refinement
242 flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, EDGE, max_mismatch);
243 } // loop over edges
244 } // loop over active elements
245
246 // If flags changed on any processor then they changed globally
247 this->comm().max(flags_changed);
248
249 return flags_changed;
250}
251
252
253
254bool MeshRefinement::limit_overrefined_boundary(const signed char max_mismatch)
255{
256 // This function must be run on all processors at once
257 parallel_object_only();
258
259 bool flags_changed = false;
260
261 // Loop over all the active elements & look for mismatches to fix.
262 for (auto & elem : _mesh.active_element_ptr_range())
263 {
264 // If we don't have an interior_parent then there's nothing to
265 // be mismatched with.
266 if ((elem->dim() >= LIBMESH_DIM) ||
267 !elem->interior_parent())
268 continue;
269
270 const unsigned char elem_level =
271 cast_int<unsigned char>(elem->level() +
272 ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
273 const unsigned char elem_p_level =
274 cast_int<unsigned char>(elem->p_level() +
275 ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
276
277 // get all relevant interior elements
278 std::set<Elem *> neighbor_set;
279 elem->find_interior_neighbors(neighbor_set);
280
281 for (auto & neighbor : neighbor_set)
282 if (max_mismatch >= 0)
283 {
284 if ((elem_level > neighbor->level() + max_mismatch) &&
285 (neighbor->refinement_flag() != Elem::REFINE))
286 {
287 neighbor->set_refinement_flag(Elem::REFINE);
288 flags_changed = true;
289 }
290
291 if ((elem_p_level > neighbor->p_level() + max_mismatch) &&
292 (neighbor->p_refinement_flag() != Elem::REFINE))
293 {
294 neighbor->set_p_refinement_flag(Elem::REFINE);
295 flags_changed = true;
296 }
297 }
298 }
299
300 // If flags changed on any processor then they changed globally
301 this->comm().max(flags_changed);
302
303 return flags_changed;
304}
305
306
307
308bool MeshRefinement::limit_underrefined_boundary(const signed char max_mismatch)
309{
310 // This function must be run on all processors at once
311 parallel_object_only();
312
313 bool flags_changed = false;
314
315 // Loop over all the active elements & look for mismatches to fix.
316 for (auto & elem : _mesh.active_element_ptr_range())
317 {
318 // If we don't have an interior_parent then there's nothing to
319 // be mismatched with.
320 if ((elem->dim() >= LIBMESH_DIM) ||
321 !elem->interior_parent())
322 continue;
323
324 // get all relevant interior elements
325 std::set<const Elem *> neighbor_set;
326 elem->find_interior_neighbors(neighbor_set);
327
328 for (const Elem * neighbor : neighbor_set)
329 {
330 const unsigned char neighbor_level =
331 cast_int<unsigned char>(neighbor->level() +
332 ((neighbor->refinement_flag() == Elem::REFINE) ? 1 : 0));
333
334 const unsigned char neighbor_p_level =
335 cast_int<unsigned char>(neighbor->p_level() +
336 ((neighbor->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
337
338 if (max_mismatch >= 0)
339 {
340 if ((neighbor_level >
341 elem->level() + max_mismatch) &&
342 (elem->refinement_flag() != Elem::REFINE))
343 {
344 elem->set_refinement_flag(Elem::REFINE);
345 flags_changed = true;
346 }
347
348 if ((neighbor_p_level >
349 elem->p_level() + max_mismatch) &&
350 (elem->p_refinement_flag() != Elem::REFINE))
351 {
352 elem->set_p_refinement_flag(Elem::REFINE);
353 flags_changed = true;
354 }
355 }
356 } // loop over interior neighbors
357 }
358
359 // If flags changed on any processor then they changed globally
360 this->comm().max(flags_changed);
361
362 return flags_changed;
363}
364
365
366
368{
369 // This function must be run on all processors at once
370 parallel_object_only();
371
372 bool flags_changed = false;
373
374 // Quick return: if unrefined patches are allowed, then we are not
375 // going to do anything here and can simply return that the flags
376 // haven't changed.
378 return flags_changed;
379
380 // Note: we *cannot* use a reference to the real pointer here, since
381 // the pointer may be reseated below and we don't want to reseat
382 // pointers held by the Mesh.
383 for (Elem * elem : _mesh.active_element_ptr_range())
384 {
385 // First, see if there's any possibility we might have to flag
386 // this element for h and p refinement - do we have any visible
387 // neighbors? Next we'll check to see if any of those neighbors
388 // are as coarse or coarser than us.
389 bool h_flag_me = false,
390 p_flag_me = false;
391 for (auto neighbor : elem->neighbor_ptr_range())
392 {
393 // Quit if the element is not a local boundary
394 if (neighbor != nullptr && neighbor != remote_elem)
395 {
396 h_flag_me = true;
397 p_flag_me = true;
398 break;
399 }
400 }
401
402 // Skip the element if it is already fully flagged for refinement
403 if (elem->p_refinement_flag() == Elem::REFINE)
404 p_flag_me = false;
405 if (elem->refinement_flag() == Elem::REFINE)
406 {
407 h_flag_me = false;
408 if (!p_flag_me)
409 continue;
410 }
411 // Test the parent if that is already flagged for coarsening
412 else if (elem->refinement_flag() == Elem::COARSEN)
413 {
414 libmesh_assert(elem->parent());
415 elem = elem->parent();
416 // FIXME - this doesn't seem right - RHS
417 if (elem->refinement_flag() != Elem::COARSEN_INACTIVE)
418 continue;
419 p_flag_me = false;
420 }
421
422 const unsigned int my_level = elem->level();
423 int my_p_adjustment = 0;
424 if (elem->p_refinement_flag() == Elem::REFINE)
425 my_p_adjustment = 1;
426 else if (elem->p_refinement_flag() == Elem::COARSEN)
427 {
428 libmesh_assert_greater (elem->p_level(), 0);
429 my_p_adjustment = -1;
430 }
431 const unsigned int my_new_p_level =
432 cast_int<unsigned int>(int(elem->p_level()) +
433 my_p_adjustment);
434
435 // Check all the element neighbors
436 for (auto neighbor : elem->neighbor_ptr_range())
437 {
438 // Quit if the element is on a local boundary
439 if (neighbor == nullptr || neighbor == remote_elem)
440 {
441 h_flag_me = false;
442 p_flag_me = false;
443 break;
444 }
445 // if the neighbor will be equally or less refined than
446 // we are, then we will not become an unrefined island.
447 // So if we are still considering h refinement:
448 if (h_flag_me &&
449 // If our neighbor is already at a lower level,
450 // it can't end up at a higher level even if it
451 // is flagged for refinement once
452 ((neighbor->level() < my_level) ||
453 // If our neighbor is at the same level but isn't
454 // flagged for refinement, it won't end up at a
455 // higher level
456 ((neighbor->active()) &&
457 (neighbor->refinement_flag() != Elem::REFINE)) ||
458 // If our neighbor is currently more refined but is
459 // a parent flagged for coarsening, it will end up
460 // at the same level.
461 (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE)))
462 {
463 // We've proven we won't become an unrefined island,
464 // so don't h refine to avoid that.
465 h_flag_me = false;
466
467 // If we've also proven we don't need to p refine,
468 // we don't need to check more neighbors
469 if (!p_flag_me)
470 break;
471 }
472 if (p_flag_me)
473 {
474 // if active neighbors will have a p level
475 // equal to or lower than ours, then we do not need to p
476 // refine ourselves.
477 if (neighbor->active())
478 {
479 int p_adjustment = 0;
480 if (neighbor->p_refinement_flag() == Elem::REFINE)
481 p_adjustment = 1;
482 else if (neighbor->p_refinement_flag() == Elem::COARSEN)
483 {
484 libmesh_assert_greater (neighbor->p_level(), 0);
485 p_adjustment = -1;
486 }
487 if (my_new_p_level >=
488 cast_int<unsigned int>(int(neighbor->p_level())
489 + p_adjustment))
490 {
491 p_flag_me = false;
492 if (!h_flag_me)
493 break;
494 }
495 }
496 // If we have inactive neighbors, we need to
497 // test all their active descendants which neighbor us
498 else if (neighbor->ancestor())
499 {
500 if (neighbor->min_new_p_level_by_neighbor(elem,
501 my_new_p_level + 2) <= my_new_p_level)
502 {
503 p_flag_me = false;
504 if (!h_flag_me)
505 break;
506 }
507 }
508 }
509 }
510
511 if (h_flag_me)
512 {
513 // Parents that would create islands should no longer
514 // coarsen
515 if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
516 {
517 for (auto & child : elem->child_ref_range())
518 {
519 libmesh_assert_equal_to (child.refinement_flag(),
521 child.set_refinement_flag(Elem::DO_NOTHING);
522 }
523 elem->set_refinement_flag(Elem::INACTIVE);
524 }
525 else
526 elem->set_refinement_flag(Elem::REFINE);
527 flags_changed = true;
528 }
529 if (p_flag_me)
530 {
531 if (elem->p_refinement_flag() == Elem::COARSEN)
532 elem->set_p_refinement_flag(Elem::DO_NOTHING);
533 else
534 elem->set_p_refinement_flag(Elem::REFINE);
535 flags_changed = true;
536 }
537 }
538
539 // If flags changed on any processor then they changed globally
540 this->comm().max(flags_changed);
541
542 return flags_changed;
543}
544
545
546
548 NeighborType nt,
549 unsigned max_mismatch)
550{
551 // Eventual return value
552 bool flags_changed = false;
553
554 // If we are enforcing the limit prior to refinement then we
555 // need to remove flags from any elements marked for refinement that
556 // would cause a mismatch
558 && elem->refinement_flag() == Elem::REFINE)
559 {
560 // get all the relevant neighbors since we may have to refine
561 // elements off edges or corners as well
562 std::set<const Elem *> neighbor_set;
563
564 if (nt == POINT)
565 elem->find_point_neighbors(neighbor_set);
566 else if (nt == EDGE)
567 elem->find_edge_neighbors(neighbor_set);
568 else
569 libmesh_error_msg("Unrecognized NeighborType: " << nt);
570
571 // Loop over the neighbors of element e
572 for (const auto & neighbor : neighbor_set)
573 {
574 if ((elem->level() + 1 - max_mismatch) > neighbor->level())
575 {
577 flags_changed = true;
578 }
579 if ((elem->p_level() + 1 - max_mismatch) > neighbor->p_level())
580 {
582 flags_changed = true;
583 }
584 } // loop over edge/point neighbors
585 } // if _enforce_mismatch_limit_prior_to_refinement
586
587 return flags_changed;
588}
589
590} // namespace libMesh
591
592
593#endif
void max(const T &r, T &o, Request &req) const
This is the base class from which all geometric element types are derived.
Definition elem.h:96
void set_p_refinement_flag(const RefinementState pflag)
Sets the value of the p-refinement flag for the element.
Definition elem.h:3251
RefinementState refinement_flag() const
Definition elem.h:3227
const Elem * parent() const
Definition elem.h:3047
@ COARSEN_INACTIVE
Definition elem.h:1452
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:967
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:1057
unsigned int level() const
Definition elem.h:3091
void set_refinement_flag(const RefinementState rflag)
Sets the value of the refinement flag for the element.
Definition elem.h:3235
unsigned int p_level() const
Definition elem.h:3125
virtual dof_id_type n_nodes() const =0
bool limit_underrefined_boundary(const signed char max_mismatch)
bool eliminate_unrefined_patches()
This algorithm selects an element for refinement if all of its neighbors are (or will be) refined.
bool _enforce_mismatch_limit_prior_to_refinement
This option enforces the mismatch level prior to refinement by checking if refining any element marke...
NeighborType
This helper function enforces the desired mismatch limits prior to refinement.
bool limit_overrefined_boundary(const signed char max_mismatch)
bool & enforce_mismatch_limit_prior_to_refinement()
Get/set the _enforce_mismatch_limit_prior_to_refinement flag.
bool limit_level_mismatch_at_edge(const unsigned int max_mismatch)
MeshBase & _mesh
Reference to the mesh.
bool limit_level_mismatch_at_node(const unsigned int max_mismatch)
This algorithm restricts the maximum level mismatch at any node in the mesh.
A Node is like a Point, but with more information.
Definition node.h:55
const Parallel::Communicator & comm() const
The libMesh namespace provides an interface to certain functionality in the library.
libmesh_assert(ctx)
const RemoteElem * remote_elem
Definition remote_elem.C:57
uint8_t dof_id_type
Definition id_types.h:67