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 478601 : MeshGenerator::validParams()
24 : {
25 478601 : InputParameters params = MooseObject::validParams();
26 :
27 1435803 : params.addParam<bool>("show_info",
28 957202 : false,
29 : "Whether or not to show mesh info after generating the mesh "
30 : "(bounding box, element types, sidesets, nodesets, subdomains, etc)");
31 1435803 : params.addParam<std::string>(
32 : "save_with_name",
33 957202 : std::string(),
34 : "Keep the mesh from this mesh generator in memory with the name specified");
35 :
36 1435803 : params.addParam<bool>(
37 957202 : "output", false, "Whether or not to output the mesh file after generating the mesh");
38 1435803 : params.addParam<bool>("nemesis",
39 957202 : false,
40 : "Whether or not to output the mesh file in the nemesis"
41 : "format (only if output = true)");
42 :
43 1914404 : params.addParamNamesToGroup("show_info output nemesis", "Debugging");
44 1914404 : params.addParamNamesToGroup("save_with_name", "Advanced");
45 478601 : params.registerBase("MeshGenerator");
46 :
47 957202 : params.addPrivateParam<bool>("_has_generate_data", false);
48 957202 : params.addPrivateParam<bool>("_has_generate_csg", false);
49 957202 : params.addPrivateParam<MooseMesh *>("_moose_mesh", nullptr);
50 478601 : params.addPrivateParam<bool>(data_only_param, false);
51 : // Controls are not created early enough
52 478601 : params.suppressParameter<std::vector<std::string>>("control_tags");
53 :
54 478601 : return params;
55 0 : }
56 :
57 57081 : MeshGenerator::MeshGenerator(const InputParameters & parameters)
58 : : MooseObject(parameters),
59 : MeshMetaDataInterface(this),
60 114162 : _mesh(getParam<MooseMesh *>("_moose_mesh") ? getParam<MooseMesh *>("_moose_mesh")
61 57081 : : _app.actionWarehouse().mesh().get()),
62 114162 : _save_with_name(getParam<std::string>("save_with_name")),
63 171243 : _data_only(getParam<bool>(data_only_param))
64 : {
65 57081 : const auto & system = _app.getMeshGeneratorSystem();
66 57081 : 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 57075 : 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 171244 : if (getParam<bool>("nemesis") && !getParam<bool>("output"))
78 0 : paramError("nemesis", "Should only be set to true if 'output=true'");
79 57072 : }
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 53563 : MeshGenerator::hasGenerateData(const InputParameters & params)
89 : {
90 53563 : 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 63489 : MeshGenerator::hasGenerateCSG(const InputParameters & params)
101 : {
102 63489 : return params.get<bool>("_has_generate_csg");
103 : }
104 :
105 : const MeshGeneratorName *
106 27784 : MeshGenerator::getMeshGeneratorNameFromParam(const std::string & param_name,
107 : const bool allow_invalid) const
108 : {
109 27784 : const auto valid_param = isParamValid(param_name);
110 27784 : if (!allow_invalid)
111 : {
112 26004 : 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 26001 : 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 1780 : else if (!valid_param)
126 1406 : return nullptr;
127 :
128 26372 : const auto & name = getParam<MeshGeneratorName>(param_name);
129 26372 : checkGetMesh(name, param_name);
130 :
131 26366 : return &name;
132 : }
133 :
134 : const std::vector<MeshGeneratorName> &
135 1981 : MeshGenerator::getMeshGeneratorNamesFromParam(const std::string & param_name) const
136 : {
137 1981 : 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 1978 : 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 1975 : const auto & names = getParam<std::vector<MeshGeneratorName>>(param_name);
151 6729 : for (const auto & name : names)
152 4757 : checkGetMesh(name, param_name);
153 :
154 1972 : return names;
155 : }
156 :
157 : void
158 63035 : MeshGenerator::checkGetMesh(const MeshGeneratorName & mesh_generator_name,
159 : const std::string & param_name) const
160 : {
161 : mooseAssert(!mesh_generator_name.empty(), "Empty name");
162 63035 : const auto & mg_sys = _app.getMeshGeneratorSystem();
163 63035 : if (!hasGenerateCSG() && !_app.constructingMeshGenerators())
164 3 : mooseError("Cannot get a mesh outside of construction");
165 63032 : 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 63017 : }
184 :
185 : std::unique_ptr<MeshBase> &
186 27666 : MeshGenerator::getMesh(const std::string & param_name, const bool allow_invalid /* = false */)
187 : {
188 27666 : const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, allow_invalid);
189 27654 : if (!name)
190 1406 : return _null_mesh;
191 26248 : return getMeshByName(*name);
192 : }
193 :
194 : std::vector<std::unique_ptr<MeshBase> *>
195 1973 : MeshGenerator::getMeshes(const std::string & param_name)
196 : {
197 1973 : return getMeshesByName(getMeshGeneratorNamesFromParam(param_name));
198 : }
199 :
200 : std::unique_ptr<MeshBase> &
201 31700 : MeshGenerator::getMeshByName(const MeshGeneratorName & mesh_generator_name)
202 : {
203 31700 : checkGetMesh(mesh_generator_name, "");
204 31691 : if (isNullMeshName(mesh_generator_name))
205 36 : return _null_mesh;
206 :
207 31655 : _requested_mesh_generators.insert(mesh_generator_name);
208 31655 : auto & mesh = _app.getMeshGeneratorSystem().getMeshGeneratorOutput(mesh_generator_name);
209 31655 : _requested_meshes.emplace_back(mesh_generator_name, &mesh);
210 31655 : return mesh;
211 : }
212 :
213 : std::vector<std::unique_ptr<MeshBase> *>
214 1967 : MeshGenerator::getMeshesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
215 : {
216 1967 : std::vector<std::unique_ptr<MeshBase> *> meshes;
217 6705 : for (const auto & name : mesh_generator_names)
218 4741 : meshes.push_back(&getMeshByName(name));
219 1964 : 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 : if (!name)
227 0 : return _null_csg_base;
228 83 : return getCSGBaseByName(*name);
229 : }
230 :
231 : std::unique_ptr<CSG::CSGBase> &
232 147 : MeshGenerator::getCSGBaseByName(const MeshGeneratorName & mesh_generator_name)
233 : {
234 147 : checkGetMesh(mesh_generator_name, "");
235 147 : if (isNullMeshName(mesh_generator_name))
236 0 : return _null_csg_base;
237 :
238 147 : auto & csg_base = _app.getMeshGeneratorSystem().getCSGBaseGeneratorOutput(mesh_generator_name);
239 147 : _requested_csg_bases.emplace_back(mesh_generator_name, &csg_base);
240 147 : return csg_base;
241 : }
242 :
243 : std::vector<std::unique_ptr<CSG::CSGBase> *>
244 8 : MeshGenerator::getCSGBases(const std::string & param_name)
245 : {
246 8 : return getCSGBasesByName(getMeshGeneratorNamesFromParam(param_name));
247 : }
248 :
249 : std::vector<std::unique_ptr<CSG::CSGBase> *>
250 8 : MeshGenerator::getCSGBasesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
251 : {
252 8 : std::vector<std::unique_ptr<CSG::CSGBase> *> csg_bases;
253 24 : for (const auto & name : mesh_generator_names)
254 16 : csg_bases.push_back(&getCSGBaseByName(name));
255 8 : return csg_bases;
256 0 : }
257 :
258 : void
259 35 : MeshGenerator::declareMeshForSub(const std::string & param_name)
260 : {
261 35 : declareMeshForSubByName(*getMeshGeneratorNameFromParam(param_name, false));
262 35 : }
263 :
264 : void
265 0 : MeshGenerator::declareMeshesForSub(const std::string & param_name)
266 : {
267 0 : declareMeshesForSubByName(getMeshGeneratorNamesFromParam(param_name));
268 0 : }
269 :
270 : void
271 59 : MeshGenerator::declareMeshForSubByName(const MeshGeneratorName & mesh_generator_name)
272 : {
273 59 : checkGetMesh(mesh_generator_name, "");
274 59 : if (isNullMeshName(mesh_generator_name))
275 24 : return;
276 :
277 35 : _requested_mesh_generators_for_sub.insert(mesh_generator_name);
278 : }
279 :
280 : void
281 12 : MeshGenerator::declareMeshesForSubByName(
282 : const std::vector<MeshGeneratorName> & mesh_generator_names)
283 : {
284 24 : for (const auto & name : mesh_generator_names)
285 12 : declareMeshForSubByName(name);
286 12 : }
287 :
288 : std::unique_ptr<MeshBase>
289 26898 : MeshGenerator::buildMeshBaseObject(unsigned int dim)
290 : {
291 : mooseAssert(_mesh, "Need a MooseMesh object");
292 26898 : return _mesh->buildMeshBaseObject(dim);
293 : }
294 :
295 : std::unique_ptr<ReplicatedMesh>
296 1505 : MeshGenerator::buildReplicatedMesh(unsigned int dim)
297 : {
298 : mooseAssert(_mesh, "Need a MooseMesh object");
299 1505 : return _mesh->buildTypedMesh<ReplicatedMesh>(dim);
300 : }
301 :
302 : std::unique_ptr<DistributedMesh>
303 781 : MeshGenerator::buildDistributedMesh(unsigned int dim)
304 : {
305 : mooseAssert(_mesh, "Need a MooseMesh object");
306 781 : return _mesh->buildTypedMesh<DistributedMesh>(dim);
307 : }
308 :
309 : std::unique_ptr<MeshBase>
310 53521 : MeshGenerator::generateInternal()
311 : {
312 : libmesh_parallel_only(comm());
313 : mooseAssert(comm().verify(type() + name()), "Inconsistent execution ordering");
314 :
315 53521 : if (hasGenerateData())
316 85 : generateData();
317 :
318 53521 : if (isDataOnly())
319 228 : return nullptr;
320 :
321 53293 : auto mesh = generate();
322 52906 : if (!mesh)
323 3 : mooseError("A mesh was not generated by this generator (it was nullptr).");
324 :
325 81929 : for (const auto & [requested_name, requested_mesh] : _requested_meshes)
326 29029 : if (*requested_mesh)
327 3 : mooseError(
328 : "The mesh from input ",
329 3 : _app.getMeshGenerator(requested_name).type(),
330 : " '",
331 3 : _app.getMeshGenerator(requested_name).name(),
332 : "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
333 : "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
334 : "is achieved with a std::move() operation within the generate() method.");
335 :
336 158700 : if (getParam<bool>("show_info"))
337 : {
338 83 : if (!mesh->is_prepared())
339 83 : mesh->prepare_for_use();
340 :
341 83 : const auto mesh_info = mesh->get_info(/* verbosity = */ 2);
342 :
343 : // We will prefix all information with "type() 'name()':" because this could potentially
344 : // output a ton of information and looks a bit better with a prefix
345 83 : std::stringstream oss;
346 166 : const auto split = MooseUtils::split(mesh_info, "\n");
347 83 : if (split.size())
348 5949 : for (std::size_t i = 0; i < split.size() - 1; ++i) // ignore the last line break
349 5866 : oss << COLOR_CYAN << "" << type() << " '" << name() << "': " << COLOR_DEFAULT << split[i]
350 5866 : << std::endl;
351 83 : _console << oss.str() << std::flush;
352 83 : }
353 :
354 : // output the current mesh block to file
355 52900 : if (hasOutput())
356 : {
357 477 : if (!mesh->is_prepared())
358 477 : mesh->prepare_for_use();
359 :
360 1431 : if (!getParam<bool>("nemesis"))
361 : {
362 463 : libMesh::ExodusII_IO exio(*mesh);
363 :
364 463 : if (mesh->mesh_dimension() == 1)
365 82 : exio.write_as_dimension(3);
366 :
367 : // Avoid truncating names
368 463 : exio.set_max_name_length(80);
369 :
370 : // Default to non-HDF5 output for wider compatibility
371 463 : exio.set_hdf5_writing(false);
372 :
373 463 : exio.write(name() + "_in.e");
374 463 : }
375 : else
376 : {
377 14 : libMesh::Nemesis_IO nemesis_io(*mesh);
378 :
379 : // Default to non-HDF5 output for wider compatibility
380 14 : nemesis_io.set_hdf5_writing(false);
381 :
382 14 : nemesis_io.write(name() + "_in.e");
383 14 : }
384 : }
385 :
386 52900 : return mesh;
387 52900 : }
388 :
389 : std::unique_ptr<CSG::CSGBase>
390 198 : MeshGenerator::generateInternalCSG()
391 : {
392 : mooseAssert(isDataOnly(), "Trying to use csg-only mode while not in data-driven mode");
393 198 : auto csg_obj = generateCSG();
394 : mooseAssert(csg_obj, "Null CSG object");
395 334 : for (const auto & [requested_name, requested_csg] : _requested_csg_bases)
396 139 : if (*requested_csg)
397 3 : mooseError(
398 : "The CSGBase object from input ",
399 3 : _app.getMeshGenerator(requested_name).type(),
400 : " '",
401 3 : _app.getMeshGenerator(requested_name).name(),
402 : "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
403 : "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
404 : "is achieved with a std::move() operation within the generateCSG() method.");
405 :
406 195 : return csg_obj;
407 0 : }
408 :
409 : void
410 196 : MeshGenerator::addMeshSubgenerator(const std::string & type,
411 : const std::string & name,
412 : InputParameters params)
413 : {
414 196 : if (!_app.constructingMeshGenerators())
415 3 : mooseError("Can only call addMeshSubgenerator() during MeshGenerator construction");
416 :
417 : // In case the user forgot it
418 193 : params.set<MooseApp *>(MooseBase::app_param) = &_app;
419 :
420 : // Set this to be data-only if this generator is data only
421 193 : params.set<bool>(data_only_param) = isDataOnly();
422 :
423 193 : _app.addMeshGenerator(type, name, params);
424 190 : _sub_mesh_generators.insert(&std::as_const(_app).getMeshGenerator(name));
425 190 : }
426 :
427 : RestartableDataValue &
428 23 : MeshGenerator::setMeshPropertyHelper(const std::string & data_name)
429 : {
430 23 : return _app.getRestartableMetaData(meshPropertyName(data_name), MooseApp::MESH_META_DATA, 0);
431 : }
432 :
433 : void
434 31436 : MeshGenerator::addParentMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
435 : {
436 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
437 31436 : _parent_mesh_generators.insert(&mg);
438 31436 : }
439 :
440 : void
441 31436 : MeshGenerator::addChildMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
442 : {
443 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
444 31436 : _child_mesh_generators.insert(&mg);
445 31436 : }
446 :
447 : bool
448 31448 : MeshGenerator::isParentMeshGenerator(const MeshGeneratorName & name,
449 : const bool direct /* = true */) const
450 : {
451 31448 : return std::find_if(getParentMeshGenerators().begin(),
452 31448 : getParentMeshGenerators().end(),
453 45236 : [&name, &direct](const auto & mg)
454 : {
455 59114 : return mg->name() == name ||
456 59114 : (!direct && mg->isParentMeshGenerator(name, /* direct = */ false));
457 62896 : }) != getParentMeshGenerators().end();
458 : }
459 :
460 : bool
461 5746 : MeshGenerator::isChildMeshGenerator(const MeshGeneratorName & name,
462 : const bool direct /* = true */) const
463 : {
464 5746 : return std::find_if(getChildMeshGenerators().begin(),
465 5746 : getChildMeshGenerators().end(),
466 4546 : [&name, &direct](const auto & mg)
467 : {
468 7483 : return mg->name() == name ||
469 7483 : (!direct && mg->isChildMeshGenerator(name, /* direct = */ false));
470 11492 : }) != getChildMeshGenerators().end();
471 : }
472 :
473 : void
474 12 : MeshGenerator::declareNullMeshName(const MeshGeneratorName & name)
475 : {
476 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
477 : mooseAssert(!_null_mesh_names.count(name), "Already declared");
478 12 : _null_mesh_names.insert(name);
479 12 : }
480 :
481 : bool
482 167339 : MeshGenerator::hasSaveMesh() const
483 : {
484 167339 : return _save_with_name.size();
485 : }
486 :
487 : bool
488 109586 : MeshGenerator::hasOutput() const
489 : {
490 328758 : return getParam<bool>("output");
491 : }
492 :
493 : const std::string &
494 130 : MeshGenerator::getSavedMeshName() const
495 : {
496 130 : return _save_with_name;
497 : }
498 :
499 : void
500 3 : MeshGenerator::generateData()
501 : {
502 : mooseAssert(!hasGenerateData(), "Inconsistent flag");
503 3 : mooseError("This MeshGenerator does not have a generateData() implementation.");
504 : }
505 :
506 : [[nodiscard]] std::unique_ptr<CSG::CSGBase>
507 0 : MeshGenerator::generateCSG()
508 : {
509 : mooseAssert(!hasGenerateCSG(), "Inconsistent flag");
510 0 : mooseError("This MeshGenerator does not have a generateCSG() implementation.");
511 : }
|