https://mooseframework.inl.gov
MeshGeneratorSystem.C
Go to the documentation of this file.
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 "MeshGeneratorSystem.h"
11 
12 #include "MooseApp.h"
13 #include "MeshGenerator.h"
14 #include "DependencyResolver.h"
15 
16 #include "libmesh/mesh_tools.h"
17 
18 using namespace libMesh;
19 
20 const std::string MeshGeneratorSystem::data_driven_generator_param = "data_driven_generator";
22  "allow_data_driven_mesh_generation";
23 
25  : PerfGraphInterface(app.perfGraph(), "MeshGeneratorSystem"),
26  ParallelObject(app),
27  _app(app),
28  _verbose(false),
29  _csg_only(false)
30 {
31 }
32 
33 void
34 MeshGeneratorSystem::addMeshGenerator(const std::string & type,
35  const std::string & name,
36  const InputParameters & params)
37 {
38  mooseAssert(!_mesh_generator_params.count(name), "Already exists");
39  _mesh_generator_params.emplace(
40  std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
41 
42  // This should be a sub mesh generator. We can assume this because if we're in the middle of
43  // constructing mesh generators (not "adding" them, where we simply store their parameters)
46 }
47 
48 const MeshGenerator &
50  const std::string & name,
51  InputParameters params)
52 {
54  mooseError("Can only call appendMeshGenerator() during the append_mesh_generator task");
55  const auto param_name_mg_name_pairs = getMeshGeneratorParamDependencies(params, true);
56 
57  // Make sure this mesh generator has one and _only_ one input, in the "input" parameter,
58  // Or several, listed in the "inputs" parameter
59  if ((param_name_mg_name_pairs.size() == 0) ||
60  (param_name_mg_name_pairs.size() == 1 && param_name_mg_name_pairs[0].first != "input" &&
61  param_name_mg_name_pairs[0].first != "inputs") ||
62  (param_name_mg_name_pairs.size() > 1 && param_name_mg_name_pairs[0].first != "inputs"))
63  mooseError("While adding ",
64  type,
65  " '",
66  name,
67  "' via appendMeshGenerator():\nCan only append a mesh generator that takes a "
68  "single input mesh generator via the parameter named 'input' or 'inputs'.");
69 
70  // If no final generator is set, we need to make sure that we have one; we will hit
71  // this the first time we add an appended MeshGenerator and only need to do it once.
72  // We'll then generate the final ordering within the execution phase. We'll also
73  // clear the ordering because it could be invalid if we append any more generators,
74  // and we'll be re-ordering within executeMeshgenerators() anyway (where we don't
75  // keep track of any state for the sake of simpler logic)
76  if (_final_generator_name.empty())
77  {
78  if (_mesh_generators.empty())
79  mooseError("Cannot use appendMeshGenerator() because there is not a generator to append to!");
80 
83  }
84 
85  // Set the final generator as the input if a single generator
86  mooseAssert(hasMeshGenerator(_final_generator_name), "Missing final generator");
87  if (params.have_parameter<MeshGeneratorName>("input"))
88  params.set<MeshGeneratorName>("input") = _final_generator_name;
89  // We'll trust the final combiner generator with its list of inputs
90 
91  // Keep track of the new final generator
93 
94  // Need to add this to the param map so that createMeshGenerator can use it
95  mooseAssert(!_mesh_generator_params.count(name), "Already exists");
96  _mesh_generator_params.emplace(
97  std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
98 
99  return *createMeshGenerator(name);
100 }
101 
102 std::vector<std::pair<std::string, MeshGeneratorName>>
104  const bool allow_empty /* = false */) const
105 {
106  std::vector<std::pair<std::string, MeshGeneratorName>> dependencies;
107 
108  auto add_dependency =
109  [&dependencies, &allow_empty](const auto & param_name, const auto & dependency)
110  {
111  if (dependency.size() || allow_empty)
112  dependencies.emplace_back(param_name, dependency);
113  };
114 
115  for (const auto & [name, param] : params)
116  if (const auto dependency =
117  dynamic_cast<const Parameters::Parameter<MeshGeneratorName> *>(param.get()))
118  add_dependency(name, dependency->get());
119  else if (const auto dependencies =
120  dynamic_cast<const Parameters::Parameter<std::vector<MeshGeneratorName>> *>(
121  param.get()))
122  {
123  if (allow_empty && dependencies->get().empty())
124  add_dependency(name, std::string());
125  for (const auto & dependency : dependencies->get())
126  add_dependency(name, dependency);
127  }
128 
129  return dependencies;
130 }
131 
132 void
134 {
135  mooseAssert(_app.actionWarehouse().getCurrentTaskName() == "create_added_mesh_generators",
136  "Should not run now");
137 
138  // No generators were added via addMeshGenerator()
139  if (_mesh_generator_params.empty())
140  return;
141 
143 
144  // Define the dependencies known so far
145  for (const auto & [name, type_params_pair] : _mesh_generator_params)
146  {
147  resolver.addItem(name);
148  for (const auto & param_dependency_pair :
149  getMeshGeneratorParamDependencies(type_params_pair.second))
150  resolver.addEdge(param_dependency_pair.second, name);
151  }
152 
153  std::vector<std::vector<std::string>> ordered_generators;
154  try
155  {
156  ordered_generators = resolver.getSortedValuesSets();
157  }
159  {
160  mooseError("Cyclic dependencies detected in mesh generation: ",
161  MooseUtils::join(e.getCyclicDependencies(), " <- "));
162  }
163 
164  const auto & moose_mesh = _app.actionWarehouse().getMesh();
165 
166  // If there is no mesh
167  if (!moose_mesh.get())
168  mooseError("No mesh created. Either add a Mesh, an ActionComponents or a Components block");
169 
170  // If we're using data-driven generation, find that requirement now
171  mooseAssert(!_data_driven_generator_name, "Should not be set");
172  if (moose_mesh->parameters().get<bool>("_mesh_generator_mesh") &&
173  moose_mesh->isParamValid(data_driven_generator_param))
174  {
175  if (!hasDataDrivenAllowed())
176  moose_mesh->paramError(
178  "This application does not support data-driven mesh generation.\n\nThis generation is an "
179  "advanced feature and must be enabled on the application via the '",
181  "' parameter.");
182 
183  mooseAssert(moose_mesh->type() == "MeshGeneratorMesh",
184  "Assumption for mesh type is now invalid");
185 
186  _data_driven_generator_name = moose_mesh->getParam<std::string>(data_driven_generator_param);
188  moose_mesh->paramError(data_driven_generator_param,
189  "The data driven generator '",
191  "' does not exist");
192  }
193 
194  // Check compatibility for CLI / meshing options with csg_only
195  const bool csg_only = getCSGOnly();
196  if (csg_only && _data_driven_generator_name)
197  moose_mesh->paramError(data_driven_generator_param,
198  "This parameter should not be set in conjunction with --csg-only");
199 
200  // Construct all of the mesh generators that we know exist
201  for (const auto & generator_names : ordered_generators)
202  for (const auto & generator_name : generator_names)
203  if (auto it = _mesh_generator_params.find(generator_name); it != _mesh_generator_params.end())
204  {
205  auto & params = it->second.second;
206 
207  // Determine now if we need to run this in data only mode
208  const bool data_only =
209  (csg_only ||
211  resolver.dependsOn(getDataDrivenGeneratorName(), generator_name)));
212  params.set<bool>(MeshGenerator::data_only_param) = data_only;
213 
214  createMeshGenerator(generator_name);
215 
216  if (csg_only && !getMeshGenerator(generator_name).hasGenerateCSG())
217  mooseError("Mesh generator ",
218  generator_name,
219  " cannot be used in csg-only mode since it does not have a generateCSG "
220  "implementation");
221 
222  mooseAssert(data_only == getMeshGenerator(generator_name).isDataOnly(),
223  "Inconsistent data only");
224  }
225 
226  mooseAssert(_mesh_generator_params.empty(), "Should be empty");
227  mooseAssert(_final_generator_name.empty(), "Should be unset at this point");
228 
229  // Set the final generator if we have one set by the user
230  // and if so make sure it also exists
231  if (moose_mesh->parameters().get<bool>("_mesh_generator_mesh") &&
232  moose_mesh->isParamValid("final_generator"))
233  {
234  mooseAssert(moose_mesh->type() == "MeshGeneratorMesh",
235  "Assumption for mesh type is now invalid");
236 
237  _final_generator_name = moose_mesh->getParam<std::string>("final_generator");
239  moose_mesh->paramError("final_generator",
240  "The forced final MeshGenerator '",
242  "' does not exist");
243  }
244 }
245 
246 void
248 {
249  mooseAssert(_app.constructingMeshGenerators() ||
250  _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
251  "Incorrect call time");
252  mooseAssert(_ordered_mesh_generators.empty(), "Already ordered");
253  mooseAssert(_mesh_generators.size(), "No mesh generators to order");
254 
255  TIME_SECTION("createMeshGeneratorOrder", 1, "Ordering Mesh Generators");
256 
257  // We dare not sort these based on address!
259 
260  // The mesh generators that must be called
261  // This is needed to mark the generators that could be cut due to a
262  // final generator being set, but should still be called because they're
263  // either being saved in memory or as output
264  std::vector<std::string> required_generators;
265  for (const auto & it : _mesh_generators)
266  if (it.second->hasSaveMesh() || it.second->hasOutput())
267  required_generators.push_back(it.second->name());
268 
269  // The mesh generator tree should have all the mesh generators that
270  // The final generator depends on and all the mesh generators
271  // with 'save in' flag. Here we loop over all the mesh generators
272  // and conditionally add all of the dependencies into the resolver
273  for (const auto & it : _mesh_generators)
274  {
275  MeshGenerator * mg = it.second.get();
276 
277  // The mesh generator has to meet one of the following conditions:
278  // Final mesh generator is not set, so we build the whole tree
279  if (_final_generator_name.empty() ||
280  // This mesh generator is the final generator
281  mg->name() == _final_generator_name ||
282  // This needs to be saved or output
283  mg->hasSaveMesh() || mg->hasOutput() ||
284  // Final mesh generator set and is a child of this generator
286  // This is a dependency of a generator that needs to be saved or output
287  std::find_if(required_generators.begin(),
288  required_generators.end(),
289  [&mg](const auto & name) { return mg->isChildMeshGenerator(name, false); }) !=
290  required_generators.end())
291  {
292  resolver.addItem(mg);
293  for (const auto & dep_mg : mg->getParentMeshGenerators())
294  resolver.addEdge(&getMeshGeneratorInternal(dep_mg->name()), mg);
295  }
296  }
297 
298  // ...and sort them
299  try
300  {
302  }
303  // It is _quite_ hard to trigger this to test it. I've tried to no avail.
304  // Now that we...
305  // - check and sort up front
306  // - know if dependencies exist at the time of requesting them
307  // - require that sub generators depend only on other sub generators in an object's
308  // tree + input dependencies that we explicitly declare
309  // I don't think it's possible. But we'll leave it here anyway and it
310  // definitely will not be covered
312  {
313  const auto & cycle = e.getCyclicDependencies();
314  std::vector<std::string> names(cycle.size());
315  for (const auto i : index_range(cycle))
316  names[i] = cycle[i]->name();
317 
318  mooseError("Cyclic dependencies detected in mesh generation: ",
319  MooseUtils::join(names, " <- "));
320  }
321 
322  mooseAssert(_ordered_mesh_generators.size(), "No mesh generators found");
323 
324  const auto & final_generators = _ordered_mesh_generators.back();
325 
326  // We haven't forced a final generator yet
327  if (_final_generator_name.empty())
328  {
329  mooseAssert(final_generators.size(), "Empty vector");
330 
331  // See if we have multiple independent trees of generators
332  const auto ancestor_list = resolver.getAncestors(final_generators.back());
333  if (ancestor_list.size() != resolver.size() && _final_generator_name.empty())
334  {
335  // Need to remove duplicates and possibly perform a difference so we'll import our list
336  // into a set for these operations.
337  std::set<MeshGenerator *, MeshGenerator::Comparator> ancestors(ancestor_list.begin(),
338  ancestor_list.end());
339  // Get all of the items from the resolver so we can compare against the tree from the
340  // final generator we just pulled.
341  const auto & allValues = resolver.getSortedValues();
342  decltype(ancestors) all(allValues.begin(), allValues.end());
343 
344  decltype(ancestors) ind_tree;
345  std::set_difference(all.begin(),
346  all.end(),
347  ancestors.begin(),
348  ancestors.end(),
349  std::inserter(ind_tree, ind_tree.end()));
350 
351  std::ostringstream oss;
352  oss << "Your MeshGenerator tree contains multiple possible generator outputs :\n\""
353  << final_generators.back()->name()
354  << "\" and one or more of the following from an independent set: \"";
355  bool first = true;
356  for (const auto & gen : ind_tree)
357  {
358  if (!first)
359  oss << ", ";
360  else
361  first = false;
362 
363  oss << gen->name();
364  }
365  oss << "\"\n\nThis may be due to a missing dependency or may be intentional. Please either\n"
366  "- check that all the mesh generators are connected as a tree and culminate in a "
367  "single final mesh. Having one wrong 'input=mg' parameter is the most common error\n"
368  "- add additional dependencies to remove the ambiguity if you are using a user-built "
369  "MeshGenerator\n"
370  "- if you intend to execute a subset of the defined generators (uncommon), select the"
371  " final MeshGenerator in the [Mesh] block with the \"final_generator\" parameter.";
372  mooseError(oss.str());
373  }
374 
375  _final_generator_name = final_generators.back()->name();
376  }
377  else
378  mooseAssert(hasMeshGenerator(_final_generator_name), "Missing the preset final generator");
379 }
380 
381 void
383 {
384  libmesh_parallel_only(comm());
385 
386  // we do not need to do this when there are no mesh generators
387  if (_mesh_generators.empty())
388  return;
389 
390  // Order the generators
392 
393  // Save all meshes marked to to_save_in_meshes and save in error checking
394  std::map<std::string, std::unique_ptr<MeshBase> *> to_save_in_meshes;
395  for (const auto & generator_set : _ordered_mesh_generators)
396  for (const auto & generator : generator_set)
397  if (generator->hasSaveMesh())
398  {
399  if (_final_generator_name == generator->name())
400  generator->paramError("save_with_name",
401  "Cannot use the save in capability with the final mesh generator");
402  if (getCSGOnly())
403  generator->paramError("save_with_name", "Cannot use in conjunction with --csg-only");
404  to_save_in_meshes.emplace(generator->getSavedMeshName(),
405  &getMeshGeneratorOutput(generator->name()));
406  }
407  // Grab the outputs from the final generator so MeshGeneratorMesh can pick it up
408  to_save_in_meshes.emplace(mainMeshGeneratorName(),
410 
411  // Run the MeshGenerators in the proper order
412  for (const auto & generator_set : _ordered_mesh_generators)
413  {
414  for (const auto & generator : generator_set)
415  {
416  const auto & name = generator->name();
417  if (_verbose)
418  _app._console << " [DBG] Executing mesh generator (" << COLOR_GREEN << std::setw(20) << name
419  << COLOR_DEFAULT << ") in type (" << COLOR_GREEN << generator->type()
420  << COLOR_DEFAULT << ")" << std::endl;
421  auto current_mesh = generator->generateInternal();
422 
423  // Only generating data for this generator
424  if (generator->isDataOnly())
425  {
426  mooseAssert(!current_mesh, "Should not have a mesh");
427  continue;
428  }
429 
430 #ifdef DEBUG
431  // Assert that the mesh is either marked as not prepared or if it is marked as prepared,
432  // that it's *actually* prepared.
433  //
434  // In newer version of libMesh, this also asserts that a mesh
435  // marked as partially prepared is indeed prepared in (at least)
436  // the aspects which are so marked.
437  if (!MeshTools::valid_is_prepared(*current_mesh))
438  generator->mooseError(
439  "The generated mesh is marked as (at least partially) prepared but is not "
440  "prepared in the marked sense(s). Please edit the '",
441  generator->type(),
442  "' class to call 'unset_is_prepared()', or more fine-grained "
443  "alternatives as appropriate.");
444 #endif
445 
446  // Now we need to possibly give this mesh to downstream generators
447  auto & outputs = _mesh_generator_outputs[name];
448 
449  if (outputs.size())
450  {
451  auto & first_output = *outputs.begin();
452 
453  first_output = std::move(current_mesh);
454 
455  const auto & copy_from = *first_output;
456 
457  auto output_it = ++outputs.begin();
458 
459  // For all of the rest we need to make a copy
460  for (; output_it != outputs.end(); ++output_it)
461  (*output_it) = copy_from.clone();
462  }
463  }
464  }
465 
466  // No save in meshes exist in csg only mode
467  if (getCSGOnly())
468  return;
469 
470  // Grab all the valid save in meshes from the temporary map to_save_in_meshes
471  // and store them in _save_in_meshes
472  for (auto & [name, mesh_ptr] : to_save_in_meshes)
473  {
474  mooseAssert(mesh_ptr, "Invalid pointer");
475  mooseAssert(*mesh_ptr, "Invalid pointer");
476  if (name != mainMeshGeneratorName())
477  mooseAssert(_save_in_meshes.count(name), "Mesh has not been requested for save");
478  _save_in_meshes[name] = std::move(*mesh_ptr);
479  }
480 }
481 
482 std::shared_ptr<MeshGenerator>
483 MeshGeneratorSystem::createMeshGenerator(const std::string & generator_name)
484 {
485  libmesh_parallel_only(comm());
486  mooseAssert(_app.constructingMeshGenerators(), "Should not run now");
487 
488  const auto find_params = _mesh_generator_params.find(generator_name);
489  mooseAssert(find_params != _mesh_generator_params.end(), "Not added");
490  const auto & [type, params] = find_params->second;
491  mooseAssert(comm().verify(type + generator_name), "Inconsistent construction order");
492 
493  std::shared_ptr<MeshGenerator> mg =
494  _app.getFactory().create<MeshGenerator>(type, generator_name, params);
495 
496  if (mg->hasSaveMesh())
497  {
498  if (_save_in_meshes.count(mg->getSavedMeshName()))
499  mg->paramError("save_with_name",
500  "The save with name '",
501  mg->getSavedMeshName(),
502  "' has already been used");
503  _save_in_meshes.emplace(mg->getSavedMeshName(), nullptr);
504  }
505 
506  // Setup the children and parents
507  for (const auto & dependency : mg->getRequestedMeshGenerators())
508  {
509  // We _shouldn't_ hit this; now that we enforce construction ordering we do
510  // all of this error checking at construction time because the info is available
511  mooseAssert(hasMeshGenerator(dependency), "Missing dependency");
512 
513  auto & dependency_mg = getMeshGeneratorInternal(dependency);
514  mg->addParentMeshGenerator(dependency_mg, MeshGenerator::AddParentChildKey());
515  dependency_mg.addChildMeshGenerator(*mg, MeshGenerator::AddParentChildKey());
516  }
517 
518  // Loop through all of the MeshGeneratorName and std::vector<MeshGeneratorName>
519  // parameters (meshes that we should depend on), and make sure that either:
520  // - We directly depend on them and requested a mesh from them
521  // - We created a sub generator that depends on them and we declared it
522  for (const auto & param_dependency_pair : getMeshGeneratorParamDependencies(mg->parameters()))
523  {
524  const auto & param_name = param_dependency_pair.first;
525  const auto & dependency_name = param_dependency_pair.second;
526 
527  if (mg->isNullMeshName(dependency_name))
528  continue;
529 
530  // True if this dependency was requested and is a parent
531  if (mg->isParentMeshGenerator(dependency_name))
532  {
533  mooseAssert(mg->getRequestedMeshGenerators().count(dependency_name), "Wasn't requested");
534  continue;
535  }
536 
537  // Whether or not this is a dependency of at least one SubGenerator
538  auto find_sub_dependency = std::find_if(mg->getSubMeshGenerators().begin(),
539  mg->getSubMeshGenerators().end(),
540  [&dependency_name](const auto & mg)
541  { return mg->isParentMeshGenerator(dependency_name); });
542  const auto is_sub_dependency = find_sub_dependency != mg->getSubMeshGenerators().end();
543 
544  // This should be used by a sub generator
545  if (mg->getRequestedMeshGeneratorsForSub().count(dependency_name))
546  {
547  if (!is_sub_dependency)
548  mg->mooseError("The sub generator dependency declared from MeshGenerator '",
549  dependency_name,
550  "' from the parameter '",
551  param_name,
552  "' was not used.\n\nDependencies that are declared by declareMeshForSub() "
553  "must be used as an input to a sub generator created by this object.");
554  }
555  // This was used by a sub generator but wasn't declared
556  else if (is_sub_dependency)
557  mg->mooseError(
558  "The MeshGenerator '",
559  dependency_name,
560  "' was referenced in the parameter '",
561  param_name,
562  "' and used in the sub generator ",
563  (*find_sub_dependency)->type(),
564  " '",
565  (*find_sub_dependency)->name(),
566  "', but was not declared as a sub dependency.\n\nTo correct this, modify the code of ",
567  mg->type(),
568  " to include a call to declareMesh(es)ForSub(\"",
569  param_name,
570  "\") in the constructor.");
571  // Isn't used at all
572  else
573  mg->mooseError(
574  "You failed to request the generated mesh(es) for the parameter '",
575  param_name,
576  "'.\n\nIn specific, the mesh from MeshGenerator '",
577  dependency_name,
578  "' was not requested.\n\nTo correct this, you should remove the parameter if the "
579  "mesh(es)\nare not needed, or request the mesh(es) with getMesh()/getMeshes().");
580  }
581 
582  mooseAssert(!_mesh_generators.count(generator_name), "Already created");
583  _mesh_generators.emplace(generator_name, mg);
584  mooseAssert(!_mesh_generator_outputs.count(generator_name), "Already exists");
585  _mesh_generator_outputs[generator_name];
586  if (getCSGOnly())
587  {
588  mooseAssert(!_csg_base_outputs.count(generator_name), "CSG already exists");
589  _csg_base_outputs[generator_name];
590  }
591  _mesh_generator_params.erase(find_params);
592 
593  return mg;
594 }
595 
596 std::unique_ptr<MeshBase> &
597 MeshGeneratorSystem::getMeshGeneratorOutput(const MeshGeneratorName & name)
598 {
599  mooseAssert(_app.constructingMeshGenerators() ||
600  _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
601  "Incorrect call time");
602 
603  auto it = _mesh_generator_outputs.find(name);
604  mooseAssert(it != _mesh_generator_outputs.end(), "Not initialized");
605  it->second.push_back(nullptr);
606  return it->second.back();
607 }
608 
609 bool
610 MeshGeneratorSystem::hasMeshGenerator(const MeshGeneratorName & name) const
611 {
612  return _mesh_generators.count(name);
613 }
614 
615 bool
616 MeshGeneratorSystem::hasMeshGeneratorParams(const MeshGeneratorName & name) const
617 {
618  return _mesh_generator_params.count(name);
619 }
620 
621 const MeshGenerator &
622 MeshGeneratorSystem::getMeshGenerator(const std::string & name) const
623 {
624  const auto it = _mesh_generators.find(name);
625  if (it == _mesh_generators.end())
626  mooseError("Failed to find a MeshGenerator with the name '", name, "'");
627  mooseAssert(it->second, "Invalid shared pointer");
628  return *it->second;
629 }
630 
631 std::vector<std::string>
633 {
634  std::vector<std::string> names;
635  for (auto & pair : _mesh_generators)
636  names.push_back(pair.first);
637  return names;
638 }
639 
640 std::vector<std::string>
642 {
643  std::vector<std::string> names;
644  for (auto & pair : _save_in_meshes)
645  names.push_back(pair.first);
646  return names;
647 }
648 
649 std::unique_ptr<MeshBase>
650 MeshGeneratorSystem::getSavedMesh(const std::string & name)
651 {
652  auto find_mesh = _save_in_meshes.find(name);
653  if (find_mesh == _save_in_meshes.end())
654  mooseError("Failed to find a saved mesh with the name '", name, "'");
655 
656  auto & mesh_unique_ptr = find_mesh->second;
657  if (!mesh_unique_ptr)
658  mooseError("While getting the saved mesh generator '",
659  name,
660  "', said mesh has already been retrieved");
661 
662  return std::move(mesh_unique_ptr);
663 }
664 
665 bool
667 {
668  return _app.actionWarehouse().getCurrentTaskName() == "append_mesh_generator";
669 }
670 
671 bool
673 {
674  return _app.parameters().get<bool>(allow_data_driven_param);
675 }
676 
677 const std::string &
679 {
680  mooseAssert(_data_driven_generator_name, "Not set");
682 }
683 
684 void
686  const std::string & message) const
687 {
688  const auto & moose_mesh = _app.actionWarehouse().getMesh();
689  moose_mesh->paramError(data_driven_generator_param,
690  "The generator '",
692  "' cannot be used in data-driven mode because the parent ",
693  generator.typeAndName(),
694  " ",
695  message);
696 }
697 
698 void
700 {
701  _csg_only = true;
702 }
703 
704 void
705 MeshGeneratorSystem::saveOutputCSGBase(const MeshGeneratorName generator_name,
706  std::unique_ptr<CSG::CSGBase> & csg_base)
707 {
708  auto & outputs = _csg_base_outputs[generator_name];
709 
710  // Store CSGBase instance for any downstream MG's that request it, creating copies
711  // as needed
712  if (outputs.size())
713  {
714  // Set first output to csg_base
715  auto & first_output = *outputs.begin();
716  first_output = std::move(csg_base);
717  const auto & copy_from = *first_output;
718  auto output_it = ++outputs.begin();
719  // For all of the rest we create a clone of csg_base
720  for (; output_it != outputs.end(); ++output_it)
721  (*output_it) = copy_from.clone();
722  }
723 }
724 
725 std::unique_ptr<CSG::CSGBase> &
726 MeshGeneratorSystem::getCSGBaseGeneratorOutput(const MeshGeneratorName & name)
727 {
728  mooseAssert(_app.constructingMeshGenerators() ||
729  _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
730  "Incorrect call time");
731 
732  auto it = _csg_base_outputs.find(name);
733  mooseAssert(it != _csg_base_outputs.end(), "CSG mesh not initialized");
734  it->second.push_back(nullptr);
735  return it->second.back();
736 }
std::string name(const ElemQuality q)
virtual bool constructingMeshGenerators() const
Whether this app is constructing mesh generators.
Definition: MooseApp.C:3221
std::unique_ptr< CSG::CSGBase > & getCSGBaseGeneratorOutput(const MeshGeneratorName &name)
Returns the output CSGBase object associated with a particular mesh generator name.
std::string _final_generator_name
The final mesh generator name to use.
MeshGeneratorSystem(MooseApp &app)
static const std::string data_only_param
The name of the private parameter for setting data only.
Definition: MeshGenerator.h:76
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...
bool isChildMeshGenerator(const MeshGeneratorName &name, const bool direct=true) const
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.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:467
bool hasSaveMesh() const
Return whether or not to save the current mesh.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
void setCSGOnly()
Set whether mesh generator system is running in CSG-only mode to true.
std::map< std::string, std::unique_ptr< libMesh::MeshBase > > _save_in_meshes
Holds the map of save in mesh -> name.
std::size_t size() const
Returns the number of unique items stored in the dependency resolver.
bool hasDataDrivenAllowed() const
const std::vector< T > & getSortedValues()
This function also returns dependency resolved values but with a simpler single vector interface...
const InputParameters & parameters() const
Get the parameters of the object.
Definition: MooseBase.h:131
const std::shared_ptr< MooseMesh > & getMesh() const
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
std::unique_ptr< libMesh::MeshBase > getSavedMesh(const std::string &name)
Get the saved mesh by name.
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 dependsOn(const T &key, const T &value)
Return true if key depends on value.
Base class for MOOSE-based applications.
Definition: MooseApp.h:108
void executeMeshGenerators()
Execute and clear the Mesh Generators data structure.
bool hasOutput() const
std::optional< std::string > _data_driven_generator_name
The name of the data driven generator, if any.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
std::list< T > getAncestors(const T &key)
Returns a list of all values that a given key depends on.
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
const std::vector< std::vector< T > > & getSortedValuesSets()
Returns a vector of sets that represent dependency resolved values.
void addEdge(const T &a, const T &b)
Add an edge between nodes &#39;a&#39; and &#39;b&#39;.
Factory & getFactory()
Retrieve a writable reference to the Factory associated with this App.
Definition: MooseApp.h:406
bool _verbose
Whether to print the names of the mesh generators being executed or not.
void addMeshGenerator(const std::string &type, const std::string &name, const InputParameters &params)
Add a mesh generator that will act on the meshes in the system.
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.
void addItem(const T &value)
Add an independent item to the set.
MooseApp & _app
The MooseApp that owns this system.
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:103
virtual std::unique_ptr< Base > create()=0
void createAddedMeshGenerators()
Creates (constructs) all of the MeshGenerators that have been declared using addMeshGenerator().
bool getCSGOnly() const
Get whether mesh generator system is running in CSG-only mode.
ActionWarehouse & actionWarehouse()
Return a writable reference to the ActionWarehouse associated with this app.
Definition: MooseApp.h:216
std::string typeAndName() const
Get the class&#39;s combined type and name; useful in error handling.
Definition: MooseBase.C:57
bool _csg_only
Whether mesh generator system is running in CSG-only mode.
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...
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.
Interface for objects interacting with the PerfGraph.
std::vector< std::string > getSavedMeshNames() const
Get all user-defined saved meshes except main and main_displaced.
static std::string mainMeshGeneratorName()
The name reserved for the "main" mesh generator which is the one used for the numerical solver downst...
std::map< std::string, std::shared_ptr< MeshGenerator > > _mesh_generators
Owning storage for mesh generators, map of name -> MeshGenerator.
const std::string & getCurrentTaskName() const
bool have_parameter(std::string_view name) const
A wrapper around the Parameters base class method.
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...
void createMeshGeneratorOrder()
Order all of the _mesh_generators into _ordered_mesh_generators for later execution in executeMeshGen...
const std::vector< T > & getCyclicDependencies() const
Class that is used as a parameter to add[Parent/Child]() that allows only MeshGeneratorSystem methods...
static const std::string data_driven_generator_param
The name of the string parameter that sets the data driven generator.
const std::set< const MeshGenerator *, Comparator > & getParentMeshGenerators() const
Gets the MeshGenerators that are parents to this MeshGenerator.
bool hasMeshGenerator(const MeshGeneratorName &name) const
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...
const MeshGenerator & getMeshGenerator(const std::string &name) const
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
bool appendingMeshGenerators() const
Whether or not mesh generators are currently being appended (append_mesh_generator task) ...
static const std::string allow_data_driven_param
The name of the boolean parameter on the MooseApp that will enable data driven generation.
const std::string & getDataDrivenGeneratorName() const
MeshGenerator & getMeshGeneratorInternal(const std::string &name)
Get a MeshGenerator with the name name.
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:33
auto index_range(const T &sizable)
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 hasMeshGeneratorParams(const MeshGeneratorName &name) const
Whether or not we know about the parameters for a MeshGenerator with the given name.
std::vector< std::pair< std::string, MeshGeneratorName > > getMeshGeneratorParamDependencies(const InputParameters &params, const bool allow_empty=false) const
Gets the MeshGeneratorNames that are referenced in an object&#39;s parameters.
std::vector< std::vector< MeshGenerator * > > _ordered_mesh_generators
Holds the ordered mesh generators from createMeshGeneratorOrder() until they are executed in executeM...