https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SideSetsFromBoundingBoxGenerator.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 "Conversion.h"
12#include "MooseTypes.h"
13#include "MooseMeshUtils.h"
14#include "CastUniquePointer.h"
15#include "MooseUtils.h"
16
17#include "libmesh/elem.h"
18#include "libmesh/parallel_sync.h"
19#include "libmesh/remote_elem.h"
20
21#include <map>
22#include <typeinfo>
23
25
28{
30
31 params.addClassDescription("Defines new sidesets using currently-defined sideset IDs inside or "
32 "outside of a bounding box.");
33
34 MooseEnum location("INSIDE OUTSIDE", "INSIDE");
35
36 params.addRequiredParam<RealVectorValue>(
37 "bottom_left", "The bottom left point (in x,y,z with spaces in-between).");
38 params.addRequiredParam<RealVectorValue>(
39 "top_right", "The bottom left point (in x,y,z with spaces in-between).");
40 params.addRequiredParam<BoundaryName>(
41 "boundary_new", "Boundary on specified block within the bounding box to assign");
42 params.addParam<bool>("boundary_id_overlap",
43 false,
44 "Set to true if boundaries need to overlap on sideset to be detected.");
45 params.addParam<MooseEnum>(
46 "location", location, "Control of where the subdomain id is to be set");
47
48 // TODO: Implement each of these in the generate() routine using utilities in SidesetGeneratorBase
49 params.suppressParameter<bool>("fixed_normal");
50 params.suppressParameter<std::vector<BoundaryName>>("new_boundary");
51
52 return params;
53}
54
56 const InputParameters & parameters)
57 : SideSetsGeneratorBase(parameters),
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"))
62{
64 {
65 const std::vector<std::string> incompatible_params = {"normal",
66 "replace",
67 "include_only_external_sides",
68 "included_subdomains",
69 "included_neighbors"};
70 for (const auto & param_name : incompatible_params)
71 if (isParamSetByUser(param_name))
72 paramError(param_name, "Parameter should not be used with boundary_id_overlap = true.");
73 }
74
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.");
78
79 _boundary_names.push_back(boundary_name);
80}
81
82std::unique_ptr<MeshBase>
84{
85 std::unique_ptr<MeshBase> mesh = std::move(_input);
86
87 // construct the FE object so we can compute normals of faces
88 setup(*mesh);
89
90 // Get a reference to our BoundaryInfo object for later use
91 BoundaryInfo & boundary_info = mesh->get_boundary_info();
92 boundary_info.build_node_list_from_side_list();
93
94 const bool inside = (_location == "INSIDE");
95
96 const auto & boundary_name = _boundary_names.front();
97 const auto boundary_id_new = MooseMeshUtils::getBoundaryIDs(*mesh, {boundary_name}, true).front();
98 if (!MooseUtils::isDigits(boundary_name))
99 {
100 boundary_info.sideset_name(boundary_id_new) = boundary_name;
101 boundary_info.nodeset_name(boundary_id_new) = boundary_name;
102 }
103
104 // Boundaries do not need to overlap
106 {
107 bool found_element = false;
108 bool found_side_sets = false;
109
110 // Request to compute normal vectors
111 const std::vector<Point> & face_normals = _fe_face->get_normals();
112
113 typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
114 std::map<processor_id_type, vec_type> queries;
115
116 auto add_side = [&](const Elem * elem, const unsigned int side)
117 {
118 if (_replace)
119 boundary_info.remove_side(elem, side);
120 boundary_info.add_side(elem, side, boundary_id_new);
121 found_side_sets = true;
122 };
123
124 // Loop over the elements
125 for (const auto & elem : mesh->active_element_ptr_range())
126 {
127 // boolean if element centroid is in bounding box
128 bool contains = _bounding_box.contains_point(elem->vertex_average());
129
130 // check if active elements are found either in or out of the bounding box, apropos "inside"
131 if (contains == inside)
132 {
133 found_element = true;
134 // loop over sides of elements within bounding box
135 for (const auto side : make_range(elem->n_sides()))
136 {
137 _fe_face->reinit(elem, side);
138 // We'll just use the normal of the first qp
139 const Point face_normal = face_normals[0];
140
141 if (_check_neighbor_subdomains && elem->neighbor_ptr(side) == remote_elem)
142 {
143 libmesh_assert(elem->processor_id() != mesh->processor_id());
144 queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
145 }
146 else if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
147 add_side(elem, side);
148 }
149 }
150 }
151
152 if (!queries.empty())
153 {
154 typedef unsigned char response_type;
155 auto gather_data = [&](processor_id_type /*pid*/,
156 const vec_type & query,
157 std::vector<response_type> & response)
158 {
159 response.reserve(query.size());
160
161 for (const auto & q : query)
162 {
163 const Elem * elem = mesh->elem_ptr(q.first);
164 const unsigned int side = q.second;
165
166 response_type side_satisfies_requirements = false;
167 if (_bounding_box.contains_point(elem->vertex_average()) == inside)
168 {
169 libmesh_assert(elem->neighbor_ptr(side) != remote_elem);
170 _fe_face->reinit(elem, side);
171 const Point face_normal = _fe_face->get_normals()[0];
172 side_satisfies_requirements =
173 elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal);
174 }
175 response.push_back(side_satisfies_requirements);
176 }
177 };
178
179 auto act_on_data = [&](processor_id_type /*pid*/,
180 const vec_type & query,
181 const std::vector<response_type> & response)
182 {
183 for (const auto i : index_range(query))
184 if (response[i])
185 add_side(mesh->elem_ptr(query[i].first), query[i].second);
186 };
187
188 const response_type * example = nullptr;
189 Parallel::pull_parallel_vector_data(mesh->comm(), queries, gather_data, act_on_data, example);
190 }
191
192 comm().max(found_element);
193 if (!found_element)
194 mooseError("No elements found ", inside ? "within" : "outside", " the bounding box");
195
196 comm().max(found_side_sets);
197 if (!found_side_sets)
198 mooseError("No side sets found on active elements within the bounding box");
199 }
200 // Boundaries need to overlap
201 else
202 {
203 if (_included_boundary_ids.size() < 2)
204 mooseError("boundary_id_old out of bounds: ",
206 " Must be 2 boundary inputs or more.");
207
208 bool found_node = false;
209
210 // Loop over the elements and assign node set id to nodes within the bounding box
211 for (const auto node : mesh->active_node_ptr_range())
212 {
213 // check if nodes are inside of bounding box
214 if (_bounding_box.contains_point(*node) == inside)
215 {
216 // read out boundary ids for nodes
217 std::vector<boundary_id_type> node_boundary_ids;
218 boundary_info.boundary_ids(node, node_boundary_ids);
219
220 // sort boundary ids on node and sort boundary ids provided in input file
221 std::sort(node_boundary_ids.begin(), node_boundary_ids.end());
222 std::sort(_included_boundary_ids.begin(), _included_boundary_ids.end());
223
224 // check if input boundary ids are all contained in the node
225 // if true, write new boundary id on respective node
226 if (std::includes(node_boundary_ids.begin(),
227 node_boundary_ids.end(),
230 {
231 boundary_info.add_node(node, boundary_id_new);
232 found_node = true;
233 }
234 }
235 }
236
237 comm().max(found_node);
238 if (!found_node)
239 mooseError("No nodes found within the bounding box");
240 }
241
242 mesh->unset_is_prepared();
243 return dynamic_pointer_cast<MeshBase>(mesh);
244}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
registerMooseObject("MooseApp", SideSetsFromBoundingBoxGenerator)
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn't required or valid in the derived class...
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...
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
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.
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
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 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.
Definition MooseBase.h:205
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
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 &parameters)
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
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
query_obj query
MeshBase & 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.