Line data Source code
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 "MeshGenerator.h"
11 : #include "MooseMesh.h"
12 : #include "MooseApp.h"
13 :
14 : #include "Exodus.h"
15 : #include "Nemesis.h"
16 :
17 : #include "libmesh/exodusII_io.h"
18 : #include "libmesh/nemesis_io.h"
19 :
20 : const std::string MeshGenerator::data_only_param = "_data_only";
21 :
22 : InputParameters
23 1471763 : MeshGenerator::validParams()
24 : {
25 1471763 : InputParameters params = MooseObject::validParams();
26 :
27 4415289 : params.addParam<bool>("show_info",
28 2943526 : false,
29 : "Whether or not to show mesh info after generating the mesh "
30 : "(bounding box, element types, sidesets, nodesets, subdomains, etc)");
31 4415289 : params.addParam<std::string>(
32 : "save_with_name",
33 2943526 : std::string(),
34 : "Keep the mesh from this mesh generator in memory with the name specified");
35 :
36 4415289 : params.addParam<bool>(
37 2943526 : "output", false, "Whether or not to output the mesh file after generating the mesh");
38 4415289 : params.addParam<bool>("nemesis",
39 2943526 : false,
40 : "Whether or not to output the mesh file in the nemesis"
41 : "format (only if output = true)");
42 :
43 1471763 : params.addParamNamesToGroup("show_info output nemesis", "Debugging");
44 1471763 : params.addParamNamesToGroup("save_with_name", "Advanced");
45 1471763 : params.registerBase("MeshGenerator");
46 :
47 1471763 : params.addPrivateParam<bool>("_has_generate_data", false);
48 1471763 : params.addPrivateParam<MooseMesh *>("_moose_mesh", nullptr);
49 1471763 : params.addPrivateParam<bool>(data_only_param, false);
50 : // Controls are not created early enough
51 1471763 : params.suppressParameter<std::vector<std::string>>("control_tags");
52 :
53 1471763 : return params;
54 0 : }
55 :
56 51015 : MeshGenerator::MeshGenerator(const InputParameters & parameters)
57 : : MooseObject(parameters),
58 : MeshMetaDataInterface(this),
59 102030 : _mesh(getParam<MooseMesh *>("_moose_mesh") ? getParam<MooseMesh *>("_moose_mesh")
60 51015 : : _app.actionWarehouse().mesh().get()),
61 51015 : _save_with_name(getParam<std::string>("save_with_name")),
62 153045 : _data_only(getParam<bool>(data_only_param))
63 : {
64 51015 : const auto & system = _app.getMeshGeneratorSystem();
65 51015 : if (isDataOnly())
66 : {
67 46 : if (!hasGenerateData())
68 4 : system.dataDrivenError(*this, "does not support data-driven generation");
69 42 : if (hasSaveMesh())
70 4 : system.dataDrivenError(*this, "has 'save_with_name' set");
71 : }
72 51007 : if (_save_with_name == system.mainMeshGeneratorName())
73 4 : paramError(
74 4 : "save_with_name", "The user-defined mesh name: '", _save_with_name, "' is a reserved name");
75 51003 : if (getParam<bool>("nemesis") && !getParam<bool>("output"))
76 0 : paramError("nemesis", "Should only be set to true if 'output=true'");
77 51003 : }
78 :
79 : void
80 28860 : MeshGenerator::setHasGenerateData(InputParameters & params)
81 : {
82 28860 : params.set<bool>("_has_generate_data") = true;
83 28860 : }
84 :
85 : bool
86 47937 : MeshGenerator::hasGenerateData(const InputParameters & params)
87 : {
88 47937 : return params.get<bool>("_has_generate_data");
89 : }
90 :
91 : const MeshGeneratorName *
92 23427 : MeshGenerator::getMeshGeneratorNameFromParam(const std::string & param_name,
93 : const bool allow_invalid) const
94 : {
95 23427 : const auto valid_param = isParamValid(param_name);
96 23427 : if (!allow_invalid)
97 : {
98 22775 : if (!valid_param)
99 4 : mooseError("Failed to get a parameter with the name \"",
100 : param_name,
101 : "\" when getting a MeshGenerator.",
102 : "\n\nKnown parameters:\n",
103 : _pars);
104 22771 : if (!_pars.isType<MeshGeneratorName>(param_name))
105 4 : paramError(param_name,
106 : "Parameter of type \"",
107 4 : _pars.type(param_name),
108 : "\" is not an expected type for getting a MeshGenerator (should be of type "
109 : "\"MeshGeneratorName\")");
110 : }
111 652 : else if (!valid_param)
112 638 : return nullptr;
113 :
114 22781 : const auto & name = getParam<MeshGeneratorName>(param_name);
115 22781 : checkGetMesh(name, param_name);
116 :
117 22773 : return &name;
118 : }
119 :
120 : const std::vector<MeshGeneratorName> &
121 1704 : MeshGenerator::getMeshGeneratorNamesFromParam(const std::string & param_name) const
122 : {
123 1704 : if (!isParamValid(param_name))
124 4 : mooseError("Failed to get a parameter with the name \"",
125 : param_name,
126 : "\" when getting MeshGenerators.",
127 : "\n\nKnown parameters:\n",
128 : _pars);
129 1700 : if (!_pars.isType<std::vector<MeshGeneratorName>>(param_name))
130 4 : paramError(param_name,
131 : "Parameter of type \"",
132 4 : _pars.type(param_name),
133 : "\" is not an expected type for getting MeshGenerators (should be of type "
134 : "\"std::vector<MeshGeneratorName>\")");
135 :
136 1696 : const auto & names = getParam<std::vector<MeshGeneratorName>>(param_name);
137 5858 : for (const auto & name : names)
138 4166 : checkGetMesh(name, param_name);
139 :
140 1692 : return names;
141 : }
142 :
143 : void
144 54608 : MeshGenerator::checkGetMesh(const MeshGeneratorName & mesh_generator_name,
145 : const std::string & param_name) const
146 : {
147 : mooseAssert(!mesh_generator_name.empty(), "Empty name");
148 54608 : const auto & mg_sys = _app.getMeshGeneratorSystem();
149 54608 : if (!_app.constructingMeshGenerators())
150 4 : mooseError("Cannot get a mesh outside of construction");
151 54604 : if (!mg_sys.hasMeshGenerator(mesh_generator_name) && !isNullMeshName(mesh_generator_name))
152 : {
153 20 : std::stringstream error;
154 20 : error << "The requested MeshGenerator with name '" << mesh_generator_name << "' ";
155 20 : if (mg_sys.hasMeshGeneratorParams(mesh_generator_name))
156 : error << "was found, but has not been constructed yet.\n\nThis can occur when your "
157 : "dependencies are not properly defined and we cannot infer the proper construction "
158 : "order of your MeshGenerators.\n\nThe most likely case is a sub generator whose "
159 4 : "input(s) are not declared as a sub dependency in the generator creating them.";
160 : else
161 : error << "was not found.\nMesh generators that can be found: "
162 16 : << Moose::stringify(mg_sys.getMeshGeneratorNames());
163 :
164 20 : if (param_name.size())
165 12 : paramError(param_name, error.str());
166 : else
167 8 : mooseError(error.str());
168 0 : }
169 54584 : }
170 :
171 : std::unique_ptr<MeshBase> &
172 23391 : MeshGenerator::getMesh(const std::string & param_name, const bool allow_invalid /* = false */)
173 : {
174 23391 : const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, allow_invalid);
175 23375 : if (!name)
176 638 : return _null_mesh;
177 22737 : return getMeshByName(*name);
178 : }
179 :
180 : std::vector<std::unique_ptr<MeshBase> *>
181 1704 : MeshGenerator::getMeshes(const std::string & param_name)
182 : {
183 1704 : return getMeshesByName(getMeshGeneratorNamesFromParam(param_name));
184 : }
185 :
186 : std::unique_ptr<MeshBase> &
187 27601 : MeshGenerator::getMeshByName(const MeshGeneratorName & mesh_generator_name)
188 : {
189 27601 : checkGetMesh(mesh_generator_name, "");
190 27589 : if (isNullMeshName(mesh_generator_name))
191 36 : return _null_mesh;
192 :
193 27553 : _requested_mesh_generators.insert(mesh_generator_name);
194 27553 : auto & mesh = _app.getMeshGeneratorSystem().getMeshGeneratorOutput(mesh_generator_name);
195 27553 : _requested_meshes.emplace_back(mesh_generator_name, &mesh);
196 27553 : return mesh;
197 : }
198 :
199 : std::vector<std::unique_ptr<MeshBase> *>
200 1696 : MeshGenerator::getMeshesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
201 : {
202 1696 : std::vector<std::unique_ptr<MeshBase> *> meshes;
203 5858 : for (const auto & name : mesh_generator_names)
204 4166 : meshes.push_back(&getMeshByName(name));
205 1692 : return meshes;
206 0 : }
207 :
208 : void
209 36 : MeshGenerator::declareMeshForSub(const std::string & param_name)
210 : {
211 36 : declareMeshForSubByName(*getMeshGeneratorNameFromParam(param_name, false));
212 36 : }
213 :
214 : void
215 0 : MeshGenerator::declareMeshesForSub(const std::string & param_name)
216 : {
217 0 : declareMeshesForSubByName(getMeshGeneratorNamesFromParam(param_name));
218 0 : }
219 :
220 : void
221 60 : MeshGenerator::declareMeshForSubByName(const MeshGeneratorName & mesh_generator_name)
222 : {
223 60 : checkGetMesh(mesh_generator_name, "");
224 60 : if (isNullMeshName(mesh_generator_name))
225 24 : return;
226 :
227 36 : _requested_mesh_generators_for_sub.insert(mesh_generator_name);
228 : }
229 :
230 : void
231 12 : MeshGenerator::declareMeshesForSubByName(
232 : const std::vector<MeshGeneratorName> & mesh_generator_names)
233 : {
234 24 : for (const auto & name : mesh_generator_names)
235 12 : declareMeshForSubByName(name);
236 12 : }
237 :
238 : std::unique_ptr<MeshBase>
239 24248 : MeshGenerator::buildMeshBaseObject(unsigned int dim)
240 : {
241 : mooseAssert(_mesh, "Need a MooseMesh object");
242 24248 : return _mesh->buildMeshBaseObject(dim);
243 : }
244 :
245 : std::unique_ptr<ReplicatedMesh>
246 682 : MeshGenerator::buildReplicatedMesh(unsigned int dim)
247 : {
248 : mooseAssert(_mesh, "Need a MooseMesh object");
249 682 : return _mesh->buildTypedMesh<ReplicatedMesh>(dim);
250 : }
251 :
252 : std::unique_ptr<DistributedMesh>
253 798 : MeshGenerator::buildDistributedMesh(unsigned int dim)
254 : {
255 : mooseAssert(_mesh, "Need a MooseMesh object");
256 798 : return _mesh->buildTypedMesh<DistributedMesh>(dim);
257 : }
258 :
259 : std::unique_ptr<MeshBase>
260 47891 : MeshGenerator::generateInternal()
261 : {
262 : libmesh_parallel_only(comm());
263 : mooseAssert(comm().verify(type() + name()), "Inconsistent execution ordering");
264 :
265 47891 : if (hasGenerateData())
266 86 : generateData();
267 :
268 47891 : if (isDataOnly())
269 30 : return nullptr;
270 :
271 47861 : auto mesh = generate();
272 47417 : if (!mesh)
273 4 : mooseError("A mesh was not generated by this generator (it was nullptr).");
274 :
275 72796 : for (const auto & [requested_name, requested_mesh] : _requested_meshes)
276 25387 : if (*requested_mesh)
277 4 : mooseError(
278 : "The mesh from input ",
279 4 : _app.getMeshGenerator(requested_name).type(),
280 : " '",
281 4 : _app.getMeshGenerator(requested_name).name(),
282 : "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
283 : "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
284 : "is achieved with a std::move() operation within the generate() method.");
285 :
286 47409 : if (getParam<bool>("show_info"))
287 : {
288 67 : const auto mesh_info = mesh->get_info(/* verbosity = */ 2);
289 :
290 : // We will prefix all information with "type() 'name()':" because this could potentially
291 : // output a ton of information and looks a bit better with a prefix
292 67 : std::stringstream oss;
293 67 : const auto split = MooseUtils::split(mesh_info, "\n");
294 67 : if (split.size())
295 4567 : for (std::size_t i = 0; i < split.size() - 1; ++i) // ignore the last line break
296 4500 : oss << COLOR_CYAN << "" << type() << " '" << name() << "': " << COLOR_DEFAULT << split[i]
297 4500 : << std::endl;
298 67 : _console << oss.str() << std::flush;
299 67 : }
300 :
301 : // output the current mesh block to file
302 47409 : if (hasOutput())
303 : {
304 315 : if (!mesh->is_prepared())
305 315 : mesh->prepare_for_use();
306 :
307 315 : if (!getParam<bool>("nemesis"))
308 : {
309 301 : libMesh::ExodusII_IO exio(*mesh);
310 :
311 301 : if (mesh->mesh_dimension() == 1)
312 10 : exio.write_as_dimension(3);
313 :
314 : // Default to non-HDF5 output for wider compatibility
315 301 : exio.set_hdf5_writing(false);
316 :
317 301 : exio.write(name() + "_in.e");
318 301 : }
319 : else
320 : {
321 14 : libMesh::Nemesis_IO nemesis_io(*mesh);
322 :
323 : // Default to non-HDF5 output for wider compatibility
324 14 : nemesis_io.set_hdf5_writing(false);
325 :
326 14 : nemesis_io.write(name() + "_in.e");
327 14 : }
328 : }
329 :
330 47409 : return mesh;
331 47409 : }
332 :
333 : void
334 208 : MeshGenerator::addMeshSubgenerator(const std::string & type,
335 : const std::string & name,
336 : InputParameters params)
337 : {
338 208 : if (!_app.constructingMeshGenerators())
339 4 : mooseError("Can only call addMeshSubgenerator() during MeshGenerator construction");
340 :
341 : // In case the user forgot it
342 204 : params.set<MooseApp *>("_moose_app") = &_app;
343 :
344 : // Set this to be data-only if this generator is data only
345 204 : params.set<bool>(data_only_param) = isDataOnly();
346 :
347 204 : _app.addMeshGenerator(type, name, params);
348 200 : _sub_mesh_generators.insert(&std::as_const(_app).getMeshGenerator(name));
349 200 : }
350 :
351 : RestartableDataValue &
352 24 : MeshGenerator::setMeshPropertyHelper(const std::string & data_name)
353 : {
354 24 : return _app.getRestartableMetaData(meshPropertyName(data_name), MooseApp::MESH_META_DATA, 0);
355 : }
356 :
357 : void
358 27305 : MeshGenerator::addParentMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
359 : {
360 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
361 27305 : _parent_mesh_generators.insert(&mg);
362 27305 : }
363 :
364 : void
365 27305 : MeshGenerator::addChildMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
366 : {
367 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
368 27305 : _child_mesh_generators.insert(&mg);
369 27305 : }
370 :
371 : bool
372 27315 : MeshGenerator::isParentMeshGenerator(const MeshGeneratorName & name,
373 : const bool direct /* = true */) const
374 : {
375 27315 : return std::find_if(getParentMeshGenerators().begin(),
376 27315 : getParentMeshGenerators().end(),
377 53239 : [&name, &direct](const auto & mg)
378 : {
379 53239 : return mg->name() == name ||
380 53239 : (!direct && mg->isParentMeshGenerator(name, /* direct = */ false));
381 54630 : }) != getParentMeshGenerators().end();
382 : }
383 :
384 : bool
385 4097 : MeshGenerator::isChildMeshGenerator(const MeshGeneratorName & name,
386 : const bool direct /* = true */) const
387 : {
388 4097 : return std::find_if(getChildMeshGenerators().begin(),
389 4097 : getChildMeshGenerators().end(),
390 6825 : [&name, &direct](const auto & mg)
391 : {
392 4986 : return mg->name() == name ||
393 4986 : (!direct && mg->isChildMeshGenerator(name, /* direct = */ false));
394 8194 : }) != getChildMeshGenerators().end();
395 : }
396 :
397 : void
398 12 : MeshGenerator::declareNullMeshName(const MeshGeneratorName & name)
399 : {
400 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
401 : mooseAssert(!_null_mesh_names.count(name), "Already declared");
402 12 : _null_mesh_names.insert(name);
403 12 : }
404 :
405 : bool
406 148963 : MeshGenerator::hasSaveMesh() const
407 : {
408 148963 : return _save_with_name.size();
409 : }
410 :
411 : bool
412 97664 : MeshGenerator::hasOutput() const
413 : {
414 97664 : return getParam<bool>("output");
415 : }
416 :
417 : const std::string &
418 142 : MeshGenerator::getSavedMeshName() const
419 : {
420 142 : return _save_with_name;
421 : }
422 :
423 : void
424 4 : MeshGenerator::generateData()
425 : {
426 : mooseAssert(!hasGenerateData(), "Inconsistent flag");
427 4 : mooseError("This MeshGenerator does not have a generateData() implementation.");
428 : }
|