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