https://mooseframework.inl.gov
Loading...
Searching...
No Matches
StitchMeshGenerator.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
10#include "StitchMeshGenerator.h"
11
12#include "CastUniquePointer.h"
13#include "MooseUtils.h"
14#include "MooseMeshUtils.h"
15
16#include "libmesh/unstructured_mesh.h"
17
19 StitchedMeshGenerator,
20 "06/30/2026 24:00",
23
26{
28 params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs", "The input MeshGenerators.");
29 params.addParam<bool>("prevent_boundary_ids_overlap",
30 true,
31 "Whether to re-number boundaries in stitched meshes to prevent merging of "
32 "unrelated boundaries");
33 params.addParam<bool>(
34 "merge_boundaries_with_same_name",
35 true,
36 "If the input meshes have boundaries with the same name (but different IDs), merge them");
37 params.addParam<bool>(
38 "subdomain_remapping",
39 true,
40 "Treat input subdomain names as primary, preserving them and remapping IDs as needed");
41 params.addParam<bool>(
42 "verbose_stitching", false, "Whether mesh stitching should have verbose output.");
43 params.addParam<bool>(
44 "enforce_all_nodes_match_on_boundaries",
45 false,
46 "Whether to have the stitcher be very picky about the nodes being stitched.");
47 params.addParam<bool>("merge_boundary_nodes_all_or_nothing",
48 false,
49 "Whether the stitcher is set to merge all nodes or none.");
51 "Allows multiple mesh files to be stitched together to form a single mesh.");
52
53 // This is used for compatibility with TestSubGenerators
54 params.addPrivateParam<bool>("_check_inputs", true);
55 return params;
56}
57
59 : StitchMeshGeneratorBase(parameters),
60 _mesh_ptrs(getMeshes("inputs")),
61 _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
62 _prevent_boundary_ids_overlap(getParam<bool>("prevent_boundary_ids_overlap")),
63 _merge_boundaries_with_same_name(getParam<bool>("merge_boundaries_with_same_name"))
64{
65 // Check inputs
66 if (_input_names.size() - 1 != _stitch_boundaries_pairs.size() && getParam<bool>("_check_inputs"))
67 paramError("stitch_boundaries_pairs",
68 "Can only stitch one pair of boundary per pair of mesh. We have '" +
69 std::to_string(_input_names.size()) +
70 "' meshes specified (=" + std::to_string(_input_names.size() - 1) +
71 " pairs) and " + std::to_string(_stitch_boundaries_pairs.size()) +
72 " pairs of boundaries specified");
73 for (const auto & pair : _stitch_boundaries_pairs)
74 if (pair.size() != 2)
75 paramError("stitch_boundaries_pairs",
76 "Stitched boundary pair '" + Moose::stringify(pair) +
77 "' is not of length 2, but of length: " + std::to_string(pair.size()));
78}
79
80std::unique_ptr<MeshBase>
82{
83 // We put the first mesh in a local pointer
84 std::unique_ptr<UnstructuredMesh> mesh = dynamic_pointer_cast<UnstructuredMesh>(*_mesh_ptrs[0]);
85 if (!mesh) // This should never happen until libMesh implements on-the-fly-Elem mesh types
86 mooseError("StitchMeshGenerator is only implemented for unstructured meshes");
87
88 // Reserve spaces for the other meshes (no need to store the first one another time)
89 std::vector<std::unique_ptr<UnstructuredMesh>> meshes(_mesh_ptrs.size() - 1);
90
91 // Read in all of the other meshes
92 for (MooseIndex(_mesh_ptrs) i = 1; i < _mesh_ptrs.size(); ++i)
93 meshes[i - 1] = dynamic_pointer_cast<UnstructuredMesh>(*_mesh_ptrs[i]);
94
95 // Stitch all the meshes to the first one
96 for (MooseIndex(meshes) i = 0; i < meshes.size(); i++)
97 {
98 const auto boundary_pair = _stitch_boundaries_pairs[i];
99
100 // Check the input boundaries
101 const auto first = getBoundaryIdToStitch(
102 *mesh,
103 (_input_names.size() ? _input_names[0] : "(unknown)") +
104 ((i == 0) ? "" : (" (stitched with " + std::to_string(i) + " previous meshes)")),
105 boundary_pair[0]);
106 auto second = getBoundaryIdToStitch(*meshes[i], name(), boundary_pair[1]);
107
108 const bool use_binary_search = (_algorithm == "BINARY");
109
110 // Meshes must be prepared to get the global boundary ids
111 if (!mesh->is_prepared())
112 mesh->prepare_for_use();
113 if (!meshes[i]->is_prepared())
114 meshes[i]->prepare_for_use();
115
116 // Avoid chaotic boundary merging due to overlapping ids in meshes by simply renumbering the
117 // boundaries in the meshes we are going to stitch onto the base mesh
118 // This is only done if there is an overlap
120 {
121 const auto & base_mesh_bids = mesh->get_boundary_info().get_global_boundary_ids();
122 const auto stitched_mesh_bids = meshes[i]->get_boundary_info().get_global_boundary_ids();
123
124 // Check for an overlap
125 bool overlap_found = false;
126 for (const auto & bid : stitched_mesh_bids)
127 if (base_mesh_bids.count(bid))
128 overlap_found = true;
129
130 if (overlap_found)
131 {
132 const auto max_boundary_id =
133 std::max(*base_mesh_bids.rbegin(), *stitched_mesh_bids.rbegin());
134 BoundaryID new_index = 1;
135 for (const auto bid : stitched_mesh_bids)
136 {
137 const auto new_bid = max_boundary_id + (new_index++);
138 meshes[i]->get_boundary_info().renumber_id(bid, new_bid);
139 if (bid == second)
140 second = new_bid;
141 }
142 }
143 }
144 else
145 {
146 // If we don't have renumbering, we can get into situations where the same boundary ID is
147 // associated with different boundary names. In this case when we stitch, we assign the
148 // boundary name of the first mesh to the ID everywhere on the domain. We throw a warning
149 // here to warn the user if this is the case.
150 const auto & base_mesh_bids = mesh->get_boundary_info().get_global_boundary_ids();
151 const auto & other_mesh_bids = meshes[i]->get_boundary_info().get_global_boundary_ids();
152
153 // We check if the same ID is present with different names
154 std::set<boundary_id_type> bd_id_intersection;
155 std::set_intersection(base_mesh_bids.begin(),
156 base_mesh_bids.end(),
157 other_mesh_bids.begin(),
158 other_mesh_bids.end(),
159 std::inserter(bd_id_intersection, bd_id_intersection.begin()));
160
161 for (const auto bid : bd_id_intersection)
162 {
163 const auto & sideset_name_on_first_mesh = mesh->get_boundary_info().get_sideset_name(bid);
164 const auto & sideset_name_on_second_mesh =
165 meshes[i]->get_boundary_info().get_sideset_name(bid);
166
167 if (sideset_name_on_first_mesh != sideset_name_on_second_mesh)
169 "Boundary ID ",
170 bid,
171 " corresponds to different boundary names on the input meshes! On the first "
172 "mesh it corresponds to `",
173 sideset_name_on_first_mesh,
174 "` while on the second mesh it corresponds to `",
175 sideset_name_on_second_mesh,
176 "`. The final mesh will replace boundary `",
177 sideset_name_on_second_mesh,
178 "` with `",
179 sideset_name_on_first_mesh,
180 "`. To avoid this situation, use the `prevent_boundary_ids_overlap` parameter!");
181 }
182 }
183
184 mesh->stitch_meshes(*meshes[i],
185 first,
186 second,
187 getParam<Real>("stitching_hmin_tolerance_factor"),
189 getParam<bool>("verbose_stitching"),
190 use_binary_search,
191 /*enforce_all_nodes_match_on_boundaries=*/
192 getParam<bool>("enforce_all_nodes_match_on_boundaries"),
193 /*merge_boundary_nodes_all_or_nothing=*/
194 getParam<bool>("merge_boundary_nodes_all_or_nothing"),
195 getParam<bool>("subdomain_remapping"));
196
199 }
200
201 mesh->unset_is_prepared();
202 return dynamic_pointer_cast<MeshBase>(mesh);
203}
boundary_id_type BoundaryID
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
registerMooseObject("MooseApp", StitchMeshGenerator)
registerMooseObjectRenamed("MooseApp", StitchedMeshGenerator, "06/30/2026 24:00", StitchMeshGenerator)
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 addPrivateParam(const std::string &name, const T &value)
These method add a parameter to the InputParameters object which can be retrieved like any other para...
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.
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
A base class for mesh generators that stitch boundaries together.
static InputParameters validParams()
boundary_id_type getBoundaryIdToStitch(const MeshBase &mesh, const std::string &input_mg_name, const BoundaryName &bname) const
Get the boundary id from the name of a boundary to stitch.
const bool _clear_stitched_boundary_ids
Whether or not to clear (remove) the stitched boundary IDs.
const std::vector< std::vector< std::string > > _stitch_boundaries_pairs
A transformed version of _stitch_boundaries into a more logical "pairwise" structure.
const MooseEnum _algorithm
Type of algorithm used to find matching nodes (binary or exhaustive)
Allows multiple mesh files to be "stitched" together to form a single mesh.
std::vector< std::unique_ptr< MeshBase > * > _mesh_ptrs
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
StitchMeshGenerator(const InputParameters &parameters)
static InputParameters validParams()
const bool _merge_boundaries_with_same_name
Whether to merge boundaries if they have the same name but different boundary IDs.
const bool _prevent_boundary_ids_overlap
Whether to renumber all boundaries in stitched meshes to prevent accidental merging of sidesets with ...
const std::vector< MeshGeneratorName > & _input_names
The mesh generator inputs to read.
MeshBase & mesh
void mergeBoundaryIDsWithSameName(MeshBase &mesh)
Merges the boundary IDs of boundaries that have the same names but different IDs.
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64