https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SideSetsGeneratorBase.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
11#include "Parser.h"
12#include "InputParameters.h"
13#include "MooseMesh.h"
14#include "MooseMeshUtils.h"
15#include "MeshTraversingUtils.h"
16
17#include "libmesh/mesh_generation.h"
18#include "libmesh/mesh.h"
19#include "libmesh/string_to_enum.h"
20#include "libmesh/quadrature_gauss.h"
21#include "libmesh/point_locator_base.h"
22#include "libmesh/elem.h"
23#include "libmesh/remote_elem.h"
24
27{
29 params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
30 params.addRequiredParam<std::vector<BoundaryName>>(
31 "new_boundary", "The list of boundary names to create on the supplied subdomain");
32 params.addParam<bool>("fixed_normal",
33 false,
34 "This Boolean determines whether we fix our normal "
35 "or allow it to vary to \"paint\" around curves");
36
37 params.addParam<bool>("replace",
38 false,
39 "If true, replace the old sidesets. If false, the current sidesets (if "
40 "any) will be preserved.");
41
42 params.addParam<std::vector<BoundaryName>>(
43 "included_boundaries",
44 "A set of boundary names or ids whose sides will be included in the new sidesets. A side "
45 "is only added if it also belongs to one of these boundaries.");
46 params.addParam<std::vector<BoundaryName>>(
47 "excluded_boundaries",
48 "A set of boundary names or ids whose sides will be excluded from the new sidesets. A side "
49 "is only added if does not belong to any of these boundaries.");
50 params.addParam<std::vector<SubdomainName>>(
51 "included_subdomains",
52 "A set of subdomain names or ids whose sides will be included in the new sidesets. A side "
53 "is only added if the subdomain id of the corresponding element is in this set.");
54 params.addParam<std::vector<SubdomainName>>("included_neighbors",
55 "A set of neighboring subdomain names or ids. A face "
56 "is only added if the subdomain id of the "
57 "neighbor is in this set");
58 params.addParam<bool>(
59 "include_only_external_sides",
60 false,
61 "Whether to only include external sides when considering sides to add to the sideset");
62
63 params.addParam<Point>("normal",
64 Point(),
65 "If supplied, only faces with normal equal to this, up to "
66 "normal_tol, will be added to the sidesets specified");
67 params.addRangeCheckedParam<Real>("normal_tol",
68 0.1,
69 "normal_tol>=0 & normal_tol<=2",
70 "If normal is supplied then faces are "
71 "only added if face_normal.normal_hat >= "
72 "1 - normal_tol, where normal_hat = "
73 "normal/|normal|");
74
75 // Sideset restriction param group
77 "included_boundaries excluded_boundaries included_subdomains included_neighbors "
78 "include_only_external_sides normal normal_tol",
79 "Sideset restrictions");
80
81 return params;
82}
83
85 : MeshGenerator(parameters),
86 _input(getMesh("input")),
87 _boundary_names(std::vector<BoundaryName>()),
88 _fixed_normal(getParam<bool>("fixed_normal")),
89 _replace(getParam<bool>("replace")),
90 _check_included_boundaries(isParamValid("included_boundaries")),
91 _check_excluded_boundaries(isParamValid("excluded_boundaries")),
92 _check_subdomains(isParamValid("included_subdomains")),
93 _check_neighbor_subdomains(isParamValid("included_neighbors")),
94 _included_boundary_ids(std::vector<boundary_id_type>()),
95 _excluded_boundary_ids(std::vector<boundary_id_type>()),
96 _included_subdomain_ids(std::vector<subdomain_id_type>()),
97 _included_neighbor_subdomain_ids(std::vector<subdomain_id_type>()),
98 _include_only_external_sides(getParam<bool>("include_only_external_sides")),
99 _using_normal(isParamSetByUser("normal")),
100 _normal(_using_normal ? Point(getParam<Point>("normal") / getParam<Point>("normal").norm())
101 : getParam<Point>("normal")),
102 _normal_tol(getParam<Real>("normal_tol"))
103{
104 if (isParamValid("new_boundary"))
105 _boundary_names = getParam<std::vector<BoundaryName>>("new_boundary");
106}
107
109
110void
112{
113 mooseAssert(_fe_face == nullptr, "FE Face has already been initialized");
114
115 // To know the dimension of the mesh
116 if (!mesh.is_prepared())
117 mesh.prepare_for_use();
118 const auto dim = mesh.mesh_dimension();
119
120 // Setup the FE Object so we can calculate normals
121 libMesh::FEType fe_type(Utility::string_to_enum<Order>("CONSTANT"),
122 Utility::string_to_enum<libMesh::FEFamily>("MONOMIAL"));
124 _qface = std::make_unique<libMesh::QGauss>(dim - 1, FIRST);
125 _fe_face->attach_quadrature_rule(_qface.get());
126 // Must always pre-request quantities you want to compute
127 _fe_face->get_normals();
128
129 // Handle incompatible parameters
131 paramError("include_only_external_sides", "External sides dont have neighbors");
132
134 {
135 const auto & included_boundaries = getParam<std::vector<BoundaryName>>("included_boundaries");
136 for (const auto & boundary_name : _boundary_names)
137 if (std::find(included_boundaries.begin(), included_boundaries.end(), boundary_name) !=
138 included_boundaries.end())
140 "new_boundary",
141 "A boundary cannot be both the new boundary and be included in the list of included "
142 "boundaries. If you are trying to restrict an existing boundary, you must use a "
143 "different name for 'new_boundary', delete the old boundary, and then rename the "
144 "new boundary to the old boundary.");
145
146 _included_boundary_ids = MooseMeshUtils::getBoundaryIDs(mesh, included_boundaries, false);
147
148 // Check that the included boundary ids/names exist in the mesh
149 for (const auto i : index_range(_included_boundary_ids))
151 paramError("included_boundaries",
152 "The boundary '",
153 included_boundaries[i],
154 "' was not found within the mesh");
155 }
156
158 {
159 const auto & excluded_boundaries = getParam<std::vector<BoundaryName>>("excluded_boundaries");
160 for (const auto & boundary_name : _boundary_names)
161 if (std::find(excluded_boundaries.begin(), excluded_boundaries.end(), boundary_name) !=
162 excluded_boundaries.end())
164 "new_boundary",
165 "A boundary cannot be both the new boundary and be excluded in the list of excluded "
166 "boundaries.");
167 _excluded_boundary_ids = MooseMeshUtils::getBoundaryIDs(mesh, excluded_boundaries, false);
168
169 // Check that the excluded boundary ids/names exist in the mesh
170 for (const auto i : index_range(_excluded_boundary_ids))
172 paramError("excluded_boundaries",
173 "The boundary '",
174 excluded_boundaries[i],
175 "' was not found within the mesh");
176
178 {
179 // Check that included and excluded boundary lists do not overlap
180 for (const auto & boundary_id : _included_boundary_ids)
181 if (std::find(_excluded_boundary_ids.begin(), _excluded_boundary_ids.end(), boundary_id) !=
183 paramError("excluded_boundaries",
184 "'included_boundaries' and 'excluded_boundaries' lists should not overlap");
185 }
186 }
187
188 // Get the boundary ids from the names
189 if (parameters().isParamValid("included_subdomains"))
190 {
191 // check that the subdomains exist in the mesh
192 const auto subdomains = getParam<std::vector<SubdomainName>>("included_subdomains");
193 for (const auto & name : subdomains)
195 paramError("included_subdomains", "The block '", name, "' was not found in the mesh");
196
198 }
199
200 if (parameters().isParamValid("included_neighbors"))
201 {
202 // check that the subdomains exist in the mesh
203 const auto subdomains = getParam<std::vector<SubdomainName>>("included_neighbors");
204 for (const auto & name : subdomains)
206 paramError("included_neighbors", "The block '", name, "' was not found in the mesh");
207
209 }
210
211 // We will want to Change the below code when we have more fine-grained control over advertising
212 // what we need and how we satisfy those needs. For now we know we need to have neighbors per
213 // #15823...and we do have an explicit `find_neighbors` call...but we don't have a
214 // `neighbors_found` API and it seems off to do:
215 //
216 // if (!mesh.is_prepared())
217 // mesh.find_neighbors()
218}
219
220void
222{
223 _qface.reset();
224 _fe_face.reset();
225}
226
227void
229 const Point & normal,
230 const boundary_id_type & side_id,
231 MeshBase & mesh)
232{
233 if (elem == nullptr || elem == remote_elem ||
234 (_visited[side_id].find(elem) != _visited[side_id].end()))
235 return;
236
237 // Skip if element is not in specified subdomains
238 if (_check_subdomains &&
240 return;
241
242 _visited[side_id].insert(elem);
243
244 // Request to compute normal vectors
245 const std::vector<Point> & face_normals = _fe_face->get_normals();
246
247 for (const auto side : make_range(elem->n_sides()))
248 {
249
250 _fe_face->reinit(elem, side);
251 // We'll just use the normal of the first qp
252 const Point face_normal = face_normals[0];
253
254 if (!elemSideSatisfiesRequirements(elem, side, mesh, normal, face_normal))
255 continue;
256
257 if (_replace)
258 mesh.get_boundary_info().remove_side(elem, side);
259
260 mesh.get_boundary_info().add_side(elem, side, side_id);
261 for (const auto neighbor : make_range(elem->n_sides()))
262 {
263 // Flood to the neighboring elements using the current matching side normal from this
264 // element.
265 // This will allow us to tolerate small changes in the normals so we can "paint" around a
266 // curve.
267 flood(elem->neighbor_ptr(neighbor), _fixed_normal ? normal : face_normal, side_id, mesh);
268 }
269 }
270}
271
272bool
274 const unsigned int side,
275 const MeshBase & mesh) const
276{
277 for (const auto & bid : _included_boundary_ids)
278 if (mesh.get_boundary_info().has_boundary_id(elem, side, bid))
279 return true;
280 return false;
281}
282
283bool
285 const unsigned int side,
286 const MeshBase & mesh) const
287{
288 for (const auto bid : _excluded_boundary_ids)
289 if (mesh.get_boundary_info().has_boundary_id(elem, side, bid))
290 return true;
291 return false;
292}
293
294bool
296 const unsigned int side,
297 const MeshBase & mesh,
298 const Point & desired_normal,
299 const Point & face_normal)
300{
301 // Skip if side has neighbor and we only want external sides
302 if ((elem->neighbor_ptr(side) && _include_only_external_sides))
303 return false;
304
305 // Skip if side is not part of included boundaries
307 return false;
308 // Skip if side is part of excluded boundaries
310 return false;
311
312 // Skip if element does not have neighbor in specified subdomains
314 {
315 const Elem * const neighbor = elem->neighbor_ptr(side);
316 // if the neighbor does not exist, then skip this face; we only add sidesets
317 // between existing elems if _check_neighbor_subdomains is true
320 return false;
321 }
322
323 if (_using_normal &&
324 !MeshTraversingUtils::normalsWithinTol(desired_normal, face_normal, _normal_tol))
325 return false;
326
327 return true;
328}
unsigned int dim
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
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...
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.
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...
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another,...
MeshGenerators are objects that can modify or add to an existing mesh.
static InputParameters validParams()
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
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 ...
Definition MooseBase.h:457
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
void setup(MeshBase &mesh)
This method is used to construct the FE object so we can compute normals of faces.
const Real _normal_tol
if normal is specified, then faces are only added if face_normal.normal_hat <= 1 - normal_tol where n...
std::unique_ptr< libMesh::QGauss > _qface
std::vector< subdomain_id_type > _included_neighbor_subdomain_ids
A list of included neighbor subdomain ids that the sides' neighbor element must be a part of.
std::unique_ptr< libMesh::FEBase > _fe_face
const bool _check_included_boundaries
whether to check boundary ids against the included boundary list when adding sides or not
std::vector< BoundaryName > _boundary_names
The list of new boundary names.
bool elementSideInExcludedBoundaries(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 excluded_boundaries ...
const bool _check_excluded_boundaries
whether to check boundary ids against the excluded boundary list when adding sides or not
static InputParameters validParams()
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's side satisfies the following parameters: include_only_external...
const bool _check_subdomains
whether to check subdomain ids of the element in the (element, side, boundary id) tuple when adding s...
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...
const bool _replace
Whether or not to remove the old sidesets (all of them, if any) when adding sidesets.
std::vector< boundary_id_type > _included_boundary_ids
A list of boundary ids that the side has to be part of, extracted from the included_boundaries parame...
bool _using_normal
true if only faces close to "normal" will be added
void finalize()
This method finalizes the object, setting names back in the boundary_info object and releasing memory...
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::vector< boundary_id_type > _excluded_boundary_ids
A list of boundary ids that the side must not be a part of, extracted from the excluded_boundaries pa...
const bool _check_neighbor_subdomains
whether to check the subdomain ids of the neighbor element (on the other 'side' of the side) when add...
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 ...
const bool _fixed_normal
Whether to fix the normal or allow it to vary to "paint" around curves.
std::map< boundary_id_type, std::set< const Elem * > > _visited
const bool _include_only_external_sides
Whether to only include external side when considering sides to add to the sideset.
SideSetsGeneratorBase(const InputParameters &parameters)
std::unique_ptr< FEGenericBase< Real > > build(const unsigned int dim, const FEType &fet)
MeshBase & mesh
bool elementSubdomainIdInList(const Elem *const elem, const std::vector< subdomain_id_type > &subdomain_id_list)
Determines whether the given element's subdomain id is in the given subdomain_id_list.
bool normalsWithinTol(const Point &normal_1, const Point &normal_2, const Real tol)
Determines whether two normal vectors are within normal_tol of each other.
bool hasSubdomainName(const MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain name exists in the mesh.
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.
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 BoundaryID INVALID_BOUNDARY_ID
Definition MooseTypes.C:22
const boundary_id_type side_id