LCOV - code coverage report
Current view: top level - src/base - MeshGeneratorSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 272 294 92.5 %
Date: 2026-05-29 20:35:17 Functions: 25 26 96.2 %
Legend: Lines: hit not hit

          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 "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";
      21             : const std::string MeshGeneratorSystem::allow_data_driven_param =
      22             :     "allow_data_driven_mesh_generation";
      23             : 
      24       66995 : MeshGeneratorSystem::MeshGeneratorSystem(MooseApp & app)
      25             :   : PerfGraphInterface(app.perfGraph(), "MeshGeneratorSystem"),
      26             :     ParallelObject(app),
      27       66995 :     _app(app),
      28       66995 :     _verbose(false),
      29      200985 :     _csg_only(false)
      30             : {
      31       66995 : }
      32             : 
      33             : void
      34       56672 : 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       56672 :   _mesh_generator_params.emplace(
      40       56672 :       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)
      44       56672 :   if (_app.constructingMeshGenerators())
      45         281 :     createMeshGenerator(name);
      46       56669 : }
      47             : 
      48             : const MeshGenerator &
      49          98 : MeshGeneratorSystem::appendMeshGenerator(const std::string & type,
      50             :                                          const std::string & name,
      51             :                                          InputParameters params)
      52             : {
      53          98 :   if (!appendingMeshGenerators())
      54           3 :     mooseError("Can only call appendMeshGenerator() during the append_mesh_generator task");
      55          95 :   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         187 :   if ((param_name_mg_name_pairs.size() == 0) ||
      60         118 :       (param_name_mg_name_pairs.size() == 1 && param_name_mg_name_pairs[0].first != "input" &&
      61         265 :        param_name_mg_name_pairs[0].first != "inputs") ||
      62         158 :       (param_name_mg_name_pairs.size() > 1 && param_name_mg_name_pairs[0].first != "inputs"))
      63           3 :     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          92 :   if (_final_generator_name.empty())
      77             :   {
      78          14 :     if (_mesh_generators.empty())
      79           3 :       mooseError("Cannot use appendMeshGenerator() because there is not a generator to append to!");
      80             : 
      81          11 :     createMeshGeneratorOrder();
      82          11 :     _ordered_mesh_generators.clear();
      83             :   }
      84             : 
      85             :   // Set the final generator as the input if a single generator
      86             :   mooseAssert(hasMeshGenerator(_final_generator_name), "Missing final generator");
      87          89 :   if (params.have_parameter<MeshGeneratorName>("input"))
      88          33 :     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
      92          89 :   _final_generator_name = name;
      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          89 :   _mesh_generator_params.emplace(
      97          89 :       std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
      98             : 
      99         178 :   return *createMeshGenerator(name);
     100          89 : }
     101             : 
     102             : std::vector<std::pair<std::string, MeshGeneratorName>>
     103      112716 : MeshGeneratorSystem::getMeshGeneratorParamDependencies(const InputParameters & params,
     104             :                                                        const bool allow_empty /* = false */) const
     105             : {
     106      112716 :   std::vector<std::pair<std::string, MeshGeneratorName>> dependencies;
     107             : 
     108             :   auto add_dependency =
     109       65940 :       [&dependencies, &allow_empty](const auto & param_name, const auto & dependency)
     110             :   {
     111       65940 :     if (dependency.size() || allow_empty)
     112       62564 :       dependencies.emplace_back(param_name, dependency);
     113      178656 :   };
     114             : 
     115     4328788 :   for (const auto & [name, param] : params)
     116     4216072 :     if (const auto dependency =
     117     4216072 :             dynamic_cast<const Parameters::Parameter<MeshGeneratorName> *>(param.get()))
     118       56622 :       add_dependency(name, dependency->get());
     119     4159450 :     else if (const auto dependencies =
     120     4159450 :                  dynamic_cast<const Parameters::Parameter<std::vector<MeshGeneratorName>> *>(
     121     8318900 :                      param.get()))
     122             :     {
     123        3886 :       if (allow_empty && dependencies->get().empty())
     124           0 :         add_dependency(name, std::string());
     125       13204 :       for (const auto & dependency : dependencies->get())
     126        9318 :         add_dependency(name, dependency);
     127             :     }
     128             : 
     129      225432 :   return dependencies;
     130           0 : }
     131             : 
     132             : void
     133       65867 : MeshGeneratorSystem::createAddedMeshGenerators()
     134             : {
     135             :   mooseAssert(_app.actionWarehouse().getCurrentTaskName() == "create_added_mesh_generators",
     136             :               "Should not run now");
     137             : 
     138             :   // No generators were added via addMeshGenerator()
     139       65867 :   if (_mesh_generator_params.empty())
     140       40387 :     return;
     141             : 
     142       25480 :   DependencyResolver<std::string> resolver;
     143             : 
     144             :   // Define the dependencies known so far
     145       81868 :   for (const auto & [name, type_params_pair] : _mesh_generator_params)
     146             :   {
     147       56388 :     resolver.addItem(name);
     148       56388 :     for (const auto & param_dependency_pair :
     149      143962 :          getMeshGeneratorParamDependencies(type_params_pair.second))
     150       87574 :       resolver.addEdge(param_dependency_pair.second, name);
     151             :   }
     152             : 
     153       25480 :   std::vector<std::vector<std::string>> ordered_generators;
     154             :   try
     155             :   {
     156       25480 :     ordered_generators = resolver.getSortedValuesSets();
     157             :   }
     158           3 :   catch (CyclicDependencyException<std::string> & e)
     159             :   {
     160           3 :     mooseError("Cyclic dependencies detected in mesh generation: ",
     161           3 :                MooseUtils::join(e.getCyclicDependencies(), " <- "));
     162           0 :   }
     163             : 
     164       25477 :   const auto & moose_mesh = _app.actionWarehouse().getMesh();
     165             : 
     166             :   // If there is no mesh
     167       25477 :   if (!moose_mesh.get())
     168           0 :     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       50908 :   if (moose_mesh->parameters().get<bool>("_mesh_generator_mesh") &&
     173       25431 :       moose_mesh->isParamValid(data_driven_generator_param))
     174             :   {
     175          32 :     if (!hasDataDrivenAllowed())
     176           3 :       moose_mesh->paramError(
     177             :           data_driven_generator_param,
     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 '",
     180             :           allow_data_driven_param,
     181             :           "' parameter.");
     182             : 
     183             :     mooseAssert(moose_mesh->type() == "MeshGeneratorMesh",
     184             :                 "Assumption for mesh type is now invalid");
     185             : 
     186          29 :     _data_driven_generator_name = moose_mesh->getParam<std::string>(data_driven_generator_param);
     187          29 :     if (!_mesh_generator_params.count(*_data_driven_generator_name))
     188           6 :       moose_mesh->paramError(data_driven_generator_param,
     189             :                              "The data driven generator '",
     190           3 :                              *_data_driven_generator_name,
     191             :                              "' does not exist");
     192             :   }
     193             : 
     194             :   // Check compatibility for CLI / meshing options with csg_only
     195       25471 :   const bool csg_only = getCSGOnly();
     196       25471 :   if (csg_only && _data_driven_generator_name)
     197           0 :     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       77471 :   for (const auto & generator_names : ordered_generators)
     202      108184 :     for (const auto & generator_name : generator_names)
     203       56184 :       if (auto it = _mesh_generator_params.find(generator_name); it != _mesh_generator_params.end())
     204             :       {
     205       56157 :         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      112180 :             (csg_only ||
     210       56023 :              (_data_driven_generator_name && getDataDrivenGeneratorName() != generator_name &&
     211          52 :               resolver.dependsOn(getDataDrivenGeneratorName(), generator_name)));
     212       56157 :         params.set<bool>(MeshGenerator::data_only_param) = data_only;
     213             : 
     214       56157 :         createMeshGenerator(generator_name);
     215             : 
     216       55857 :         if (csg_only && !getMeshGenerator(generator_name).hasGenerateCSG())
     217           0 :           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       50296 :   if (moose_mesh->parameters().get<bool>("_mesh_generator_mesh") &&
     232      100546 :       moose_mesh->isParamValid("final_generator"))
     233             :   {
     234             :     mooseAssert(moose_mesh->type() == "MeshGeneratorMesh",
     235             :                 "Assumption for mesh type is now invalid");
     236             : 
     237         972 :     _final_generator_name = moose_mesh->getParam<std::string>("final_generator");
     238         486 :     if (!hasMeshGenerator(_final_generator_name))
     239           6 :       moose_mesh->paramError("final_generator",
     240             :                              "The forced final MeshGenerator '",
     241           3 :                              _final_generator_name,
     242             :                              "' does not exist");
     243             :   }
     244       25168 : }
     245             : 
     246             : void
     247       24057 : MeshGeneratorSystem::createMeshGeneratorOrder()
     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      120285 :   TIME_SECTION("createMeshGeneratorOrder", 1, "Ordering Mesh Generators");
     256             : 
     257             :   // We dare not sort these based on address!
     258       24057 :   DependencyResolver<MeshGenerator *, MeshGenerator::Comparator> resolver;
     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       24057 :   std::vector<std::string> required_generators;
     265       77799 :   for (const auto & it : _mesh_generators)
     266       53742 :     if (it.second->hasSaveMesh() || it.second->hasOutput())
     267         519 :       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       77799 :   for (const auto & it : _mesh_generators)
     274             :   {
     275       53742 :     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        2962 :     if (_final_generator_name.empty() ||
     280             :         // This mesh generator is the final generator
     281        2962 :         mg->name() == _final_generator_name ||
     282             :         // This needs to be saved or output
     283        4787 :         mg->hasSaveMesh() || mg->hasOutput() ||
     284             :         // Final mesh generator set and is a child of this generator
     285      113655 :         (_final_generator_name.size() && mg->isChildMeshGenerator(_final_generator_name, false)) ||
     286             :         // This is a dependency of a generator that needs to be saved or output
     287         900 :         std::find_if(required_generators.begin(),
     288             :                      required_generators.end(),
     289        1400 :                      [&mg](const auto & name) { return mg->isChildMeshGenerator(name, false); }) !=
     290       54642 :             required_generators.end())
     291             :     {
     292       53042 :       resolver.addItem(mg);
     293       82456 :       for (const auto & dep_mg : mg->getParentMeshGenerators())
     294       29414 :         resolver.addEdge(&getMeshGeneratorInternal(dep_mg->name()), mg);
     295             :     }
     296             :   }
     297             : 
     298             :   // ...and sort them
     299             :   try
     300             :   {
     301       24057 :     _ordered_mesh_generators = resolver.getSortedValuesSets();
     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
     311           0 :   catch (CyclicDependencyException<MeshGenerator *, MeshGenerator::Comparator> & e)
     312             :   {
     313           0 :     const auto & cycle = e.getCyclicDependencies();
     314           0 :     std::vector<std::string> names(cycle.size());
     315           0 :     for (const auto i : index_range(cycle))
     316           0 :       names[i] = cycle[i]->name();
     317             : 
     318           0 :     mooseError("Cyclic dependencies detected in mesh generation: ",
     319           0 :                MooseUtils::join(names, " <- "));
     320           0 :   }
     321             : 
     322             :   mooseAssert(_ordered_mesh_generators.size(), "No mesh generators found");
     323             : 
     324       24057 :   const auto & final_generators = _ordered_mesh_generators.back();
     325             : 
     326             :   // We haven't forced a final generator yet
     327       24057 :   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       23573 :     const auto ancestor_list = resolver.getAncestors(final_generators.back());
     333       23573 :     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           6 :                                                                      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           6 :       const auto & allValues = resolver.getSortedValues();
     342           6 :       decltype(ancestors) all(allValues.begin(), allValues.end());
     343             : 
     344           6 :       decltype(ancestors) ind_tree;
     345           6 :       std::set_difference(all.begin(),
     346             :                           all.end(),
     347             :                           ancestors.begin(),
     348             :                           ancestors.end(),
     349             :                           std::inserter(ind_tree, ind_tree.end()));
     350             : 
     351           6 :       std::ostringstream oss;
     352             :       oss << "Your MeshGenerator tree contains multiple possible generator outputs :\n\""
     353           6 :           << final_generators.back()->name()
     354          12 :           << "\" and one or more of the following from an independent set: \"";
     355           6 :       bool first = true;
     356          20 :       for (const auto & gen : ind_tree)
     357             :       {
     358          14 :         if (!first)
     359           8 :           oss << ", ";
     360             :         else
     361           6 :           first = false;
     362             : 
     363          14 :         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           6 :              " final MeshGenerator in the [Mesh] block with the \"final_generator\" parameter.";
     372           6 :       mooseError(oss.str());
     373           0 :     }
     374             : 
     375       23567 :     _final_generator_name = final_generators.back()->name();
     376       23567 :   }
     377             :   else
     378             :     mooseAssert(hasMeshGenerator(_final_generator_name), "Missing the preset final generator");
     379       24051 : }
     380             : 
     381             : void
     382       61232 : MeshGeneratorSystem::executeMeshGenerators()
     383             : {
     384             :   libmesh_parallel_only(comm());
     385             : 
     386             :   // we do not need to do this when there are no mesh generators
     387       61232 :   if (_mesh_generators.empty())
     388       37253 :     return;
     389             : 
     390             :   // Order the generators
     391       24046 :   createMeshGeneratorOrder();
     392             : 
     393             :   // Save all meshes marked to to_save_in_meshes and save in error checking
     394       24040 :   std::map<std::string, std::unique_ptr<MeshBase> *> to_save_in_meshes;
     395       73501 :   for (const auto & generator_set : _ordered_mesh_generators)
     396      102471 :     for (const auto & generator : generator_set)
     397       53010 :       if (generator->hasSaveMesh())
     398             :       {
     399          39 :         if (_final_generator_name == generator->name())
     400           6 :           generator->paramError("save_with_name",
     401             :                                 "Cannot use the save in capability with the final mesh generator");
     402          36 :         if (getCSGOnly())
     403           0 :           generator->paramError("save_with_name", "Cannot use in conjunction with --csg-only");
     404          36 :         to_save_in_meshes.emplace(generator->getSavedMeshName(),
     405          72 :                                   &getMeshGeneratorOutput(generator->name()));
     406             :       }
     407             :   // Grab the outputs from the final generator so MeshGeneratorMesh can pick it up
     408       24037 :   to_save_in_meshes.emplace(mainMeshGeneratorName(),
     409       48074 :                             &getMeshGeneratorOutput(_final_generator_name));
     410             : 
     411             :   // Run the MeshGenerators in the proper order
     412       73084 :   for (const auto & generator_set : _ordered_mesh_generators)
     413             :   {
     414      102027 :     for (const auto & generator : generator_set)
     415             :     {
     416       52980 :       const auto & name = generator->name();
     417       52980 :       if (_verbose)
     418           0 :         _app._console << " [DBG] Executing mesh generator (" << COLOR_GREEN << std::setw(20) << name
     419           0 :                       << COLOR_DEFAULT << ") in type (" << COLOR_GREEN << generator->type()
     420           0 :                       << COLOR_DEFAULT << ")" << std::endl;
     421       52980 :       auto current_mesh = generator->generateInternal();
     422             : 
     423             :       // Only generating data for this generator
     424       52587 :       if (generator->isDataOnly())
     425             :       {
     426             :         mooseAssert(!current_mesh, "Should not have a mesh");
     427         228 :         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       52359 :       auto & outputs = _mesh_generator_outputs[name];
     448             : 
     449       52359 :       if (outputs.size())
     450             :       {
     451       52229 :         auto & first_output = *outputs.begin();
     452             : 
     453       52229 :         first_output = std::move(current_mesh);
     454             : 
     455       52229 :         const auto & copy_from = *first_output;
     456             : 
     457       52229 :         auto output_it = ++outputs.begin();
     458             : 
     459             :         // For all of the rest we need to make a copy
     460       53057 :         for (; output_it != outputs.end(); ++output_it)
     461         828 :           (*output_it) = copy_from.clone();
     462             :       }
     463       52587 :     }
     464             :   }
     465             : 
     466             :   // No save in meshes exist in csg only mode
     467       23644 :   if (getCSGOnly())
     468          67 :     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       47190 :   for (auto & [name, mesh_ptr] : to_save_in_meshes)
     473             :   {
     474             :     mooseAssert(mesh_ptr, "Invalid pointer");
     475             :     mooseAssert(*mesh_ptr, "Invalid pointer");
     476       23613 :     if (name != mainMeshGeneratorName())
     477             :       mooseAssert(_save_in_meshes.count(name), "Mesh has not been requested for save");
     478       23613 :     _save_in_meshes[name] = std::move(*mesh_ptr);
     479             :   }
     480       23653 : }
     481             : 
     482             : std::shared_ptr<MeshGenerator>
     483       56527 : MeshGeneratorSystem::createMeshGenerator(const std::string & generator_name)
     484             : {
     485             :   libmesh_parallel_only(comm());
     486             :   mooseAssert(_app.constructingMeshGenerators(), "Should not run now");
     487             : 
     488       56527 :   const auto find_params = _mesh_generator_params.find(generator_name);
     489             :   mooseAssert(find_params != _mesh_generator_params.end(), "Not added");
     490       56527 :   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       56527 :       _app.getFactory().create<MeshGenerator>(type, generator_name, params);
     495             : 
     496       56236 :   if (mg->hasSaveMesh())
     497             :   {
     498          47 :     if (_save_in_meshes.count(mg->getSavedMeshName()))
     499           6 :       mg->paramError("save_with_name",
     500             :                      "The save with name '",
     501           3 :                      mg->getSavedMeshName(),
     502             :                      "' has already been used");
     503          44 :     _save_in_meshes.emplace(mg->getSavedMeshName(), nullptr);
     504             :   }
     505             : 
     506             :   // Setup the children and parents
     507       87447 :   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       31214 :     auto & dependency_mg = getMeshGeneratorInternal(dependency);
     514       31214 :     mg->addParentMeshGenerator(dependency_mg, MeshGenerator::AddParentChildKey());
     515       31214 :     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       87390 :   for (const auto & param_dependency_pair : getMeshGeneratorParamDependencies(mg->parameters()))
     523             :   {
     524       31166 :     const auto & param_name = param_dependency_pair.first;
     525       31166 :     const auto & dependency_name = param_dependency_pair.second;
     526             : 
     527       31166 :     if (mg->isNullMeshName(dependency_name))
     528       31133 :       continue;
     529             : 
     530             :     // True if this dependency was requested and is a parent
     531       31142 :     if (mg->isParentMeshGenerator(dependency_name))
     532             :     {
     533             :       mooseAssert(mg->getRequestedMeshGenerators().count(dependency_name), "Wasn't requested");
     534       31109 :       continue;
     535             :     }
     536             : 
     537             :     // Whether or not this is a dependency of at least one SubGenerator
     538          33 :     auto find_sub_dependency = std::find_if(mg->getSubMeshGenerators().begin(),
     539          33 :                                             mg->getSubMeshGenerators().end(),
     540          84 :                                             [&dependency_name](const auto & mg)
     541          84 :                                             { return mg->isParentMeshGenerator(dependency_name); });
     542          33 :     const auto is_sub_dependency = find_sub_dependency != mg->getSubMeshGenerators().end();
     543             : 
     544             :     // This should be used by a sub generator
     545          33 :     if (mg->getRequestedMeshGeneratorsForSub().count(dependency_name))
     546             :     {
     547          27 :       if (!is_sub_dependency)
     548           3 :         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           6 :     else if (is_sub_dependency)
     557           6 :       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           3 :           (*find_sub_dependency)->type(),
     564             :           " '",
     565           3 :           (*find_sub_dependency)->name(),
     566             :           "', but was not declared as a sub dependency.\n\nTo correct this, modify the code of ",
     567           3 :           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           3 :       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       56224 :   }
     581             : 
     582             :   mooseAssert(!_mesh_generators.count(generator_name), "Already created");
     583       56224 :   _mesh_generators.emplace(generator_name, mg);
     584             :   mooseAssert(!_mesh_generator_outputs.count(generator_name), "Already exists");
     585       56224 :   _mesh_generator_outputs[generator_name];
     586       56224 :   if (getCSGOnly())
     587             :   {
     588             :     mooseAssert(!_csg_base_outputs.count(generator_name), "CSG already exists");
     589         206 :     _csg_base_outputs[generator_name];
     590             :   }
     591       56224 :   _mesh_generator_params.erase(find_params);
     592             : 
     593      112448 :   return mg;
     594           0 : }
     595             : 
     596             : std::unique_ptr<MeshBase> &
     597       55506 : MeshGeneratorSystem::getMeshGeneratorOutput(const MeshGeneratorName & name)
     598             : {
     599             :   mooseAssert(_app.constructingMeshGenerators() ||
     600             :                   _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
     601             :               "Incorrect call time");
     602             : 
     603       55506 :   auto it = _mesh_generator_outputs.find(name);
     604             :   mooseAssert(it != _mesh_generator_outputs.end(), "Not initialized");
     605       55506 :   it->second.push_back(nullptr);
     606      111012 :   return it->second.back();
     607             : }
     608             : 
     609             : bool
     610       63074 : MeshGeneratorSystem::hasMeshGenerator(const MeshGeneratorName & name) const
     611             : {
     612       63074 :   return _mesh_generators.count(name);
     613             : }
     614             : 
     615             : bool
     616          15 : MeshGeneratorSystem::hasMeshGeneratorParams(const MeshGeneratorName & name) const
     617             : {
     618          15 :   return _mesh_generator_params.count(name);
     619             : }
     620             : 
     621             : const MeshGenerator &
     622       61039 : MeshGeneratorSystem::getMeshGenerator(const std::string & name) const
     623             : {
     624       61039 :   const auto it = _mesh_generators.find(name);
     625       61039 :   if (it == _mesh_generators.end())
     626           3 :     mooseError("Failed to find a MeshGenerator with the name '", name, "'");
     627             :   mooseAssert(it->second, "Invalid shared pointer");
     628      122072 :   return *it->second;
     629             : }
     630             : 
     631             : std::vector<std::string>
     632      105365 : MeshGeneratorSystem::getMeshGeneratorNames() const
     633             : {
     634      105365 :   std::vector<std::string> names;
     635      163682 :   for (auto & pair : _mesh_generators)
     636       58317 :     names.push_back(pair.first);
     637      105365 :   return names;
     638           0 : }
     639             : 
     640             : std::vector<std::string>
     641          14 : MeshGeneratorSystem::getSavedMeshNames() const
     642             : {
     643          14 :   std::vector<std::string> names;
     644          42 :   for (auto & pair : _save_in_meshes)
     645          28 :     names.push_back(pair.first);
     646          14 :   return names;
     647           0 : }
     648             : 
     649             : std::unique_ptr<MeshBase>
     650       23597 : MeshGeneratorSystem::getSavedMesh(const std::string & name)
     651             : {
     652       23597 :   auto find_mesh = _save_in_meshes.find(name);
     653       23597 :   if (find_mesh == _save_in_meshes.end())
     654           3 :     mooseError("Failed to find a saved mesh with the name '", name, "'");
     655             : 
     656       23594 :   auto & mesh_unique_ptr = find_mesh->second;
     657       23594 :   if (!mesh_unique_ptr)
     658           3 :     mooseError("While getting the saved mesh generator '",
     659             :                name,
     660             :                "', said mesh has already been retrieved");
     661             : 
     662       47182 :   return std::move(mesh_unique_ptr);
     663             : }
     664             : 
     665             : bool
     666       57204 : MeshGeneratorSystem::appendingMeshGenerators() const
     667             : {
     668       57204 :   return _app.actionWarehouse().getCurrentTaskName() == "append_mesh_generator";
     669             : }
     670             : 
     671             : bool
     672          32 : MeshGeneratorSystem::hasDataDrivenAllowed() const
     673             : {
     674          32 :   return _app.parameters().get<bool>(allow_data_driven_param);
     675             : }
     676             : 
     677             : const std::string &
     678         130 : MeshGeneratorSystem::getDataDrivenGeneratorName() const
     679             : {
     680             :   mooseAssert(_data_driven_generator_name, "Not set");
     681         130 :   return *_data_driven_generator_name;
     682             : }
     683             : 
     684             : void
     685           6 : MeshGeneratorSystem::dataDrivenError(const MeshGenerator & generator,
     686             :                                      const std::string & message) const
     687             : {
     688           6 :   const auto & moose_mesh = _app.actionWarehouse().getMesh();
     689          12 :   moose_mesh->paramError(data_driven_generator_param,
     690             :                          "The generator '",
     691           6 :                          getDataDrivenGeneratorName(),
     692             :                          "' cannot be used in data-driven mode because the parent ",
     693           6 :                          generator.typeAndName(),
     694             :                          " ",
     695             :                          message);
     696             : }
     697             : 
     698             : void
     699          67 : MeshGeneratorSystem::setCSGOnly()
     700             : {
     701          67 :   _csg_only = true;
     702          67 : }
     703             : 
     704             : void
     705         131 : MeshGeneratorSystem::saveOutputCSGBase(const MeshGeneratorName generator_name,
     706             :                                        std::unique_ptr<CSG::CSGBase> & csg_base)
     707             : {
     708         131 :   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         131 :   if (outputs.size())
     713             :   {
     714             :     // Set first output to csg_base
     715         131 :     auto & first_output = *outputs.begin();
     716         131 :     first_output = std::move(csg_base);
     717         131 :     const auto & copy_from = *first_output;
     718         131 :     auto output_it = ++outputs.begin();
     719             :     // For all of the rest we create a clone of csg_base
     720         139 :     for (; output_it != outputs.end(); ++output_it)
     721           8 :       (*output_it) = copy_from.clone();
     722             :   }
     723         131 : }
     724             : 
     725             : std::unique_ptr<CSG::CSGBase> &
     726         147 : MeshGeneratorSystem::getCSGBaseGeneratorOutput(const MeshGeneratorName & name)
     727             : {
     728             :   mooseAssert(_app.constructingMeshGenerators() ||
     729             :                   _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
     730             :               "Incorrect call time");
     731             : 
     732         147 :   auto it = _csg_base_outputs.find(name);
     733             :   mooseAssert(it != _csg_base_outputs.end(), "CSG mesh not initialized");
     734         147 :   it->second.push_back(nullptr);
     735         294 :   return it->second.back();
     736             : }

Generated by: LCOV version 1.14