LCOV - code coverage report
Current view: top level - src/base - MeshGeneratorSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31706 (f8ed4a) with base bb0a08 Lines: 265 287 92.3 %
Date: 2025-11-03 17:23:24 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       70055 : MeshGeneratorSystem::MeshGeneratorSystem(MooseApp & app)
      25             :   : PerfGraphInterface(app.perfGraph(), "MeshGeneratorSystem"),
      26             :     ParallelObject(app),
      27       70055 :     _app(app),
      28       70055 :     _has_bmbb(false),
      29       70055 :     _verbose(false),
      30      210165 :     _csg_only(false)
      31             : {
      32       70055 : }
      33             : 
      34             : void
      35       58045 : MeshGeneratorSystem::addMeshGenerator(const std::string & type,
      36             :                                       const std::string & name,
      37             :                                       const InputParameters & params)
      38             : {
      39             :   mooseAssert(!_mesh_generator_params.count(name), "Already exists");
      40       58045 :   _mesh_generator_params.emplace(
      41       58045 :       std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
      42             : 
      43             :   // This should be a sub mesh generator. We can assume this because if we're in the middle of
      44             :   // constructing mesh generators (not "adding" them, where we simply store their parameters)
      45       58045 :   if (_app.constructingMeshGenerators())
      46         244 :     createMeshGenerator(name);
      47             : 
      48       58041 :   if (type == "BreakMeshByBlockGenerator")
      49         268 :     _has_bmbb = true;
      50       58041 : }
      51             : 
      52             : const MeshGenerator &
      53         111 : MeshGeneratorSystem::appendMeshGenerator(const std::string & type,
      54             :                                          const std::string & name,
      55             :                                          InputParameters params)
      56             : {
      57         111 :   if (!appendingMeshGenerators())
      58           4 :     mooseError("Can only call appendMeshGenerator() during the append_mesh_generator task");
      59         107 :   const auto param_name_mg_name_pairs = getMeshGeneratorParamDependencies(params, true);
      60             : 
      61             :   // Make sure this mesh generator has one and _only_ one input, in the "input" parameter,
      62             :   // Or several, listed in the "inputs" parameter
      63         210 :   if ((param_name_mg_name_pairs.size() == 0) ||
      64         133 :       (param_name_mg_name_pairs.size() == 1 && param_name_mg_name_pairs[0].first != "input" &&
      65         296 :        param_name_mg_name_pairs[0].first != "inputs") ||
      66         176 :       (param_name_mg_name_pairs.size() > 1 && param_name_mg_name_pairs[0].first != "inputs"))
      67           4 :     mooseError("While adding ",
      68             :                type,
      69             :                " '",
      70             :                name,
      71             :                "' via appendMeshGenerator():\nCan only append a mesh generator that takes a "
      72             :                "single input mesh generator via the parameter named 'input' or 'inputs'.");
      73             : 
      74             :   // If no final generator is set, we need to make sure that we have one; we will hit
      75             :   // this the first time we add an appended MeshGenerator and only need to do it once.
      76             :   // We'll then generate the final ordering within the execution phase. We'll also
      77             :   // clear the ordering because it could be invalid if we append any more generators,
      78             :   // and we'll be re-ordering within executeMeshgenerators() anyway (where we don't
      79             :   // keep track of any state for the sake of simpler logic)
      80         103 :   if (_final_generator_name.empty())
      81             :   {
      82          17 :     if (_mesh_generators.empty())
      83           4 :       mooseError("Cannot use appendMeshGenerator() because there is not a generator to append to!");
      84             : 
      85          13 :     createMeshGeneratorOrder();
      86          13 :     _ordered_mesh_generators.clear();
      87             :   }
      88             : 
      89             :   // Set the final generator as the input if a single generator
      90             :   mooseAssert(hasMeshGenerator(_final_generator_name), "Missing final generator");
      91          99 :   if (params.have_parameter<MeshGeneratorName>("input"))
      92          39 :     params.set<MeshGeneratorName>("input") = _final_generator_name;
      93             :   // We'll trust the final combiner generator with its list of inputs
      94             : 
      95             :   // Keep track of the new final generator
      96          99 :   _final_generator_name = name;
      97             : 
      98             :   // Need to add this to the param map so that createMeshGenerator can use it
      99             :   mooseAssert(!_mesh_generator_params.count(name), "Already exists");
     100          99 :   _mesh_generator_params.emplace(
     101          99 :       std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(type, params));
     102             : 
     103         198 :   return *createMeshGenerator(name);
     104          99 : }
     105             : 
     106             : std::vector<std::pair<std::string, MeshGeneratorName>>
     107      115384 : MeshGeneratorSystem::getMeshGeneratorParamDependencies(const InputParameters & params,
     108             :                                                        const bool allow_empty /* = false */) const
     109             : {
     110      115384 :   std::vector<std::pair<std::string, MeshGeneratorName>> dependencies;
     111             : 
     112             :   auto add_dependency =
     113       64496 :       [&dependencies, &allow_empty](const auto & param_name, const auto & dependency)
     114             :   {
     115       64496 :     if (dependency.size() || allow_empty)
     116       62580 :       dependencies.emplace_back(param_name, dependency);
     117      179880 :   };
     118             : 
     119     4412695 :   for (const auto & [name, param] : params)
     120     4297311 :     if (const auto dependency =
     121     4297311 :             dynamic_cast<const Parameters::Parameter<MeshGeneratorName> *>(param.get()))
     122       55048 :       add_dependency(name, dependency->get());
     123     4242263 :     else if (const auto dependencies =
     124     4242263 :                  dynamic_cast<const Parameters::Parameter<std::vector<MeshGeneratorName>> *>(
     125     8484526 :                      param.get()))
     126             :     {
     127        3894 :       if (allow_empty && dependencies->get().empty())
     128           0 :         add_dependency(name, std::string());
     129       13342 :       for (const auto & dependency : dependencies->get())
     130        9448 :         add_dependency(name, dependency);
     131             :     }
     132             : 
     133      230768 :   return dependencies;
     134           0 : }
     135             : 
     136             : void
     137       68915 : MeshGeneratorSystem::createAddedMeshGenerators()
     138             : {
     139             :   mooseAssert(_app.actionWarehouse().getCurrentTaskName() == "create_added_mesh_generators",
     140             :               "Should not run now");
     141             : 
     142             :   // No generators were added via addMeshGenerator()
     143       68915 :   if (_mesh_generator_params.empty())
     144       42250 :     return;
     145             : 
     146       26665 :   DependencyResolver<std::string> resolver;
     147             : 
     148             :   // Define the dependencies known so far
     149       84462 :   for (const auto & [name, type_params_pair] : _mesh_generator_params)
     150             :   {
     151       57797 :     resolver.addItem(name);
     152       57797 :     for (const auto & param_dependency_pair :
     153      146844 :          getMeshGeneratorParamDependencies(type_params_pair.second))
     154       89047 :       resolver.addEdge(param_dependency_pair.second, name);
     155             :   }
     156             : 
     157       26665 :   std::vector<std::vector<std::string>> ordered_generators;
     158             :   try
     159             :   {
     160       26665 :     ordered_generators = resolver.getSortedValuesSets();
     161             :   }
     162           4 :   catch (CyclicDependencyException<std::string> & e)
     163             :   {
     164           4 :     mooseError("Cyclic dependencies detected in mesh generation: ",
     165           4 :                MooseUtils::join(e.getCyclicDependencies(), " <- "));
     166           0 :   }
     167             : 
     168       26661 :   const auto & moose_mesh = _app.actionWarehouse().getMesh();
     169             : 
     170             :   // If there is no mesh
     171       26661 :   if (!moose_mesh.get())
     172           0 :     mooseError("No mesh created. Either add a Mesh, an ActionComponents or a Components block");
     173             : 
     174             :   // If we're using data-driven generation, find that requirement now
     175             :   mooseAssert(!_data_driven_generator_name, "Should not be set");
     176       53266 :   if (moose_mesh->parameters().get<bool>("_mesh_generator_mesh") &&
     177       26605 :       moose_mesh->isParamValid(data_driven_generator_param))
     178             :   {
     179          38 :     if (!hasDataDrivenAllowed())
     180           4 :       moose_mesh->paramError(
     181             :           data_driven_generator_param,
     182             :           "This application does not support data-driven mesh generation.\n\nThis generation is an "
     183             :           "advanced feature and must be enabled on the application via the '",
     184             :           allow_data_driven_param,
     185             :           "' parameter.");
     186             : 
     187             :     mooseAssert(moose_mesh->type() == "MeshGeneratorMesh",
     188             :                 "Assumption for mesh type is now invalid");
     189             : 
     190          34 :     _data_driven_generator_name = moose_mesh->getParam<std::string>(data_driven_generator_param);
     191          34 :     if (!_mesh_generator_params.count(*_data_driven_generator_name))
     192           8 :       moose_mesh->paramError(data_driven_generator_param,
     193             :                              "The data driven generator '",
     194           4 :                              *_data_driven_generator_name,
     195             :                              "' does not exist");
     196             :   }
     197             : 
     198             :   // Check compatibility for CLI / meshing options with csg_only
     199       26653 :   const bool csg_only = getCSGOnly();
     200       26653 :   if (csg_only && _data_driven_generator_name)
     201           0 :     moose_mesh->paramError(data_driven_generator_param,
     202             :                            "This parameter should not be set in conjunction with --csg-only");
     203             : 
     204             :   // Construct all of the mesh generators that we know exist
     205       79908 :   for (const auto & generator_names : ordered_generators)
     206      110777 :     for (const auto & generator_name : generator_names)
     207       57522 :       if (auto it = _mesh_generator_params.find(generator_name); it != _mesh_generator_params.end())
     208             :       {
     209       57489 :         auto & params = it->second.second;
     210             : 
     211             :         // Determine now if we need to run this in data only mode
     212             :         const bool data_only =
     213      115007 :             (csg_only ||
     214       57518 :              (_data_driven_generator_name && getDataDrivenGeneratorName() != generator_name &&
     215          60 :               resolver.dependsOn(getDataDrivenGeneratorName(), generator_name)));
     216       57489 :         params.set<bool>(MeshGenerator::data_only_param) = data_only;
     217             : 
     218       57489 :         createMeshGenerator(generator_name);
     219             : 
     220       57129 :         if (csg_only && !getMeshGenerator(generator_name).hasGenerateCSG())
     221           0 :           mooseError("Mesh generator ",
     222             :                      generator_name,
     223             :                      " cannot be used in csg-only mode since it does not have a generateCSG "
     224             :                      "implementation");
     225             : 
     226             :         mooseAssert(data_only == getMeshGenerator(generator_name).isDataOnly(),
     227             :                     "Inconsistent data only");
     228             :       }
     229             : 
     230             :   mooseAssert(_mesh_generator_params.empty(), "Should be empty");
     231             :   mooseAssert(_final_generator_name.empty(), "Should be unset at this point");
     232             : 
     233             :   // Set the final generator if we have one set by the user
     234             :   // and if so make sure it also exists
     235       52530 :   if (moose_mesh->parameters().get<bool>("_mesh_generator_mesh") &&
     236      105004 :       moose_mesh->isParamValid("final_generator"))
     237             :   {
     238             :     mooseAssert(moose_mesh->type() == "MeshGeneratorMesh",
     239             :                 "Assumption for mesh type is now invalid");
     240             : 
     241         932 :     _final_generator_name = moose_mesh->getParam<std::string>("final_generator");
     242         466 :     if (!hasMeshGenerator(_final_generator_name))
     243           8 :       moose_mesh->paramError("final_generator",
     244             :                              "The forced final MeshGenerator '",
     245           4 :                              _final_generator_name,
     246             :                              "' does not exist");
     247             :   }
     248       26289 : }
     249             : 
     250             : void
     251       25271 : MeshGeneratorSystem::createMeshGeneratorOrder()
     252             : {
     253             :   mooseAssert(_app.constructingMeshGenerators() ||
     254             :                   _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
     255             :               "Incorrect call time");
     256             :   mooseAssert(_ordered_mesh_generators.empty(), "Already ordered");
     257             :   mooseAssert(_mesh_generators.size(), "No mesh generators to order");
     258             : 
     259      126355 :   TIME_SECTION("createMeshGeneratorOrder", 1, "Ordering Mesh Generators");
     260             : 
     261             :   // We dare not sort these based on address!
     262       25271 :   DependencyResolver<MeshGenerator *, MeshGenerator::Comparator> resolver;
     263             : 
     264             :   // The mesh generators that must be called
     265             :   // This is needed to mark the generators that could be cut due to a
     266             :   // final generator being set, but should still be called because they're
     267             :   // either being saved in memory or as output
     268       25271 :   std::vector<std::string> required_generators;
     269       80357 :   for (const auto & it : _mesh_generators)
     270       55086 :     if (it.second->hasSaveMesh() || it.second->hasOutput())
     271         396 :       required_generators.push_back(it.second->name());
     272             : 
     273             :   // The mesh generator tree should have all the mesh generators that
     274             :   // The final generator depends on and all the mesh generators
     275             :   // with 'save in' flag. Here we loop over all the mesh generators
     276             :   // and conditionally add all of the dependencies into the resolver
     277       80357 :   for (const auto & it : _mesh_generators)
     278             :   {
     279       55086 :     MeshGenerator * mg = it.second.get();
     280             : 
     281             :     // The mesh generator has to meet one of the following conditions:
     282             :     // Final mesh generator is not set, so we build the whole tree
     283        2835 :     if (_final_generator_name.empty() ||
     284             :         // This mesh generator is the final generator
     285        2835 :         mg->name() == _final_generator_name ||
     286             :         // This needs to be saved or output
     287        4552 :         mg->hasSaveMesh() || mg->hasOutput() ||
     288             :         // Final mesh generator set and is a child of this generator
     289      116093 :         (_final_generator_name.size() && mg->isChildMeshGenerator(_final_generator_name, false)) ||
     290             :         // This is a dependency of a generator that needs to be saved or output
     291         905 :         std::find_if(required_generators.begin(),
     292             :                      required_generators.end(),
     293        1462 :                      [&mg](const auto & name) { return mg->isChildMeshGenerator(name, false); }) !=
     294       55991 :             required_generators.end())
     295             :     {
     296       54408 :       resolver.addItem(mg);
     297       83802 :       for (const auto & dep_mg : mg->getParentMeshGenerators())
     298       29394 :         resolver.addEdge(&getMeshGeneratorInternal(dep_mg->name()), mg);
     299             :     }
     300             :   }
     301             : 
     302             :   // ...and sort them
     303             :   try
     304             :   {
     305       25271 :     _ordered_mesh_generators = resolver.getSortedValuesSets();
     306             :   }
     307             :   // It is _quite_ hard to trigger this to test it. I've tried to no avail.
     308             :   // Now that we...
     309             :   // - check and sort up front
     310             :   // - know if dependencies exist at the time of requesting them
     311             :   // - require that sub generators depend only on other sub generators in an object's
     312             :   //   tree + input dependencies that we explicitly declare
     313             :   // I don't think it's possible. But we'll leave it here anyway and it
     314             :   // definitely will not be covered
     315           0 :   catch (CyclicDependencyException<MeshGenerator *, MeshGenerator::Comparator> & e)
     316             :   {
     317           0 :     const auto & cycle = e.getCyclicDependencies();
     318           0 :     std::vector<std::string> names(cycle.size());
     319           0 :     for (const auto i : index_range(cycle))
     320           0 :       names[i] = cycle[i]->name();
     321             : 
     322           0 :     mooseError("Cyclic dependencies detected in mesh generation: ",
     323           0 :                MooseUtils::join(names, " <- "));
     324           0 :   }
     325             : 
     326             :   mooseAssert(_ordered_mesh_generators.size(), "No mesh generators found");
     327             : 
     328       25271 :   const auto & final_generators = _ordered_mesh_generators.back();
     329             : 
     330             :   // We haven't forced a final generator yet
     331       25271 :   if (_final_generator_name.empty())
     332             :   {
     333             :     mooseAssert(final_generators.size(), "Empty vector");
     334             : 
     335             :     // See if we have multiple independent trees of generators
     336       24807 :     const auto ancestor_list = resolver.getAncestors(final_generators.back());
     337       24807 :     if (ancestor_list.size() != resolver.size() && _final_generator_name.empty())
     338             :     {
     339             :       // Need to remove duplicates and possibly perform a difference so we'll import our list
     340             :       // into a set for these operations.
     341             :       std::set<MeshGenerator *, MeshGenerator::Comparator> ancestors(ancestor_list.begin(),
     342           8 :                                                                      ancestor_list.end());
     343             :       // Get all of the items from the resolver so we can compare against the tree from the
     344             :       // final generator we just pulled.
     345           8 :       const auto & allValues = resolver.getSortedValues();
     346           8 :       decltype(ancestors) all(allValues.begin(), allValues.end());
     347             : 
     348           8 :       decltype(ancestors) ind_tree;
     349           8 :       std::set_difference(all.begin(),
     350             :                           all.end(),
     351             :                           ancestors.begin(),
     352             :                           ancestors.end(),
     353             :                           std::inserter(ind_tree, ind_tree.end()));
     354             : 
     355           8 :       std::ostringstream oss;
     356             :       oss << "Your MeshGenerator tree contains multiple possible generator outputs :\n\""
     357           8 :           << final_generators.back()->name()
     358          16 :           << "\" and one or more of the following from an independent set: \"";
     359           8 :       bool first = true;
     360          27 :       for (const auto & gen : ind_tree)
     361             :       {
     362          19 :         if (!first)
     363          11 :           oss << ", ";
     364             :         else
     365           8 :           first = false;
     366             : 
     367          19 :         oss << gen->name();
     368             :       }
     369             :       oss << "\"\n\nThis may be due to a missing dependency or may be intentional. Please either\n"
     370             :              "- check that all the mesh generators are connected as a tree and culminate in a "
     371             :              "single final mesh. Having one wrong 'input=mg' parameter is the most common error\n"
     372             :              "- add additional dependencies to remove the ambiguity if you are using a user-built "
     373             :              "MeshGenerator\n"
     374             :              "- if you intend to execute a subset of the defined generators (uncommon), select the"
     375           8 :              " final MeshGenerator in the [Mesh] block with the \"final_generator\" parameter.";
     376           8 :       mooseError(oss.str());
     377           0 :     }
     378             : 
     379       24799 :     _final_generator_name = final_generators.back()->name();
     380       24799 :   }
     381             :   else
     382             :     mooseAssert(hasMeshGenerator(_final_generator_name), "Missing the preset final generator");
     383       25263 : }
     384             : 
     385             : void
     386       64289 : MeshGeneratorSystem::executeMeshGenerators()
     387             : {
     388             :   libmesh_parallel_only(comm());
     389             : 
     390             :   // we do not need to do this when there are no mesh generators
     391       64289 :   if (_mesh_generators.empty())
     392       39062 :     return;
     393             : 
     394             :   // Order the generators
     395       25258 :   createMeshGeneratorOrder();
     396             : 
     397             :   // Save all meshes marked to to_save_in_meshes and save in error checking
     398       25250 :   std::map<std::string, std::unique_ptr<MeshBase> *> to_save_in_meshes;
     399       76040 :   for (const auto & generator_set : _ordered_mesh_generators)
     400      105157 :     for (const auto & generator : generator_set)
     401       54367 :       if (generator->hasSaveMesh())
     402             :       {
     403          45 :         if (_final_generator_name == generator->name())
     404           8 :           generator->paramError("save_with_name",
     405             :                                 "Cannot use the save in capability with the final mesh generator");
     406          41 :         if (getCSGOnly())
     407           0 :           generator->paramError("save_with_name", "Cannot use in conjunction with --csg-only");
     408          41 :         to_save_in_meshes.emplace(generator->getSavedMeshName(),
     409          82 :                                   &getMeshGeneratorOutput(generator->name()));
     410             :       }
     411             :   // Grab the outputs from the final generator so MeshGeneratorMesh can pick it up
     412       25246 :   to_save_in_meshes.emplace(mainMeshGeneratorName(),
     413       50492 :                             &getMeshGeneratorOutput(_final_generator_name));
     414             : 
     415             :   // Run the MeshGenerators in the proper order
     416       75520 :   for (const auto & generator_set : _ordered_mesh_generators)
     417             :   {
     418      104609 :     for (const auto & generator : generator_set)
     419             :     {
     420       54335 :       const auto & name = generator->name();
     421       54335 :       if (_verbose)
     422           0 :         _app._console << " [DBG] Executing mesh generator (" << COLOR_GREEN << std::setw(20) << name
     423           0 :                       << COLOR_DEFAULT << ") in type (" << COLOR_GREEN << generator->type()
     424           0 :                       << COLOR_DEFAULT << ")" << std::endl;
     425       54335 :       auto current_mesh = generator->generateInternal();
     426             : 
     427             :       // Only generating data for this generator
     428       53839 :       if (generator->isDataOnly())
     429             :       {
     430             :         mooseAssert(!current_mesh, "Should not have a mesh");
     431          77 :         continue;
     432             :       }
     433             : 
     434             : #ifdef DEBUG
     435             :       // Assert that the mesh is either marked as not prepared or if it is marked as prepared,
     436             :       // that it's *actually* prepared
     437             :       if (!_has_bmbb && !MeshTools::valid_is_prepared(*current_mesh))
     438             :         generator->mooseError("The generated mesh is marked as prepared but is not actually "
     439             :                               "prepared. Please edit the '",
     440             :                               generator->type(),
     441             :                               "' class to call 'set_isnt_prepared()'");
     442             : #endif
     443             : 
     444             :       // Now we need to possibly give this mesh to downstream generators
     445       53762 :       auto & outputs = _mesh_generator_outputs[name];
     446             : 
     447       53762 :       if (outputs.size())
     448             :       {
     449       53617 :         auto & first_output = *outputs.begin();
     450             : 
     451       53617 :         first_output = std::move(current_mesh);
     452             : 
     453       53617 :         const auto & copy_from = *first_output;
     454             : 
     455       53617 :         auto output_it = ++outputs.begin();
     456             : 
     457             :         // For all of the rest we need to make a copy
     458       54276 :         for (; output_it != outputs.end(); ++output_it)
     459         659 :           (*output_it) = copy_from.clone();
     460             :       }
     461       53839 :     }
     462             :   }
     463             : 
     464             :   // No save in meshes exist in csg only mode
     465       24750 :   if (getCSGOnly())
     466          31 :     return;
     467             : 
     468             :   // Grab all the valid save in meshes from the temporary map to_save_in_meshes
     469             :   // and store them in _save_in_meshes
     470       49479 :   for (auto & [name, mesh_ptr] : to_save_in_meshes)
     471             :   {
     472             :     mooseAssert(mesh_ptr, "Invalid pointer");
     473             :     mooseAssert(*mesh_ptr, "Invalid pointer");
     474       24760 :     if (name != mainMeshGeneratorName())
     475             :       mooseAssert(_save_in_meshes.count(name), "Mesh has not been requested for save");
     476       24760 :     _save_in_meshes[name] = std::move(*mesh_ptr);
     477             :   }
     478       24762 : }
     479             : 
     480             : std::shared_ptr<MeshGenerator>
     481       57832 : MeshGeneratorSystem::createMeshGenerator(const std::string & generator_name)
     482             : {
     483             :   libmesh_parallel_only(comm());
     484             :   mooseAssert(_app.constructingMeshGenerators(), "Should not run now");
     485             : 
     486       57832 :   const auto find_params = _mesh_generator_params.find(generator_name);
     487             :   mooseAssert(find_params != _mesh_generator_params.end(), "Not added");
     488       57832 :   const auto & [type, params] = find_params->second;
     489             :   mooseAssert(comm().verify(type + generator_name), "Inconsistent construction order");
     490             : 
     491             :   std::shared_ptr<MeshGenerator> mg =
     492       57832 :       _app.getFactory().create<MeshGenerator>(type, generator_name, params);
     493             : 
     494       57484 :   if (mg->hasSaveMesh())
     495             :   {
     496          55 :     if (_save_in_meshes.count(mg->getSavedMeshName()))
     497           8 :       mg->paramError("save_with_name",
     498             :                      "The save with name '",
     499           4 :                      mg->getSavedMeshName(),
     500             :                      "' has already been used");
     501          51 :     _save_in_meshes.emplace(mg->getSavedMeshName(), nullptr);
     502             :   }
     503             : 
     504             :   // Setup the children and parents
     505       88632 :   for (const auto & dependency : mg->getRequestedMeshGenerators())
     506             :   {
     507             :     // We _shouldn't_ hit this; now that we enforce construction ordering we do
     508             :     // all of this error checking at construction time because the info is available
     509             :     mooseAssert(hasMeshGenerator(dependency), "Missing dependency");
     510             : 
     511       31152 :     auto & dependency_mg = getMeshGeneratorInternal(dependency);
     512       31152 :     mg->addParentMeshGenerator(dependency_mg, MeshGenerator::AddParentChildKey());
     513       31152 :     dependency_mg.addChildMeshGenerator(*mg, MeshGenerator::AddParentChildKey());
     514             :   }
     515             : 
     516             :   // Loop through all of the MeshGeneratorName and std::vector<MeshGeneratorName>
     517             :   // parameters (meshes that we should depend on), and make sure that either:
     518             :   // - We directly depend on them and requested a mesh from them
     519             :   // - We created a sub generator that depends on them and we declared it
     520       88562 :   for (const auto & param_dependency_pair : getMeshGeneratorParamDependencies(mg->parameters()))
     521             :   {
     522       31094 :     const auto & param_name = param_dependency_pair.first;
     523       31094 :     const auto & dependency_name = param_dependency_pair.second;
     524             : 
     525       31094 :     if (mg->isNullMeshName(dependency_name))
     526       31055 :       continue;
     527             : 
     528             :     // True if this dependency was requested and is a parent
     529       31068 :     if (mg->isParentMeshGenerator(dependency_name))
     530             :     {
     531             :       mooseAssert(mg->getRequestedMeshGenerators().count(dependency_name), "Wasn't requested");
     532       31029 :       continue;
     533             :     }
     534             : 
     535             :     // Whether or not this is a dependency of at least one SubGenerator
     536          39 :     auto find_sub_dependency = std::find_if(mg->getSubMeshGenerators().begin(),
     537          39 :                                             mg->getSubMeshGenerators().end(),
     538          97 :                                             [&dependency_name](const auto & mg)
     539          97 :                                             { return mg->isParentMeshGenerator(dependency_name); });
     540          39 :     const auto is_sub_dependency = find_sub_dependency != mg->getSubMeshGenerators().end();
     541             : 
     542             :     // This should be used by a sub generator
     543          39 :     if (mg->getRequestedMeshGeneratorsForSub().count(dependency_name))
     544             :     {
     545          31 :       if (!is_sub_dependency)
     546           4 :         mg->mooseError("The sub generator dependency declared from MeshGenerator '",
     547             :                        dependency_name,
     548             :                        "' from the parameter '",
     549             :                        param_name,
     550             :                        "' was not used.\n\nDependencies that are declared by declareMeshForSub() "
     551             :                        "must be used as an input to a sub generator created by this object.");
     552             :     }
     553             :     // This was used by a sub generator but wasn't declared
     554           8 :     else if (is_sub_dependency)
     555           8 :       mg->mooseError(
     556             :           "The MeshGenerator '",
     557             :           dependency_name,
     558             :           "' was referenced in the parameter '",
     559             :           param_name,
     560             :           "' and used in the sub generator ",
     561           4 :           (*find_sub_dependency)->type(),
     562             :           " '",
     563           4 :           (*find_sub_dependency)->name(),
     564             :           "', but was not declared as a sub dependency.\n\nTo correct this, modify the code of ",
     565           4 :           mg->type(),
     566             :           " to include a call to declareMesh(es)ForSub(\"",
     567             :           param_name,
     568             :           "\") in the constructor.");
     569             :     // Isn't used at all
     570             :     else
     571           4 :       mg->mooseError(
     572             :           "You failed to request the generated mesh(es) for the parameter '",
     573             :           param_name,
     574             :           "'.\n\nIn specific, the mesh from MeshGenerator '",
     575             :           dependency_name,
     576             :           "' was not requested.\n\nTo correct this, you should remove the parameter if the "
     577             :           "mesh(es)\nare not needed, or request the mesh(es) with getMesh()/getMeshes().");
     578       57468 :   }
     579             : 
     580             :   mooseAssert(!_mesh_generators.count(generator_name), "Already created");
     581       57468 :   _mesh_generators.emplace(generator_name, mg);
     582             :   mooseAssert(!_mesh_generator_outputs.count(generator_name), "Already exists");
     583       57468 :   _mesh_generator_outputs[generator_name];
     584       57468 :   _mesh_generator_params.erase(find_params);
     585             : 
     586      114936 :   return mg;
     587           0 : }
     588             : 
     589             : std::unique_ptr<MeshBase> &
     590       56687 : MeshGeneratorSystem::getMeshGeneratorOutput(const MeshGeneratorName & name)
     591             : {
     592             :   mooseAssert(_app.constructingMeshGenerators() ||
     593             :                   _app.actionWarehouse().getCurrentTaskName() == "execute_mesh_generators",
     594             :               "Incorrect call time");
     595             : 
     596       56687 :   auto it = _mesh_generator_outputs.find(name);
     597             :   mooseAssert(it != _mesh_generator_outputs.end(), "Not initialized");
     598       56687 :   it->second.push_back(nullptr);
     599      113374 :   return it->second.back();
     600             : }
     601             : 
     602             : bool
     603       62720 : MeshGeneratorSystem::hasMeshGenerator(const MeshGeneratorName & name) const
     604             : {
     605       62720 :   return _mesh_generators.count(name);
     606             : }
     607             : 
     608             : bool
     609          20 : MeshGeneratorSystem::hasMeshGeneratorParams(const MeshGeneratorName & name) const
     610             : {
     611          20 :   return _mesh_generator_params.count(name);
     612             : }
     613             : 
     614             : const MeshGenerator &
     615       60838 : MeshGeneratorSystem::getMeshGenerator(const std::string & name) const
     616             : {
     617       60838 :   const auto it = _mesh_generators.find(name);
     618       60838 :   if (it == _mesh_generators.end())
     619           4 :     mooseError("Failed to find a MeshGenerator with the name '", name, "'");
     620             :   mooseAssert(it->second, "Invalid shared pointer");
     621      121668 :   return *it->second;
     622             : }
     623             : 
     624             : std::vector<std::string>
     625      109797 : MeshGeneratorSystem::getMeshGeneratorNames() const
     626             : {
     627      109797 :   std::vector<std::string> names;
     628      168371 :   for (auto & pair : _mesh_generators)
     629       58574 :     names.push_back(pair.first);
     630      109797 :   return names;
     631           0 : }
     632             : 
     633             : std::vector<std::string>
     634          17 : MeshGeneratorSystem::getSavedMeshNames() const
     635             : {
     636          17 :   std::vector<std::string> names;
     637          51 :   for (auto & pair : _save_in_meshes)
     638          34 :     names.push_back(pair.first);
     639          17 :   return names;
     640           0 : }
     641             : 
     642             : std::unique_ptr<MeshBase>
     643       24744 : MeshGeneratorSystem::getSavedMesh(const std::string & name)
     644             : {
     645       24744 :   auto find_mesh = _save_in_meshes.find(name);
     646       24744 :   if (find_mesh == _save_in_meshes.end())
     647           4 :     mooseError("Failed to find a saved mesh with the name '", name, "'");
     648             : 
     649       24740 :   auto & mesh_unique_ptr = find_mesh->second;
     650       24740 :   if (!mesh_unique_ptr)
     651           4 :     mooseError("While getting the saved mesh generator '",
     652             :                name,
     653             :                "', said mesh has already been retrieved");
     654             : 
     655       49472 :   return std::move(mesh_unique_ptr);
     656             : }
     657             : 
     658             : bool
     659       58477 : MeshGeneratorSystem::appendingMeshGenerators() const
     660             : {
     661       58477 :   return _app.actionWarehouse().getCurrentTaskName() == "append_mesh_generator";
     662             : }
     663             : 
     664             : bool
     665          38 : MeshGeneratorSystem::hasDataDrivenAllowed() const
     666             : {
     667          38 :   return _app.parameters().get<bool>(allow_data_driven_param);
     668             : }
     669             : 
     670             : const std::string &
     671         150 : MeshGeneratorSystem::getDataDrivenGeneratorName() const
     672             : {
     673             :   mooseAssert(_data_driven_generator_name, "Not set");
     674         150 :   return *_data_driven_generator_name;
     675             : }
     676             : 
     677             : void
     678           8 : MeshGeneratorSystem::dataDrivenError(const MeshGenerator & generator,
     679             :                                      const std::string & message) const
     680             : {
     681           8 :   const auto & moose_mesh = _app.actionWarehouse().getMesh();
     682          16 :   moose_mesh->paramError(data_driven_generator_param,
     683             :                          "The generator '",
     684           8 :                          getDataDrivenGeneratorName(),
     685             :                          "' cannot be used in data-driven mode because the parent ",
     686           8 :                          generator.typeAndName(),
     687             :                          " ",
     688             :                          message);
     689             : }
     690             : 
     691             : void
     692          31 : MeshGeneratorSystem::setCSGOnly()
     693             : {
     694          31 :   _csg_only = true;
     695          31 : }
     696             : 
     697             : void
     698          13 : MeshGeneratorSystem::saveOutputCSGBase(const MeshGeneratorName generator_name,
     699             :                                        std::unique_ptr<CSG::CSGBase> & csg_base)
     700             : {
     701             :   mooseAssert(_csg_base_output.find(generator_name) == _csg_base_output.end(),
     702             :               "CSG mesh already exists");
     703          13 :   _csg_base_output[generator_name] = std::move(csg_base);
     704          13 : }
     705             : 
     706             : std::unique_ptr<CSG::CSGBase> &
     707          13 : MeshGeneratorSystem::getCSGBaseGeneratorOutput(const MeshGeneratorName & name)
     708             : {
     709             :   mooseAssert(_app.actionWarehouse().getCurrentTaskName() == "execute_csg_generators",
     710             :               "Incorrect call time");
     711             : 
     712          13 :   auto it = _csg_base_output.find(name);
     713             :   mooseAssert(it != _csg_base_output.end(), "CSG mesh not initialized");
     714          26 :   return it->second;
     715             : }

Generated by: LCOV version 1.14