https://mooseframework.inl.gov
LowerDBlockFromSidesetGenerator.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 "CastUniquePointer.h"
14 #include "MooseMeshUtils.h"
15 
16 #include "libmesh/distributed_mesh.h"
17 #include "libmesh/elem.h"
18 #include "libmesh/parallel_elem.h"
19 #include "libmesh/parallel_node.h"
20 #include "libmesh/compare_elems_by_level.h"
21 #include "libmesh/mesh_communication.h"
22 
23 #include "timpi/parallel_sync.h"
24 
25 #include <set>
26 #include <typeinfo>
27 
29 
32 {
34 
35  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
36  params.addParam<SubdomainID>("new_block_id", "The lower dimensional block id to create");
37  params.addParam<SubdomainName>("new_block_name",
38  "The lower dimensional block name to create (optional)");
39  params.addRequiredParam<std::vector<BoundaryName>>(
40  "sidesets", "The sidesets from which to create the new block");
41 
42  params.addClassDescription("Adds lower dimensional elements on the specified sidesets.");
43 
44  return params;
45 }
46 
48  : MeshGenerator(parameters),
49  _input(getMesh("input")),
50  _sideset_names(getParam<std::vector<BoundaryName>>("sidesets"))
51 {
52 }
53 
54 // Used to temporarily store information about which lower-dimensional
55 // sides to add and what subdomain id to use for the added sides.
57 {
58  ElemSideDouble(Elem * elem_in, unsigned short int side_in) : elem(elem_in), side(side_in) {}
59 
60  Elem * elem;
61  unsigned short int side;
62 };
63 
64 std::unique_ptr<MeshBase>
66 {
67  std::unique_ptr<MeshBase> mesh = std::move(_input);
68 
69  // Generate a new block id if one isn't supplied.
70  SubdomainID new_block_id = isParamValid("new_block_id")
71  ? getParam<SubdomainID>("new_block_id")
73 
74  // Make sure our boundary info and parallel counts are setup
75  if (!mesh->is_prepared())
76  {
77  const bool allow_remote_element_removal = mesh->allow_remote_element_removal();
78  // We want all of our boundary elements available, so avoid removing them if they haven't
79  // already been so
80  mesh->allow_remote_element_removal(false);
81  mesh->prepare_for_use();
82  mesh->allow_remote_element_removal(allow_remote_element_removal);
83  }
84 
85  // Check that the sidesets are present in the mesh
86  for (const auto & sideset : _sideset_names)
88  paramError("sidesets", "The sideset '", sideset, "' was not found within the mesh");
89 
90  auto sideset_ids = MooseMeshUtils::getBoundaryIDs(*mesh, _sideset_names, true);
91  std::set<boundary_id_type> sidesets(sideset_ids.begin(), sideset_ids.end());
92  auto side_list = mesh->get_boundary_info().build_side_list();
93  if (!mesh->is_serial() && mesh->comm().size() > 1)
94  {
95  std::vector<Elem *> elements_to_send;
96  unsigned short i_need_boundary_elems = 0;
97  for (const auto & [elem_id, side, bc_id] : side_list)
98  {
99  libmesh_ignore(side);
100  if (sidesets.count(bc_id))
101  {
102  // Whether we have this boundary information through our locally owned element or a ghosted
103  // element, we'll need the boundary elements for parallel consistent addition
104  i_need_boundary_elems = 1;
105  auto * elem = mesh->elem_ptr(elem_id);
106  if (elem->processor_id() == mesh->processor_id())
107  elements_to_send.push_back(elem);
108  }
109  }
110 
111  std::set<const Elem *, libMesh::CompareElemIdsByLevel> connected_elements(
112  elements_to_send.begin(), elements_to_send.end());
113  std::set<const Node *> connected_nodes;
114  reconnect_nodes(connected_elements, connected_nodes);
115  std::set<dof_id_type> connected_node_ids;
116  for (auto * nd : connected_nodes)
117  connected_node_ids.insert(nd->id());
118 
119  std::vector<unsigned short> need_boundary_elems(mesh->comm().size());
120  mesh->comm().allgather(i_need_boundary_elems, need_boundary_elems);
121  std::unordered_map<processor_id_type, decltype(elements_to_send)> push_element_data;
122  std::unordered_map<processor_id_type, decltype(connected_nodes)> push_node_data;
123 
124  for (const auto pid : index_range(mesh->comm()))
125  // Don't need to send to self
126  if (pid != mesh->processor_id() && need_boundary_elems[pid])
127  {
128  if (elements_to_send.size())
129  push_element_data[pid] = elements_to_send;
130  if (connected_nodes.size())
131  push_node_data[pid] = connected_nodes;
132  }
133 
134  auto node_action_functor = [](processor_id_type, const auto &)
135  {
136  // Node packing specialization already has unpacked node into mesh, so nothing to do
137  };
138  Parallel::push_parallel_packed_range(
139  mesh->comm(), push_node_data, mesh.get(), node_action_functor);
140  auto elem_action_functor = [](processor_id_type, const auto &)
141  {
142  // Elem packing specialization already has unpacked elem into mesh, so nothing to do
143  };
145  mesh->comm(), push_element_data, mesh.get(), elem_action_functor);
146 
147  // now that we've gathered everything, we need to rebuild the side list
148  side_list = mesh->get_boundary_info().build_side_list();
149  }
150 
151  std::vector<std::pair<dof_id_type, ElemSideDouble>> element_sides_on_boundary;
152  dof_id_type counter = 0;
153  for (const auto & triple : side_list)
154  if (sidesets.count(std::get<2>(triple)))
155  {
156  if (auto elem = mesh->query_elem_ptr(std::get<0>(triple)))
157  {
158  if (!elem->active())
159  mooseError(
160  "Only active, level 0 elements can be made interior parents of new level 0 lower-d "
161  "elements. Make sure that ",
162  type(),
163  "s are run before any refinement generators");
164  element_sides_on_boundary.push_back(
165  std::make_pair(counter, ElemSideDouble(elem, std::get<1>(triple))));
166  }
167  ++counter;
168  }
169 
170  dof_id_type max_elem_id = mesh->max_elem_id();
171  unique_id_type max_unique_id = mesh->parallel_max_unique_id();
172 
173  // Making an important assumption that at least our boundary elements are the same on all
174  // processes even in distributed mesh mode (this is reliant on the correct ghosting functors
175  // existing on the mesh)
176  for (auto & [i, elem_side] : element_sides_on_boundary)
177  {
178  Elem * elem = elem_side.elem;
179 
180  const auto side = elem_side.side;
181 
182  // Build a non-proxy element from this side.
183  std::unique_ptr<Elem> side_elem(elem->build_side_ptr(side));
184 
185  // The side will be added with the same processor id as the parent.
186  side_elem->processor_id() = elem->processor_id();
187 
188  // Add subdomain ID
189  side_elem->subdomain_id() = new_block_id;
190 
191  // Also assign the side's interior parent, so it is always
192  // easy to figure out the Elem we came from.
193  side_elem->set_interior_parent(elem);
194 
195  // Add id
196  side_elem->set_id(max_elem_id + i);
197  side_elem->set_unique_id(max_unique_id + i);
198 
199  // Finally, add the lower-dimensional element to the Mesh.
200  mesh->add_elem(side_elem.release());
201  };
202 
203  // Assign block name, if provided
204  if (isParamValid("new_block_name"))
205  mesh->subdomain_name(new_block_id) = getParam<SubdomainName>("new_block_name");
206 
207  const bool skip_partitioning_old = mesh->skip_partitioning();
208  mesh->skip_partitioning(true);
209  mesh->prepare_for_use();
210  mesh->skip_partitioning(skip_partitioning_old);
211 
212  return mesh;
213 }
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the 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
void reconnect_nodes(connected_elem_set_type &connected_elements, connected_node_set_type &connected_nodes)
std::set< std::string > sideset
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
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::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
uint8_t processor_id_type
void libmesh_ignore(const Args &...)
registerMooseObject("MooseApp", LowerDBlockFromSidesetGenerator)
void push_parallel_packed_range(const Communicator &comm, MapToContainers &&data, Context *context, const ActionFunctor &act_on_data)
LowerDBlockFromSidesetGenerator(const InputParameters &parameters)
const std::string & type() const
Get the type of this class.
Definition: MooseBase.h:89
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()
Definition: MeshGenerator.C:23
ElemSideDouble(Elem *elem_in, unsigned short int side_in)
Creates lower-dimensional elements on the specified sidesets.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:267
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...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
const std::vector< BoundaryName > _sideset_names
a vector of the names of the sidesets to add the lower-D elements to
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
uint8_t unique_id_type
auto index_range(const T &sizable)
uint8_t dof_id_type