https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SideSetsAroundSubdomainGenerator.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 "InputParameters.h"
12#include "MooseTypes.h"
13#include "MeshTraversingUtils.h"
14#include "MooseMeshUtils.h"
15#include "CastUniquePointer.h"
16
17#include "libmesh/mesh.h"
18#include "libmesh/remote_elem.h"
19#include "libmesh/point.h"
20#include "libmesh/fe_base.h"
21
23
26{
28
29 params.renameParam("included_subdomains", "block", "The blocks around which to create sidesets");
30 params.makeParamRequired<std::vector<SubdomainName>>("block");
31
32 // Not implemented, but could be implemented
33 params.suppressParameter<std::vector<BoundaryName>>("included_boundaries");
34 params.suppressParameter<std::vector<BoundaryName>>("excluded_boundaries");
35 params.suppressParameter<std::vector<SubdomainName>>("included_neighbors");
36
38 "Adds element faces that are on the exterior of the given block to the sidesets specified");
39
40 return params;
41}
42
48
49std::unique_ptr<MeshBase>
51{
52 std::unique_ptr<MeshBase> mesh = std::move(_input);
53
54 // construct the FE object so we can compute normals of faces
55 setup(*mesh);
56
57 // Create the boundary IDs from the list of names provided (the true flag creates ids from unknown
58 // names)
59 std::vector<boundary_id_type> boundary_ids =
61
62 // Get a reference to our BoundaryInfo object for later use
63 BoundaryInfo & boundary_info = mesh->get_boundary_info();
64
65 // Prepare to query about sides adjacent to remote elements if we're
66 // on a distributed mesh
67 const processor_id_type my_n_proc = mesh->n_processors();
68 const processor_id_type my_proc_id = mesh->processor_id();
69 typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
70 std::vector<vec_type> queries(my_n_proc);
71
72 // Request to compute normal vectors
73 const std::vector<Point> & face_normals = _fe_face->get_normals();
74
75 // Loop over the elements
76 for (const auto & elem : mesh->active_element_ptr_range())
77 {
78 // We only need to loop over elements in the source subdomain
81 continue;
82
83 for (const auto side : make_range(elem->n_sides()))
84 {
85 const auto * neighbor = elem->neighbor_ptr(side);
86
87 // On a replicated mesh, we add all subdomain sides ourselves.
88 // On a distributed mesh, we may have missed sides which
89 // neighbor remote elements. We should query any such cases.
90 if (neighbor == remote_elem)
91 {
92 queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
93 }
94 else if (elemSideOnBoundary(elem, side))
95 {
96 _fe_face->reinit(elem, side);
97 // We'll just use the normal of the first qp
98 const Point & face_normal = face_normals[0];
99 // Add the boundaries, if appropriate
100 if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
101 {
102 if (_replace)
103 boundary_info.remove_side(elem, side);
104 for (const auto & boundary_id : boundary_ids)
105 boundary_info.add_side(elem, side, boundary_id);
106 }
107 }
108 }
109 }
110
111 if (!mesh->is_serial())
112 {
113 const auto queries_tag = mesh->comm().get_unique_tag(),
114 replies_tag = mesh->comm().get_unique_tag();
115
116 std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
117
118 // Make all requests
119 for (processor_id_type p = 0; p != my_n_proc; ++p)
120 {
121 if (p == my_proc_id)
122 continue;
123
124 Parallel::Request & request = side_requests[p - (p > my_proc_id)];
125
126 mesh->comm().send(p, queries[p], request, queries_tag);
127 }
128
129 // Reply to all requests
130 std::vector<vec_type> responses(my_n_proc - 1);
131
132 for (processor_id_type p = 1; p != my_n_proc; ++p)
133 {
134 vec_type query;
135
136 Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
137 const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
138
139 mesh->comm().receive(source_pid, query, queries_tag);
140
141 Parallel::Request & request = reply_requests[p - 1];
142
143 for (const auto & q : query)
144 {
145 const Elem * elem = mesh->elem_ptr(q.first);
146 const unsigned int side = q.second;
147
148 _fe_face->reinit(elem, side);
149 // We'll just use the normal of the first qp
150 const Point & face_normal = _fe_face->get_normals()[0];
151 if (elemSideOnBoundary(elem, side) &&
152 elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
153 responses[p - 1].push_back(std::make_pair(elem->id(), side));
154 }
155
156 mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
157 }
158
159 // Process all incoming replies
160 for (processor_id_type p = 1; p != my_n_proc; ++p)
161 {
162 Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
163 const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
164
165 vec_type response;
166
167 this->comm().receive(source_pid, response, replies_tag);
168
169 for (const auto & r : response)
170 {
171 const Elem * elem = mesh->elem_ptr(r.first);
172 const unsigned int side = r.second;
173
174 if (_replace)
175 boundary_info.remove_side(elem, side);
176 for (const auto & boundary_id : boundary_ids)
177 boundary_info.add_side(elem, side, boundary_id);
178 }
179 }
180
181 Parallel::wait(side_requests);
182 Parallel::wait(reply_requests);
183 }
184
185 // Assign the supplied names to the newly created side sets
186 for (unsigned int i = 0; i < boundary_ids.size(); ++i)
187 boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
188
189 mesh->unset_is_prepared();
190 return dynamic_pointer_cast<MeshBase>(mesh);
191}
192
193bool
195 const unsigned int side) const
196{
197 const auto neighbor = elem->neighbor_ptr(side);
198 return (neighbor == nullptr) || (elem->subdomain_id() != neighbor->subdomain_id());
199}
registerMooseObject("MooseApp", SideSetsAroundSubdomainGenerator)
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 renameParam(const std::string &old_name, const std::string &new_name, const std::string &new_docstring)
Rename a parameter and provide a new documentation string.
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 makeParamRequired(const std::string &name)
Changes the parameter to be required.
Adds the faces on the boundary of given block to the sidesets specified by "boundary" Optionally,...
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
bool elemSideOnBoundary(const Elem *const elem, const unsigned int side) const
Determine whether the given side of an element resides on an external or internal boundary.
SideSetsAroundSubdomainGenerator(const InputParameters &parameters)
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...
const bool _check_subdomains
whether to check subdomain ids of the element in the (element, side, boundary id) tuple when adding s...
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< 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...
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
const Parallel::Communicator & comm() const
query_obj query
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.
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.