Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
RefineSidesetGenerator.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 "RefineSidesetGenerator.h"
11 #include "MooseMeshUtils.h"
12 
13 #include "libmesh/elem.h"
14 #include "libmesh/mesh_refinement.h"
15 #include "CastUniquePointer.h"
16 
18 
21 {
23  params.addClassDescription("Mesh generator which refines one or more sidesets");
24  params.addRequiredParam<MeshGeneratorName>("input", "Input mesh to modify");
25  params.addRequiredParam<std::vector<BoundaryName>>("boundaries",
26  "The list of boundaries to be modified");
27  params.addRequiredParam<std::vector<int>>(
28  "refinement",
29  "The amount of times to refine each sideset, corresponding to their index in 'boundaries'");
30  params.addParam<bool>(
31  "enable_neighbor_refinement",
32  true,
33  "Toggles whether neighboring level one elements should be refined or not. Defaults to true. "
34  "False may lead to unsupported mesh non-conformality without great care.");
35  MultiMooseEnum boundary_side("primary secondary both", "both");
36  params.addParam<MultiMooseEnum>("boundary_side",
37  boundary_side,
38  "Whether the generator should refine itself(primary), its "
39  "neighbors(secondary), or itself and its neighbors(both)");
40 
41  return params;
42 }
43 
45  : MeshGenerator(parameters),
46  _input(getMesh("input")),
47  _boundaries(getParam<std::vector<BoundaryName>>("boundaries")),
48  _refinement(getParam<std::vector<int>>("refinement")),
49  _enable_neighbor_refinement(getParam<bool>("enable_neighbor_refinement")),
50  _boundary_side(getParam<MultiMooseEnum>("boundary_side"))
51 {
52  if (_boundaries.size() != _refinement.size())
53  paramError("refinement",
54  "The boundaries and refinement parameter vectors should be the same size");
55  if (_boundaries.size() != _boundary_side.size())
56  paramError("boundary_side",
57  "The boundaries and boundary_side parameter vectors should be the same size");
58 }
59 
60 std::unique_ptr<MeshBase>
62 {
63  // Get the list of boundary ids from the boundary names
64  const auto boundary_ids = MooseMeshUtils::getBoundaryIDs(
65  *_input, getParam<std::vector<BoundaryName>>("boundaries"), false);
66 
67  // Check that the boundary ids/names exist in the mesh
68  for (std::size_t i = 0; i < boundary_ids.size(); ++i)
69  if (boundary_ids[i] == Moose::INVALID_BOUNDARY_ID)
70  paramError("boundaries",
71  "The boundary '",
72  getParam<std::vector<BoundaryName>>("boundaries")[i],
73  "' was not found within the mesh");
74  std::unique_ptr<MeshBase> mesh = std::move(_input);
75  int max = *std::max_element(_refinement.begin(), _refinement.end());
76  return recursive_refine(boundary_ids, mesh, _refinement, max);
77 }
78 
79 std::unique_ptr<MeshBase>
80 RefineSidesetGenerator::recursive_refine(std::vector<boundary_id_type> boundary_ids,
81  std::unique_ptr<MeshBase> & mesh,
82  std::vector<int> refinement,
83  int max,
84  int ref_step)
85 {
86  // If the refinement step has reached the largest value in the _refinement array, return the mesh,
87  // as we are done.
88  if (ref_step == max)
89  return dynamic_pointer_cast<MeshBase>(mesh);
90 
91  const bool old_allow_remote_element_removal = mesh->allow_remote_element_removal();
92  if (mesh->is_serial())
93  // If our mesh is already serial then we will keep it that way to avoid doing communication
94  mesh->allow_remote_element_removal(false);
95  if (!mesh->is_prepared())
96  mesh->prepare_for_use();
97 
98  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> sideList =
99  mesh->get_boundary_info().build_active_side_list();
100 
101  // If on one process a sideset element is semilocal, then any semilocal active neighbors might be
102  // marked for refinement. However, if on another process that sideset element is *not* semilocal,
103  // then obviously no neighboring elements can be marked for refinement. With no communication this
104  // can lead to elements on the former process being flagged for refinement while on the latter
105  // they will be marked to do nothing. This is a violation of parallel consistency, so we make sure
106  // to communicate neighbors that need to be refined
107  std::vector<dof_id_type> neighbors_to_refine;
108 
109  for (std::size_t i = 0; i < boundary_ids.size(); i++)
110  {
111  if (refinement[i] > 0 && refinement[i] > ref_step)
112  {
113  for (std::tuple<dof_id_type, unsigned short int, boundary_id_type> tuple : sideList)
114  {
115  if (std::get<2>(tuple) == boundary_ids[i])
116  {
117  Elem * elem = mesh->elem_ptr(std::get<0>(tuple));
118  if (_boundary_side[i] == "primary" || _boundary_side[i] == "both")
119  elem->set_refinement_flag(Elem::REFINE);
120  if (_boundary_side[i] == "secondary" || _boundary_side[i] == "both")
121  {
122  auto neighbor = elem->neighbor_ptr(std::get<1>(tuple));
123  // when we have multiple domains, domains will only refine the elements that they own
124  // since there can be instances where there is no neighbor, this null_ptr check is
125  // necessary
126  if (neighbor)
127  {
128  if (neighbor->active())
129  {
130  neighbor->set_refinement_flag(Elem::REFINE);
131  if (!mesh->is_serial())
132  neighbors_to_refine.push_back(neighbor->id());
133  }
134  else
135  {
136  std::vector<Elem *> family_tree;
137  neighbor->active_family_tree_by_neighbor(family_tree, elem);
138  for (auto child_elem : family_tree)
139  {
140  child_elem->set_refinement_flag(Elem::REFINE);
141  if (!mesh->is_serial())
142  neighbors_to_refine.push_back(child_elem->id());
143  }
144  }
145  }
146  }
147  }
148  }
149  }
150  }
151 
152  if (!mesh->is_serial())
153  {
154  mesh->comm().allgather(neighbors_to_refine);
155  std::sort(neighbors_to_refine.begin(), neighbors_to_refine.end());
156  auto new_last = std::unique(neighbors_to_refine.begin(), neighbors_to_refine.end());
157  neighbors_to_refine.erase(new_last, neighbors_to_refine.end());
158  for (const auto id : neighbors_to_refine)
159  if (Elem * const elem = mesh->query_elem_ptr(id))
160  elem->set_refinement_flag(Elem::REFINE);
161  }
162 
163  libMesh::MeshRefinement refinedmesh(*mesh);
165  refinedmesh.face_level_mismatch_limit() = 0;
166 
167  // This calls prepare_for_use
168  refinedmesh.refine_elements();
169  mesh->allow_remote_element_removal(old_allow_remote_element_removal);
170  ref_step++;
171  return recursive_refine(boundary_ids, mesh, refinement, max, ref_step);
172 }
static InputParameters validParams()
const BoundaryID INVALID_BOUNDARY_ID
Definition: MooseTypes.C:22
MeshBase & mesh
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
MeshGenerator for refining one or more sidesets.
const std::vector< int > _refinement
The amount of times to refine each boundary, corresponding to their index in &#39;boundaries&#39;.
registerMooseObject("MooseApp", RefineSidesetGenerator)
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
auto max(const L &left, const R &right)
const bool _enable_neighbor_refinement
Toggles whether neighboring level one elements should be refined or not. Defaults to true...
std::unique_ptr< MeshBase > recursive_refine(const std::vector< boundary_id_type > boundary_ids, std::unique_ptr< MeshBase > &mesh, const std::vector< int > refinement, const int max, int ref_step=0)
The actual function refining the boundaries.
const MultiMooseEnum _boundary_side
Side(s) of the boundary/boundaries to be refined. Can be either "primary"(just the boundary elements)...
void family_tree(T elem, std::vector< T > &family, bool reset=true)
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
virtual std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
static InputParameters validParams()
Definition: MeshGenerator.C:23
unsigned char & face_level_mismatch_limit()
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type...
RefineSidesetGenerator(const InputParameters &parameters)
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
void ErrorVector unsigned int
const std::vector< BoundaryName > _boundaries
List of boundarie(s) to refine.
std::unique_ptr< MeshBase > & _input
Input mesh to refine.