www.mooseframework.org
SideSetsBetweenSubdomainsGenerator.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
26  params.addParam<std::vector<SubdomainName>>(
27  "primary_block", "The primary set of blocks for which to draw a sideset between");
28  params.addDeprecatedParam<std::vector<SubdomainName>>(
29  "master_block",
30  "The primary set of blocks for which to draw a sideset between",
31  "The 'master_block' param is deprecated and will be removed on January 1, 2021. Please use "
32  "the 'primary_block' parameter instead.");
33  params.addRequiredParam<std::vector<SubdomainName>>(
34  "paired_block", "The paired set of blocks for which to draw a sideset between");
35  params.addRequiredParam<std::vector<BoundaryName>>("new_boundary",
36  "The name of the boundary to create");
37  params.addClassDescription("MeshGenerator that creates a sideset composed of the nodes located "
38  "between two or more subdomains.");
39 
40  return params;
41 }
42 
44  const InputParameters & parameters)
45  : MeshGenerator(parameters), _input(getMesh("input"))
46 {
47 }
48 
49 std::unique_ptr<MeshBase>
51 {
52  auto primary_block = isParamValid("primary_block")
53  ? getParam<std::vector<SubdomainName>>("primary_block")
54  : getParam<std::vector<SubdomainName>>("master_block");
55 
56  auto paired_block = getParam<std::vector<SubdomainName>>("paired_block");
57 
58  // Check that the block ids/names exist in the mesh
59  for (const auto & b : primary_block)
61  paramError("primary_block", "The block '", b, "' was not found within the mesh");
62 
63  for (const auto & b : paired_block)
65  paramError("paired_block", "The block '", b, "' was not found within the mesh");
66 
67  std::unique_ptr<MeshBase> mesh = std::move(_input);
68 
69  // Make sure that the mesh is prepared
70  if (!mesh->is_prepared())
71  mesh->find_neighbors();
72 
73  std::vector<subdomain_id_type> vec_primary_ids =
74  MooseMeshUtils::getSubdomainIDs(*mesh, primary_block);
75  std::set<subdomain_id_type> primary_ids(vec_primary_ids.begin(), vec_primary_ids.end());
76 
77  std::vector<subdomain_id_type> vec_paired_ids =
78  MooseMeshUtils::getSubdomainIDs(*mesh, paired_block);
79  std::set<subdomain_id_type> paired_ids(vec_paired_ids.begin(), vec_paired_ids.end());
80 
81  std::vector<BoundaryName> boundary_names = getParam<std::vector<BoundaryName>>("new_boundary");
82  std::vector<boundary_id_type> boundary_ids =
83  MooseMeshUtils::getBoundaryIDs(*mesh, boundary_names, true);
84 
85  // Get a reference to our BoundaryInfo object for later use
86  BoundaryInfo & boundary_info = mesh->get_boundary_info();
87 
88  // Prepare to query about sides adjacent to remote elements if we're
89  // on a distributed mesh
90  const processor_id_type my_n_proc = mesh->n_processors();
91  const processor_id_type my_proc_id = mesh->processor_id();
92  typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
93  std::vector<vec_type> queries(my_n_proc);
94 
95  for (const auto & elem : mesh->active_element_ptr_range())
96  {
97  subdomain_id_type curr_subdomain = elem->subdomain_id();
98 
99  // We only need to loop over elements in the primary subdomain
100  if (primary_ids.count(curr_subdomain) == 0)
101  continue;
102 
103  for (unsigned int side = 0; side < elem->n_sides(); side++)
104  {
105  const Elem * neighbor = elem->neighbor_ptr(side);
106 
107  // On a replicated mesh, we add all subdomain sides ourselves.
108  // On a distributed mesh, we may have missed sides which
109  // neighbor remote elements. We should query any such cases.
110  if (neighbor == remote_elem)
111  {
112  queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
113  }
114  else if (neighbor != NULL && paired_ids.count(neighbor->subdomain_id()) > 0)
115 
116  // Add the boundaries
117  for (const auto & boundary_id : boundary_ids)
118  boundary_info.add_side(elem, side, boundary_id);
119  }
120  }
121 
122  if (!mesh->is_serial())
123  {
124  const auto queries_tag = mesh->comm().get_unique_tag(),
125  replies_tag = mesh->comm().get_unique_tag();
126 
127  std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
128 
129  // Make all requests
130  for (processor_id_type p = 0; p != my_n_proc; ++p)
131  {
132  if (p == my_proc_id)
133  continue;
134 
135  Parallel::Request & request = side_requests[p - (p > my_proc_id)];
136 
137  mesh->comm().send(p, queries[p], request, queries_tag);
138  }
139 
140  // Reply to all requests
141  std::vector<vec_type> responses(my_n_proc - 1);
142 
143  for (processor_id_type p = 1; p != my_n_proc; ++p)
144  {
145  vec_type query;
146 
147  Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
148  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
149 
150  mesh->comm().receive(source_pid, query, queries_tag);
151 
152  Parallel::Request & request = reply_requests[p - 1];
153 
154  for (const auto & q : query)
155  {
156  const Elem * elem = mesh->elem_ptr(q.first);
157  const unsigned int side = q.second;
158  const Elem * neighbor = elem->neighbor_ptr(side);
159 
160  if (neighbor != NULL && paired_ids.count(neighbor->subdomain_id()) > 0)
161  {
162  responses[p - 1].push_back(std::make_pair(elem->id(), side));
163  }
164  }
165 
166  mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
167  }
168 
169  // Process all incoming replies
170  for (processor_id_type p = 1; p != my_n_proc; ++p)
171  {
172  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
173  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
174 
175  vec_type response;
176 
177  this->comm().receive(source_pid, response, replies_tag);
178 
179  for (const auto & r : response)
180  {
181  const Elem * elem = mesh->elem_ptr(r.first);
182  const unsigned int side = r.second;
183 
184  for (const auto & boundary_id : boundary_ids)
185  boundary_info.add_side(elem, side, boundary_id);
186  }
187  }
188 
189  Parallel::wait(side_requests);
190  Parallel::wait(reply_requests);
191  }
192 
193  for (unsigned int i = 0; i < boundary_ids.size(); ++i)
194  boundary_info.sideset_name(boundary_ids[i]) = boundary_names[i];
195 
196  mesh->set_isnt_prepared();
197  return dynamic_pointer_cast<MeshBase>(mesh);
198 }
MPI_Request request
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
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.
std::vector< subdomain_id_type > getSubdomainIDs(const libMesh::MeshBase &mesh, const std::vector< SubdomainName > &subdomain_name)
Get the associated subdomainIDs for the subdomain names that are passed in.
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
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
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
bool hasSubdomainName(MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain name exists in the mesh.
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.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
static InputParameters validParams()
Definition: MeshGenerator.C:23
SideSetsBetweenSubdomainsGenerator(const InputParameters &parameters)
query_obj query
MeshGenerator that creates a sideset composed of the nodes located between two or more subdomains...
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 addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
const RemoteElem * remote_elem