https://mooseframework.inl.gov
Loading...
Searching...
No Matches
CombinerGenerator.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 "CombinerGenerator.h"
11
12#include "CastUniquePointer.h"
13#include "MooseUtils.h"
14#include "DelimitedFileReader.h"
15#include "MooseMeshUtils.h"
16
17#include "libmesh/replicated_mesh.h"
18#include "libmesh/unstructured_mesh.h"
19#include "libmesh/mesh_modification.h"
20#include "libmesh/point.h"
21#include "libmesh/node.h"
22
24
27{
29
31 "Combine multiple meshes (or copies of one mesh) together into one (disjoint) mesh. Can "
32 "optionally translate those meshes before combining them.");
33
34 params.addRequiredParam<std::vector<MeshGeneratorName>>(
35 "inputs",
36 "The input MeshGenerators. This can either be N generators or 1 generator. If only 1 is "
37 "given then 'positions' must also be given.");
38
39 params.addParam<std::vector<Point>>(
40 "positions",
41 "The (optional) position of each given mesh. If N 'inputs' were given then this must either "
42 "be left blank or N positions must be given. If 1 input was given then this MUST be "
43 "provided.");
44
45 params.addParam<std::vector<FileName>>(
46 "positions_file", "Alternative way to provide the position of each given mesh.");
47
48 params.addParam<bool>("avoid_merging_subdomains",
49 false,
50 "Whether to prevent merging subdomains by offsetting ids. The first mesh "
51 "in the input will keep the same subdomains ids, the others will have "
52 "offsets. All subdomain names will remain valid");
53 params.addParam<bool>("avoid_merging_boundaries",
54 false,
55 "Whether to prevent merging sidesets by offsetting ids. The first mesh "
56 "in the input will keep the same boundary ids, the others will have "
57 "offsets. All boundary names will remain valid");
58
59 return params;
60}
61
63 : MeshGenerator(parameters),
64 _meshes(getMeshes("inputs")),
65 _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
66 _avoid_merging_subdomains(getParam<bool>("avoid_merging_subdomains")),
67 _avoid_merging_boundaries(getParam<bool>("avoid_merging_boundaries"))
68{
69 if (_input_names.empty())
70 paramError("input_names", "You need to specify at least one MeshGenerator as an input.");
71
72 if (isParamValid("positions") && isParamValid("positions_file"))
73 mooseError("Both 'positions' and 'positions_file' cannot be specified simultaneously in "
74 "CombinerGenerator ",
75 _name);
76
77 if (_input_names.size() == 1)
78 if (!isParamValid("positions") && !isParamValid("positions_file"))
79 paramError("positions",
80 "If only one input mesh is given, then 'positions' or 'positions_file' must also "
81 "be supplied");
82}
83
84void
86{
87 if (isParamValid("positions"))
88 {
89 _positions = getParam<std::vector<Point>>("positions");
90
91 // the check in the constructor wont catch error where the user sets positions = ''
92 if ((_input_names.size() == 1) && _positions.empty())
93 paramError("positions", "If only one input mesh is given, then 'positions' cannot be empty.");
94
95 if (_input_names.size() != 1)
96 if (_positions.size() && (_input_names.size() != _positions.size()))
98 "positions",
99 "If more than one input mesh is provided then the number of positions provided must "
100 "exactly match the number of input meshes.");
101 }
102 else if (isParamValid("positions_file"))
103 {
104 std::vector<FileName> positions_file = getParam<std::vector<FileName>>("positions_file");
105
106 // the check in the constructor wont catch error where the user sets positions_file = ''
107 if ((_input_names.size() == 1) && positions_file.empty())
108 paramError("positions_file",
109 "If only one input mesh is given, then 'positions_file' cannot be empty.");
110
111 for (const auto & f : positions_file)
112 {
115 file.read();
116
117 const std::vector<Point> & data = file.getDataAsPoints();
118
119 if (_input_names.size() != 1)
120 if (data.size() && (_input_names.size() != data.size()))
121 paramError("positions_file",
122 "If more than one input mesh is provided then the number of positions must "
123 "exactly match the number of input meshes.");
124
125 for (const auto & d : data)
126 _positions.push_back(d);
127 }
128 }
129}
130
131std::unique_ptr<MeshBase>
133{
134 // Two cases:
135 // 1. Multiple input meshes and optional positions
136 // 2. One input mesh and multiple positions
138
139 // Case 1
140 if (_meshes.size() != 1)
141 {
142 // merge all meshes into the first one
143 auto mesh = dynamic_pointer_cast<UnstructuredMesh>(*_meshes[0]);
144
145 if (!mesh)
146 paramError("inputs", _input_names[0], " is not a valid unstructured mesh");
147
148 // Move the first input mesh if applicable
149 if (_positions.size())
150 {
151 MeshTools::Modification::translate(
152 *mesh, _positions[0](0), _positions[0](1), _positions[0](2));
153 }
154
155 // Read in all of the other meshes
156 for (MooseIndex(_meshes) i = 1; i < _meshes.size(); ++i)
157 {
158 auto other_mesh = dynamic_pointer_cast<UnstructuredMesh>(*_meshes[i]);
159
160 if (!other_mesh)
161 paramError("inputs", _input_names[i], " is not a valid unstructured mesh");
162
163 // We'll be using cached subdomain sets in copyIntoMesh, so our
164 // const inputs need caches ready.
165 if (!other_mesh->preparation().has_cached_elem_data)
166 other_mesh->cache_elem_data();
167
168 // Move It
169 if (_positions.size())
170 {
171 MeshTools::Modification::translate(
172 *other_mesh, _positions[i](0), _positions[i](1), _positions[i](2));
173 }
174
176 *mesh,
177 *other_mesh,
181 }
182
183 mesh->unset_is_prepared();
184 return dynamic_pointer_cast<MeshBase>(mesh);
185 }
186 else // Case 2
187 {
188 auto input_mesh = dynamic_pointer_cast<UnstructuredMesh>(*_meshes[0]);
189
190 // We'll be using cached subdomain sets in copyIntoMesh
191 if (!input_mesh->preparation().has_cached_elem_data)
192 input_mesh->cache_elem_data();
193
194 if (!input_mesh)
195 paramError("inputs", _input_names[0], " is not a valid unstructured mesh");
196
197 // Make a copy and displace it in order to get the final mesh started
198 auto copy =
199 input_mesh->clone(); // This is required because dynamic_pointer_cast() requires an l-value
200 auto final_mesh = dynamic_pointer_cast<UnstructuredMesh>(copy);
201
202 if (!final_mesh)
203 mooseError("Unable to copy mesh!");
204
205 MeshTools::Modification::translate(
206 *final_mesh, _positions[0](0), _positions[0](1), _positions[0](2));
207
208 // Here's the way this is going to work:
209 // I'm going to make one more copy of the input_mesh so that I can move it and copy it in
210 // Then, after it's copied in I'm going to reset its coordinates by looping over the input_mesh
211 // and resetting the nodal positions.
212 // This could be done without the copy - you would translate the mesh then translate it back...
213 // However, I'm worried about floating point roundoff. If you were doing this 100,000 times or
214 // more then the mesh could "drift" away from its original position. I really want the
215 // translations to be exact each time.
216 // I suppose that it is technically possible to just save off a datastructure (map, etc.) that
217 // could hold the nodal positions only (instead of a copy of the mesh) but I'm not sure that
218 // would really save much... we'll see if it shows up in profiling somewhere
219 copy = input_mesh->clone();
220 auto translated_mesh = dynamic_pointer_cast<UnstructuredMesh>(copy);
221
222 if (!translated_mesh)
223 mooseError("Unable to copy mesh!");
224
225 for (MooseIndex(_meshes) i = 1; i < _positions.size(); ++i)
226 {
227 // Move
228 MeshTools::Modification::translate(
229 *translated_mesh, _positions[i](0), _positions[i](1), _positions[i](2));
230
231 // Copy into final mesh
233 *final_mesh,
234 *translated_mesh,
238
239 // Reset nodal coordinates
240 for (auto translated_node_ptr : translated_mesh->node_ptr_range())
241 {
242 auto & translated_node = *translated_node_ptr;
243 auto & input_node = input_mesh->node_ref(translated_node_ptr->id());
244
245 for (MooseIndex(LIBMESH_DIM) i = 0; i < LIBMESH_DIM; i++)
246 translated_node(i) = input_node(i);
247 }
248 }
249
250 final_mesh->unset_is_prepared();
251 return dynamic_pointer_cast<MeshBase>(final_mesh);
252 }
253}
registerMooseObject("MooseApp", CombinerGenerator)
Collects multiple meshes into a single (unconnected) mesh.
std::vector< Point > _positions
The (offsets) positions for each mesh.
const bool _avoid_merging_subdomains
Boolean to control whether to prevent merging subdomains.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
CombinerGenerator(const InputParameters &parameters)
void fillPositions()
Fill the offset positions for each mesh.
const std::vector< std::unique_ptr< MeshBase > * > _meshes
static InputParameters validParams()
const std::vector< MeshGeneratorName > & _input_names
The mesh generators to use.
const bool _avoid_merging_boundaries
Boolean to control whether to prevent merging boundaries.
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.
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
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
const std::string & _name
The name of this class.
Definition MooseBase.h:381
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
Utility class for reading delimited data (e.g., CSV data).
const std::vector< Point > getDataAsPoints() const
Get the data in Point format.
void read()
Perform the actual data reading.
const Parallel::Communicator & _communicator
MeshBase & mesh
void copyIntoMesh(MeshGenerator &mg, UnstructuredMesh &destination, const UnstructuredMesh &source, const bool avoid_merging_subdomains, const bool avoid_merging_boundaries, const Parallel::Communicator &communicator)
Helper function for copying one mesh into another.