https://mooseframework.inl.gov
Loading...
Searching...
No Matches
RenameBoundaryGenerator.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/mesh_modification.h"
15
16#include <set>
17#include <sstream>
18
20
23{
25
26 params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
27
28 params.addRequiredParam<std::vector<BoundaryName>>(
29 "old_boundary",
30 "Elements with these boundary ID(s)/name(s) will be given the new boundary information "
31 "specified in 'new_boundary'");
32 params.addRequiredParam<std::vector<BoundaryName>>(
33 "new_boundary",
34 "The new boundary ID(s)/name(s) to be given by the boundary elements defined in "
35 "'old_boundary'.");
36
38 "Changes the boundary IDs and/or boundary names for a given set of "
39 "boundaries defined by either boundary ID or boundary name. The "
40 "changes are independent of ordering. The merging of boundaries is supported.");
41
42 return params;
43}
44
46 : MeshGenerator(params), _input(getMesh("input"))
47{
48 _old_boundary = getParam<std::vector<BoundaryName>>("old_boundary");
49
50 _new_boundary = getParam<std::vector<BoundaryName>>("new_boundary");
51
52 if (_old_boundary.size() != _new_boundary.size())
53 paramError("new_boundary", "Must be the same length as 'old_boundary'");
54}
55
56std::unique_ptr<MeshBase>
58{
59 std::unique_ptr<MeshBase> mesh = std::move(_input);
60
61 auto & boundary_info = mesh->get_boundary_info();
62
63 // Get the current boundary IDs - take a copy so that we can also use it
64 // to keep track of boundaries that we add before adding them to nodes/sides
65 std::set<BoundaryID> boundary_ids = boundary_info.get_boundary_ids();
66 // Take the union just in case someone else has added new boundaries in a
67 // non-replicated manner
68 mesh->comm().set_union(boundary_ids);
69
70 // Helper for getting an unused boundary ID, and keeping track of it
71 // so that we can generate more later
72 auto get_unused_boundary_id = [this, &boundary_ids, &boundary_info]()
73 {
74 for (BoundaryID id = 0; id != Moose::INVALID_BOUNDARY_ID; ++id)
75 {
76 if (!boundary_ids.count(id) && !boundary_info.get_sideset_name_map().count(id) &&
77 !boundary_info.get_nodeset_name_map().count(id))
78 {
79 boundary_ids.insert(id);
80 return id;
81 }
82 }
83
84 mooseError("Failed to find an unused ID!");
85 };
86
87 // Helper for checking whether or not a BoundaryName (which could be an ID or a name)
88 // is really input as an ID
89 const auto is_boundary_id = [](const BoundaryName & boundary_name)
90 { return MooseUtils::isDigits(boundary_name); };
91
92 const auto num_boundaries = _old_boundary.size();
93
94 // Get the old boundary IDs and make sure they exist
95 std::vector<BoundaryID> old_boundary_ids(num_boundaries, Moose::INVALID_BOUNDARY_ID);
96 std::vector<std::string> old_boundary_names(num_boundaries);
97 std::stringstream missing_boundary;
98 for (const auto i : make_range(num_boundaries))
99 {
100 const BoundaryName & name = _old_boundary[i];
101
102 // Convert the BoundaryName to an id and store
103 const auto id = MooseMeshUtils::getBoundaryID(name, *mesh);
104 old_boundary_ids[i] = id;
105
106 // Boundary does not exist - store for a future error
107 if (!boundary_ids.count(id))
108 missing_boundary << name << " ";
109
110 // Keep track of the boundary names
111 // If this BoundaryName is an ID, try to see if it has a name set
112 if (is_boundary_id(name))
113 {
114 old_boundary_names[i] = boundary_info.get_sideset_name(id);
115 if (old_boundary_names[i].empty())
116 old_boundary_names[i] = boundary_info.get_nodeset_name(id);
117 }
118 // If this BoundaryName is a name, use said name
119 else
120 old_boundary_names[i] = name;
121 }
122 if (missing_boundary.str().size())
123 paramError("old_boundary",
124 "The following boundaries were requested to be renamed, but do not exist: ",
125 missing_boundary.str());
126
127 // Get the boundary IDs that we're moving to
128 std::vector<BoundaryID> new_boundary_ids(num_boundaries, Moose::INVALID_BOUNDARY_ID);
129 std::map<BoundaryID, std::string> new_names;
130 for (const auto i : make_range(num_boundaries))
131 {
132 const BoundaryName & name = _new_boundary[i];
133
134 // If the user input an ID, we have the ID
135 if (is_boundary_id(name))
136 {
137 const auto id = MooseMeshUtils::getBoundaryID(name, *mesh);
138 new_boundary_ids[i] = id;
139
140 // In the case that this is a new boundary ID, keep track of it so that we
141 // don't reuse it if we have to create temproraries
142 boundary_ids.insert(id);
143
144 // Preserve the old boundary name if there was one
145 if (old_boundary_names[i].size())
146 {
147 // if the name was the same as the ID, change the name as well
148 if (old_boundary_names[i] == std::to_string(old_boundary_ids[i]))
149 new_names[id] = std::to_string(new_boundary_ids[i]);
150 else
151 new_names[id] = old_boundary_names[i];
152 }
153 }
154 // If the user input a name, we will use the ID that it is coming from for the
155 // "new" name if the new name does not name a current boundary. If the name does
156 // exist, we will merge with said boundary.
157 else
158 {
159 bool name_already_exists = false;
160
161 // If the target boundary already exists, merge into that one
162 // Check both the old maps and the new map
163 for (const auto map : {&boundary_info.set_sideset_name_map(),
164 &boundary_info.set_nodeset_name_map(),
165 &new_names})
166 for (const auto & id_name_pair : *map)
167 if (!name_already_exists && id_name_pair.second == name)
168 {
169 new_boundary_ids[i] = id_name_pair.first;
170 new_names[id_name_pair.first] = name;
171 name_already_exists = true;
172 }
173
174 // Target name doesn't exist, so use the source id/name
175 if (!name_already_exists)
176 {
177 new_boundary_ids[i] = old_boundary_ids[i];
178 new_names[new_boundary_ids[i]] = name;
179 }
180 }
181 }
182
183 // Create temproraries if needed; recall that this generator is independent
184 // of input ordering and does _not_ merge sidesets.
185 //
186 // Take the example where we want to move 0 -> 1 and 1 -> 2. If we just
187 // move them in order, we will actually end up with (0, 1) -> 2. This is
188 // bad. In this case, we want to first make a temprorary for 1 (call it 3).
189 // We then do: 0 -> 3, 1 -> 2, 3 -> 1 in order to get the desired behavior.
190 // We will accomplish this by creating temproraries as needed, modifying
191 // the initial move to the temproraries as needed, and then moving the
192 // temproraries back. temp_change_ids here are the (from -> to) pairs
193 // that we will move at the end.
194 auto temp_new_boundary_ids = new_boundary_ids;
195 std::vector<std::pair<BoundaryID, BoundaryID>> temp_change_ids;
196 // Loop through all new IDs
197 for (const auto new_i : make_range(num_boundaries))
198 {
199 // Look at all of the old IDs that will be moved after the move to the new ID.
200 // If any of the old IDs after are IDs that we are moving to, create a temprorary
201 // and keep track of it so we can move it back at the end.
202 for (const auto old_i : make_range(new_i + 1, num_boundaries))
203 if (new_boundary_ids[new_i] == old_boundary_ids[old_i])
204 {
205 const auto temp_id = get_unused_boundary_id();
206 temp_change_ids.emplace_back(temp_id, new_boundary_ids[new_i]);
207 temp_new_boundary_ids[new_i] = temp_id;
208 break;
209 }
210 }
211
212 // First pass through changing the boundary ids
213 for (const auto i : make_range(num_boundaries))
214 MeshTools::Modification::change_boundary_id(
215 *mesh, old_boundary_ids[i], temp_new_boundary_ids[i]);
216
217 // Pass through moving the temproraries to the actual boundaries, if necessary
218 for (const auto & pair : temp_change_ids)
219 MeshTools::Modification::change_boundary_id(*mesh, pair.first, pair.second);
220
221 // First go through and remove all of the old names
222 for (const auto i : make_range(num_boundaries))
223 {
224 if (boundary_info.get_sideset_name_map().count(old_boundary_ids[i]))
225 boundary_info.set_sideset_name_map().erase(old_boundary_ids[i]);
226 if (boundary_info.get_nodeset_name_map().count(old_boundary_ids[i]))
227 boundary_info.set_nodeset_name_map().erase(old_boundary_ids[i]);
228 }
229
230 // With the old names removed, add the new names if there are any to add
231 for (const auto & pair : new_names)
232 {
233 boundary_info.sideset_name(pair.first) = pair.second;
234 boundary_info.nodeset_name(pair.first) = pair.second;
235 }
236
237 mesh->unset_is_prepared();
238 return dynamic_pointer_cast<MeshBase>(mesh);
239}
boundary_id_type BoundaryID
registerMooseObject("MooseApp", RenameBoundaryGenerator)
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...
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.
MeshGenerators are objects that can modify or add to an existing mesh.
static InputParameters validParams()
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
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
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:271
MeshGenerator for re-numbering or re-naming boundaries.
static InputParameters validParams()
std::unique_ptr< MeshBase > & _input
std::vector< BoundaryName > _old_boundary
The old boundaries.
RenameBoundaryGenerator(const InputParameters &parameters)
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
std::vector< BoundaryName > _new_boundary
The new boundaries.
MeshBase & mesh
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
const BoundaryID INVALID_BOUNDARY_ID
Definition MooseTypes.C:22