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