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 "MooseMeshUtils.h"
14 #include "CastUniquePointer.h"
15 
16 #include "libmesh/remote_elem.h"
17 
19 
22 {
24 
25  params.renameParam("included_subdomains",
26  "primary_block",
27  "The primary set of blocks for which to draw a sideset between");
28  params.makeParamRequired<std::vector<SubdomainName>>("primary_block");
29  params.renameParam("included_neighbors",
30  "paired_block",
31  "The paired set of blocks for which to draw a sideset between");
32  params.makeParamRequired<std::vector<SubdomainName>>("paired_block");
33  params.addClassDescription("MeshGenerator that creates a sideset composed of the nodes located "
34  "between two or more subdomains.");
35 
36  // TODO: Implement each of these in the generate() routine using utilities in SidesetGeneratorBase
37  params.suppressParameter<bool>("fixed_normal");
38  params.suppressParameter<bool>("include_only_external_sides");
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  std::vector<boundary_id_type> boundary_ids =
59 
60  // Get a reference to our BoundaryInfo object for later use
61  BoundaryInfo & boundary_info = mesh->get_boundary_info();
62 
63  // Prepare to query about sides adjacent to remote elements if we're
64  // on a distributed mesh
65  const processor_id_type my_n_proc = mesh->n_processors();
66  const processor_id_type my_proc_id = mesh->processor_id();
67  typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
68  std::vector<vec_type> queries(my_n_proc);
69 
70  // Request to compute normal vectors
71  const std::vector<Point> & face_normals = _fe_face->get_normals();
72 
73  for (const auto & elem : mesh->active_element_ptr_range())
74  {
75  // We only need to loop over elements in the primary subdomain
77  continue;
78 
79  for (const auto & side : make_range(elem->n_sides()))
80  {
81  const Elem * neighbor = elem->neighbor_ptr(side);
82 
83  // On a replicated mesh, we add all subdomain sides ourselves.
84  // On a distributed mesh, we may have missed sides which
85  // neighbor remote elements. We should query any such cases.
86  if (neighbor == remote_elem)
87  {
88  queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
89  }
90  else if (neighbor != NULL)
91  {
92  _fe_face->reinit(elem, side);
93  // We'll just use the normal of the first qp
94  const Point & face_normal = face_normals[0];
95  // Add the boundaries, if appropriate
96  if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
97  {
98  // Add the boundaries
99  if (_replace)
100  boundary_info.remove_side(elem, side);
101  for (const auto & boundary_id : boundary_ids)
102  boundary_info.add_side(elem, side, boundary_id);
103  }
104  }
105  }
106  }
107 
108  if (!mesh->is_serial())
109  {
110  const auto queries_tag = mesh->comm().get_unique_tag(),
111  replies_tag = mesh->comm().get_unique_tag();
112 
113  std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
114 
115  // Make all requests
116  for (const auto & p : make_range(my_n_proc))
117  {
118  if (p == my_proc_id)
119  continue;
120 
121  Parallel::Request & request = side_requests[p - (p > my_proc_id)];
122 
123  mesh->comm().send(p, queries[p], request, queries_tag);
124  }
125 
126  // Reply to all requests
127  std::vector<vec_type> responses(my_n_proc - 1);
128 
129  for (const auto & p : make_range(uint(1), my_n_proc))
130  {
131  vec_type query;
132 
133  Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
134  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
135 
136  mesh->comm().receive(source_pid, query, queries_tag);
137 
138  Parallel::Request & request = reply_requests[p - 1];
139 
140  for (const auto & q : query)
141  {
142  const Elem * elem = mesh->elem_ptr(q.first);
143  const unsigned int side = q.second;
144  const Elem * neighbor = elem->neighbor_ptr(side);
145 
146  if (neighbor != NULL)
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  // Add the boundaries, if appropriate
152  if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
153  responses[p - 1].push_back(std::make_pair(elem->id(), side));
154  }
155  }
156 
157  mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
158  }
159 
160  // Process all incoming replies
161  for (processor_id_type p = 1; p != my_n_proc; ++p)
162  {
163  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
164  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
165 
166  vec_type response;
167 
168  this->comm().receive(source_pid, response, replies_tag);
169 
170  for (const auto & r : response)
171  {
172  const Elem * elem = mesh->elem_ptr(r.first);
173  const unsigned int side = r.second;
174 
175  if (_replace)
176  boundary_info.remove_side(elem, side);
177  for (const auto & boundary_id : boundary_ids)
178  boundary_info.add_side(elem, side, boundary_id);
179  }
180  }
181 
182  Parallel::wait(side_requests);
183  Parallel::wait(reply_requests);
184  }
185 
186  for (const auto & i : make_range(boundary_ids.size()))
187  boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
188 
189  mesh->set_isnt_prepared();
190  return dynamic_pointer_cast<MeshBase>(mesh);
191 }
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.
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