https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
54std::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 // New nodes were added with non-contiguous IDs (DistributedMesh's
81 // unpartitioned counter strides by n_procs+1). Renumber so that
82 // max_node_id == n_nodes, which is required by non-parallel output formats.
83 if (mesh->allow_renumbering())
84 mesh->renumber_nodes_and_elements();
85
86 // We need to update the global_boundary_ids, and this is faster
87 // than a full prepare_for_use()
88 boundary_info.regenerate_id_sets();
89
90 return dynamic_pointer_cast<MeshBase>(mesh);
91}
92
95 std::unique_ptr<MeshBase> & mesh, const std::vector<SubdomainID> & subdomains) const
96{
97 NodeToElemMapType node_to_elem_map;
98 for (const auto & elem : mesh->active_element_ptr_range())
99 {
100 // Skip if subdomains are specified and the element is not in them
101 if (!subdomains.empty() &&
102 std::find(subdomains.begin(), subdomains.end(), elem->subdomain_id()) == subdomains.end())
103 continue;
104
105 std::set<const Elem *> neighbors;
106 elem->find_point_neighbors(neighbors);
107
108 for (auto n : make_range(elem->n_nodes()))
109 {
110 // if ANY neighboring element that contains this node is not in specified subdomains,
111 // don't add this node to the map, i.e. don't split this node.
112 bool should_duplicate = true;
113 if (!subdomains.empty())
114 for (auto neighbor : neighbors)
115 if (neighbor->contains_point(elem->node_ref(n)) &&
116 std::find(subdomains.begin(), subdomains.end(), neighbor->subdomain_id()) ==
117 subdomains.end())
118 {
119 should_duplicate = false;
120 break;
121 }
122
123 if (should_duplicate)
124 node_to_elem_map[elem->node_id(n)].insert(elem->id());
125 }
126 }
127
128 return node_to_elem_map;
129}
130
131void
132BreakMeshByElementGenerator::duplicateNodes(std::unique_ptr<MeshBase> & mesh,
133 const NodeToElemMapType & node_to_elem_map) const
134{
135 for (const auto & [node_id, connected_elem_ids] : node_to_elem_map)
136 for (auto & connected_elem_id : connected_elem_ids)
137 if (connected_elem_id != *connected_elem_ids.begin())
138 duplicateNode(mesh, mesh->elem_ptr(connected_elem_id), mesh->node_ptr(node_id));
139}
140
141void
142BreakMeshByElementGenerator::duplicateNode(std::unique_ptr<MeshBase> & mesh,
143 Elem * elem,
144 const Node * node) const
145{
146 std::unique_ptr<Node> new_node = Node::build(*node, Node::invalid_id);
147 Node * added_node = mesh->add_node(std::move(new_node));
148 added_node->processor_id() = elem->processor_id();
149 for (const auto j : elem->node_index_range())
150 if (elem->node_id(j) == node->id())
151 {
152 elem->set_node(j, added_node);
153 break;
154 }
155
156 // Add boundary info to the new node
157 BoundaryInfo & boundary_info = mesh->get_boundary_info();
158 std::vector<boundary_id_type> node_boundary_ids;
159 boundary_info.boundary_ids(node, node_boundary_ids);
160 boundary_info.add_node(added_node, node_boundary_ids);
161}
162
163void
165 const NodeToElemMapType & node_to_elem_map) const
166{
167 std::set<std::pair<dof_id_type, unsigned int>> sides_breaking;
168
169 for (const auto & node_to_elems : node_to_elem_map)
170 for (const auto & elem_id_i : node_to_elems.second)
171 {
172 Elem * elem_i = mesh.elem_ptr(elem_id_i);
173 for (const auto & elem_id_j : node_to_elems.second)
174 {
175 Elem * elem_j = mesh.elem_ptr(elem_id_j);
176 if (elem_i != elem_j && elem_i->has_neighbor(elem_j))
177 sides_breaking.insert(std::make_pair(elem_id_i, elem_i->which_neighbor_am_i(elem_j)));
178 }
179 }
180
182 {
183 BoundaryInfo & boundary_info = mesh.get_boundary_info();
184
185 const auto & existing_boundary_ids = boundary_info.get_boundary_ids();
186 const boundary_id_type interface_id =
187 existing_boundary_ids.empty() ? 0 : *existing_boundary_ids.rbegin() + 1;
188 boundary_info.sideset_name(interface_id) = _interface_name;
189
190 for (const auto & [elem_id, side] : sides_breaking)
191 if (_interface_sides > 1 || elem_id > mesh.elem_ptr(elem_id)->neighbor_ptr(side)->id())
192 boundary_info.add_side(elem_id, side, interface_id);
193 }
194
195 // Remove element neighbor connections on the broken sides
196 for (const auto & [elem_id, side] : sides_breaking)
197 mesh.elem_ref(elem_id).set_neighbor(side, nullptr);
198}
registerMooseObjectRenamed("MooseApp", ExplodeMeshGenerator, "05/18/2024 24:00", BreakMeshByElementGenerator)
registerMooseObject("MooseApp", BreakMeshByElementGenerator)
void ErrorVector unsigned int
BreakMeshByElementGenerator(const InputParameters &parameters)
void createInterface(MeshBase &mesh, const NodeToElemMapType &node_to_elem_map) const
const std::vector< SubdomainID > & _subdomains
std::map< const dof_id_type, std::set< dof_id_type > > NodeToElemMapType
std::unique_ptr< MeshBase > & _input
The mesh to modify.
NodeToElemMapType buildSubdomainRestrictedNodeToElemMap(std::unique_ptr< MeshBase > &mesh, const std::vector< SubdomainID > &subdomains) const
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
void duplicateNode(std::unique_ptr< MeshBase > &mesh, Elem *elem, const Node *node) const
void duplicateNodes(std::unique_ptr< MeshBase > &mesh, const NodeToElemMapType &node_to_elem_map) const
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
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.
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...
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 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.
static InputParameters validParams()
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:457
MeshBase & mesh
bool hasSubdomainID(const MeshBase &input_mesh, const SubdomainID &id)
Whether a particular subdomain ID exists in the mesh.
const BoundaryID INVALID_BOUNDARY_ID
Definition MooseTypes.C:22