17#include "libmesh/elem.h"
18#include "libmesh/parallel_sync.h"
19#include "libmesh/remote_elem.h"
31 params.
addClassDescription(
"Defines new sidesets using currently-defined sideset IDs inside or "
32 "outside of a bounding box.");
34 MooseEnum location(
"INSIDE OUTSIDE",
"INSIDE");
37 "bottom_left",
"The bottom left point (in x,y,z with spaces in-between).");
39 "top_right",
"The bottom left point (in x,y,z with spaces in-between).");
41 "boundary_new",
"Boundary on specified block within the bounding box to assign");
42 params.
addParam<
bool>(
"boundary_id_overlap",
44 "Set to true if boundaries need to overlap on sideset to be detected.");
46 "location", location,
"Control of where the subdomain id is to be set");
58 _location(parameters.get<
MooseEnum>(
"location")),
59 _bounding_box(
MooseUtils::buildBoundingBox(parameters.get<RealVectorValue>(
"bottom_left"),
60 parameters.get<RealVectorValue>(
"top_right"))),
61 _boundary_id_overlap(parameters.get<bool>(
"boundary_id_overlap"))
65 const std::vector<std::string> incompatible_params = {
"normal",
67 "include_only_external_sides",
68 "included_subdomains",
69 "included_neighbors"};
70 for (
const auto & param_name : incompatible_params)
72 paramError(param_name,
"Parameter should not be used with boundary_id_overlap = true.");
75 const auto & boundary_name =
parameters.
get<BoundaryName>(
"boundary_new");
76 if (boundary_name.empty())
77 paramError(
"boundary_new",
"Boundary name must not be empty.");
82std::unique_ptr<MeshBase>
85 std::unique_ptr<MeshBase>
mesh = std::move(
_input);
91 BoundaryInfo & boundary_info =
mesh->get_boundary_info();
92 boundary_info.build_node_list_from_side_list();
94 const bool inside = (
_location ==
"INSIDE");
98 if (!MooseUtils::isDigits(boundary_name))
100 boundary_info.sideset_name(boundary_id_new) = boundary_name;
101 boundary_info.nodeset_name(boundary_id_new) = boundary_name;
107 bool found_element =
false;
108 bool found_side_sets =
false;
111 const std::vector<Point> & face_normals =
_fe_face->get_normals();
113 typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
114 std::map<processor_id_type, vec_type> queries;
116 auto add_side = [&](
const Elem * elem,
const unsigned int side)
119 boundary_info.remove_side(elem, side);
120 boundary_info.add_side(elem, side, boundary_id_new);
121 found_side_sets =
true;
125 for (
const auto & elem :
mesh->active_element_ptr_range())
128 bool contains =
_bounding_box.contains_point(elem->vertex_average());
131 if (contains == inside)
133 found_element =
true;
135 for (
const auto side : make_range(elem->n_sides()))
139 const Point face_normal = face_normals[0];
143 libmesh_assert(elem->processor_id() !=
mesh->processor_id());
144 queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
147 add_side(elem, side);
152 if (!queries.empty())
154 typedef unsigned char response_type;
155 auto gather_data = [&](processor_id_type ,
156 const vec_type &
query,
157 std::vector<response_type> & response)
159 response.reserve(
query.size());
161 for (
const auto & q :
query)
163 const Elem * elem =
mesh->elem_ptr(q.first);
164 const unsigned int side = q.second;
166 response_type side_satisfies_requirements =
false;
167 if (
_bounding_box.contains_point(elem->vertex_average()) == inside)
169 libmesh_assert(elem->neighbor_ptr(side) != remote_elem);
171 const Point face_normal =
_fe_face->get_normals()[0];
172 side_satisfies_requirements =
175 response.push_back(side_satisfies_requirements);
179 auto act_on_data = [&](processor_id_type ,
180 const vec_type &
query,
181 const std::vector<response_type> & response)
183 for (
const auto i : index_range(
query))
188 const response_type * example =
nullptr;
189 Parallel::pull_parallel_vector_data(
mesh->comm(), queries, gather_data, act_on_data, example);
194 mooseError(
"No elements found ", inside ?
"within" :
"outside",
" the bounding box");
197 if (!found_side_sets)
198 mooseError(
"No side sets found on active elements within the bounding box");
206 " Must be 2 boundary inputs or more.");
208 bool found_node =
false;
211 for (
const auto node :
mesh->active_node_ptr_range())
217 std::vector<boundary_id_type> node_boundary_ids;
218 boundary_info.boundary_ids(node, node_boundary_ids);
221 std::sort(node_boundary_ids.begin(), node_boundary_ids.end());
226 if (std::includes(node_boundary_ids.begin(),
227 node_boundary_ids.end(),
231 boundary_info.add_node(node, boundary_id_new);
239 mooseError(
"No nodes found within the bounding box");
242 mesh->unset_is_prepared();
243 return dynamic_pointer_cast<MeshBase>(
mesh);
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
registerMooseObject("MooseApp", SideSetsFromBoundingBoxGenerator)
const InputParameters & parameters() const
Get the parameters of the object.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
MeshGenerator for defining sidesets inside or outside of a bounding box.
const BoundingBox _bounding_box
Bounding box for testing element centroids against.
SideSetsFromBoundingBoxGenerator(const InputParameters ¶meters)
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
static InputParameters validParams()
const bool _boundary_id_overlap
Flag to determine if the provided boundaries need to overlap.
const MooseEnum _location
ID location (inside of outside of box)
void setup(MeshBase &mesh)
This method is used to construct the FE object so we can compute normals of faces.
std::unique_ptr< libMesh::FEBase > _fe_face
std::vector< BoundaryName > _boundary_names
The list of new boundary names.
Point _normal
if specified, then faces are only added if their normal is close to this
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...
std::unique_ptr< MeshBase > & _input
the mesh to add the sidesets to
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...
const bool _check_neighbor_subdomains
whether to check the subdomain ids of the neighbor element (on the other 'side' of the side) when add...
void max(const T &r, T &o, Request &req) const
const Parallel::Communicator & comm() const
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.