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 : #pragma once
11 :
12 : #include "MooseObject.h"
13 : #include "MeshMetaDataInterface.h"
14 : #include "MooseApp.h"
15 :
16 : // Included so mesh generators don't need to include this when constructing MeshBase objects
17 : #include "MooseMesh.h"
18 :
19 : #include "libmesh/mesh_base.h"
20 : #include "libmesh/parameters.h"
21 :
22 : class MooseMesh;
23 : namespace libMesh
24 : {
25 : class ReplicatedMesh;
26 : class DistributedMesh;
27 : }
28 :
29 : /**
30 : * MeshGenerators are objects that can modify or add to an existing mesh.
31 : */
32 : class MeshGenerator : public MooseObject, public MeshMetaDataInterface
33 : {
34 : public:
35 : /**
36 : * Comparator for MeshGenerators that sorts by name
37 : */
38 : struct Comparator
39 : {
40 2978783 : bool operator()(const MeshGenerator * const & a, const MeshGenerator * const & b) const
41 : {
42 2978783 : return a->name() < b->name();
43 : }
44 : };
45 :
46 : static InputParameters validParams();
47 :
48 : /**
49 : * Sets that a mesh generator has a generateData() implementation.
50 : *
51 : * This must be called in the validParams() implementation for all
52 : * mesh generators that implement generateData().
53 : */
54 : static void setHasGenerateData(InputParameters & params);
55 : /**
56 : * @return Whether or not the mesh generator noted by the given parameters
57 : * has a generateData() implementation
58 : */
59 : static bool hasGenerateData(const InputParameters & params);
60 :
61 : /// The name of the private parameter for setting data only
62 : static const std::string data_only_param;
63 :
64 : MeshGenerator(const InputParameters & parameters);
65 :
66 : /**
67 : * Generate / modify the mesh
68 : */
69 : virtual std::unique_ptr<MeshBase> generate() = 0;
70 :
71 : /**
72 : * Internal generation method - this is what is actually called
73 : * within MooseApp to execute the MeshGenerator.
74 : */
75 : [[nodiscard]] std::unique_ptr<MeshBase> generateInternal();
76 :
77 : /**
78 : * @returns The names of the MeshGenerators that were requested in the getMesh methods
79 : */
80 50659 : const std::set<MeshGeneratorName> & getRequestedMeshGenerators() const
81 : {
82 50659 : return _requested_mesh_generators;
83 : }
84 : /**
85 : * @returns The names of the MeshGenerators that were requested in the declareMeshForSub
86 : * methods
87 : */
88 36 : const std::set<MeshGeneratorName> & getRequestedMeshGeneratorsForSub() const
89 : {
90 36 : return _requested_mesh_generators_for_sub;
91 : }
92 :
93 : /**
94 : * Class that is used as a parameter to add[Parent/Child]() that allows only
95 : * MeshGeneratorSystem methods to call said methods
96 : */
97 : class AddParentChildKey
98 : {
99 : friend class MeshGeneratorSystem;
100 54610 : AddParentChildKey() {}
101 : AddParentChildKey(const AddParentChildKey &) {}
102 : };
103 :
104 : /**
105 : * Adds the MeshGenerator \p mg as a parent.
106 : *
107 : * Protected by the AddParentChildKey so that parents can only be
108 : * added by the MooseApp.
109 : */
110 : void addParentMeshGenerator(const MeshGenerator & mg, const AddParentChildKey);
111 : /**
112 : * Adds the MeshGenerator \p mg as a child.
113 : *
114 : * Protected by the AddParentChildKey so that parents can only be
115 : * added by the MooseApp.
116 : */
117 : void addChildMeshGenerator(const MeshGenerator & mg, const AddParentChildKey);
118 :
119 : /**
120 : * Gets the MeshGenerators that are parents to this MeshGenerator.
121 : */
122 129908 : const std::set<const MeshGenerator *, Comparator> & getParentMeshGenerators() const
123 : {
124 129908 : return _parent_mesh_generators;
125 : }
126 : /**
127 : * Gets the MeshGenerators that are children to this MeshGenerator.
128 : */
129 12291 : const std::set<const MeshGenerator *, Comparator> & getChildMeshGenerators() const
130 : {
131 12291 : return _child_mesh_generators;
132 : }
133 : /**
134 : * Gets the MeshGenerators that are children to this MeshGenerator.
135 : */
136 108 : const std::set<const MeshGenerator *, Comparator> & getSubMeshGenerators() const
137 : {
138 108 : return _sub_mesh_generators;
139 : }
140 :
141 : /**
142 : * @returns Whether or not the MeshGenerator with the name \p name is a parent of this
143 : * MeshGenerator.
144 : *
145 : * If \p direct = true, check only immediate parents of this generator. Otherwise, check
146 : * all parents.
147 : */
148 : bool isParentMeshGenerator(const MeshGeneratorName & name, const bool direct = true) const;
149 :
150 : /**
151 : * @returns Whether or not the MeshGenerator with the name \p name is a child of this
152 : * MeshGenerator.
153 : *
154 : * If \p direct = true, check only immediate children of this generator. Otherwise, check
155 : * all children.
156 : */
157 : bool isChildMeshGenerator(const MeshGeneratorName & name, const bool direct = true) const;
158 :
159 : /**
160 : * @returns Whether or not the name \p name is registered as a "null" mesh, that is,
161 : * a MeshGenerator that will not represent an input mesh when requested via getMesh.
162 : *
163 : * See declareNullMeshName().
164 : */
165 55004 : bool isNullMeshName(const MeshGeneratorName & name) const { return _null_mesh_names.count(name); }
166 :
167 : /**
168 : * Return whether or not to save the current mesh
169 : */
170 : bool hasSaveMesh() const;
171 :
172 : /**
173 : * @return Whether or not to output this mesh generator separately (output parameter is set)
174 : */
175 : bool hasOutput() const;
176 :
177 : /**
178 : * Return the name of the saved mesh
179 : */
180 : const std::string & getSavedMeshName() const;
181 :
182 : /**
183 : * @return Whether or not this generator has a generateData() implementation
184 : */
185 47937 : bool hasGenerateData() const { return hasGenerateData(_pars); }
186 :
187 : /**
188 : * @return Whether or not this generator is to be generated in data-only mode
189 : */
190 146549 : bool isDataOnly() const { return _data_only; }
191 :
192 : protected:
193 : /**
194 : * Generate the mesh data
195 : */
196 : virtual void generateData();
197 :
198 : /**
199 : * Methods for writing out attributes to the mesh meta-data store, which can be retrieved from
200 : * most other MOOSE systems and is recoverable.
201 : */
202 : ///@{
203 : template <typename T, typename... Args>
204 : T & declareMeshProperty(const std::string & data_name, Args &&... args);
205 : template <typename T>
206 178976 : T & declareMeshProperty(const std::string & data_name, const T & data_value)
207 : {
208 178976 : return declareMeshProperty<T, const T &>(data_name, data_value);
209 : }
210 : ///@}
211 :
212 : /**
213 : * Method for updating attributes to the mesh meta-data store, which can only be invoked in
214 : * the MeshGenerator generate routine only if the mesh generator property has already been
215 : * declared.
216 : */
217 : ///@{
218 : template <typename T, typename... Args>
219 : T & setMeshProperty(const std::string & data_name, Args &&... args);
220 : template <typename T>
221 : T & setMeshProperty(const std::string & data_name, const T & data_value)
222 : {
223 : return setMeshProperty<T, const T &>(data_name, data_value);
224 : }
225 : ///@}
226 :
227 : /**
228 : * Method for copying attribute from input mesh meta-data store to current mesh meta-data store.
229 : * This may often be avoided as getMeshProperty calls can traverse the tree of mesh generators to
230 : * find a metadata instance
231 : */
232 : template <typename T>
233 : T & copyMeshProperty(const std::string & target_data_name,
234 : const std::string & source_data_name,
235 : const std::string & source_mesh)
236 : {
237 : return declareMeshProperty(target_data_name, getMeshProperty<T>(source_data_name, source_mesh));
238 : }
239 :
240 : /**
241 : * Method for copying attribute from input mesh meta-data store to current mesh meta-data store,
242 : * keeping source and target data names the same. This may often be avoided as getMeshProperty
243 : * calls can traverse the tree of mesh generators to find a metadata instance
244 : */
245 : template <typename T>
246 : T & copyMeshProperty(const std::string & source_data_name, const std::string & source_mesh)
247 : {
248 : return copyMeshProperty<T>(source_data_name, source_data_name, source_mesh);
249 : }
250 :
251 : /**
252 : * Takes the name of a MeshGeneratorName parameter and then gets a pointer to the
253 : * Mesh that MeshGenerator is going to create.
254 : *
255 : * That MeshGenerator is made to be a dependency of this one, so
256 : * will generate() its mesh first.
257 : *
258 : * @param param_name The name of the parameter that contains the name of the MeshGenerator
259 : * @param allow_invalid If true, will allow for invalid parameters and will return a nullptr
260 : * mesh if said parameter does not exist
261 : * @return The Mesh generated by that MeshGenerator
262 : *
263 : * NOTE: You MUST catch this by reference!
264 : */
265 : [[nodiscard]] std::unique_ptr<MeshBase> & getMesh(const std::string & param_name,
266 : const bool allow_invalid = false);
267 : /**
268 : * Like getMesh(), but for multiple generators.
269 : *
270 : * @returns The generated meshes
271 : */
272 : [[nodiscard]] std::vector<std::unique_ptr<MeshBase> *> getMeshes(const std::string & param_name);
273 : /**
274 : * Like \p getMesh(), but takes the name of another MeshGenerator directly.
275 : *
276 : * NOTE: You MUST catch this by reference!
277 : *
278 : * @return The Mesh generated by that MeshGenerator
279 : */
280 : [[nodiscard]] std::unique_ptr<MeshBase> &
281 : getMeshByName(const MeshGeneratorName & mesh_generator_name);
282 : /**
283 : * Like getMeshByName(), but for multiple generators.
284 : *
285 : * @returns The generated meshes
286 : */
287 : [[nodiscard]] std::vector<std::unique_ptr<MeshBase> *>
288 : getMeshesByName(const std::vector<MeshGeneratorName> & mesh_generator_names);
289 :
290 : /**
291 : * Declares that a MeshGenerator referenced in the InputParameters is to be
292 : * used as a dependency of a sub MeshGenerator created by this MeshGenerator
293 : * (see addSubMeshGenerator)
294 : *
295 : * You _must_ declare all such MeshGenerators that are passed by parameter to this
296 : * MeshGenerator but instead used in a sub MeshGenerator. This is in order to
297 : * declare the intention to use an input mesh as a dependency for a sub generator
298 : * instead of this one.
299 : */
300 : void declareMeshForSub(const std::string & param_name);
301 : /**
302 : * Like declareMeshForSub(), but for multiple generators.
303 : */
304 : void declareMeshesForSub(const std::string & param_name);
305 : /**
306 : * Like declareMeshForSub(), but takes the name of another MeshGenerator directly.
307 : */
308 : void declareMeshForSubByName(const MeshGeneratorName & mesh_generator_name);
309 : /**
310 : * Like declareMeshForSubByName(), but for multiple generators.
311 : */
312 : void declareMeshesForSubByName(const std::vector<MeshGeneratorName> & mesh_generator_names);
313 :
314 : /**
315 : * Build a \p MeshBase object whose underlying type will be determined by the Mesh input file
316 : * block
317 : * @param dim The logical dimension of the mesh, e.g. 3 for hexes/tets, 2 for quads/tris. If the
318 : * caller doesn't specify a value for \p dim, then the value in the \p Mesh input file block will
319 : * be used
320 : */
321 : [[nodiscard]] std::unique_ptr<MeshBase>
322 : buildMeshBaseObject(unsigned int dim = libMesh::invalid_uint);
323 :
324 : /**
325 : * Build a replicated mesh
326 : * @param dim The logical dimension of the mesh, e.g. 3 for hexes/tets, 2 for quads/tris. If the
327 : * caller doesn't specify a value for \p dim, then the value in the \p Mesh input file block will
328 : * be used
329 : */
330 : [[nodiscard]] std::unique_ptr<ReplicatedMesh>
331 : buildReplicatedMesh(unsigned int dim = libMesh::invalid_uint);
332 :
333 : /**
334 : * Build a distributed mesh that has correct remote element removal behavior and geometric
335 : * ghosting functors based on the simulation objects
336 : * @param dim The logical dimension of the mesh, e.g. 3 for hexes/tets, 2 for quads/tris. If the
337 : * caller doesn't specify a value for \p dim, then the value in the \p Mesh input file block will
338 : * be used
339 : */
340 : [[nodiscard]] std::unique_ptr<DistributedMesh>
341 : buildDistributedMesh(unsigned int dim = libMesh::invalid_uint);
342 :
343 : /**
344 : * Construct a "subgenerator", a different MeshGenerator subclass
345 : * that will be added to the same MooseApp on the fly.
346 : *
347 : * @param type The type of MeshGenerator
348 : * @param name The name of the MeshGenerator
349 : * @param extra_input_parameters ... Additional InputParameters to pass
350 : *
351 : * Sub generators must be added in the order that they are executed.
352 : *
353 : * Any input dependencies for a sub generator that come from inputs for
354 : * this generator must first be declared with the declareMesh(es)ForSub()
355 : * method.
356 : *
357 : * You can use the output of a sub generator as a mesh in this generator
358 : * by calling getMesh() with the sub generator's name _after_ adding
359 : * said sub generator.
360 : */
361 : template <typename... Ts>
362 : void addMeshSubgenerator(const std::string & type,
363 : const std::string & name,
364 : Ts... extra_input_parameters);
365 :
366 : /**
367 : * Construct a "subgenerator", as above. User code is responsible
368 : * for constructing valid InputParameters.
369 : *
370 : * @param type The type of MeshGenerator
371 : * @param name The name of the MeshGenerator
372 : * @param params The parameters to use to construct the MeshGenerator
373 : */
374 : void
375 : addMeshSubgenerator(const std::string & type, const std::string & name, InputParameters params);
376 :
377 : /**
378 : * Registers the name \p name as a "null" mesh, which is a MeshGenerator used in
379 : * InputParameters that will not represent an input mesh when requested via getMesh.
380 : *
381 : * An example use case for this is when you as a developer want users to represent a hole
382 : * in a mesh pattern that is defined in input.
383 : *
384 : */
385 : void declareNullMeshName(const MeshGeneratorName & name);
386 :
387 : /// Pointer to the owning mesh
388 : MooseMesh * const _mesh;
389 :
390 : private:
391 : /**
392 : * Override of the default prefix to use when getting mesh properties.
393 : *
394 : * Until we support getting mesh properties from other mesh generators (which is coming),
395 : * we will default to properties returned by this generator.
396 : */
397 358632 : virtual std::string meshPropertyPrefix(const std::string &) const override final
398 : {
399 358632 : return name();
400 : }
401 :
402 : /**
403 : * Helper for performing error checking in the getMesh methods.
404 : */
405 : void checkGetMesh(const MeshGeneratorName & mesh_generator_name,
406 : const std::string & param_name) const;
407 :
408 : /**
409 : * Helper for getting a MeshGeneratorName parameter
410 : */
411 : const MeshGeneratorName * getMeshGeneratorNameFromParam(const std::string & param_name,
412 : const bool allow_invalid) const;
413 : /**
414 : * Helper for getting a std::vector<MeshGeneratorName> parameter
415 : */
416 : const std::vector<MeshGeneratorName> &
417 : getMeshGeneratorNamesFromParam(const std::string & param_name) const;
418 :
419 : /**
420 : * Helper for getting a writable reference to a mesh property, used in
421 : * declareMeshProperty and setMeshProperty.
422 : */
423 : RestartableDataValue & setMeshPropertyHelper(const std::string & data_name);
424 :
425 : /// The names of the MeshGenerators that were requested in the getMesh methods
426 : std::set<MeshGeneratorName> _requested_mesh_generators;
427 : /// The names of the MeshGenerators that were requested in the declareMeshForSub methods
428 : std::set<MeshGeneratorName> _requested_mesh_generators_for_sub;
429 : /// The meshes that were requested by this MeshGenerator; used to verify that
430 : /// any input meshes that are requested are properly released after generation
431 : std::vector<std::pair<std::string, std::unique_ptr<MeshBase> *>> _requested_meshes;
432 :
433 : /// A nullptr to use for when inputs aren't specified
434 : std::unique_ptr<MeshBase> _null_mesh = nullptr;
435 :
436 : /// The MeshGenerators that are parents to this MeshGenerator
437 : std::set<const MeshGenerator *, Comparator> _parent_mesh_generators;
438 : /// The MeshGenerators that are children to this MeshGenerator
439 : std::set<const MeshGenerator *, Comparator> _child_mesh_generators;
440 : /// The sub MeshGenerators constructed by this MeshGenerator
441 : std::set<const MeshGenerator *, Comparator> _sub_mesh_generators;
442 :
443 : /// The declared "null" mesh names that will not represent a mesh in input; see declareNullMeshName()
444 : std::set<std::string> _null_mesh_names;
445 :
446 : /// A user-defined name to save the mesh
447 : const std::string & _save_with_name;
448 :
449 : /// Whether or not this mesh generator will run in data only mode
450 : const bool _data_only;
451 : };
452 :
453 : template <typename T, typename... Args>
454 : T &
455 179300 : MeshGenerator::declareMeshProperty(const std::string & data_name, Args &&... args)
456 : {
457 179300 : if (!_app.constructingMeshGenerators())
458 4 : mooseError("Can only call declareMeshProperty() during MeshGenerator construction");
459 :
460 : // We sort construction ordering so that we _must_ declare before retrieving
461 179296 : if (hasMeshProperty(data_name))
462 4 : mooseError("While declaring mesh property '",
463 : data_name,
464 : "' with type '",
465 : MooseUtils::prettyCppType<T>(),
466 : "',\nsaid property has already been declared with type '",
467 4 : setMeshPropertyHelper(data_name).type(),
468 : "'");
469 :
470 179292 : const auto full_name = meshPropertyName(data_name);
471 179292 : auto new_T_value =
472 179292 : std::make_unique<RestartableData<T>>(full_name, nullptr, std::forward<Args>(args)...);
473 : auto value =
474 179292 : &_app.registerRestartableData(std::move(new_T_value), 0, false, MooseApp::MESH_META_DATA);
475 : mooseAssert(value->declared(), "Should be declared");
476 :
477 179292 : RestartableData<T> * T_value = dynamic_cast<RestartableData<T> *>(value);
478 : mooseAssert(T_value, "Bad cast");
479 :
480 358584 : return T_value->set();
481 179292 : }
482 :
483 : template <typename T, typename... Args>
484 : T &
485 20 : MeshGenerator::setMeshProperty(const std::string & data_name, Args &&... args)
486 : {
487 20 : if (_app.actionWarehouse().getCurrentTaskName() != "execute_mesh_generators")
488 0 : mooseError("Updating mesh meta data with setMeshProperty() can only be called during "
489 : "MeshGenerator::generate()");
490 :
491 20 : if (!hasMeshProperty(data_name))
492 0 : mooseError("Failed to get the mesh property '", data_name, "'");
493 20 : RestartableDataValue * value = &setMeshPropertyHelper(data_name);
494 20 : RestartableData<T> * T_value = dynamic_cast<RestartableData<T> *>(value);
495 20 : if (!T_value)
496 0 : mooseError("While retrieving mesh property '",
497 : data_name,
498 : "' with type '",
499 : MooseUtils::prettyCppType<T>(),
500 : "',\nthe property was found with type '",
501 0 : value->type(),
502 : "'");
503 :
504 : // Set the value if someone provided arguments to set it to
505 : if constexpr (sizeof...(args) > 0)
506 : T_value->set() = T(std::forward<Args>(args)...);
507 :
508 20 : return T_value->set();
509 : }
510 :
511 : template <typename... Ts>
512 : void
513 8 : MeshGenerator::addMeshSubgenerator(const std::string & type,
514 : const std::string & name,
515 : Ts... extra_input_parameters)
516 : {
517 8 : InputParameters subgenerator_params = _app.getFactory().getValidParams(type);
518 :
519 8 : subgenerator_params.setParameters(extra_input_parameters...);
520 :
521 8 : addMeshSubgenerator(type, name, subgenerator_params);
522 8 : }
|