16#include "libmesh/mesh_tools.h"
20 "allow_data_driven_mesh_generation";
33 const std::string & name,
38 std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
48 const std::string & name,
52 mooseError(
"Can only call appendMeshGenerator() during the append_mesh_generator task");
57 if ((param_name_mg_name_pairs.size() == 0) ||
58 (param_name_mg_name_pairs.size() == 1 && param_name_mg_name_pairs[0].first !=
"input" &&
59 param_name_mg_name_pairs[0].first !=
"inputs") ||
60 (param_name_mg_name_pairs.size() > 1 && param_name_mg_name_pairs[0].first !=
"inputs"))
65 "' via appendMeshGenerator():\nCan only append a mesh generator that takes a "
66 "single input mesh generator via the parameter named 'input' or 'inputs'.");
77 mooseError(
"Cannot use appendMeshGenerator() because there is not a generator to append to!");
95 std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
100std::vector<std::pair<std::string, MeshGeneratorName>>
102 const bool allow_empty )
const
104 std::vector<std::pair<std::string, MeshGeneratorName>> dependencies;
106 auto add_dependency =
107 [&dependencies, &allow_empty](
const auto & param_name,
const auto & dependency)
109 if (dependency.size() || allow_empty)
110 dependencies.emplace_back(param_name, dependency);
113 for (
const auto & [name, param] : params)
114 if (
const auto dependency =
116 add_dependency(name, dependency->get());
117 else if (
const auto dependencies =
dynamic_cast<
121 if (allow_empty && dependencies->get().empty())
122 add_dependency(name, std::string());
123 for (
const auto & dependency : dependencies->get())
124 add_dependency(name, dependency);
134 "Should not run now");
146 for (
const auto & param_dependency_pair :
148 resolver.
addEdge(param_dependency_pair.second, name);
151 std::vector<std::vector<std::string>> ordered_generators;
158 mooseError(
"Cyclic dependencies detected in mesh generation: ",
165 if (!moose_mesh.get())
166 mooseError(
"No mesh created. Either add a Mesh, an ActionComponents or a Components block");
170 if (moose_mesh->parameters().get<
bool>(
"_mesh_generator_mesh") &&
174 moose_mesh->paramError(
176 "This application does not support data-driven mesh generation.\n\nThis generation is an "
177 "advanced feature and must be enabled on the application via the '",
181 mooseAssert(moose_mesh->type() ==
"MeshGeneratorMesh",
182 "Assumption for mesh type is now invalid");
187 "The data driven generator '",
196 "This parameter should not be set in conjunction with --csg-only");
199 for (
const auto & generator_names : ordered_generators)
200 for (
const auto & generator_name : generator_names)
203 auto & params = it->second.second;
206 const bool data_only =
217 " cannot be used in csg-only mode since it does not have a generateCSG "
221 "Inconsistent data only");
229 if (moose_mesh->parameters().get<
bool>(
"_mesh_generator_mesh") &&
230 moose_mesh->isParamValid(
"final_generator"))
232 mooseAssert(moose_mesh->type() ==
"MeshGeneratorMesh",
233 "Assumption for mesh type is now invalid");
237 moose_mesh->paramError(
"final_generator",
238 "The forced final MeshGenerator '",
249 "Incorrect call time");
253 TIME_SECTION(
"createMeshGeneratorOrder", 1,
"Ordering Mesh Generators");
262 std::vector<std::string> required_generators;
264 if (it.second->hasSaveMesh() || it.second->hasOutput())
265 required_generators.push_back(it.second->name());
285 std::find_if(required_generators.begin(),
286 required_generators.end(),
288 required_generators.end())
312 std::vector<std::string> names(cycle.size());
313 for (
const auto i : index_range(cycle))
314 names[i] = cycle[i]->name();
316 mooseError(
"Cyclic dependencies detected in mesh generation: ",
317 MooseUtils::join(names,
" <- "));
327 mooseAssert(final_generators.size(),
"Empty vector");
330 const auto ancestor_list = resolver.
getAncestors(final_generators.back());
335 std::set<MeshGenerator *, MeshGenerator::Comparator> ancestors(ancestor_list.begin(),
336 ancestor_list.end());
340 decltype(ancestors) all(allValues.begin(), allValues.end());
342 decltype(ancestors) ind_tree;
343 std::set_difference(all.begin(),
347 std::inserter(ind_tree, ind_tree.end()));
349 std::ostringstream oss;
350 oss <<
"Your MeshGenerator tree contains multiple possible generator outputs :\n\""
351 << final_generators.back()->name()
352 <<
"\" and one or more of the following from an independent set: \"";
354 for (
const auto & gen : ind_tree)
363 oss <<
"\"\n\nThis may be due to a missing dependency or may be intentional. Please either\n"
364 "- check that all the mesh generators are connected as a tree and culminate in a "
365 "single final mesh. Having one wrong 'input=mg' parameter is the most common error\n"
366 "- add additional dependencies to remove the ambiguity if you are using a user-built "
368 "- if you intend to execute a subset of the defined generators (uncommon), select the"
369 " final MeshGenerator in the [Mesh] block with the \"final_generator\" parameter.";
382 libmesh_parallel_only(
comm());
392 std::map<std::string, std::unique_ptr<MeshBase> *> to_save_in_meshes;
394 for (
const auto & generator : generator_set)
395 if (generator->hasSaveMesh())
398 generator->paramError(
"save_with_name",
399 "Cannot use the save in capability with the final mesh generator");
401 generator->paramError(
"save_with_name",
"Cannot use in conjunction with --csg-only");
402 to_save_in_meshes.emplace(generator->getSavedMeshName(),
412 for (
const auto & generator : generator_set)
414 mooseAssert(
comm().verify(generator->typeAndName().size()) &&
415 comm().verify(generator->typeAndName()),
416 "Mesh generator generation is parallel inconsistent; about to execute "
417 << generator->typeAndName());
419 const auto & name = generator->name();
421 _app.
_console <<
" [DBG] Executing mesh generator (" << COLOR_GREEN << std::setw(20) << name
422 << COLOR_DEFAULT <<
") in type (" << COLOR_GREEN << generator->type()
423 << COLOR_DEFAULT <<
")" << std::endl;
424 auto current_mesh = generator->generateInternal();
426 if (!generator->isDataOnly())
427 mooseAssert(
comm().verify(current_mesh->is_prepared()),
428 "Mesh prepared state after " << generator->typeAndName()
429 <<
" is parallel inconsistent");
431 mooseAssert(
comm().verify(generator->typeAndName().size()) &&
432 comm().verify(generator->typeAndName()),
433 "Mesh generator generation is parallel inconsistent; just executed "
434 << generator->typeAndName());
437 if (generator->isDataOnly())
439 mooseAssert(!current_mesh,
"Should not have a mesh");
451 generator->mooseError(
452 "The generated mesh is marked as (at least partially) prepared but is not "
453 "prepared in the marked sense(s). Please edit the '",
455 "' class to call 'unset_is_prepared()', or more fine-grained "
456 "alternatives as appropriate.");
464 auto & first_output = *outputs.begin();
466 first_output = std::move(current_mesh);
468 const auto & copy_from = *first_output;
470 auto output_it = ++outputs.begin();
473 for (; output_it != outputs.end(); ++output_it)
474 (*output_it) = copy_from.clone();
485 for (
auto & [name, mesh_ptr] : to_save_in_meshes)
487 mooseAssert(mesh_ptr,
"Invalid pointer");
488 mooseAssert(*mesh_ptr,
"Invalid pointer");
490 mooseAssert(
_save_in_meshes.count(name),
"Mesh has not been requested for save");
495std::shared_ptr<MeshGenerator>
498 libmesh_parallel_only(
comm());
503 const auto & [type, params] = find_params->second;
504 mooseAssert(
comm().verify(type + generator_name),
"Inconsistent construction order");
506 std::shared_ptr<MeshGenerator> mg =
509 if (mg->hasSaveMesh())
513 "The save with name '",
514 mg->getSavedMeshName(),
515 "' has already been used");
520 for (
const auto & dependency : mg->getRequestedMeshGenerators())
537 const auto & param_name = param_dependency_pair.first;
538 const auto & dependency_name = param_dependency_pair.second;
540 if (mg->isNullMeshName(dependency_name))
544 if (mg->isParentMeshGenerator(dependency_name))
546 mooseAssert(mg->getRequestedMeshGenerators().count(dependency_name),
"Wasn't requested");
551 auto find_sub_dependency = std::find_if(mg->getSubMeshGenerators().begin(),
552 mg->getSubMeshGenerators().end(),
553 [&dependency_name](
const auto & mg)
554 { return mg->isParentMeshGenerator(dependency_name); });
555 const auto is_sub_dependency = find_sub_dependency != mg->getSubMeshGenerators().end();
558 if (mg->getRequestedMeshGeneratorsForSub().count(dependency_name))
560 if (!is_sub_dependency)
561 mg->mooseError(
"The sub generator dependency declared from MeshGenerator '",
563 "' from the parameter '",
565 "' was not used.\n\nDependencies that are declared by declareMeshForSub() "
566 "must be used as an input to a sub generator created by this object.");
569 else if (is_sub_dependency)
571 "The MeshGenerator '",
573 "' was referenced in the parameter '",
575 "' and used in the sub generator ",
576 (*find_sub_dependency)->type(),
578 (*find_sub_dependency)->name(),
579 "', but was not declared as a sub dependency.\n\nTo correct this, modify the code of ",
581 " to include a call to declareMesh(es)ForSub(\"",
583 "\") in the constructor.");
587 "You failed to request the generated mesh(es) for the parameter '",
589 "'.\n\nIn specific, the mesh from MeshGenerator '",
591 "' was not requested.\n\nTo correct this, you should remove the parameter if the "
592 "mesh(es)\nare not needed, or request the mesh(es) with getMesh()/getMeshes().");
609std::unique_ptr<MeshBase> &
614 "Incorrect call time");
618 it->second.push_back(
nullptr);
619 return it->second.back();
639 mooseError(
"Failed to find a MeshGenerator with the name '", name,
"'");
640 mooseAssert(it->second,
"Invalid shared pointer");
644std::vector<std::string>
647 std::vector<std::string> names;
649 names.push_back(pair.first);
653std::vector<std::string>
656 std::vector<std::string> names;
658 names.push_back(pair.first);
662std::unique_ptr<MeshBase>
667 mooseError(
"Failed to find a saved mesh with the name '", name,
"'");
669 auto & mesh_unique_ptr = find_mesh->second;
670 if (!mesh_unique_ptr)
671 mooseError(
"While getting the saved mesh generator '",
673 "', said mesh has already been retrieved");
675 return std::move(mesh_unique_ptr);
699 const std::string & message)
const
705 "' cannot be used in data-driven mode because the parent ",
719 std::unique_ptr<CSG::CSGBase> & csg_base)
728 auto & first_output = *outputs.begin();
729 first_output = std::move(csg_base);
730 const auto & copy_from = *first_output;
731 auto output_it = ++outputs.begin();
733 for (; output_it != outputs.end(); ++output_it)
734 (*output_it) = copy_from.clone();
738std::unique_ptr<CSG::CSGBase> &
743 "Incorrect call time");
747 it->second.push_back(
nullptr);
748 return it->second.back();
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
const std::string & getCurrentTaskName() const
const std::shared_ptr< MooseMesh > & getMesh() const
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
const std::vector< T > & getCyclicDependencies() const
Class that represents the dependecy as a graph.
bool dependsOn(const T &key, const T &value)
Return true if key depends on value.
std::list< T > getAncestors(const T &key)
Returns a list of all values that a given key depends on.
void addItem(const T &value)
Add an independent item to the set.
std::size_t size() const
Returns the number of unique items stored in the dependency resolver.
const std::vector< T > & getSortedValues()
This function also returns dependency resolved values but with a simpler single vector interface.
void addEdge(const T &a, const T &b)
Add an edge between nodes 'a' and 'b'.
const std::vector< std::vector< T > > & getSortedValuesSets()
Returns a vector of sets that represent dependency resolved values.
std::shared_ptr< MooseObject > create(const std::string &obj_name, const std::string &name, const InputParameters ¶meters, THREAD_ID tid=0, bool print_deprecated=true)
void saveOutputCSGBase(const MeshGeneratorName generator_name, std::unique_ptr< CSG::CSGBase > &csg_base)
Saves the CSGBase object to the global map storage, _csg_base_output, for a particular mesh generator...
MooseApp & _app
The MooseApp that owns this system.
void addMeshGenerator(const std::string &type, const std::string &name, const InputParameters ¶ms)
Add a mesh generator that will act on the meshes in the system.
std::vector< std::string > getMeshGeneratorNames() const
Get names of all mesh generators Note: This function should be called after all mesh generators are a...
bool hasMeshGeneratorParams(const MeshGeneratorName &name) const
Whether or not we know about the parameters for a MeshGenerator with the given name.
std::vector< std::vector< MeshGenerator * > > _ordered_mesh_generators
Holds the ordered mesh generators from createMeshGeneratorOrder() until they are executed in executeM...
std::shared_ptr< MeshGenerator > createMeshGenerator(const std::string &name)
Internal method for actually constructing a mesh generator after it has been declared externally in a...
std::unique_ptr< libMesh::MeshBase > & getMeshGeneratorOutput(const MeshGeneratorName &name)
Get a reference to a pointer that will be the output of the MeshGenerator named name.
std::map< std::string, std::list< std::unique_ptr< libMesh::MeshBase > > > _mesh_generator_outputs
Holds the output for each mesh generator - including duplicates needed downstream.
std::map< std::string, std::shared_ptr< MeshGenerator > > _mesh_generators
Owning storage for mesh generators, map of name -> MeshGenerator.
std::unordered_map< std::string, std::pair< std::string, InputParameters > > _mesh_generator_params
The MeshGenerators declared using addMeshGenerator(), cleared after createMeshGenerators() Key is the...
bool hasMeshGenerator(const MeshGeneratorName &name) const
void createAddedMeshGenerators()
Creates (constructs) all of the MeshGenerators that have been declared using addMeshGenerator().
static const std::string allow_data_driven_param
The name of the boolean parameter on the MooseApp that will enable data driven generation.
std::unique_ptr< CSG::CSGBase > & getCSGBaseGeneratorOutput(const MeshGeneratorName &name)
Returns the output CSGBase object associated with a particular mesh generator name.
std::map< std::string, std::unique_ptr< libMesh::MeshBase > > _save_in_meshes
Holds the map of save in mesh -> name.
void setCSGOnly()
Set whether mesh generator system is running in CSG-only mode to true.
const std::string & getDataDrivenGeneratorName() const
std::optional< std::string > _data_driven_generator_name
The name of the data driven generator, if any.
static std::string mainMeshGeneratorName()
The name reserved for the "main" mesh generator which is the one used for the numerical solver downst...
std::vector< std::pair< std::string, MeshGeneratorName > > getMeshGeneratorParamDependencies(const InputParameters ¶ms, const bool allow_empty=false) const
Gets the MeshGeneratorNames that are referenced in an object's parameters.
static const std::string data_driven_generator_param
The name of the string parameter that sets the data driven generator.
void executeMeshGenerators()
Execute and clear the Mesh Generators data structure.
bool appendingMeshGenerators() const
Whether or not mesh generators are currently being appended (append_mesh_generator task)
bool getCSGOnly() const
Get whether mesh generator system is running in CSG-only mode.
const MeshGenerator & appendMeshGenerator(const std::string &type, const std::string &name, InputParameters params)
Append a mesh generator that will act on the current final mesh generator in the system.
std::vector< std::string > getSavedMeshNames() const
Get all user-defined saved meshes except main and main_displaced.
bool _csg_only
Whether mesh generator system is running in CSG-only mode.
std::unique_ptr< libMesh::MeshBase > getSavedMesh(const std::string &name)
Get the saved mesh by name.
bool hasDataDrivenAllowed() const
std::map< std::string, std::list< std::unique_ptr< CSG::CSGBase > > > _csg_base_outputs
Holds the output CSGBase object for each mesh generator - including duplicates when needed by multipl...
MeshGenerator & getMeshGeneratorInternal(const std::string &name)
Get a MeshGenerator with the name name.
const MeshGenerator & getMeshGenerator(const std::string &name) const
bool _verbose
Whether to print the names of the mesh generators being executed or not.
MeshGeneratorSystem(MooseApp &app)
std::string _final_generator_name
The final mesh generator name to use.
void dataDrivenError(const MeshGenerator &generator, const std::string &message) const
Reports an error with the context of the data driven parameter, coming from the generator generator w...
void createMeshGeneratorOrder()
Order all of the _mesh_generators into _ordered_mesh_generators for later execution in executeMeshGen...
Class that is used as a parameter to add[Parent/Child]() that allows only MeshGeneratorSystem methods...
MeshGenerators are objects that can modify or add to an existing mesh.
bool hasSaveMesh() const
Return whether or not to save the current mesh.
static const std::string data_only_param
The name of the private parameter for setting data only.
const std::set< const MeshGenerator *, Comparator > & getParentMeshGenerators() const
Gets the MeshGenerators that are parents to this MeshGenerator.
bool isChildMeshGenerator(const MeshGeneratorName &name, const bool direct=true) const
Base class for MOOSE-based applications.
ActionWarehouse & actionWarehouse()
Return a writable reference to the ActionWarehouse associated with this app.
virtual bool constructingMeshGenerators() const
Whether this app is constructing mesh generators.
Factory & getFactory()
Retrieve a writable reference to the Factory associated with this App.
const InputParameters & parameters() const
Get the parameters of the object.
std::string typeAndName() const
Get the class's combined type and name; useful in error handling.
const std::string & name() const
Get the name of the class.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Interface for objects interacting with the PerfGraph.
const Parallel::Communicator & comm() const