www.mooseframework.org
SideSetsAroundSubdomain.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 "MooseMesh.h"
14 
15 #include "libmesh/mesh.h"
16 #include "libmesh/remote_elem.h"
17 #include "libmesh/fe_base.h"
18 
20 
21 template <>
24 {
26  params.addRequiredParam<std::vector<BoundaryName>>(
27  "new_boundary", "The list of boundary IDs to create on the supplied subdomain");
28  params.addRequiredParam<std::vector<SubdomainName>>("block",
29  "The blocks around which to create sidesets");
30  params.addParam<Point>("normal",
31  "If supplied, only faces with normal equal to this, up to "
32  "normal_tol, will be added to the sidesets specified");
33  params.addRangeCheckedParam<Real>("normal_tol",
34  0.1,
35  "normal_tol>=0 & normal_tol<=2",
36  "If normal is supplied then faces are "
37  "only added if face_normal.normal_hat >= "
38  "1 - normal_tol, where normal_hat = "
39  "normal/|normal|");
40 
41  params.addClassDescription(
42  "Adds element faces that are on the exterior of the given block to the sidesets specified");
43  return params;
44 }
45 
47  : AddSideSetsBase(parameters),
48  _boundary_names(getParam<std::vector<BoundaryName>>("new_boundary")),
49  _using_normal(isParamValid("normal")),
50  _normal_tol(getParam<Real>("normal_tol")),
51  _normal(_using_normal ? getParam<Point>("normal") : Point())
52 {
53  if (_using_normal)
54  {
55  // normalize
56  mooseAssert(_normal.norm() >= 1E-5, "Normal is zero");
57  _normal /= _normal.norm();
58  }
59 }
60 
61 void
63 {
64  // Reference the the libMesh::MeshBase
65  MeshBase & mesh = _mesh_ptr->getMesh();
66 
67  // Extract the block ID
68  auto blocks = _mesh_ptr->getSubdomainIDs(getParam<std::vector<SubdomainName>>("block"));
69  std::set<SubdomainID> block_ids(blocks.begin(), blocks.end());
70 
71  // Create the boundary IDs from the list of names provided (the true flag creates ids from unknown
72  // names)
73  std::vector<BoundaryID> boundary_ids = _mesh_ptr->getBoundaryIDs(_boundary_names, true);
74 
75  // construct the FE object so we can compute normals of faces
76  setup();
77  Point face_normal;
78  bool add_to_bdy = true;
79 
80  // Get a reference to our BoundaryInfo object for later use
81  BoundaryInfo & boundary_info = mesh.get_boundary_info();
82 
83  // Prepare to query about sides adjacent to remote elements if we're
84  // on a distributed mesh
85  const processor_id_type my_n_proc = mesh.n_processors();
86  const processor_id_type my_proc_id = mesh.processor_id();
87  typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
88  std::vector<vec_type> queries(my_n_proc);
89 
90  // Loop over the elements
91  for (const auto & elem : mesh.active_element_ptr_range())
92  {
93  SubdomainID curr_subdomain = elem->subdomain_id();
94 
95  // We only need to loop over elements in the source subdomain
96  if (block_ids.count(curr_subdomain) == 0)
97  continue;
98 
99  for (unsigned int side = 0; side < elem->n_sides(); ++side)
100  {
101  const Elem * neighbor = elem->neighbor_ptr(side);
102 
103  // On a replicated mesh, we add all subdomain sides ourselves.
104  // On a distributed mesh, we may have missed sides which
105  // neighbor remote elements. We should query any such cases.
106  if (neighbor == remote_elem)
107  {
108  queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
109  }
110  else if (neighbor == nullptr || // element on boundary OR
111  block_ids.count(neighbor->subdomain_id()) ==
112  0) // neighboring element is on a different subdomain
113  {
114  if (_using_normal)
115  {
116  _fe_face->reinit(elem, side);
117  face_normal = _fe_face->get_normals()[0];
118  add_to_bdy = (_normal * face_normal >= 1.0 - _normal_tol);
119  }
120 
121  // Add the boundaries, if appropriate
122  if (add_to_bdy)
123  for (const auto & boundary_id : boundary_ids)
124  boundary_info.add_side(elem, side, boundary_id);
125  }
126  }
127  }
128 
129  if (!mesh.is_serial())
130  {
131  Parallel::MessageTag queries_tag = mesh.comm().get_unique_tag(867),
132  replies_tag = mesh.comm().get_unique_tag(5309);
133 
134  std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
135 
136  // Make all requests
137  for (processor_id_type p = 0; p != my_n_proc; ++p)
138  {
139  if (p == my_proc_id)
140  continue;
141 
142  Parallel::Request & request = side_requests[p - (p > my_proc_id)];
143 
144  mesh.comm().send(p, queries[p], request, queries_tag);
145  }
146 
147  // Reply to all requests
148  std::vector<vec_type> responses(my_n_proc - 1);
149 
150  for (processor_id_type p = 1; p != my_n_proc; ++p)
151  {
152  vec_type query;
153 
154  Parallel::Status status(mesh.comm().probe(Parallel::any_source, queries_tag));
155  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
156 
157  mesh.comm().receive(source_pid, query, queries_tag);
158 
159  Parallel::Request & request = reply_requests[p - 1];
160 
161  for (const auto & q : query)
162  {
163  const Elem * elem = mesh.elem_ptr(q.first);
164  const unsigned int side = q.second;
165  const Elem * neighbor = elem->neighbor_ptr(side);
166 
167  if (neighbor == nullptr || // element on boundary OR
168  block_ids.count(neighbor->subdomain_id()) ==
169  0) // neighboring element is on a different subdomain
170  {
171  if (_using_normal)
172  {
173  _fe_face->reinit(elem, side);
174  face_normal = _fe_face->get_normals()[0];
175  add_to_bdy = (_normal * face_normal >= 1.0 - _normal_tol);
176  }
177 
178  // Add the boundaries, if appropriate
179  if (add_to_bdy)
180  responses[p - 1].push_back(std::make_pair(elem->id(), side));
181  }
182  }
183 
184  mesh.comm().send(source_pid, responses[p - 1], request, replies_tag);
185  }
186 
187  // Process all incoming replies
188  for (processor_id_type p = 1; p != my_n_proc; ++p)
189  {
190  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
191  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
192 
193  vec_type response;
194 
195  this->comm().receive(source_pid, response, replies_tag);
196 
197  for (const auto & r : response)
198  {
199  const Elem * elem = mesh.elem_ptr(r.first);
200  const unsigned int side = r.second;
201 
202  for (const auto & boundary_id : boundary_ids)
203  boundary_info.add_side(elem, side, boundary_id);
204  }
205  }
206 
207  Parallel::wait(side_requests);
208  Parallel::wait(reply_requests);
209  }
210 
211  finalize();
212 
213  // Assign the supplied names to the newly created side sets
214  for (unsigned int i = 0; i < boundary_ids.size(); ++i)
215  boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
216 }
SideSetsAroundSubdomain(const InputParameters &parameters)
std::unique_ptr< FEBase > _fe_face
Point _normal
if specified, then faces are only added if their normal is close to this
InputParameters validParams< SideSetsAroundSubdomain >()
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
virtual void modify() override
Pure virtual modify function MUST be overridden by children classes.
void finalize()
This method finalizes the object, setting names back in the boundary_info object and releasing memory...
Real _normal_tol
if normal is specified, then faces are only added if face_normal.normal_hat <= 1 - normal_tol where n...
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
Definition: MooseObject.h:191
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...
MooseMesh * _mesh_ptr
Pointer to the mesh.
Definition: MeshModifier.h:68
bool _using_normal
true if only faces close to "normal" will be added
Adds the faces on the boundary of given block to the sidesets specified by "boundary" Optionally...
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:2567
subdomain_id_type SubdomainID
InputParameters validParams< AddSideSetsBase >()
MPI_Comm comm
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::vector< BoundaryID > getBoundaryIDs(const Elem *const elem, const unsigned short int side) const
Returns a vector of boundary IDs for the requested element on the requested side. ...
Definition: MooseMesh.C:2153
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...
std::vector< SubdomainID > getSubdomainIDs(const std::vector< SubdomainName > &subdomain_name) const
Get the associated subdomainIDs for the subdomain names that are passed in.
Definition: MooseMesh.C:1090
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
std::vector< BoundaryName > _boundary_names
names of the sidesets to which the faces will be added
void setup()
This method is used to construct the FE object so we can compute normals of faces.
registerMooseObject("MooseApp", SideSetsAroundSubdomain)