LCOV - code coverage report
Current view: top level - src/meshgenerators - MeshGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 226 237 95.4 %
Date: 2026-05-29 20:35:17 Functions: 38 40 95.0 %
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 "MeshGenerator.h"
      11             : #include "MooseMesh.h"
      12             : #include "MooseApp.h"
      13             : 
      14             : #include "Exodus.h"
      15             : #include "Nemesis.h"
      16             : 
      17             : #include "libmesh/exodusII_io.h"
      18             : #include "libmesh/nemesis_io.h"
      19             : 
      20             : const std::string MeshGenerator::data_only_param = "_data_only";
      21             : 
      22             : InputParameters
      23      474448 : MeshGenerator::validParams()
      24             : {
      25      474448 :   InputParameters params = MooseObject::validParams();
      26             : 
      27     1423344 :   params.addParam<bool>("show_info",
      28      948896 :                         false,
      29             :                         "Whether or not to show mesh info after generating the mesh "
      30             :                         "(bounding box, element types, sidesets, nodesets, subdomains, etc)");
      31     1423344 :   params.addParam<std::string>(
      32             :       "save_with_name",
      33      948896 :       std::string(),
      34             :       "Keep the mesh from this mesh generator in memory with the name specified");
      35             : 
      36     1423344 :   params.addParam<bool>(
      37      948896 :       "output", false, "Whether or not to output the mesh file after generating the mesh");
      38     1423344 :   params.addParam<bool>("nemesis",
      39      948896 :                         false,
      40             :                         "Whether or not to output the mesh file in the nemesis"
      41             :                         "format (only if output = true)");
      42             : 
      43     1897792 :   params.addParamNamesToGroup("show_info output nemesis", "Debugging");
      44     1897792 :   params.addParamNamesToGroup("save_with_name", "Advanced");
      45      474448 :   params.registerBase("MeshGenerator");
      46             : 
      47      948896 :   params.addPrivateParam<bool>("_has_generate_data", false);
      48      948896 :   params.addPrivateParam<bool>("_has_generate_csg", false);
      49      948896 :   params.addPrivateParam<MooseMesh *>("_moose_mesh", nullptr);
      50      474448 :   params.addPrivateParam<bool>(data_only_param, false);
      51             :   // Controls are not created early enough
      52      474448 :   params.suppressParameter<std::vector<std::string>>("control_tags");
      53             : 
      54      474448 :   return params;
      55           0 : }
      56             : 
      57       56535 : MeshGenerator::MeshGenerator(const InputParameters & parameters)
      58             :   : MooseObject(parameters),
      59             :     MeshMetaDataInterface(this),
      60      113070 :     _mesh(getParam<MooseMesh *>("_moose_mesh") ? getParam<MooseMesh *>("_moose_mesh")
      61       56535 :                                                : _app.actionWarehouse().mesh().get()),
      62      113070 :     _save_with_name(getParam<std::string>("save_with_name")),
      63      169605 :     _data_only(getParam<bool>(data_only_param))
      64             : {
      65       56535 :   const auto & system = _app.getMeshGeneratorSystem();
      66       56535 :   if (isDataOnly())
      67             :   {
      68             :     // Skip the requirement for generateData() if we are generating CSG object
      69         248 :     if (!hasGenerateCSG() && !hasGenerateData())
      70           3 :       system.dataDrivenError(*this, "does not support data-driven generation");
      71         245 :     if (hasSaveMesh())
      72           3 :       system.dataDrivenError(*this, "has 'save_with_name' set");
      73             :   }
      74       56529 :   if (_save_with_name == system.mainMeshGeneratorName())
      75           3 :     paramError(
      76           3 :         "save_with_name", "The user-defined mesh name: '", _save_with_name, "' is a reserved name");
      77      169606 :   if (getParam<bool>("nemesis") && !getParam<bool>("output"))
      78           0 :     paramError("nemesis", "Should only be set to true if 'output=true'");
      79       56526 : }
      80             : 
      81             : void
      82        6409 : MeshGenerator::setHasGenerateData(InputParameters & params)
      83             : {
      84        6409 :   params.set<bool>("_has_generate_data") = true;
      85        6409 : }
      86             : 
      87             : bool
      88       53022 : MeshGenerator::hasGenerateData(const InputParameters & params)
      89             : {
      90       53022 :   return params.get<bool>("_has_generate_data");
      91             : }
      92             : 
      93             : void
      94       24880 : MeshGenerator::setHasGenerateCSG(InputParameters & params)
      95             : {
      96       24880 :   params.set<bool>("_has_generate_csg") = true;
      97       24880 : }
      98             : 
      99             : bool
     100       63045 : MeshGenerator::hasGenerateCSG(const InputParameters & params)
     101             : {
     102       63045 :   return params.get<bool>("_has_generate_csg");
     103             : }
     104             : 
     105             : const MeshGeneratorName *
     106       27581 : MeshGenerator::getMeshGeneratorNameFromParam(const std::string & param_name,
     107             :                                              const bool allow_invalid) const
     108             : {
     109       27581 :   const auto valid_param = isParamValid(param_name);
     110       27581 :   if (!allow_invalid)
     111             :   {
     112       25829 :     if (!valid_param)
     113           3 :       mooseError("Failed to get a parameter with the name \"",
     114             :                  param_name,
     115             :                  "\" when getting a MeshGenerator.",
     116             :                  "\n\nKnown parameters:\n",
     117             :                  _pars);
     118       25826 :     if (!_pars.isType<MeshGeneratorName>(param_name))
     119           3 :       paramError(param_name,
     120             :                  "Parameter of type \"",
     121           3 :                  _pars.type(param_name),
     122             :                  "\" is not an expected type for getting a MeshGenerator (should be of type "
     123             :                  "\"MeshGeneratorName\")");
     124             :   }
     125        1752 :   else if (!valid_param)
     126        1399 :     return nullptr;
     127             : 
     128       26176 :   const auto & name = getParam<MeshGeneratorName>(param_name);
     129       26176 :   checkGetMesh(name, param_name);
     130             : 
     131       26170 :   return &name;
     132             : }
     133             : 
     134             : const std::vector<MeshGeneratorName> &
     135        1968 : MeshGenerator::getMeshGeneratorNamesFromParam(const std::string & param_name) const
     136             : {
     137        1968 :   if (!isParamValid(param_name))
     138           3 :     mooseError("Failed to get a parameter with the name \"",
     139             :                param_name,
     140             :                "\" when getting MeshGenerators.",
     141             :                "\n\nKnown parameters:\n",
     142             :                _pars);
     143        1965 :   if (!_pars.isType<std::vector<MeshGeneratorName>>(param_name))
     144           3 :     paramError(param_name,
     145             :                "Parameter of type \"",
     146           3 :                _pars.type(param_name),
     147             :                "\" is not an expected type for getting MeshGenerators (should be of type "
     148             :                "\"std::vector<MeshGeneratorName>\")");
     149             : 
     150        1962 :   const auto & names = getParam<std::vector<MeshGeneratorName>>(param_name);
     151        6690 :   for (const auto & name : names)
     152        4731 :     checkGetMesh(name, param_name);
     153             : 
     154        1959 :   return names;
     155             : }
     156             : 
     157             : void
     158       62591 : MeshGenerator::checkGetMesh(const MeshGeneratorName & mesh_generator_name,
     159             :                             const std::string & param_name) const
     160             : {
     161             :   mooseAssert(!mesh_generator_name.empty(), "Empty name");
     162       62591 :   const auto & mg_sys = _app.getMeshGeneratorSystem();
     163       62591 :   if (!hasGenerateCSG() && !_app.constructingMeshGenerators())
     164           3 :     mooseError("Cannot get a mesh outside of construction");
     165       62588 :   if (!mg_sys.hasMeshGenerator(mesh_generator_name) && !isNullMeshName(mesh_generator_name))
     166             :   {
     167          15 :     std::stringstream error;
     168          15 :     error << "The requested MeshGenerator with name '" << mesh_generator_name << "' ";
     169          15 :     if (mg_sys.hasMeshGeneratorParams(mesh_generator_name))
     170             :       error << "was found, but has not been constructed yet.\n\nThis can occur when your "
     171             :                "dependencies are not properly defined and we cannot infer the proper construction "
     172             :                "order of your MeshGenerators.\n\nThe most likely case is a sub generator whose "
     173           3 :                "input(s) are not declared as a sub dependency in the generator creating them.";
     174             :     else
     175             :       error << "was not found.\nMesh generators that can be found: "
     176          60 :             << Moose::stringify(mg_sys.getMeshGeneratorNames());
     177             : 
     178          15 :     if (param_name.size())
     179           9 :       paramError(param_name, error.str());
     180             :     else
     181           6 :       mooseError(error.str());
     182           0 :   }
     183       62573 : }
     184             : 
     185             : std::unique_ptr<MeshBase> &
     186       27463 : MeshGenerator::getMesh(const std::string & param_name, const bool allow_invalid /* = false */)
     187             : {
     188       27463 :   const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, allow_invalid);
     189       27451 :   if (!name)
     190        1399 :     return _null_mesh;
     191       26052 :   return getMeshByName(*name);
     192             : }
     193             : 
     194             : std::vector<std::unique_ptr<MeshBase> *>
     195        1960 : MeshGenerator::getMeshes(const std::string & param_name)
     196             : {
     197        1960 :   return getMeshesByName(getMeshGeneratorNamesFromParam(param_name));
     198             : }
     199             : 
     200             : std::unique_ptr<MeshBase> &
     201       31478 : MeshGenerator::getMeshByName(const MeshGeneratorName & mesh_generator_name)
     202             : {
     203       31478 :   checkGetMesh(mesh_generator_name, "");
     204       31469 :   if (isNullMeshName(mesh_generator_name))
     205          36 :     return _null_mesh;
     206             : 
     207       31433 :   _requested_mesh_generators.insert(mesh_generator_name);
     208       31433 :   auto & mesh = _app.getMeshGeneratorSystem().getMeshGeneratorOutput(mesh_generator_name);
     209       31433 :   _requested_meshes.emplace_back(mesh_generator_name, &mesh);
     210       31433 :   return mesh;
     211             : }
     212             : 
     213             : std::vector<std::unique_ptr<MeshBase> *>
     214        1954 : MeshGenerator::getMeshesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
     215             : {
     216        1954 :   std::vector<std::unique_ptr<MeshBase> *> meshes;
     217        6666 :   for (const auto & name : mesh_generator_names)
     218        4715 :     meshes.push_back(&getMeshByName(name));
     219        1951 :   return meshes;
     220           0 : }
     221             : 
     222             : std::unique_ptr<CSG::CSGBase> &
     223          83 : MeshGenerator::getCSGBase(const std::string & param_name)
     224             : {
     225          83 :   const MeshGeneratorName * name = getMeshGeneratorNameFromParam(param_name, false);
     226          83 :   return getCSGBaseByName(*name);
     227             : }
     228             : 
     229             : std::unique_ptr<CSG::CSGBase> &
     230         147 : MeshGenerator::getCSGBaseByName(const MeshGeneratorName & mesh_generator_name)
     231             : {
     232         147 :   checkGetMesh(mesh_generator_name, "");
     233             : 
     234         147 :   auto & csg_base = _app.getMeshGeneratorSystem().getCSGBaseGeneratorOutput(mesh_generator_name);
     235         147 :   _requested_csg_bases.emplace_back(mesh_generator_name, &csg_base);
     236         147 :   return csg_base;
     237             : }
     238             : 
     239             : std::vector<std::unique_ptr<CSG::CSGBase> *>
     240           8 : MeshGenerator::getCSGBases(const std::string & param_name)
     241             : {
     242           8 :   return getCSGBasesByName(getMeshGeneratorNamesFromParam(param_name));
     243             : }
     244             : 
     245             : std::vector<std::unique_ptr<CSG::CSGBase> *>
     246           8 : MeshGenerator::getCSGBasesByName(const std::vector<MeshGeneratorName> & mesh_generator_names)
     247             : {
     248           8 :   std::vector<std::unique_ptr<CSG::CSGBase> *> csg_bases;
     249          24 :   for (const auto & name : mesh_generator_names)
     250          16 :     csg_bases.push_back(&getCSGBaseByName(name));
     251           8 :   return csg_bases;
     252           0 : }
     253             : 
     254             : void
     255          35 : MeshGenerator::declareMeshForSub(const std::string & param_name)
     256             : {
     257          35 :   declareMeshForSubByName(*getMeshGeneratorNameFromParam(param_name, false));
     258          35 : }
     259             : 
     260             : void
     261           0 : MeshGenerator::declareMeshesForSub(const std::string & param_name)
     262             : {
     263           0 :   declareMeshesForSubByName(getMeshGeneratorNamesFromParam(param_name));
     264           0 : }
     265             : 
     266             : void
     267          59 : MeshGenerator::declareMeshForSubByName(const MeshGeneratorName & mesh_generator_name)
     268             : {
     269          59 :   checkGetMesh(mesh_generator_name, "");
     270          59 :   if (isNullMeshName(mesh_generator_name))
     271          24 :     return;
     272             : 
     273          35 :   _requested_mesh_generators_for_sub.insert(mesh_generator_name);
     274             : }
     275             : 
     276             : void
     277          12 : MeshGenerator::declareMeshesForSubByName(
     278             :     const std::vector<MeshGeneratorName> & mesh_generator_names)
     279             : {
     280          24 :   for (const auto & name : mesh_generator_names)
     281          12 :     declareMeshForSubByName(name);
     282          12 : }
     283             : 
     284             : std::unique_ptr<MeshBase>
     285       26666 : MeshGenerator::buildMeshBaseObject(unsigned int dim)
     286             : {
     287             :   mooseAssert(_mesh, "Need a MooseMesh object");
     288       26666 :   return _mesh->buildMeshBaseObject(dim);
     289             : }
     290             : 
     291             : std::unique_ptr<ReplicatedMesh>
     292        1395 : MeshGenerator::buildReplicatedMesh(unsigned int dim)
     293             : {
     294             :   mooseAssert(_mesh, "Need a MooseMesh object");
     295        1395 :   return _mesh->buildTypedMesh<ReplicatedMesh>(dim);
     296             : }
     297             : 
     298             : std::unique_ptr<DistributedMesh>
     299         781 : MeshGenerator::buildDistributedMesh(unsigned int dim)
     300             : {
     301             :   mooseAssert(_mesh, "Need a MooseMesh object");
     302         781 :   return _mesh->buildTypedMesh<DistributedMesh>(dim);
     303             : }
     304             : 
     305             : std::unique_ptr<MeshBase>
     306       52980 : MeshGenerator::generateInternal()
     307             : {
     308             :   libmesh_parallel_only(comm());
     309             :   mooseAssert(comm().verify(type() + name()), "Inconsistent execution ordering");
     310             : 
     311       52980 :   if (hasGenerateData())
     312          85 :     generateData();
     313             : 
     314       52980 :   if (isDataOnly())
     315         228 :     return nullptr;
     316             : 
     317       52752 :   auto mesh = generate();
     318       52365 :   if (!mesh)
     319           3 :     mooseError("A mesh was not generated by this generator (it was nullptr).");
     320             : 
     321       81166 :   for (const auto & [requested_name, requested_mesh] : _requested_meshes)
     322       28807 :     if (*requested_mesh)
     323           3 :       mooseError(
     324             :           "The mesh from input ",
     325           3 :           _app.getMeshGenerator(requested_name).type(),
     326             :           " '",
     327           3 :           _app.getMeshGenerator(requested_name).name(),
     328             :           "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
     329             :           "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
     330             :           "is achieved with a std::move() operation within the generate() method.");
     331             : 
     332      157077 :   if (getParam<bool>("show_info"))
     333             :   {
     334          83 :     if (!mesh->is_prepared())
     335          83 :       mesh->prepare_for_use();
     336             : 
     337          83 :     const auto mesh_info = mesh->get_info(/* verbosity = */ 2);
     338             : 
     339             :     // We will prefix all information with "type() 'name()':" because this could potentially
     340             :     // output a ton of information and looks a bit better with a prefix
     341          83 :     std::stringstream oss;
     342         166 :     const auto split = MooseUtils::split(mesh_info, "\n");
     343          83 :     if (split.size())
     344        5949 :       for (std::size_t i = 0; i < split.size() - 1; ++i) // ignore the last line break
     345        5866 :         oss << COLOR_CYAN << "" << type() << " '" << name() << "': " << COLOR_DEFAULT << split[i]
     346        5866 :             << std::endl;
     347          83 :     _console << oss.str() << std::flush;
     348          83 :   }
     349             : 
     350             :   // output the current mesh block to file
     351       52359 :   if (hasOutput())
     352             :   {
     353         477 :     if (!mesh->is_prepared())
     354         477 :       mesh->prepare_for_use();
     355             : 
     356        1431 :     if (!getParam<bool>("nemesis"))
     357             :     {
     358         463 :       libMesh::ExodusII_IO exio(*mesh);
     359             : 
     360         463 :       if (mesh->mesh_dimension() == 1)
     361          82 :         exio.write_as_dimension(3);
     362             : 
     363             :       // Avoid truncating names
     364         463 :       exio.set_max_name_length(80);
     365             : 
     366             :       // Default to non-HDF5 output for wider compatibility
     367         463 :       exio.set_hdf5_writing(false);
     368             : 
     369         463 :       exio.write(name() + "_in.e");
     370         463 :     }
     371             :     else
     372             :     {
     373          14 :       libMesh::Nemesis_IO nemesis_io(*mesh);
     374             : 
     375             :       // Default to non-HDF5 output for wider compatibility
     376          14 :       nemesis_io.set_hdf5_writing(false);
     377             : 
     378          14 :       nemesis_io.write(name() + "_in.e");
     379          14 :     }
     380             :   }
     381             : 
     382       52359 :   return mesh;
     383       52359 : }
     384             : 
     385             : std::unique_ptr<CSG::CSGBase>
     386         198 : MeshGenerator::generateInternalCSG()
     387             : {
     388             :   mooseAssert(isDataOnly(), "Trying to use csg-only mode while not in data-driven mode");
     389         198 :   auto csg_obj = generateCSG();
     390             :   mooseAssert(csg_obj, "Null CSG object");
     391         334 :   for (const auto & [requested_name, requested_csg] : _requested_csg_bases)
     392         139 :     if (*requested_csg)
     393           3 :       mooseError(
     394             :           "The CSGBase object from input ",
     395           3 :           _app.getMeshGenerator(requested_name).type(),
     396             :           " '",
     397           3 :           _app.getMeshGenerator(requested_name).name(),
     398             :           "' was not moved.\n\nThe MeshGenerator system requires that the memory from all input "
     399             :           "meshes\nare managed by the requesting MeshGenerator during the generate phase.\n\nThis "
     400             :           "is achieved with a std::move() operation within the generateCSG() method.");
     401             : 
     402         195 :   return csg_obj;
     403           0 : }
     404             : 
     405             : void
     406         196 : MeshGenerator::addMeshSubgenerator(const std::string & type,
     407             :                                    const std::string & name,
     408             :                                    InputParameters params)
     409             : {
     410         196 :   if (!_app.constructingMeshGenerators())
     411           3 :     mooseError("Can only call addMeshSubgenerator() during MeshGenerator construction");
     412             : 
     413             :   // In case the user forgot it
     414         193 :   params.set<MooseApp *>(MooseBase::app_param) = &_app;
     415             : 
     416             :   // Set this to be data-only if this generator is data only
     417         193 :   params.set<bool>(data_only_param) = isDataOnly();
     418             : 
     419         193 :   _app.addMeshGenerator(type, name, params);
     420         190 :   _sub_mesh_generators.insert(&std::as_const(_app).getMeshGenerator(name));
     421         190 : }
     422             : 
     423             : RestartableDataValue &
     424          23 : MeshGenerator::setMeshPropertyHelper(const std::string & data_name)
     425             : {
     426          23 :   return _app.getRestartableMetaData(meshPropertyName(data_name), MooseApp::MESH_META_DATA, 0);
     427             : }
     428             : 
     429             : void
     430       31214 : MeshGenerator::addParentMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
     431             : {
     432             :   mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
     433       31214 :   _parent_mesh_generators.insert(&mg);
     434       31214 : }
     435             : 
     436             : void
     437       31214 : MeshGenerator::addChildMeshGenerator(const MeshGenerator & mg, const AddParentChildKey)
     438             : {
     439             :   mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
     440       31214 :   _child_mesh_generators.insert(&mg);
     441       31214 : }
     442             : 
     443             : bool
     444       31226 : MeshGenerator::isParentMeshGenerator(const MeshGeneratorName & name,
     445             :                                      const bool direct /* = true */) const
     446             : {
     447       31226 :   return std::find_if(getParentMeshGenerators().begin(),
     448       31226 :                       getParentMeshGenerators().end(),
     449       44981 :                       [&name, &direct](const auto & mg)
     450             :                       {
     451       58826 :                         return mg->name() == name ||
     452       58826 :                                (!direct && mg->isParentMeshGenerator(name, /* direct = */ false));
     453       62452 :                       }) != getParentMeshGenerators().end();
     454             : }
     455             : 
     456             : bool
     457        5746 : MeshGenerator::isChildMeshGenerator(const MeshGeneratorName & name,
     458             :                                     const bool direct /* = true */) const
     459             : {
     460        5746 :   return std::find_if(getChildMeshGenerators().begin(),
     461        5746 :                       getChildMeshGenerators().end(),
     462        4546 :                       [&name, &direct](const auto & mg)
     463             :                       {
     464        7483 :                         return mg->name() == name ||
     465        7483 :                                (!direct && mg->isChildMeshGenerator(name, /* direct = */ false));
     466       11492 :                       }) != getChildMeshGenerators().end();
     467             : }
     468             : 
     469             : void
     470          12 : MeshGenerator::declareNullMeshName(const MeshGeneratorName & name)
     471             : {
     472             :   mooseAssert(_app.constructingMeshGenerators(), "Should only be called at construction");
     473             :   mooseAssert(!_null_mesh_names.count(name), "Already declared");
     474          12 :   _null_mesh_names.insert(name);
     475          12 : }
     476             : 
     477             : bool
     478      165711 : MeshGenerator::hasSaveMesh() const
     479             : {
     480      165711 :   return _save_with_name.size();
     481             : }
     482             : 
     483             : bool
     484      108504 : MeshGenerator::hasOutput() const
     485             : {
     486      325512 :   return getParam<bool>("output");
     487             : }
     488             : 
     489             : const std::string &
     490         130 : MeshGenerator::getSavedMeshName() const
     491             : {
     492         130 :   return _save_with_name;
     493             : }
     494             : 
     495             : void
     496           3 : MeshGenerator::generateData()
     497             : {
     498             :   mooseAssert(!hasGenerateData(), "Inconsistent flag");
     499           3 :   mooseError("This MeshGenerator does not have a generateData() implementation.");
     500             : }
     501             : 
     502             : [[nodiscard]] std::unique_ptr<CSG::CSGBase>
     503           0 : MeshGenerator::generateCSG()
     504             : {
     505             :   mooseAssert(!hasGenerateCSG(), "Inconsistent flag");
     506           0 :   mooseError("This MeshGenerator does not have a generateCSG() implementation.");
     507             : }

Generated by: LCOV version 1.14