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 1494388 : MeshGenerator::validParams()
24 : {
25 1494388 : InputParameters params = MooseObject::validParams();
26 :
27 4483164 : params.addParam<bool>("show_info",
28 2988776 : false,
29 : "Whether or not to show mesh info after generating the mesh "
30 : "(bounding box, element types, sidesets, nodesets, subdomains, etc)");
31 4483164 : params.addParam<std::string>(
32 : "save_with_name",
33 2988776 : std::string(),
34 : "Keep the mesh from this mesh generator in memory with the name specified");
35 :
36 4483164 : params.addParam<bool>(
37 2988776 : "output", false, "Whether or not to output the mesh file after generating the mesh");
38 4483164 : params.addParam<bool>("nemesis",
39 2988776 : false,
40 : "Whether or not to output the mesh file in the nemesis"
41 : "format (only if output = true)");
42 :
43 1494388 : params.addParamNamesToGroup("show_info output nemesis", "Debugging");
44 1494388 : params.addParamNamesToGroup("save_with_name", "Advanced");
45 1494388 : params.registerBase("MeshGenerator");
46 :
47 1494388 : params.addPrivateParam<bool>("_has_generate_data", false);
48 1494388 : params.addPrivateParam<MooseMesh *>("_moose_mesh", nullptr);
49 1494388 : params.addPrivateParam<bool>(data_only_param, false);
50 : // Controls are not created early enough
51 1494388 : params.suppressParameter<std::vector<std::string>>("control_tags");
52 :
53 1494388 : return params;
54 0 : }
55 :
56 55186 : MeshGenerator::MeshGenerator(const InputParameters & parameters)
57 : : MooseObject(parameters),
58 : MeshMetaDataInterface(this),
59 110372 : _mesh(getParam<MooseMesh *>("_moose_mesh") ? getParam<MooseMesh *>("_moose_mesh")
60 55186 : : _app.actionWarehouse().mesh().get()),
61 55186 : _save_with_name(getParam<std::string>("save_with_name")),
62 165558 : _data_only(getParam<bool>(data_only_param))
63 : {
64 55186 : const auto & system = _app.getMeshGeneratorSystem();
65 55186 : if (isDataOnly())
66 : {
67 49 : if (!hasGenerateData())
68 4 : system.dataDrivenError(*this, "does not support data-driven generation");
69 45 : if (hasSaveMesh())
70 4 : system.dataDrivenError(*this, "has 'save_with_name' set");
71 : }
72 55178 : 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 55174 : if (getParam<bool>("nemesis") && !getParam<bool>("output"))
76 0 : paramError("nemesis", "Should only be set to true if 'output=true'");
77 55174 : }
78 :
79 : void
80 28876 : MeshGenerator::setHasGenerateData(InputParameters & params)
81 : {
82 28876 : params.set<bool>("_has_generate_data") = true;
83 28876 : }
84 :
85 : bool
86 52052 : MeshGenerator::hasGenerateData(const InputParameters & params)
87 : {
88 52052 : return params.get<bool>("_has_generate_data");
89 : }
90 :
91 : const MeshGeneratorName *
92 25235 : MeshGenerator::getMeshGeneratorNameFromParam(const std::string & param_name,
93 : const bool allow_invalid) const
94 : {
95 25235 : const auto valid_param = isParamValid(param_name);
96 25235 : if (!allow_invalid)
97 : {
98 24530 : 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 24526 : 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 705 : else if (!valid_param)
112 690 : return nullptr;
113 :
114 24537 : const auto & name = getParam<MeshGeneratorName>(param_name);
115 24537 : checkGetMesh(name, param_name);
116 :
117 24529 : return &name;
118 : }
119 :
120 : const std::vector<MeshGeneratorName> &
121 1865 : MeshGenerator::getMeshGeneratorNamesFromParam(const std::string & param_name) const
122 : {
123 1865 : 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 1861 : 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 1857 : const auto & names = getParam<std::vector<MeshGeneratorName>>(param_name);
137 6435 : for (const auto & name : names)
138 4582 : checkGetMesh(name, param_name);
139 :
140 1853 : return names;
141 : }
142 :
143 : void
144 59005 : MeshGenerator::checkGetMesh(const MeshGeneratorName & mesh_generator_name,
145 : const std::string & param_name) const
146 : {
147 : mooseAssert(!mesh_generator_name.empty(), "Empty name");
148 59005 : const auto & mg_sys = _app.getMeshGeneratorSystem();
149 59005 : if (!_app.constructingMeshGenerators())
150 4 : mooseError("Cannot get a mesh outside of construction");
151 59001 : 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 58981 : }
170 :
171 : std::unique_ptr<MeshBase> &
172 25195 : MeshGenerator::getMesh(const std::string & param_name, const bool allow_invalid /* = false */)
173 : {
174 25195 : const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, allow_invalid);
175 25179 : if (!name)
176 690 : return _null_mesh;
177 24489 : return getMeshByName(*name);
178 : }
179 :
180 : std::vector<std::unique_ptr<MeshBase> *>
181 1865 : MeshGenerator::getMeshes(const std::string & param_name)
182 : {
183 1865 : return getMeshesByName(getMeshGeneratorNamesFromParam(param_name));
184 : }
185 :
186 : std::unique_ptr<MeshBase> &
187 29820 : MeshGenerator::getMeshByName(const MeshGeneratorName & mesh_generator_name)
188 : {
189 29820 : checkGetMesh(mesh_generator_name, "");
190 29808 : if (isNullMeshName(mesh_generator_name))
191 39 : return _null_mesh;
192 :
193 29769 : _requested_mesh_generators.insert(mesh_generator_name);
194 29769 : auto & mesh = _app.getMeshGeneratorSystem().getMeshGeneratorOutput(mesh_generator_name);
195 29769 : _requested_meshes.emplace_back(mesh_generator_name, &mesh);
196 29769 : return mesh;
197 : }
198 :
199 : std::vector<std::unique_ptr<MeshBase> *>
200 1857 : MeshGenerator::getMeshesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
201 : {
202 1857 : std::vector<std::unique_ptr<MeshBase> *> meshes;
203 6435 : for (const auto & name : mesh_generator_names)
204 4582 : meshes.push_back(&getMeshByName(name));
205 1853 : return meshes;
206 0 : }
207 :
208 : void
209 40 : MeshGenerator::declareMeshForSub(const std::string & param_name)
210 : {
211 40 : declareMeshForSubByName(*getMeshGeneratorNameFromParam(param_name, false));
212 40 : }
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 66 : MeshGenerator::declareMeshForSubByName(const MeshGeneratorName & mesh_generator_name)
222 : {
223 66 : checkGetMesh(mesh_generator_name, "");
224 66 : if (isNullMeshName(mesh_generator_name))
225 26 : return;
226 :
227 40 : _requested_mesh_generators_for_sub.insert(mesh_generator_name);
228 : }
229 :
230 : void
231 13 : MeshGenerator::declareMeshesForSubByName(
232 : const std::vector<MeshGeneratorName> & mesh_generator_names)
233 : {
234 26 : for (const auto & name : mesh_generator_names)
235 13 : declareMeshForSubByName(name);
236 13 : }
237 :
238 : std::unique_ptr<MeshBase>
239 26408 : MeshGenerator::buildMeshBaseObject(unsigned int dim)
240 : {
241 : mooseAssert(_mesh, "Need a MooseMesh object");
242 26408 : return _mesh->buildMeshBaseObject(dim);
243 : }
244 :
245 : std::unique_ptr<ReplicatedMesh>
246 741 : MeshGenerator::buildReplicatedMesh(unsigned int dim)
247 : {
248 : mooseAssert(_mesh, "Need a MooseMesh object");
249 741 : return _mesh->buildTypedMesh<ReplicatedMesh>(dim);
250 : }
251 :
252 : std::unique_ptr<DistributedMesh>
253 880 : MeshGenerator::buildDistributedMesh(unsigned int dim)
254 : {
255 : mooseAssert(_mesh, "Need a MooseMesh object");
256 880 : return _mesh->buildTypedMesh<DistributedMesh>(dim);
257 : }
258 :
259 : std::unique_ptr<MeshBase>
260 52003 : MeshGenerator::generateInternal()
261 : {
262 : libmesh_parallel_only(comm());
263 : mooseAssert(comm().verify(type() + name()), "Inconsistent execution ordering");
264 :
265 52003 : if (hasGenerateData())
266 94 : generateData();
267 :
268 52003 : if (isDataOnly())
269 33 : return nullptr;
270 :
271 51970 : auto mesh = generate();
272 51526 : if (!mesh)
273 4 : mooseError("A mesh was not generated by this generator (it was nullptr).");
274 :
275 79082 : for (const auto & [requested_name, requested_mesh] : _requested_meshes)
276 27564 : 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 51518 : if (getParam<bool>("show_info"))
287 : {
288 75 : 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 75 : std::stringstream oss;
293 75 : const auto split = MooseUtils::split(mesh_info, "\n");
294 75 : if (split.size())
295 5238 : for (std::size_t i = 0; i < split.size() - 1; ++i) // ignore the last line break
296 5163 : oss << COLOR_CYAN << "" << type() << " '" << name() << "': " << COLOR_DEFAULT << split[i]
297 5163 : << std::endl;
298 75 : _console << oss.str() << std::flush;
299 75 : }
300 :
301 : // output the current mesh block to file
302 51518 : if (hasOutput())
303 : {
304 347 : if (!mesh->is_prepared())
305 347 : mesh->prepare_for_use();
306 :
307 347 : if (!getParam<bool>("nemesis"))
308 : {
309 331 : libMesh::ExodusII_IO exio(*mesh);
310 :
311 331 : if (mesh->mesh_dimension() == 1)
312 11 : exio.write_as_dimension(3);
313 :
314 : // Default to non-HDF5 output for wider compatibility
315 331 : exio.set_hdf5_writing(false);
316 :
317 331 : exio.write(name() + "_in.e");
318 331 : }
319 : else
320 : {
321 16 : libMesh::Nemesis_IO nemesis_io(*mesh);
322 :
323 : // Default to non-HDF5 output for wider compatibility
324 16 : nemesis_io.set_hdf5_writing(false);
325 :
326 16 : nemesis_io.write(name() + "_in.e");
327 16 : }
328 : }
329 :
330 51518 : return mesh;
331 51518 : }
332 :
333 : void
334 227 : MeshGenerator::addMeshSubgenerator(const std::string & type,
335 : const std::string & name,
336 : InputParameters params)
337 : {
338 227 : if (!_app.constructingMeshGenerators())
339 4 : mooseError("Can only call addMeshSubgenerator() during MeshGenerator construction");
340 :
341 : // In case the user forgot it
342 223 : params.set<MooseApp *>("_moose_app") = &_app;
343 :
344 : // Set this to be data-only if this generator is data only
345 223 : params.set<bool>(data_only_param) = isDataOnly();
346 :
347 223 : _app.addMeshGenerator(type, name, params);
348 219 : _sub_mesh_generators.insert(&std::as_const(_app).getMeshGenerator(name));
349 219 : }
350 :
351 : RestartableDataValue &
352 26 : MeshGenerator::setMeshPropertyHelper(const std::string & data_name)
353 : {
354 26 : return _app.getRestartableMetaData(meshPropertyName(data_name), MooseApp::MESH_META_DATA, 0);
355 : }
356 :
357 : void
358 29521 : MeshGenerator::addParentMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
359 : {
360 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
361 29521 : _parent_mesh_generators.insert(&mg);
362 29521 : }
363 :
364 : void
365 29521 : MeshGenerator::addChildMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
366 : {
367 : mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
368 29521 : _child_mesh_generators.insert(&mg);
369 29521 : }
370 :
371 : bool
372 29534 : MeshGenerator::isParentMeshGenerator(const MeshGeneratorName & name,
373 : const bool direct /* = true */) const
374 : {
375 29534 : return std::find_if(getParentMeshGenerators().begin(),
376 29534 : getParentMeshGenerators().end(),
377 58133 : [&name, &direct](const auto & mg)
378 : {
379 58133 : return mg->name() == name ||
380 58133 : (!direct && mg->isParentMeshGenerator(name, /* direct = */ false));
381 59068 : }) != getParentMeshGenerators().end();
382 : }
383 :
384 : bool
385 4497 : MeshGenerator::isChildMeshGenerator(const MeshGeneratorName & name,
386 : const bool direct /* = true */) const
387 : {
388 4497 : return std::find_if(getChildMeshGenerators().begin(),
389 4497 : getChildMeshGenerators().end(),
390 7491 : [&name, &direct](const auto & mg)
391 : {
392 5471 : return mg->name() == name ||
393 5471 : (!direct && mg->isChildMeshGenerator(name, /* direct = */ false));
394 8994 : }) != getChildMeshGenerators().end();
395 : }
396 :
397 : void
398 13 : 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 13 : _null_mesh_names.insert(name);
403 13 : }
404 :
405 : bool
406 161589 : MeshGenerator::hasSaveMesh() const
407 : {
408 161589 : return _save_with_name.size();
409 : }
410 :
411 : bool
412 106107 : MeshGenerator::hasOutput() const
413 : {
414 106107 : return getParam<bool>("output");
415 : }
416 :
417 : const std::string &
418 151 : MeshGenerator::getSavedMeshName() const
419 : {
420 151 : 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 : }
|