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