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 474448 : MeshGenerator::validParams()
24 : {
25 474448 : InputParameters params = MooseObject::validParams();
26 :
27 1423344 : params.addParam<bool>("show_info",
28 948896 : false,
29 : "Whether or not to show mesh info after generating the mesh "
30 : "(bounding box, element types, sidesets, nodesets, subdomains, etc)");
31 1423344 : params.addParam<std::string>(
32 : "save_with_name",
33 948896 : std::string(),
34 : "Keep the mesh from this mesh generator in memory with the name specified");
35 :
36 1423344 : params.addParam<bool>(
37 948896 : "output", false, "Whether or not to output the mesh file after generating the mesh");
38 1423344 : params.addParam<bool>("nemesis",
39 948896 : false,
40 : "Whether or not to output the mesh file in the nemesis"
41 : "format (only if output = true)");
42 :
43 1897792 : params.addParamNamesToGroup("show_info output nemesis", "Debugging");
44 1897792 : params.addParamNamesToGroup("save_with_name", "Advanced");
45 474448 : params.registerBase("MeshGenerator");
46 :
47 948896 : params.addPrivateParam<bool>("_has_generate_data", false);
48 948896 : params.addPrivateParam<bool>("_has_generate_csg", false);
49 948896 : params.addPrivateParam<MooseMesh *>("_moose_mesh", nullptr);
50 474448 : params.addPrivateParam<bool>(data_only_param, false);
51 : // Controls are not created early enough
52 474448 : params.suppressParameter<std::vector<std::string>>("control_tags");
53 :
54 474448 : return params;
55 0 : }
56 :
57 56535 : MeshGenerator::MeshGenerator(const InputParameters & parameters)
58 : : MooseObject(parameters),
59 : MeshMetaDataInterface(this),
60 113070 : _mesh(getParam<MooseMesh *>("_moose_mesh") ? getParam<MooseMesh *>("_moose_mesh")
61 56535 : : _app.actionWarehouse().mesh().get()),
62 113070 : _save_with_name(getParam<std::string>("save_with_name")),
63 169605 : _data_only(getParam<bool>(data_only_param))
64 : {
65 56535 : const auto & system = _app.getMeshGeneratorSystem();
66 56535 : if (isDataOnly())
67 : {
68 : // Skip the requirement for generateData() if we are generating CSG object
69 248 : if (!hasGenerateCSG() && !hasGenerateData())
70 3 : system.dataDrivenError(*this, "does not support data-driven generation");
71 245 : if (hasSaveMesh())
72 3 : system.dataDrivenError(*this, "has 'save_with_name' set");
73 : }
74 56529 : if (_save_with_name == system.mainMeshGeneratorName())
75 3 : paramError(
76 3 : "save_with_name", "The user-defined mesh name: '", _save_with_name, "' is a reserved name");
77 169606 : if (getParam<bool>("nemesis") && !getParam<bool>("output"))
78 0 : paramError("nemesis", "Should only be set to true if 'output=true'");
79 56526 : }
80 :
81 : void
82 6409 : MeshGenerator::setHasGenerateData(InputParameters & params)
83 : {
84 6409 : params.set<bool>("_has_generate_data") = true;
85 6409 : }
86 :
87 : bool
88 53022 : MeshGenerator::hasGenerateData(const InputParameters & params)
89 : {
90 53022 : return params.get<bool>("_has_generate_data");
91 : }
92 :
93 : void
94 24880 : MeshGenerator::setHasGenerateCSG(InputParameters & params)
95 : {
96 24880 : params.set<bool>("_has_generate_csg") = true;
97 24880 : }
98 :
99 : bool
100 63045 : MeshGenerator::hasGenerateCSG(const InputParameters & params)
101 : {
102 63045 : return params.get<bool>("_has_generate_csg");
103 : }
104 :
105 : const MeshGeneratorName *
106 27581 : MeshGenerator::getMeshGeneratorNameFromParam(const std::string & param_name,
107 : const bool allow_invalid) const
108 : {
109 27581 : const auto valid_param = isParamValid(param_name);
110 27581 : if (!allow_invalid)
111 : {
112 25829 : if (!valid_param)
113 3 : mooseError("Failed to get a parameter with the name \"",
114 : param_name,
115 : "\" when getting a MeshGenerator.",
116 : "\n\nKnown parameters:\n",
117 : _pars);
118 25826 : if (!_pars.isType<MeshGeneratorName>(param_name))
119 3 : paramError(param_name,
120 : "Parameter of type \"",
121 3 : _pars.type(param_name),
122 : "\" is not an expected type for getting a MeshGenerator (should be of type "
123 : "\"MeshGeneratorName\")");
124 : }
125 1752 : else if (!valid_param)
126 1399 : return nullptr;
127 :
128 26176 : const auto & name = getParam<MeshGeneratorName>(param_name);
129 26176 : checkGetMesh(name, param_name);
130 :
131 26170 : return &name;
132 : }
133 :
134 : const std::vector<MeshGeneratorName> &
135 1968 : MeshGenerator::getMeshGeneratorNamesFromParam(const std::string & param_name) const
136 : {
137 1968 : if (!isParamValid(param_name))
138 3 : mooseError("Failed to get a parameter with the name \"",
139 : param_name,
140 : "\" when getting MeshGenerators.",
141 : "\n\nKnown parameters:\n",
142 : _pars);
143 1965 : if (!_pars.isType<std::vector<MeshGeneratorName>>(param_name))
144 3 : paramError(param_name,
145 : "Parameter of type \"",
146 3 : _pars.type(param_name),
147 : "\" is not an expected type for getting MeshGenerators (should be of type "
148 : "\"std::vector<MeshGeneratorName>\")");
149 :
150 1962 : const auto & names = getParam<std::vector<MeshGeneratorName>>(param_name);
151 6690 : for (const auto & name : names)
152 4731 : checkGetMesh(name, param_name);
153 :
154 1959 : return names;
155 : }
156 :
157 : void
158 62591 : MeshGenerator::checkGetMesh(const MeshGeneratorName & mesh_generator_name,
159 : const std::string & param_name) const
160 : {
161 : mooseAssert(!mesh_generator_name.empty(), "Empty name");
162 62591 : const auto & mg_sys = _app.getMeshGeneratorSystem();
163 62591 : if (!hasGenerateCSG() && !_app.constructingMeshGenerators())
164 3 : mooseError("Cannot get a mesh outside of construction");
165 62588 : if (!mg_sys.hasMeshGenerator(mesh_generator_name) && !isNullMeshName(mesh_generator_name))
166 : {
167 15 : std::stringstream error;
168 15 : error << "The requested MeshGenerator with name '" << mesh_generator_name << "' ";
169 15 : if (mg_sys.hasMeshGeneratorParams(mesh_generator_name))
170 : error << "was found, but has not been constructed yet.\n\nThis can occur when your "
171 : "dependencies are not properly defined and we cannot infer the proper construction "
172 : "order of your MeshGenerators.\n\nThe most likely case is a sub generator whose "
173 3 : "input(s) are not declared as a sub dependency in the generator creating them.";
174 : else
175 : error << "was not found.\nMesh generators that can be found: "
176 60 : << Moose::stringify(mg_sys.getMeshGeneratorNames());
177 :
178 15 : if (param_name.size())
179 9 : paramError(param_name, error.str());
180 : else
181 6 : mooseError(error.str());
182 0 : }
183 62573 : }
184 :
185 : std::unique_ptr<MeshBase> &
186 27463 : MeshGenerator::getMesh(const std::string & param_name, const bool allow_invalid /* = false */)
187 : {
188 27463 : const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, allow_invalid);
189 27451 : if (!name)
190 1399 : return _null_mesh;
191 26052 : return getMeshByName(*name);
192 : }
193 :
194 : std::vector<std::unique_ptr<MeshBase> *>
195 1960 : MeshGenerator::getMeshes(const std::string & param_name)
196 : {
197 1960 : return getMeshesByName(getMeshGeneratorNamesFromParam(param_name));
198 : }
199 :
200 : std::unique_ptr<MeshBase> &
201 31478 : MeshGenerator::getMeshByName(const MeshGeneratorName & mesh_generator_name)
202 : {
203 31478 : checkGetMesh(mesh_generator_name, "");
204 31469 : if (isNullMeshName(mesh_generator_name))
205 36 : return _null_mesh;
206 :
207 31433 : _requested_mesh_generators.insert(mesh_generator_name);
208 31433 : auto & mesh = _app.getMeshGeneratorSystem().getMeshGeneratorOutput(mesh_generator_name);
209 31433 : _requested_meshes.emplace_back(mesh_generator_name, &mesh);
210 31433 : return mesh;
211 : }
212 :
213 : std::vector<std::unique_ptr<MeshBase> *>
214 1954 : MeshGenerator::getMeshesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
215 : {
216 1954 : std::vector<std::unique_ptr<MeshBase> *> meshes;
217 6666 : for (const auto & name : mesh_generator_names)
218 4715 : meshes.push_back(&getMeshByName(name));
219 1951 : return meshes;
220 0 : }
221 :
222 : std::unique_ptr<CSG::CSGBase> &
223 83 : MeshGenerator::getCSGBase(const std::string & param_name)
224 : {
225 83 : const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, false);
226 83 : return getCSGBaseByName(*name);
227 : }
228 :
229 : std::unique_ptr<CSG::CSGBase> &
230 147 : MeshGenerator::getCSGBaseByName(const MeshGeneratorName & mesh_generator_name)
231 : {
232 147 : checkGetMesh(mesh_generator_name, "");
233 :
234 147 : auto & csg_base = _app.getMeshGeneratorSystem().getCSGBaseGeneratorOutput(mesh_generator_name);
235 147 : _requested_csg_bases.emplace_back(mesh_generator_name, &csg_base);
236 147 : return csg_base;
237 : }
238 :
239 : std::vector<std::unique_ptr<CSG::CSGBase> *>
240 8 : MeshGenerator::getCSGBases(const std::string & param_name)
241 : {
242 8 : return getCSGBasesByName(getMeshGeneratorNamesFromParam(param_name));
243 : }
244 :
245 : std::vector<std::unique_ptr<CSG::CSGBase> *>
246 8 : MeshGenerator::getCSGBasesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
247 : {
248 8 : std::vector<std::unique_ptr<CSG::CSGBase> *> csg_bases;
249 24 : for (const auto & name : mesh_generator_names)
250 16 : csg_bases.push_back(&getCSGBaseByName(name));
251 8 : return csg_bases;
252 0 : }
253 :
254 : void
255 35 : MeshGenerator::declareMeshForSub(const std::string & param_name)
256 : {
257 35 : declareMeshForSubByName(*getMeshGeneratorNameFromParam(param_name, false));
258 35 : }
259 :
260 : void
261 0 : MeshGenerator::declareMeshesForSub(const std::string & param_name)
262 : {
263 0 : declareMeshesForSubByName(getMeshGeneratorNamesFromParam(param_name));
264 0 : }
265 :
266 : void
267 59 : MeshGenerator::declareMeshForSubByName(const MeshGeneratorName & mesh_generator_name)
268 : {
269 59 : checkGetMesh(mesh_generator_name, "");
270 59 : if (isNullMeshName(mesh_generator_name))
271 24 : return;
272 :
273 35 : _requested_mesh_generators_for_sub.insert(mesh_generator_name);
274 : }
275 :
276 : void
277 12 : MeshGenerator::declareMeshesForSubByName(
278 : const std::vector<MeshGeneratorName> & mesh_generator_names)
279 : {
280 24 : for (const auto & name : mesh_generator_names)
281 12 : declareMeshForSubByName(name);
282 12 : }
283 :
284 : std::unique_ptr<MeshBase>
285 26666 : MeshGenerator::buildMeshBaseObject(unsigned int dim)
286 : {
287 : mooseAssert(_mesh, "Need a MooseMesh object");
288 26666 : return _mesh->buildMeshBaseObject(dim);
289 : }
290 :
291 : std::unique_ptr<ReplicatedMesh>
292 1395 : MeshGenerator::buildReplicatedMesh(unsigned int dim)
293 : {
294 : mooseAssert(_mesh, "Need a MooseMesh object");
295 1395 : return _mesh->buildTypedMesh<ReplicatedMesh>(dim);
296 : }
297 :
298 : std::unique_ptr<DistributedMesh>
299 781 : MeshGenerator::buildDistributedMesh(unsigned int dim)
300 : {
301 : mooseAssert(_mesh, "Need a MooseMesh object");
302 781 : return _mesh->buildTypedMesh<DistributedMesh>(dim);
303 : }
304 :
305 : std::unique_ptr<MeshBase>
306 52980 : MeshGenerator::generateInternal()
307 : {
308 : libmesh_parallel_only(comm());
309 : mooseAssert(comm().verify(type() + name()), "Inconsistent execution ordering");
310 :
311 52980 : if (hasGenerateData())
312 85 : generateData();
313 :
314 52980 : if (isDataOnly())
315 228 : return nullptr;
316 :
317 52752 : auto mesh = generate();
318 52365 : if (!mesh)
319 3 : mooseError("A mesh was not generated by this generator (it was nullptr).");
320 :
321 81166 : for (const auto & [requested_name, requested_mesh] : _requested_meshes)
322 28807 : if (*requested_mesh)
323 3 : mooseError(
324 : "The mesh from input ",
325 3 : _app.getMeshGenerator(requested_name).type(),
326 : " '",
327 3 : _app.getMeshGenerator(requested_name).name(),
328 : "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
329 : "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
330 : "is achieved with a std::move() operation within the generate() method.");
331 :
332 157077 : if (getParam<bool>("show_info"))
333 : {
334 83 : if (!mesh->is_prepared())
335 83 : mesh->prepare_for_use();
336 :
337 83 : const auto mesh_info = mesh->get_info(/* verbosity = */ 2);
338 :
339 : // We will prefix all information with "type() 'name()':" because this could potentially
340 : // output a ton of information and looks a bit better with a prefix
341 83 : std::stringstream oss;
342 166 : const auto split = MooseUtils::split(mesh_info, "\n");
343 83 : if (split.size())
344 5949 : for (std::size_t i = 0; i < split.size() - 1; ++i) // ignore the last line break
345 5866 : oss << COLOR_CYAN << "" << type() << " '" << name() << "': " << COLOR_DEFAULT << split[i]
346 5866 : << std::endl;
347 83 : _console << oss.str() << std::flush;
348 83 : }
349 :
350 : // output the current mesh block to file
351 52359 : if (hasOutput())
352 : {
353 477 : if (!mesh->is_prepared())
354 477 : mesh->prepare_for_use();
355 :
356 1431 : if (!getParam<bool>("nemesis"))
357 : {
358 463 : libMesh::ExodusII_IO exio(*mesh);
359 :
360 463 : if (mesh->mesh_dimension() == 1)
361 82 : exio.write_as_dimension(3);
362 :
363 : // Avoid truncating names
364 463 : exio.set_max_name_length(80);
365 :
366 : // Default to non-HDF5 output for wider compatibility
367 463 : exio.set_hdf5_writing(false);
368 :
369 463 : exio.write(name() + "_in.e");
370 463 : }
371 : else
372 : {
373 14 : libMesh::Nemesis_IO nemesis_io(*mesh);
374 :
375 : // Default to non-HDF5 output for wider compatibility
376 14 : nemesis_io.set_hdf5_writing(false);
377 :
378 14 : nemesis_io.write(name() + "_in.e");
379 14 : }
380 : }
381 :
382 52359 : return mesh;
383 52359 : }
384 :
385 : std::unique_ptr<CSG::CSGBase>
386 198 : MeshGenerator::generateInternalCSG()
387 : {
388 : mooseAssert(isDataOnly(), "Trying to use csg-only mode while not in data-driven mode");
389 198 : auto csg_obj = generateCSG();
390 : mooseAssert(csg_obj, "Null CSG object");
391 334 : for (const auto & [requested_name, requested_csg] : _requested_csg_bases)
392 139 : if (*requested_csg)
393 3 : mooseError(
394 : "The CSGBase object from input ",
395 3 : _app.getMeshGenerator(requested_name).type(),
396 : " '",
397 3 : _app.getMeshGenerator(requested_name).name(),
398 : "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
399 : "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
400 : "is achieved with a std::move() operation within the generateCSG() method.");
401 :
402 195 : return csg_obj;
403 0 : }
404 :
405 : void
406 196 : MeshGenerator::addMeshSubgenerator(const std::string & type,
407 : const std::string & name,
408 : InputParameters params)
409 : {
410 196 : if (!_app.constructingMeshGenerators())
411 3 : mooseError("Can only call addMeshSubgenerator() during MeshGenerator construction");
412 :
413 : // In case the user forgot it
414 193 : params.set<MooseApp *>(MooseBase::app_param) = &_app;
415 :
416 : // Set this to be data-only if this generator is data only
417 193 : params.set<bool>(data_only_param) = isDataOnly();
418 :
419 193 : _app.addMeshGenerator(type, name, params);
420 190 : _sub_mesh_generators.insert(&std::as_const(_app).getMeshGenerator(name));
421 190 : }
422 :
423 : RestartableDataValue &
424 23 : MeshGenerator::setMeshPropertyHelper(const std::string & data_name)
425 : {
426 23 : return _app.getRestartableMetaData(meshPropertyName(data_name), MooseApp::MESH_META_DATA, 0);
427 : }
428 :
429 : void
430 31214 : MeshGenerator::addParentMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
431 : {
432 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
433 31214 : _parent_mesh_generators.insert(&mg);
434 31214 : }
435 :
436 : void
437 31214 : MeshGenerator::addChildMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
438 : {
439 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
440 31214 : _child_mesh_generators.insert(&mg);
441 31214 : }
442 :
443 : bool
444 31226 : MeshGenerator::isParentMeshGenerator(const MeshGeneratorName & name,
445 : const bool direct /* = true */) const
446 : {
447 31226 : return std::find_if(getParentMeshGenerators().begin(),
448 31226 : getParentMeshGenerators().end(),
449 44981 : [&name, &direct](const auto & mg)
450 : {
451 58826 : return mg->name() == name ||
452 58826 : (!direct && mg->isParentMeshGenerator(name, /* direct = */ false));
453 62452 : }) != getParentMeshGenerators().end();
454 : }
455 :
456 : bool
457 5746 : MeshGenerator::isChildMeshGenerator(const MeshGeneratorName & name,
458 : const bool direct /* = true */) const
459 : {
460 5746 : return std::find_if(getChildMeshGenerators().begin(),
461 5746 : getChildMeshGenerators().end(),
462 4546 : [&name, &direct](const auto & mg)
463 : {
464 7483 : return mg->name() == name ||
465 7483 : (!direct && mg->isChildMeshGenerator(name, /* direct = */ false));
466 11492 : }) != getChildMeshGenerators().end();
467 : }
468 :
469 : void
470 12 : MeshGenerator::declareNullMeshName(const MeshGeneratorName & name)
471 : {
472 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
473 : mooseAssert(!_null_mesh_names.count(name), "Already declared");
474 12 : _null_mesh_names.insert(name);
475 12 : }
476 :
477 : bool
478 165711 : MeshGenerator::hasSaveMesh() const
479 : {
480 165711 : return _save_with_name.size();
481 : }
482 :
483 : bool
484 108504 : MeshGenerator::hasOutput() const
485 : {
486 325512 : return getParam<bool>("output");
487 : }
488 :
489 : const std::string &
490 130 : MeshGenerator::getSavedMeshName() const
491 : {
492 130 : return _save_with_name;
493 : }
494 :
495 : void
496 3 : MeshGenerator::generateData()
497 : {
498 : mooseAssert(!hasGenerateData(), "Inconsistent flag");
499 3 : mooseError("This MeshGenerator does not have a generateData() implementation.");
500 : }
501 :
502 : [[nodiscard]] std::unique_ptr<CSG::CSGBase>
503 0 : MeshGenerator::generateCSG()
504 : {
505 : mooseAssert(!hasGenerateCSG(), "Inconsistent flag");
506 0 : mooseError("This MeshGenerator does not have a generateCSG() implementation.");
507 : }
|