https://mooseframework.inl.gov
BreakMeshByElementGenerator.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 "CastUniquePointer.h"
12 #include "MooseMeshUtils.h"
13 
14 #include "libmesh/partitioner.h"
15 
18  ExplodeMeshGenerator,
19  "05/18/2024 24:00",
21 
24 {
26  params.addClassDescription("Break all element-element interfaces in the specified subdomains.");
27  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
28  params.addParam<std::vector<SubdomainID>>(
29  "subdomains",
30  std::vector<SubdomainID>(),
31  "The list of subdomain IDs to explode. Leave unset to explode all subdomains.");
32  params.addParam<BoundaryName>(
33  "interface_name",
34  "element_boundaries",
35  "The boundary name containing all broken element-element interfaces.");
36  params.addRangeCheckedParam<unsigned int>(
37  "interface_sides",
38  1,
39  "interface_sides<3",
40  "Whether to add no interface boundary, a 1-sided boundary (facing from lower to higher "
41  "element id), or a 2-sided boundary");
42  return params;
43 }
44 
46  : MeshGenerator(parameters),
47  _input(getMesh("input")),
48  _subdomains(getParam<std::vector<SubdomainID>>("subdomains")),
49  _interface_name(getParam<BoundaryName>("interface_name")),
50  _interface_sides(getParam<unsigned int>("interface_sides"))
51 {
52 }
53 
54 std::unique_ptr<MeshBase>
56 {
57  std::unique_ptr<MeshBase> mesh = std::move(_input);
58 
59  if (!mesh->is_prepared())
60  mesh->prepare_for_use();
61 
62  // check that the subdomain IDs exist in the mesh
63  for (const auto & id : _subdomains)
65  paramError("subdomains", "The block ID '", id, "' was not found in the mesh");
66 
67  BoundaryInfo & boundary_info = mesh->get_boundary_info();
68  if (_interface_sides &&
69  boundary_info.get_id_by_name(_interface_name) != Moose::INVALID_BOUNDARY_ID)
70  paramError("interface_name", "The specified interface name already exists in the mesh.");
71 
72  const auto node_to_elem_map = buildSubdomainRestrictedNodeToElemMap(mesh, _subdomains);
73 
74  duplicateNodes(mesh, node_to_elem_map);
75 
76  createInterface(*mesh, node_to_elem_map);
77 
78  Partitioner::set_node_processor_ids(*mesh);
79 
80  // We need to update the global_boundary_ids, and this is faster
81  // than a full prepare_for_use()
82  boundary_info.regenerate_id_sets();
83 
84  return dynamic_pointer_cast<MeshBase>(mesh);
85 }
86 
89  std::unique_ptr<MeshBase> & mesh, const std::vector<SubdomainID> & subdomains) const
90 {
91  NodeToElemMapType node_to_elem_map;
92  for (const auto & elem : mesh->active_element_ptr_range())
93  {
94  // Skip if subdomains are specified and the element is not in them
95  if (!subdomains.empty() &&
96  std::find(subdomains.begin(), subdomains.end(), elem->subdomain_id()) == subdomains.end())
97  continue;
98 
99  std::set<const Elem *> neighbors;
100  elem->find_point_neighbors(neighbors);
101 
102  for (auto n : make_range(elem->n_nodes()))
103  {
104  // if ANY neighboring element that contains this node is not in specified subdomains,
105  // don't add this node to the map, i.e. don't split this node.
106  bool should_duplicate = true;
107  if (!subdomains.empty())
108  for (auto neighbor : neighbors)
109  if (neighbor->contains_point(elem->node_ref(n)) &&
110  std::find(subdomains.begin(), subdomains.end(), neighbor->subdomain_id()) ==
111  subdomains.end())
112  {
113  should_duplicate = false;
114  break;
115  }
116 
117  if (should_duplicate)
118  node_to_elem_map[elem->node_id(n)].insert(elem->id());
119  }
120  }
121 
122  return node_to_elem_map;
123 }
124 
125 void
126 BreakMeshByElementGenerator::duplicateNodes(std::unique_ptr<MeshBase> & mesh,
127  const NodeToElemMapType & node_to_elem_map) const
128 {
129  for (const auto & [node_id, connected_elem_ids] : node_to_elem_map)
130  for (auto & connected_elem_id : connected_elem_ids)
131  if (connected_elem_id != *connected_elem_ids.begin())
132  duplicateNode(mesh, mesh->elem_ptr(connected_elem_id), mesh->node_ptr(node_id));
133 }
134 
135 void
136 BreakMeshByElementGenerator::duplicateNode(std::unique_ptr<MeshBase> & mesh,
137  Elem * elem,
138  const Node * node) const
139 {
140  std::unique_ptr<Node> new_node = Node::build(*node, Node::invalid_id);
141  new_node->processor_id() = elem->processor_id();
142  Node * added_node = mesh->add_node(std::move(new_node));
143  for (const auto j : elem->node_index_range())
144  if (elem->node_id(j) == node->id())
145  {
146  elem->set_node(j, added_node);
147  break;
148  }
149 
150  // Add boundary info to the new node
151  BoundaryInfo & boundary_info = mesh->get_boundary_info();
152  std::vector<boundary_id_type> node_boundary_ids;
153  boundary_info.boundary_ids(node, node_boundary_ids);
154  boundary_info.add_node(added_node, node_boundary_ids);
155 }
156 
157 void
159  const NodeToElemMapType & node_to_elem_map) const
160 {
161  std::set<std::pair<dof_id_type, unsigned int>> sides_breaking;
162 
163  for (const auto & node_to_elems : node_to_elem_map)
164  for (const auto & elem_id_i : node_to_elems.second)
165  {
166  Elem * elem_i = mesh.elem_ptr(elem_id_i);
167  for (const auto & elem_id_j : node_to_elems.second)
168  {
169  Elem * elem_j = mesh.elem_ptr(elem_id_j);
170  if (elem_i != elem_j && elem_i->has_neighbor(elem_j))
171  sides_breaking.insert(std::make_pair(elem_id_i, elem_i->which_neighbor_am_i(elem_j)));
172  }
173  }
174 
175  if (_interface_sides)
176  {
177  BoundaryInfo & boundary_info = mesh.get_boundary_info();
178 
179  const auto & existing_boundary_ids = boundary_info.get_boundary_ids();
180  const boundary_id_type interface_id =
181  existing_boundary_ids.empty() ? 0 : *existing_boundary_ids.rbegin() + 1;
182  boundary_info.sideset_name(interface_id) = _interface_name;
183 
184  for (const auto & [elem_id, side] : sides_breaking)
185  if (_interface_sides > 1 || elem_id > mesh.elem_ptr(elem_id)->neighbor_ptr(side)->id())
186  boundary_info.add_side(elem_id, side, interface_id);
187  }
188 
189  // Remove element neighbor connections on the broken sides
190  for (const auto & [elem_id, side] : sides_breaking)
191  mesh.elem_ref(elem_id).set_neighbor(side, nullptr);
192 }
std::map< const dof_id_type, std::set< dof_id_type > > NodeToElemMapType
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:30
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:439
NodeToElemMapType buildSubdomainRestrictedNodeToElemMap(std::unique_ptr< MeshBase > &mesh, const std::vector< SubdomainID > &subdomains) const
const BoundaryID INVALID_BOUNDARY_ID
Definition: MooseTypes.C:22
static InputParameters validParams()
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
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.
registerMooseObject("MooseApp", BreakMeshByElementGenerator)
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 hasSubdomainID(const MeshBase &input_mesh, const SubdomainID &id)
Whether a particular subdomain ID exists in the mesh.
int8_t boundary_id_type
std::unique_ptr< MeshBase > & _input
The mesh to modify.
static InputParameters validParams()
Definition: MeshGenerator.C:23
registerMooseObjectRenamed("MooseApp", ExplodeMeshGenerator, "05/18/2024 24:00", BreakMeshByElementGenerator)
void duplicateNode(std::unique_ptr< MeshBase > &mesh, Elem *elem, const Node *node) const
IntRange< T > make_range(T beg, T end)
void duplicateNodes(std::unique_ptr< MeshBase > &mesh, const NodeToElemMapType &node_to_elem_map) const
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
BreakMeshByElementGenerator(const InputParameters &parameters)
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 std::vector< SubdomainID > & _subdomains
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
void ErrorVector unsigned int
void createInterface(MeshBase &mesh, const NodeToElemMapType &node_to_elem_map) const