www.mooseframework.org
SideSetsGeneratorBase.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 "SideSetsGeneratorBase.h"
11 #include "Parser.h"
12 #include "InputParameters.h"
13 #include "MooseMesh.h"
14 #include "MooseMeshUtils.h"
15 
16 #include "libmesh/mesh_generation.h"
17 #include "libmesh/mesh.h"
18 #include "libmesh/string_to_enum.h"
19 #include "libmesh/quadrature_gauss.h"
20 #include "libmesh/point_locator_base.h"
21 #include "libmesh/elem.h"
22 
25 {
27  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
28  params.addRequiredParam<std::vector<BoundaryName>>(
29  "new_boundary", "The list of boundary names to create on the supplied subdomain");
30  params.addParam<bool>("fixed_normal",
31  false,
32  "This Boolean determines whether we fix our normal "
33  "or allow it to vary to \"paint\" around curves");
34 
35  params.addParam<bool>("replace",
36  false,
37  "If true, replace the old sidesets. If false, the current sidesets (if "
38  "any) will be preserved.");
39 
40  params.addParam<std::vector<BoundaryName>>(
41  "included_boundaries",
42  "A set of boundary names or ids whose sides will be included in the new sidesets");
43  params.addParam<std::vector<SubdomainName>>(
44  "included_subdomains",
45  "A set of subdomain names or ids whose sides will be included in the new sidesets");
46  params.addParam<std::vector<SubdomainName>>("included_neighbors",
47  "A set of neighboring subdomain names or ids. A face "
48  "is only added if the subdomain id of the "
49  "neighbor is in this set");
50  params.addParam<bool>(
51  "include_only_external_sides",
52  false,
53  "Whether to only include external sides when considering sides to add to the sideset");
54 
55  params.addParam<Point>("normal",
56  Point(),
57  "If supplied, only faces with normal equal to this, up to "
58  "normal_tol, will be added to the sidesets specified");
59  params.addRangeCheckedParam<Real>("normal_tol",
60  0.1,
61  "normal_tol>=0 & normal_tol<=2",
62  "If normal is supplied then faces are "
63  "only added if face_normal.normal_hat >= "
64  "1 - normal_tol, where normal_hat = "
65  "normal/|normal|");
66  params.addDeprecatedParam<Real>("variance",
67  "The variance allowed when comparing normals",
68  "Deprecated, use 'normal_tol' instead");
69  params.deprecateParam("variance", "normal_tol", "4/01/2025");
70 
71  // Sideset restriction param group
72  params.addParamNamesToGroup("included_boundaries included_subdomains included_neighbors "
73  "include_only_external_sides normal normal_tol",
74  "Sideset restrictions");
75 
76  return params;
77 }
78 
80  : MeshGenerator(parameters),
81  _input(getMesh("input")),
82  _boundary_names(std::vector<BoundaryName>()),
83  _fixed_normal(getParam<bool>("fixed_normal")),
84  _replace(getParam<bool>("replace")),
85  _check_boundaries(isParamValid("included_boundaries")),
86  _check_subdomains(isParamValid("included_subdomains")),
87  _check_neighbor_subdomains(isParamValid("included_neighbors")),
88  _restricted_boundary_ids(std::vector<boundary_id_type>()),
89  _included_subdomain_ids(std::vector<subdomain_id_type>()),
90  _included_neighbor_subdomain_ids(std::vector<subdomain_id_type>()),
91  _include_only_external_sides(getParam<bool>("include_only_external_sides")),
92  _using_normal(isParamSetByUser("normal")),
93  _normal(_using_normal ? Point(getParam<Point>("normal") / getParam<Point>("normal").norm())
94  : getParam<Point>("normal")),
95  _normal_tol(getParam<Real>("normal_tol"))
96 {
97  if (isParamValid("new_boundary"))
98  _boundary_names = getParam<std::vector<BoundaryName>>("new_boundary");
99 }
100 
102 
103 void
105 {
106  mooseAssert(_fe_face == nullptr, "FE Face has already been initialized");
107 
108  // To know the dimension of the mesh
109  if (!mesh.is_prepared())
110  mesh.prepare_for_use();
111  const auto dim = mesh.mesh_dimension();
112 
113  // Setup the FE Object so we can calculate normals
114  FEType fe_type(Utility::string_to_enum<Order>("CONSTANT"),
115  Utility::string_to_enum<FEFamily>("MONOMIAL"));
116  _fe_face = FEBase::build(dim, fe_type);
117  _qface = std::make_unique<QGauss>(dim - 1, FIRST);
118  _fe_face->attach_quadrature_rule(_qface.get());
119 
120  // Handle incompatible parameters
122  paramError("include_only_external_sides", "External sides dont have neighbors");
123 
124  if (_check_boundaries)
125  {
126  const auto & included_boundaries = getParam<std::vector<BoundaryName>>("included_boundaries");
127  for (const auto & boundary_name : _boundary_names)
128  if (std::find(included_boundaries.begin(), included_boundaries.end(), boundary_name) !=
129  included_boundaries.end())
130  paramError(
131  "new_boundary",
132  "A boundary cannot be both the new boundary and be included in the list of included "
133  "boundaries. If you are trying to restrict an existing boundary, you must use a "
134  "different name for 'new_boundary', delete the old boundary, and then rename the "
135  "new boundary to the old boundary.");
136 
137  _restricted_boundary_ids = MooseMeshUtils::getBoundaryIDs(mesh, included_boundaries, false);
138 
139  // Check that the included boundary ids/names exist in the mesh
140  for (const auto & i : make_range(_restricted_boundary_ids.size()))
142  paramError("boundaries",
143  "The boundary '",
144  included_boundaries[i],
145  "' was not found within the mesh");
146  }
147 
148  // Get the boundary ids from the names
149  if (parameters().isParamValid("included_subdomains"))
150  {
151  // check that the subdomains exist in the mesh
152  const auto subdomains = getParam<std::vector<SubdomainName>>("included_subdomains");
153  for (const auto & name : subdomains)
155  paramError("included_subdomains", "The block '", name, "' was not found in the mesh");
156 
158  }
159 
160  if (parameters().isParamValid("included_neighbors"))
161  {
162  // check that the subdomains exist in the mesh
163  const auto subdomains = getParam<std::vector<SubdomainName>>("included_neighbors");
164  for (const auto & name : subdomains)
166  paramError("included_neighbors", "The block '", name, "' was not found in the mesh");
167 
169  }
170 
171  // We will want to Change the below code when we have more fine-grained control over advertising
172  // what we need and how we satisfy those needs. For now we know we need to have neighbors per
173  // #15823...and we do have an explicit `find_neighbors` call...but we don't have a
174  // `neighbors_found` API and it seems off to do:
175  //
176  // if (!mesh.is_prepared())
177  // mesh.find_neighbors()
178 }
179 
180 void
182 {
183  _qface.reset();
184  _fe_face.reset();
185 }
186 
187 void
189  const Point & normal,
190  const boundary_id_type & side_id,
191  MeshBase & mesh)
192 {
193  if (elem == nullptr || (_visited[side_id].find(elem) != _visited[side_id].end()))
194  return;
195 
196  // Skip if element is not in specified subdomains
198  return;
199 
200  _visited[side_id].insert(elem);
201 
202  for (const auto side : make_range(elem->n_sides()))
203  {
204 
205  _fe_face->reinit(elem, side);
206  // We'll just use the normal of the first qp
207  const Point face_normal = _fe_face->get_normals()[0];
208 
209  if (!elemSideSatisfiesRequirements(elem, side, mesh, normal, face_normal))
210  continue;
211 
212  if (_replace)
213  mesh.get_boundary_info().remove_side(elem, side);
214 
215  mesh.get_boundary_info().add_side(elem, side, side_id);
216  for (const auto neighbor : make_range(elem->n_sides()))
217  {
218  // Flood to the neighboring elements using the current matching side normal from this
219  // element.
220  // This will allow us to tolerate small changes in the normals so we can "paint" around a
221  // curve.
222  flood(elem->neighbor_ptr(neighbor), _fixed_normal ? normal : face_normal, side_id, mesh);
223  }
224  }
225 }
226 
227 bool
229  const Point & normal_2,
230  const Real & tol) const
231 {
232  return (1.0 - normal_1 * normal_2) <= tol;
233 }
234 
235 bool
237  const Elem * const elem, const std::vector<subdomain_id_type> & subdomain_id_list) const
238 {
239  subdomain_id_type curr_subdomain = elem->subdomain_id();
240  return std::find(subdomain_id_list.begin(), subdomain_id_list.end(), curr_subdomain) !=
241  subdomain_id_list.end();
242 }
243 
244 bool
246  const unsigned int side,
247  const MeshBase & mesh) const
248 {
249  for (const auto bid : _restricted_boundary_ids)
250  if (mesh.get_boundary_info().has_boundary_id(elem, side, bid))
251  return true;
252  return false;
253 }
254 
255 bool
257  const unsigned int side,
258  const MeshBase & mesh,
259  const Point & desired_normal,
260  const Point & face_normal)
261 {
262  // Skip if side has neighbor and we only want external sides
263  if ((elem->neighbor_ptr(side) && _include_only_external_sides))
264  return false;
265 
266  // Skip if side is not part of included boundaries
268  return false;
269 
270  // Skip if element does not have neighbor in specified subdomains
272  {
273  const Elem * const neighbor = elem->neighbor_ptr(side);
274  // if the neighbor does not exist, then skip this face; we only add sidesets
275  // between existing elems if _check_neighbor_subdomains is true
276  if (!(neighbor && elementSubdomainIdInList(neighbor, _included_neighbor_subdomain_ids)))
277  return false;
278  }
279 
280  if (_using_normal && !normalsWithinTol(desired_normal, face_normal, _normal_tol))
281  return false;
282 
283  return true;
284 }
bool elementSubdomainIdInList(const Elem *const elem, const std::vector< subdomain_id_type > &subdomain_id_list) const
Determines whether the given element&#39;s subdomain id is in the given subdomain_id_list.
const bool _fixed_normal
Whether to fix the normal or allow it to vary to "paint" around curves.
bool elemSideSatisfiesRequirements(const Elem *const elem, const unsigned int side, const MeshBase &mesh, const Point &normal, const Point &face_normal)
Determines whether the given element&#39;s side satisfies the following parameters: include_only_external...
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
const Real _normal_tol
if normal is specified, then faces are only added if face_normal.normal_hat <= 1 - normal_tol where n...
const BoundaryID INVALID_BOUNDARY_ID
Definition: MooseTypes.C:24
std::vector< subdomain_id_type > _included_neighbor_subdomain_ids
A list of included neighbor subdomain ids that the sides&#39; neighbor element must be a part of...
FIRST
const boundary_id_type side_id
SideSetsGeneratorBase(const InputParameters &parameters)
MeshBase & mesh
const bool _replace
Whether or not to remove the old sidesets (all of them, if any) when adding sidesets.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:148
bool normalsWithinTol(const Point &normal_1, const Point &normal_2, const Real &tol) const
Determines whether two normal vectors are within normal_tol of each other.
std::vector< BoundaryName > _boundary_names
The list of new boundary names.
std::vector< subdomain_id_type > getSubdomainIDs(const libMesh::MeshBase &mesh, const std::vector< SubdomainName > &subdomain_name)
Get the associated subdomainIDs for the subdomain names that are passed in.
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:57
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...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
std::vector< subdomain_id_type > _included_subdomain_ids
A list of included subdomain ids that the side has to be part of, extracted from the included_subdoma...
std::unique_ptr< QGauss > _qface
const bool _include_only_external_sides
Whether to only include external side when considering sides to add to the sideset.
int8_t boundary_id_type
void deprecateParam(const std::string &old_name, const std::string &new_name, const std::string &removal_date)
void flood(const Elem *elem, const Point &normal, const boundary_id_type &side_id, MeshBase &mesh)
This method implements a recursive flood routine to paint a sideset of mesh to neighboring faces give...
bool elementSideInIncludedBoundaries(const Elem *const elem, const unsigned int side, const MeshBase &mesh) const
Determines whether the given side of an element belongs to any boundaries in the included_boundaries ...
std::unique_ptr< FEBase > _fe_face
bool hasSubdomainName(MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain name exists in the mesh.
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.
const bool _check_boundaries
whether to check boundary ids when adding sides or not
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 ...
auto norm(const T &a) -> decltype(std::abs(a))
static InputParameters validParams()
Definition: MeshGenerator.C:23
void finalize()
This method finalizes the object, setting names back in the boundary_info object and releasing memory...
static InputParameters validParams()
bool _using_normal
true if only faces close to "normal" will be added
const bool _check_subdomains
whether to check subdomain ids of the element in the (element, side, boundary id) tuple when adding s...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
const InputParameters & parameters() const
Get the parameters of the object.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
const bool _check_neighbor_subdomains
whether to check the subdomain ids of the neighbor element (on the other &#39;side&#39; of the side) when add...
std::map< boundary_id_type, std::set< const Elem * > > _visited
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
void setup(MeshBase &mesh)
This method is used to construct the FE object so we can compute normals of faces.
std::vector< boundary_id_type > _restricted_boundary_ids
A list of included boundary ids that the side has to be part of, extracted from the included_boundari...
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...