https://mooseframework.inl.gov
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 
37  params.addClassDescription(
38  "Adds element faces that are on the exterior of the given block to the sidesets specified");
39 
40  return params;
41 }
42 
44  const InputParameters & parameters)
45  : SideSetsGeneratorBase(parameters)
46 {
47 }
48 
49 std::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
79  if (_check_subdomains &&
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 
193 bool
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 }
SideSetsAroundSubdomainGenerator(const InputParameters &parameters)
bool elementSubdomainIdInList(const Elem *const elem, const std::vector< subdomain_id_type > &subdomain_id_list)
Determines whether the given element&#39;s subdomain id is in the given subdomain_id_list.
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.
MPI_Request request
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...
std::unique_ptr< MeshBase > & _input
the mesh to add the sidesets to
Point _normal
if specified, then faces are only added if their normal is close to this
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...
const Parallel::Communicator & comm() const
std::vector< BoundaryName > _boundary_names
The list of new boundary names.
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn&#39;t required or valid in the derived class...
MPI_Status status
uint8_t processor_id_type
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
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< 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.
static InputParameters validParams()
query_obj query
const bool _check_subdomains
whether to check subdomain ids of the element in the (element, side, boundary id) tuple when adding s...
IntRange< T > make_range(T beg, T end)
registerMooseObject("MooseApp", SideSetsAroundSubdomainGenerator)
void makeParamRequired(const std::string &name)
Changes the parameter to be required.
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...
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...
Adds the faces on the boundary of given block to the sidesets specified by "boundary" Optionally...
std::unique_ptr< libMesh::FEBase > _fe_face
void setup(MeshBase &mesh)
This method is used to construct the FE object so we can compute normals of faces.
const RemoteElem * remote_elem