www.mooseframework.org
RenameBlockGenerator.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
10 #include "RenameBlockGenerator.h"
11 
12 #include "CastUniquePointer.h"
13 #include "MooseMeshUtils.h"
14 
15 #include "libmesh/mesh_modification.h"
16 
18 
21 {
23 
24  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
25 
26  params.addDeprecatedParam<std::vector<SubdomainID>>(
27  "old_block_id",
28  "Elements with this block number will be given the new_block_number or "
29  "new_block_name. You must supply either old_block_id or old_block_name. "
30  "You may supply a vector of old_block_id, in which case the new_block "
31  "information must also be a vector.",
32  "Use 'old_block' instead of 'old_block_id'.");
33  params.addDeprecatedParam<std::vector<SubdomainName>>(
34  "old_block_name",
35  "Elements with this block name will be given the new_block_number or "
36  "new_block_name. You must supply either old_block_id or old_block_name. "
37  "You may supply a vector of old_block_name, in which case the new_block "
38  "information must also be a vector.",
39  "Use 'old_block' instead of 'old_block_name'.");
40  params.addDeprecatedParam<std::vector<SubdomainID>>(
41  "new_block_id",
42  "Elements with the old block number (or name) will be given this block "
43  "number. If the old blocks are named, their names will be passed onto the "
44  "newly numbered blocks.",
45  "Use 'new_block' instead of 'new_block_id'.");
46  params.addDeprecatedParam<std::vector<SubdomainName>>(
47  "new_block_name",
48  "Elements with the old block number (or name) will be given this block "
49  "name. No change of block ID is performed, unless multiple old blocks are "
50  "given the same name, in which case they are all given the first old block "
51  "number.",
52  "Use 'new_block' instead of 'new_block_name'.");
53 
54  params.addParam<std::vector<SubdomainName>>(
55  "old_block",
56  "Elements with these block ID(s)/name(s) will be given the new block information specified "
57  "in 'new_block'");
58  params.addParam<std::vector<SubdomainName>>(
59  "new_block",
60  "The new block ID(s)/name(s) to be given by the elements defined in 'old_block'.");
61 
62  params.addClassDescription("Changes the block IDs and/or block names for a given set of blocks "
63  "defined by either block ID or block name. The changes are "
64  "independent of ordering. The merging of blocks is supported.");
65 
66  return params;
67 }
68 
70  : MeshGenerator(parameters), _input(getMesh("input"))
71 {
72  if (isParamValid("old_block_id") && isParamValid("old_block_name"))
73  paramError("old_block_id",
74  "Cannot use in combination with 'old_block_name'. Please use 'old_block' "
75  "instead; 'old_block_id' and 'old_block_name' are deprecated.");
76  if (isParamValid("new_block_id") && isParamValid("new_block_name"))
77  paramError("new_block_id",
78  "Cannot use in combination with 'new_block_name'. Please use 'new_block' "
79  "instead; 'new_block_id' and 'new_block_name' are deprecated.");
80 
81  if (isParamValid("old_block"))
82  {
83  if (isParamValid("old_block_id"))
84  paramError("old_block_id",
85  "Cannot use with 'old_block'. Use only 'old_block'; 'old_block_id' is "
86  "deprecated.");
87  if (isParamValid("old_block_name"))
88  paramError("old_block_name",
89  "Cannot use with 'old_block'. Use only 'old_block'; 'old_block_name' is "
90  "deprecated.");
91  _old_block = getParam<std::vector<SubdomainName>>("old_block");
92  _old_block_param_name = "old_block";
93  }
94  else if (isParamValid("old_block_id"))
95  {
96  for (const auto id : getParam<std::vector<SubdomainID>>("old_block_id"))
97  _old_block.push_back(std::to_string(id));
98  _old_block_param_name = "old_block_id";
99  }
100  else
101  {
102  _old_block = isParamValid("old_block_name")
103  ? getParam<std::vector<SubdomainName>>("old_block_name")
104  : std::vector<SubdomainName>{};
105  _old_block_param_name = "old_block_name";
106  }
107 
108  std::string new_block_param_name;
109  if (isParamValid("new_block"))
110  {
111  if (isParamValid("new_block_id"))
112  paramError("new_block_id",
113  "Cannot use with 'new_block'. Use only 'new_block'; 'new_block_id' is "
114  "deprecated.");
115  if (isParamValid("new_block_name"))
116  paramError("new_block_name",
117  "Cannot use with 'new_block'. Use only 'new_block'; 'new_block_name' is "
118  "deprecated.");
119  _new_block = getParam<std::vector<SubdomainName>>("new_block");
120  new_block_param_name = "new_block";
121  }
122  else if (isParamValid("new_block_id"))
123  {
124  for (const auto id : getParam<std::vector<SubdomainID>>("new_block_id"))
125  _new_block.push_back(std::to_string(id));
126  new_block_param_name = "new_block_id";
127  }
128  else
129  {
130  _new_block = isParamValid("new_block_name")
131  ? getParam<std::vector<SubdomainName>>("new_block_name")
132  : std::vector<SubdomainName>{};
133  new_block_param_name = "new_block_name";
134  }
135 
136  if (_old_block.size() != _new_block.size())
137  paramError(new_block_param_name, "Must be the same length as '", _old_block_param_name, "'");
138 }
139 
140 std::unique_ptr<MeshBase>
142 {
143  std::unique_ptr<MeshBase> mesh = std::move(_input);
144 
145  // MeshBase::subdomain_name will insert, so we need a const ref
146  const MeshBase & const_mesh = *mesh;
147 
148  // Get the subdomains in the mesh (this is global)
149  std::set<subdomain_id_type> block_ids;
150  mesh->subdomain_ids(block_ids);
151 
152  // Helper for getting an unused block ID, and keeping track of it
153  // so that we can generate more later
154  auto get_unused_block_id = [this, &block_ids, &const_mesh]()
155  {
156  for (const auto id : make_range(Moose::INVALID_BLOCK_ID))
157  if (!block_ids.count(id) && !const_mesh.get_subdomain_name_map().count(id))
158  {
159  block_ids.insert(id);
160  return id;
161  }
162 
163  mooseError("Failed to find an unused ID!");
164  };
165 
166  const auto num_blocks = _old_block.size();
167 
168  // Helper for checking whether or not a SubdomainName (which could be an ID or a name)
169  // is really input as an ID
170  const auto is_subdomain_id = [](const SubdomainName & subdomain_name)
171  { return MooseUtils::isDigits(subdomain_name); };
172 
173  // Get the old block IDs and make sure they exist
174  std::vector<SubdomainID> old_block_ids(num_blocks, Moose::INVALID_BLOCK_ID);
175  std::vector<SubdomainName> old_block_names(num_blocks);
176  std::stringstream missing_block;
177  for (const auto i : make_range(num_blocks))
178  {
179  const SubdomainName & name = _old_block[i];
180 
181  // Convert the SubdomainName to an id and store
182  const auto id = MooseMeshUtils::getSubdomainID(name, *mesh);
183  old_block_ids[i] = id;
184 
185  // Block does not exist - store for a future error
186  if (!block_ids.count(id))
187  missing_block << name << " ";
188 
189  // Keep track of the block names
190  // If this SubdomainName is an ID, try to see if it has a name set
191  if (is_subdomain_id(name))
192  old_block_names[i] = const_mesh.subdomain_name(id);
193  // If this SubdomainName is a name, use said name
194  else
195  old_block_names[i] = name;
196  }
197  if (missing_block.str().size())
199  "The following blocks were requested to be renamed, but do not exist: ",
200  missing_block.str());
201 
202  // Get the block IDs that we're moving to
203  std::vector<SubdomainID> new_block_ids(num_blocks, Moose::INVALID_BLOCK_ID);
204  std::map<SubdomainID, std::string> new_names;
205  for (const auto i : make_range(num_blocks))
206  {
207  const SubdomainName & name = _new_block[i];
208 
209  // If the user input an ID, we have the ID
210  if (is_subdomain_id(name))
211  {
212  const auto id = MooseMeshUtils::getSubdomainID(name, *mesh);
213  new_block_ids[i] = id;
214 
215  // In the case that this is a new block ID, keep track of it so that we
216  // don't reuse it if we have to create temporaries
217  block_ids.insert(id);
218 
219  // Preserve the old block name if there was one
220  if (old_block_names[i].size())
221  new_names[id] = old_block_names[i];
222  }
223  // If the user input a name, we will use the ID that it is coming from for the
224  // "new" name if the new name does not name a current block. If the name does
225  // exist, we will merge with said block.
226  else
227  {
228  bool name_already_exists = false;
229 
230  // If the target block already exists, merge into that one
231  // Check both the old maps and the new map
232  for (const auto map : {&const_mesh.get_subdomain_name_map(),
233  const_cast<const std::map<SubdomainID, std::string> *>(&new_names)})
234  for (const auto & id_name_pair : *map)
235  if (!name_already_exists && id_name_pair.second == name)
236  {
237  new_block_ids[i] = id_name_pair.first;
238  new_names[id_name_pair.first] = name;
239  name_already_exists = true;
240  }
241 
242  // Target name doesn't exist, so use the source id/name
243  if (!name_already_exists)
244  {
245  new_block_ids[i] = old_block_ids[i];
246  new_names[new_block_ids[i]] = name;
247  }
248  }
249  }
250 
251  // Create temporaries if needed; recall that this generator is independent
252  // of input ordering and does _not_ merge subdomains.
253  //
254  // Take the example where we want to move 0 -> 1 and 1 -> 2. If we just
255  // move them in order, we will actually end up with (0, 1) -> 2. This is
256  // bad. In this case, we want to first make a temporary for 1 (call it 3).
257  // We then do: 0 -> 3, 1 -> 2, 3 -> 1 in order to get the desired behavior.
258  // We will accomplish this by creating temporaries as needed, modifying
259  // the initial move to the temporaries as needed, and then moving the
260  // temporaries back. temp_change_ids here are the (from -> to) pairs
261  // that we will move at the end.
262  auto temp_new_block_ids = new_block_ids;
263  std::vector<std::pair<SubdomainID, SubdomainID>> temp_change_ids;
264  // Loop through all new IDs
265  for (const auto new_i : make_range(num_blocks))
266  {
267  // Look at all of the old IDs that will be moved after the move to the new ID.
268  // If any of the old IDs after are IDs that we are moving to, create a temporary
269  // and keep track of it so we can move it back at the end.
270  for (const auto old_i : make_range(new_i + 1, num_blocks))
271  if (new_block_ids[new_i] == old_block_ids[old_i])
272  {
273  const auto temp_id = get_unused_block_id();
274  temp_change_ids.emplace_back(temp_id, new_block_ids[new_i]);
275  temp_new_block_ids[new_i] = temp_id;
276  break;
277  }
278  }
279 
280  // First pass through changing the block ids
281  for (const auto i : make_range(num_blocks))
282  MeshTools::Modification::change_subdomain_id(*mesh, old_block_ids[i], temp_new_block_ids[i]);
283  // Pass through moving the temporaries to the actual blocks, if necessary
284  for (const auto & pair : temp_change_ids)
285  MeshTools::Modification::change_subdomain_id(*mesh, pair.first, pair.second);
286 
287  // First go through and remove all of the old names
288  for (const auto i : make_range(num_blocks))
289  if (mesh->get_subdomain_name_map().count(old_block_ids[i]))
290  mesh->set_subdomain_name_map().erase(old_block_ids[i]);
291  // With the old names removed, add the new names if there are any to add
292  for (const auto & pair : new_names)
293  mesh->subdomain_name(pair.first) = pair.second;
294 
295  mesh->set_isnt_prepared();
296  return dynamic_pointer_cast<MeshBase>(mesh);
297 }
std::vector< SubdomainName > _old_block
The old blocks.
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
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.
MeshGenerator for re-numbering or re-naming blocks.
RenameBlockGenerator(const InputParameters &parameters)
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:56
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...
SubdomainID getSubdomainID(const SubdomainName &subdomain_name, const MeshBase &mesh)
Gets the subdomain ID associated with the given SubdomainName.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
const SubdomainID INVALID_BLOCK_ID
Definition: MooseTypes.C:22
std::unique_ptr< MeshBase > & _input
static InputParameters validParams()
std::string _old_block_param_name
The name of the parameter that specifies the old blocks.
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
std::unique_ptr< MeshBase > generate() override
Generate / modify 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 ...
static InputParameters validParams()
Definition: MeshGenerator.C:23
std::vector< SubdomainName > _new_block
The new blocks.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
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...
registerMooseObject("MooseApp", RenameBlockGenerator)
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
bool isDigits(const std::string &str)
Courtesy https://stackoverflow.com/a/8889045 and https://en.cppreference.com/w/cpp/string/byte/isdigi...
Definition: MooseUtils.h:1200
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32