https://mooseframework.inl.gov
SidesetAroundSubdomainUpdater.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 "DisplacedProblem.h"
12 #include "Assembly.h"
13 
14 #include "libmesh/parallel_algebra.h"
15 #include "libmesh/parallel_sync.h"
16 
18 
21 {
23  params.addClassDescription("Sets up a boundary between inner_subdomains and outer_subdomains");
24  params.addParam<std::vector<SubdomainName>>("inner_subdomains",
25  "Subdomains that own the boundary");
26  params.addParam<std::vector<SubdomainName>>("outer_subdomains",
27  "Subdomains on the outside of the boundary");
28  params.addParam<BoundaryName>("mask_side",
29  "If specified, only add sides where this sideset exists.");
30  params.addParam<bool>("assign_outer_surface_sides",
31  true,
32  "Assign sides of elements im `inner_subdomains` that have no neighbor.");
33  params.addRequiredParam<BoundaryName>("update_sideset_name",
34  "The name of the sideset to be updated. If the boundary "
35  "does not exist it will be added to the system.");
36  params.renameParam(
37  "update_sideset_name", "update_boundary_name", "The boundary name which is updated.");
38  params.addParam<BoundaryID>("update_sideset_id",
40  "The ID of the sideset to be updated. If the boundary "
41  "does not exist it will be added to the system.");
42  params.renameParam(
43  "update_sideset_id", "update_boundary_id", "The boundary id which is updated.");
44  params.registerBase("MeshModifier");
45  params.addParam<bool>("verbose", false, "Whether to output some information during execution");
46  return params;
47 }
48 
50  : DomainUserObject(parameters),
51  _pid(_communicator.rank()),
52  _displaced_problem(_fe_problem.getDisplacedProblem().get()),
53  _neighbor_side(_assembly.neighborSide()),
54  _assign_outer_surface_sides(getParam<bool>("assign_outer_surface_sides")),
55  _boundary_name(getParam<BoundaryName>("update_boundary_name")),
56  _boundary_id(_mesh.getBoundaryID(_boundary_name)),
57  _mask_side(isParamValid("mask_side") ? _mesh.getBoundaryID(getParam<BoundaryName>("mask_side"))
59  _boundary_info(_mesh.getMesh().get_boundary_info()),
60  _displaced_boundary_info(
61  _displaced_problem ? &_displaced_problem->mesh().getMesh().get_boundary_info() : nullptr)
62 {
63  // subdomains
64  const auto & inner_subdomains = getParam<std::vector<SubdomainName>>("inner_subdomains");
65  const auto & outer_subdomains = getParam<std::vector<SubdomainName>>("outer_subdomains");
66  for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), inner_subdomains))
67  _inner_ids.insert(id);
68  for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), outer_subdomains))
69  _outer_ids.insert(id);
70  std::set<SubdomainID> mesh_subdomains = _mesh.meshSubdomains();
71 
72  for (const auto & id : _inner_ids)
73  if (mesh_subdomains.find(id) == mesh_subdomains.end())
74  paramError("inner_subdomains", "The block '", id, "' was not found in the mesh");
75  for (const auto & id : _outer_ids)
76  if (mesh_subdomains.find(id) == mesh_subdomains.end())
77  paramError("outer_subdomains", "The block '", id, "' was not found in the mesh");
78 
79  // save boundary name
83  {
86  }
88  mooseDoOnce(
89  mooseWarning("The user has selected 'construct_node_list_from_side_list' as false, but "
90  "SidesetAroundSubdomainUpdate is building node lists from the side lists."));
91 }
92 
93 void
94 SidesetAroundSubdomainUpdater::executeOnExternalSide(const Elem * elem, unsigned int side)
95 {
96  // we should add the sideset only of the current element is in the "inner" set _and_ the user set
97  // assign_surface_sides
98  if (_inner_ids.count(elem->subdomain_id()))
99  {
100  if (_assign_outer_surface_sides && !_boundary_info.has_boundary_id(elem, side, _boundary_id) &&
102  _boundary_info.has_boundary_id(elem, side, _mask_side)))
103  _add[_pid].emplace_back(elem->id(), side);
104  }
105  else
106  {
107  if (_boundary_info.has_boundary_id(elem, side, _boundary_id))
108  _remove[_pid].emplace_back(elem->id(), side);
109  }
110 }
111 
112 void
114 {
117 }
118 
119 void
121  unsigned short int primary_side,
122  const Elem * secondary_elem)
123 {
124  // undisplaced mesh
125  if (_inner_ids.count(primary_elem->subdomain_id()) &&
126  _outer_ids.count(secondary_elem->subdomain_id()))
127  {
128 
129  // we are on an inner element facing an outer element->add boundary
130  if ((!_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id)) &&
132  _boundary_info.has_boundary_id(primary_elem, primary_side, _mask_side)))
133  _add[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
134  }
135  else
136  {
137  // we are on an outer, between inner elements, or other elements etc., delete
138  // the boundary for sure
139  if (_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id))
140  _remove[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
141  }
142 }
143 
144 void
146 {
147  _add.clear();
148  _remove.clear();
149 }
150 
151 void
153 {
154  const auto & sas = static_cast<const SidesetAroundSubdomainUpdater &>(uo);
155 
156  for (const auto & [pid, list] : sas._add)
157  _add[pid].insert(_add[pid].end(), list.begin(), list.end());
158 
159  for (const auto & [pid, list] : sas._remove)
160  _remove[pid].insert(_remove[pid].end(), list.begin(), list.end());
161 }
162 
163 void
165 {
166  const auto & mesh = _mesh.getMesh();
167  const auto * displaced_mesh =
169  if (getParam<bool>("verbose"))
170  {
171  unsigned int total_remove = 0, total_add = 0;
172  for (const auto & [pid, list] : _remove)
173  total_remove += _remove[pid].size();
174  for (const auto & [pid, list] : _add)
175  total_add += _add[pid].size();
176  comm().sum(total_remove);
177  comm().sum(total_add);
178 
179  if (total_remove)
180  _console << "Removing " << total_remove << " sides from sideset " << _boundary_id
181  << std::endl;
182  if (total_add)
183  _console << "Adding " << total_add << " sides to sideset " << _boundary_id << std::endl;
184  }
185 
186  auto add_functor = [this, &mesh, &displaced_mesh](const processor_id_type, const auto & sent_data)
187  {
188  for (auto & [elem_id, side] : sent_data)
189  {
190  _boundary_info.add_side(mesh.elem_ptr(elem_id), side, _boundary_id);
192  _displaced_boundary_info->add_side(displaced_mesh->elem_ptr(elem_id), side, _boundary_id);
193  }
194  };
195 
196  auto remove_functor =
197  [this, &mesh, &displaced_mesh](const processor_id_type, const SideList & sent_data)
198  {
199  for (const auto & [elem_id, side] : sent_data)
200  {
201  const auto elem = mesh.elem_ptr(elem_id);
202  _boundary_info.remove_side(elem, side, _boundary_id);
203  for (const auto local_node_id : elem->nodes_on_side(side))
204  _boundary_info.remove_node(elem->node_ptr(local_node_id), _boundary_id);
206  {
207  const auto displaced_elem = displaced_mesh->elem_ptr(elem_id);
208  _displaced_boundary_info->remove_side(displaced_elem, side, _boundary_id);
209  for (const auto local_node_id : displaced_elem->nodes_on_side(side))
210  _displaced_boundary_info->remove_node(displaced_elem->node_ptr(local_node_id),
211  _boundary_id);
212  }
213  }
214  };
215 
216  // communicate and act on remote and local changes
219 
220  auto sync = [](auto & mesh)
221  {
222  mesh.getMesh().get_boundary_info().parallel_sync_side_ids();
223  mesh.getMesh().get_boundary_info().parallel_sync_node_ids();
224  mesh.getMesh().get_boundary_info().build_node_list_from_side_list();
225  mesh.update();
226  };
227  sync(_mesh);
228  if (_displaced_problem)
229  sync(_displaced_problem->mesh());
230 
231  // Reinit equation systems
233  /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
234 }
virtual MooseMesh & mesh() override
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.
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
bool getConstructNodeListFromSideList()
Return construct node list from side list boolean.
Definition: MooseMesh.h:1409
MooseMesh & _mesh
the Moose mesh
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 ...
Definition: MooseBase.h:435
DisplacedProblem * _displaced_problem
Pointer to the displaced problem.
registerMooseObject("MooseApp", SidesetAroundSubdomainUpdater)
const BoundaryID INVALID_BOUNDARY_ID
Definition: MooseTypes.C:22
virtual void finalize() override
Finalize.
const Elem *const & _neighbor_elem
The neighboring element (available during executeOnInternalSide() and executeOnInterface()) ...
T * get(const std::unique_ptr< T > &u)
The MooseUtils::get() specializations are used to support making forwards-compatible code changes fro...
Definition: MooseUtils.h:1155
virtual void threadJoin(const UserObject &) override
Must override.
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
const Parallel::Communicator & _communicator
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.
This user object allows related evaluations on elements, boundaries, internal sides, interfaces in one single place.
std::set< SubdomainID > _inner_ids
Subdomains on the two sides of the boundary.
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...
std::vector< std::tuple< dof_id_type, unsigned short int > > SideList
std::map< processor_id_type, SideList > _remove
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
Update side sets around subdomains during a run, as subdomain IDs are changing.
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
BoundaryName _boundary_name
Boundary / sideset to update.
void push_parallel_vector_data(const Communicator &comm, MapToVectors &&data, const ActionFunctor &act_on_data)
uint8_t processor_id_type
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3448
const unsigned int & _neighbor_side
Current side on the neighboring element.
boundary_id_type BoundaryID
static InputParameters validParams()
SidesetAroundSubdomainUpdater(const InputParameters &parameters)
const Elem *const & _current_elem
The current element pointer (available during all execute functions)
const bool _assign_outer_surface_sides
assign sideset to sides that have no neighbor elements
std::map< processor_id_type, SideList > _add
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
Definition: UserObject.h:211
virtual void initialize() override
Called before execute() is ever called so that data can be cleared.
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
Definition: MooseBase.h:295
virtual void executeOnInternalSide() override
execute method that is called during ComputeUserObjects::onInternalSide
void processSide(const Elem *primary_elem, unsigned short int primary_side, const Elem *secondary_elem)
const processor_id_type _pid
The MPI rank of this processor.
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 optional parameter and a documentation string to the InputParameters object...
const unsigned int & _current_side
Current side of the current element (available during executeOnInternalSide() and executeOnBoundary()...
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
virtual void executeOnExternalSide(const Elem *, unsigned int) override
execute method that is called during ComputeUserObjects::onExternalSide
Base class for user-specific data.
Definition: UserObject.h:40
const std::set< SubdomainID > & meshSubdomains() const
Returns a read-only reference to the set of subdomains currently present in the Mesh.
Definition: MooseMesh.C:3171
const BoundaryID _mask_side
If specified, only sides also on this boundary will be updated.