www.mooseframework.org
StitchedMeshGenerator.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 "StitchedMeshGenerator.h"
11 
12 #include "CastUniquePointer.h"
13 #include "MooseUtils.h"
14 
15 #include "libmesh/unstructured_mesh.h"
16 
18 
21 {
23 
24  MooseEnum algorithm("BINARY EXHAUSTIVE", "BINARY");
25 
26  params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs", "The input MeshGenerators.");
27  params.addParam<bool>(
28  "clear_stitched_boundary_ids", true, "Whether or not to clear the stitched boundary IDs");
29  params.addRequiredParam<std::vector<std::vector<std::string>>>(
30  "stitch_boundaries_pairs",
31  "Pairs of boundaries to be stitched together between the 1st mesh in inputs and each "
32  "consecutive mesh");
33  params.addParam<MooseEnum>(
34  "algorithm",
35  algorithm,
36  "Control the use of binary search for the nodes of the stitched surfaces.");
37  params.addParam<bool>("prevent_boundary_ids_overlap",
38  true,
39  "Whether to re-number boundaries in stitched meshes to prevent merging of "
40  "unrelated boundaries");
41  params.addClassDescription(
42  "Allows multiple mesh files to be stitched together to form a single mesh.");
43 
44  return params;
45 }
46 
48  : MeshGenerator(parameters),
49  _mesh_ptrs(getMeshes("inputs")),
50  _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
51  _clear_stitched_boundary_ids(getParam<bool>("clear_stitched_boundary_ids")),
52  _stitch_boundaries_pairs(
53  getParam<std::vector<std::vector<std::string>>>("stitch_boundaries_pairs")),
54  _algorithm(parameters.get<MooseEnum>("algorithm")),
55  _prevent_boundary_ids_overlap(getParam<bool>("prevent_boundary_ids_overlap"))
56 {
57 }
58 
59 std::unique_ptr<MeshBase>
61 {
62  // We put the first mesh in a local pointer
63  std::unique_ptr<UnstructuredMesh> mesh = dynamic_pointer_cast<UnstructuredMesh>(*_mesh_ptrs[0]);
64  if (!mesh) // This should never happen until libMesh implements on-the-fly-Elem mesh types
65  mooseError("StitchedMeshGenerator is only implemented for unstructured meshes");
66 
67  // Reserve spaces for the other meshes (no need to store the first one another time)
68  std::vector<std::unique_ptr<UnstructuredMesh>> meshes(_mesh_ptrs.size() - 1);
69 
70  // Read in all of the other meshes
71  for (MooseIndex(_mesh_ptrs) i = 1; i < _mesh_ptrs.size(); ++i)
72  meshes[i - 1] = dynamic_pointer_cast<UnstructuredMesh>(*_mesh_ptrs[i]);
73 
74  // Stitch all the meshes to the first one
75  for (MooseIndex(meshes) i = 0; i < meshes.size(); i++)
76  {
77  auto boundary_pair = _stitch_boundaries_pairs[i];
78 
79  boundary_id_type first, second;
80 
81  try
82  {
83  first = MooseUtils::convert<boundary_id_type>(boundary_pair[0], true);
84  }
85  catch (...)
86  {
87  first = mesh->get_boundary_info().get_id_by_name(boundary_pair[0]);
88 
89  if (first == BoundaryInfo::invalid_id)
90  {
91  std::stringstream error;
92 
93  error << "Boundary " << boundary_pair[0] << " doesn't exist on mesh '" << _input_names[0]
94  << "' in generator " << name() << "\n";
95  error << "Boundary (sideset) names that do exist: \n";
96  error << " ID : Name\n";
97 
98  auto & sideset_id_name_map = mesh->get_boundary_info().get_sideset_name_map();
99 
100  for (auto & ss_name_map_pair : sideset_id_name_map)
101  error << " " << ss_name_map_pair.first << " : " << ss_name_map_pair.second << "\n";
102 
103  error << "\nBoundary (nodeset) names that do exist: \n";
104  error << " ID : Name\n";
105 
106  auto & nodeset_id_name_map = mesh->get_boundary_info().get_nodeset_name_map();
107 
108  for (auto & ns_name_map_pair : nodeset_id_name_map)
109  error << " " << ns_name_map_pair.first << " : " << ns_name_map_pair.second << "\n";
110 
111  paramError("stitch_boundaries_pairs", error.str());
112  }
113  }
114 
115  try
116  {
117  second = MooseUtils::convert<boundary_id_type>(boundary_pair[1], true);
118  }
119  catch (...)
120  {
121  second = meshes[i]->get_boundary_info().get_id_by_name(boundary_pair[1]);
122 
123  if (second == BoundaryInfo::invalid_id)
124  {
125  meshes[i]->print_info();
126 
127  std::stringstream error;
128 
129  error << "Boundary " << boundary_pair[1] << " doesn't exist on mesh '" << _input_names[i]
130  << "' in generator " << name() << "\n";
131  error << "Boundary (sideset) names that do exist: \n";
132  error << " ID : Name\n";
133 
134  auto & sideset_id_name_map = meshes[i]->get_boundary_info().get_sideset_name_map();
135 
136  for (auto & ss_name_map_pair : sideset_id_name_map)
137  error << " " << ss_name_map_pair.first << " : " << ss_name_map_pair.second << "\n";
138 
139  error << "\nBoundary (nodeset) names that do exist: \n";
140  error << " ID : Name\n";
141 
142  auto & nodeset_id_name_map = mesh->get_boundary_info().get_nodeset_name_map();
143 
144  for (auto & ns_name_map_pair : nodeset_id_name_map)
145  error << " " << ns_name_map_pair.first << " : " << ns_name_map_pair.second << "\n";
146 
147  paramError("stitch_boundaries_pairs", error.str());
148  }
149  }
150 
151  const bool use_binary_search = (_algorithm == "BINARY");
152 
153  // Avoid chaotic boundary merging due to overlapping ids in meshes by simply renumbering the
154  // boundaries in the meshes we are going to stitch onto the base mesh
155  // This is only done if there is an overlap
157  {
158  // Meshes must be prepared to get the global boundary ids and global boundary ids
159  // must be used in parallel to be sure to renumber boundaries consistently across processes
160  if (!mesh->is_prepared())
161  mesh->prepare_for_use();
162  if (!meshes[i]->is_prepared())
163  meshes[i]->prepare_for_use();
164 
165  const auto & base_mesh_bids = mesh->get_boundary_info().get_global_boundary_ids();
166  const auto stitched_mesh_bids = meshes[i]->get_boundary_info().get_global_boundary_ids();
167  // Check for an overlap
168  bool overlap_found = false;
169  for (const auto & bid : stitched_mesh_bids)
170  if (base_mesh_bids.count(bid))
171  overlap_found = true;
172 
173  if (overlap_found)
174  {
175  const auto max_boundary_id = *base_mesh_bids.rbegin();
176  BoundaryID new_index = 1;
177  for (const auto bid : stitched_mesh_bids)
178  {
179  const auto new_bid = max_boundary_id + (new_index++);
180  meshes[i]->get_boundary_info().renumber_id(bid, new_bid);
181  if (bid == second)
182  second = new_bid;
183  }
184  }
185  }
186 
187  mesh->stitch_meshes(*meshes[i],
188  first,
189  second,
190  TOLERANCE,
192  /*verbose = */ true,
193  use_binary_search);
194  }
195 
196  mesh->set_isnt_prepared();
197  return dynamic_pointer_cast<MeshBase>(mesh);
198 }
const bool _prevent_boundary_ids_overlap
Whether to renumber all boundaries in stitched meshes to prevent accidental merging of sidesets with ...
static InputParameters validParams()
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
T * get(const std::unique_ptr< T > &u)
The MooseUtils::get() specializations are used to support making forwards-compatible code changes fro...
Definition: MooseUtils.h:1147
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.
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:57
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::vector< std::vector< std::string > > _stitch_boundaries_pairs
A transformed version of _stitch_boundaries into a more logical "pairwise" structure.
int8_t boundary_id_type
std::vector< std::unique_ptr< MeshBase > * > _mesh_ptrs
boundary_id_type BoundaryID
StitchedMeshGenerator(const InputParameters &parameters)
const bool & _clear_stitched_boundary_ids
Whether or not to clear (remove) the stitched boundary IDs.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:31
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
const std::vector< MeshGeneratorName > & _input_names
The mesh generator inputs to read.
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...
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...
registerMooseObject("MooseApp", StitchedMeshGenerator)
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
Allows multiple mesh files to be "stitched" together to form a single mesh.
MooseEnum _algorithm
Type of algorithm used to find matching nodes (binary or exhaustive)