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