https://mooseframework.inl.gov
SideSetsBetweenSubdomainsGenerator.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/remote_elem.h"
18 
20 
23 {
25 
26  params.renameParam("included_subdomains",
27  "primary_block",
28  "The primary set of blocks for which to draw a sideset between");
29  params.makeParamRequired<std::vector<SubdomainName>>("primary_block");
30  params.renameParam("included_neighbors",
31  "paired_block",
32  "The paired set of blocks for which to draw a sideset between");
33  params.makeParamRequired<std::vector<SubdomainName>>("paired_block");
34  params.addClassDescription("MeshGenerator that creates a sideset composed of the nodes located "
35  "between two or more subdomains.");
36 
37  // TODO: Implement each of these in the generate() routine using utilities in SidesetGeneratorBase
38  params.suppressParameter<bool>("fixed_normal");
39  params.suppressParameter<bool>("include_only_external_sides");
40 
41  return params;
42 }
43 
45  const InputParameters & parameters)
46  : SideSetsGeneratorBase(parameters)
47 {
48 }
49 
50 std::unique_ptr<MeshBase>
52 {
53  std::unique_ptr<MeshBase> mesh = std::move(_input);
54 
55  // construct the FE object so we can compute normals of faces
56  setup(*mesh);
57 
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  for (const auto & elem : mesh->active_element_ptr_range())
75  {
76  // We only need to loop over elements in the primary subdomain
77  if (_check_subdomains &&
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 (neighbor != NULL)
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  // Add the boundaries
101  if (_replace)
102  boundary_info.remove_side(elem, side);
103  for (const auto & boundary_id : boundary_ids)
104  boundary_info.add_side(elem, side, boundary_id);
105  }
106  }
107  }
108  }
109 
110  if (!mesh->is_serial())
111  {
112  const auto queries_tag = mesh->comm().get_unique_tag(),
113  replies_tag = mesh->comm().get_unique_tag();
114 
115  std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
116 
117  // Make all requests
118  for (const auto & p : make_range(my_n_proc))
119  {
120  if (p == my_proc_id)
121  continue;
122 
123  Parallel::Request & request = side_requests[p - (p > my_proc_id)];
124 
125  mesh->comm().send(p, queries[p], request, queries_tag);
126  }
127 
128  // Reply to all requests
129  std::vector<vec_type> responses(my_n_proc - 1);
130 
131  for (const auto & p : make_range(uint(1), my_n_proc))
132  {
133  vec_type query;
134 
135  Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
136  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
137 
138  mesh->comm().receive(source_pid, query, queries_tag);
139 
140  Parallel::Request & request = reply_requests[p - 1];
141 
142  for (const auto & q : query)
143  {
144  const Elem * elem = mesh->elem_ptr(q.first);
145  const unsigned int side = q.second;
146  const Elem * neighbor = elem->neighbor_ptr(side);
147 
148  if (neighbor != NULL)
149  {
150  _fe_face->reinit(elem, side);
151  // We'll just use the normal of the first qp
152  const Point & face_normal = _fe_face->get_normals()[0];
153  // Add the boundaries, if appropriate
154  if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
155  responses[p - 1].push_back(std::make_pair(elem->id(), side));
156  }
157  }
158 
159  mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
160  }
161 
162  // Process all incoming replies
163  for (processor_id_type p = 1; p != my_n_proc; ++p)
164  {
165  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
166  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
167 
168  vec_type response;
169 
170  this->comm().receive(source_pid, response, replies_tag);
171 
172  for (const auto & r : response)
173  {
174  const Elem * elem = mesh->elem_ptr(r.first);
175  const unsigned int side = r.second;
176 
177  if (_replace)
178  boundary_info.remove_side(elem, side);
179  for (const auto & boundary_id : boundary_ids)
180  boundary_info.add_side(elem, side, boundary_id);
181  }
182  }
183 
184  Parallel::wait(side_requests);
185  Parallel::wait(reply_requests);
186  }
187 
188  for (const auto & i : make_range(boundary_ids.size()))
189  boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
190 
191  mesh->unset_is_prepared();
192  return dynamic_pointer_cast<MeshBase>(mesh);
193 }
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
registerMooseObject("MooseApp", SideSetsBetweenSubdomainsGenerator)
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()
SideSetsBetweenSubdomainsGenerator(const InputParameters &parameters)
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...
MeshGenerator that creates a sideset composed of the nodes located between two or more subdomains...
IntRange< T > make_range(T beg, T end)
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...
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