LCOV - code coverage report
Current view: top level - src/actions - SetupMeshAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 157 171 91.8 %
Date: 2026-05-29 20:35:17 Functions: 5 5 100.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 "SetupMeshAction.h"
      11             : #include "MooseApp.h"
      12             : #include "MooseMesh.h"
      13             : #include "FileMesh.h"
      14             : #include "FEProblem.h"
      15             : #include "ActionWarehouse.h"
      16             : #include "Factory.h"
      17             : #include "AddMeshGeneratorAction.h"
      18             : 
      19             : #include <functional>
      20             : #include <algorithm>
      21             : 
      22             : registerMooseAction("MooseApp", SetupMeshAction, "setup_mesh");
      23             : registerMooseAction("MooseApp", SetupMeshAction, "set_mesh_base");
      24             : registerMooseAction("MooseApp", SetupMeshAction, "init_mesh");
      25             : 
      26             : InputParameters
      27       66222 : SetupMeshAction::validParams()
      28             : {
      29       66222 :   InputParameters params = MooseObjectAction::validParams();
      30      132444 :   params.addClassDescription("Add or create Mesh object to the simulation.");
      31             : 
      32             :   // Here we are setting the default type of the mesh to construct to "FileMesh". This is to support
      33             :   // the very long-running legacy syntax where only a file parameter is required to determine the
      34             :   // type of the "Mesh" block. We are re-adding it though so that we can detect whether or not the
      35             :   // user has explicitly set the type in an input file. We do this because we want to support
      36             :   // automatically building a "MeshGeneratorMesh" type when MeshGenerators are added to the
      37             :   // simulation.
      38      264888 :   params.addParam<std::string>(
      39             :       "type",
      40             :       "FileMesh",
      41             :       "A string representing the Moose Object that will be built by this Action");
      42             : 
      43      198666 :   params.addParam<bool>("second_order",
      44      132444 :                         false,
      45             :                         "Converts a first order mesh to a second order "
      46             :                         "mesh.  Note: This is NOT needed if you are reading "
      47             :                         "an actual first order mesh.");
      48             : 
      49      264888 :   params.addParam<std::vector<SubdomainID>>("block_id", "IDs of the block id/name pairs");
      50      264888 :   params.addParam<std::vector<SubdomainName>>(
      51             :       "block_name", "Names of the block id/name pairs (must correspond with \"block_id\"");
      52             : 
      53      264888 :   params.addParam<std::vector<BoundaryID>>("boundary_id", {}, "IDs of the boundary id/name pairs");
      54      264888 :   params.addParam<std::vector<BoundaryName>>(
      55             :       "boundary_name",
      56             :       {},
      57             :       "Names of the boundary id/name pairs (must correspond with \"boundary_id\"");
      58             : 
      59      198666 :   params.addParam<bool>("construct_side_list_from_node_list",
      60      132444 :                         false,
      61             :                         "If true, construct side lists from the nodesets in the mesh (i.e. if "
      62             :                         "every node on a give side is in a nodeset then add that side to a "
      63             :                         "sideset");
      64             : 
      65      264888 :   params.addParam<std::vector<std::string>>(
      66             :       "displacements",
      67             :       "The variables corresponding to the x y z displacements of the mesh.  If "
      68             :       "this is provided then the displacements will be taken into account during "
      69             :       "the computation. Creation of the displaced mesh can be suppressed even if "
      70             :       "this is set by setting 'use_displaced_mesh = false'.");
      71      198666 :   params.addParam<bool>(
      72             :       "use_displaced_mesh",
      73      132444 :       true,
      74             :       "Create the displaced mesh if the 'displacements' "
      75             :       "parameter is set. If this is 'false', a displaced mesh will not be created, "
      76             :       "regardless of whether 'displacements' is set.");
      77      264888 :   params.addParam<std::vector<BoundaryName>>(
      78             :       "ghosted_boundaries", {}, "Boundaries to be ghosted if using Nemesis");
      79      264888 :   params.addParam<std::vector<Real>>("ghosted_boundaries_inflation",
      80             :                                      "If you are using ghosted boundaries you will want to set "
      81             :                                      "this value to a vector of amounts to inflate the bounding "
      82             :                                      "boxes by.  ie if you are running a 3D problem you might set "
      83             :                                      "it to '0.2 0.1 0.4'");
      84             : 
      85      198666 :   params.addParam<unsigned int>(
      86      132444 :       "uniform_refine", 0, "Specify the level of uniform refinement applied to the initial mesh");
      87             : 
      88      264888 :   params.addParam<bool>("skip_deletion_repartition_after_refine",
      89      132444 :                         false,
      90             :                         "If the flag is true, uniform refinements will run more efficiently, "
      91             :                         "but at the same time, there might be extra ghosting elements. "
      92             :                         "The number of layers of additional ghosting elements depends "
      93             :                         "on the number of uniform refinement levels.  This flag "
      94             :                         "should be used only when you have a 'fine enough' coarse mesh and want "
      95             :                         "to refine the mesh by a few levels. Otherwise, it might introduce an "
      96             :                         "unbalanced workload and too large ghosting domain. ");
      97             : 
      98      198666 :   params.addParam<bool>("skip_partitioning",
      99      132444 :                         false,
     100             :                         "If true the mesh won't be partitioned. This may cause large load "
     101             :                         "imbalances.");
     102             : 
     103      198666 :   params.addParam<bool>(
     104             :       "use_split",
     105      132444 :       false,
     106             :       "Use split distributed mesh files; is overriden by the --use-split command line option");
     107      264888 :   params.addParam<std::string>("split_file",
     108             :                                "",
     109             :                                "Optional name of split mesh file(s) to write/read; is overridden "
     110             :                                "by the --split-file command line option");
     111             : 
     112             :   // groups
     113      264888 :   params.addParamNamesToGroup("displacements ghosted_boundaries ghosted_boundaries_inflation",
     114             :                               "Advanced");
     115      264888 :   params.addParamNamesToGroup("second_order construct_side_list_from_node_list skip_partitioning",
     116             :                               "Advanced");
     117      264888 :   params.addParamNamesToGroup("block_id block_name boundary_id boundary_name", "Add Names");
     118      198666 :   params.addParamNamesToGroup("use_split split_file", "Split Mesh");
     119             : 
     120       66222 :   return params;
     121           0 : }
     122             : 
     123       66121 : SetupMeshAction::SetupMeshAction(const InputParameters & params)
     124             :   : MooseObjectAction(params),
     125      198297 :     _use_split(getParam<bool>("use_split") || _app.getParam<bool>("use_split")),
     126      264783 :     _split_file(_app.isParamSetByUser("split_file") ? _app.getParam<std::string>("split_file")
     127      329708 :                                                     : getParam<std::string>("split_file"))
     128             : {
     129       66121 : }
     130             : 
     131             : void
     132       66325 : SetupMeshAction::setupMesh(MooseMesh * mesh)
     133             : {
     134      198975 :   if (isParamValid("ghosted_boundaries"))
     135      198975 :     for (const auto & bnd_name : getParam<std::vector<BoundaryName>>("ghosted_boundaries"))
     136           0 :       mesh->addGhostedBoundary(mesh->getBoundaryID(bnd_name));
     137             : 
     138      198975 :   if (isParamValid("ghosted_boundaries_inflation"))
     139             :   {
     140             :     std::vector<Real> ghosted_boundaries_inflation =
     141           0 :         getParam<std::vector<Real>>("ghosted_boundaries_inflation");
     142           0 :     mesh->setGhostedBoundaryInflation(ghosted_boundaries_inflation);
     143           0 :   }
     144             : 
     145       66325 :   mesh->ghostGhostedBoundaries();
     146             : 
     147      198975 :   if (getParam<bool>("second_order"))
     148        1413 :     mesh->getMesh().all_second_order(true);
     149             : 
     150             : #ifdef LIBMESH_ENABLE_AMR
     151      132650 :   unsigned int level = getParam<unsigned int>("uniform_refine");
     152             : 
     153             :   // Did they specify extra refinement levels on the command-line?
     154      198975 :   if (_app.isParamSetByUser("refinements"))
     155          72 :     level += _app.getParam<unsigned int>("refinements");
     156             : 
     157      132650 :   mesh->setUniformRefineLevel(level, getParam<bool>("skip_deletion_repartition_after_refine"));
     158             : #endif // LIBMESH_ENABLE_AMR
     159             : 
     160             :   // Add entity names to the mesh
     161      199043 :   if (_pars.isParamValid("block_id") && _pars.isParamValid("block_name"))
     162             :   {
     163          68 :     std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("block_id");
     164          68 :     std::vector<SubdomainName> names = getParam<std::vector<SubdomainName>>("block_name");
     165          34 :     std::set<SubdomainName> seen_it;
     166             : 
     167          34 :     if (ids.size() != names.size())
     168           3 :       mooseError("You must supply the same number of block ids and names parameters");
     169             : 
     170         105 :     for (unsigned int i = 0; i < ids.size(); ++i)
     171             :     {
     172          77 :       if (seen_it.find(names[i]) != seen_it.end())
     173           3 :         mooseError("The following dynamic block name is not unique: " + names[i]);
     174          74 :       seen_it.insert(names[i]);
     175          74 :       mesh->setSubdomainName(ids[i], names[i]);
     176             :     }
     177          28 :   }
     178      331595 :   if (_pars.isParamValid("boundary_id") && _pars.isParamValid("boundary_name"))
     179             :   {
     180      132638 :     std::vector<BoundaryID> ids = getParam<std::vector<BoundaryID>>("boundary_id");
     181      132638 :     std::vector<BoundaryName> names = getParam<std::vector<BoundaryName>>("boundary_name");
     182       66319 :     std::set<SubdomainName> seen_it;
     183             : 
     184       66319 :     if (ids.size() != names.size())
     185           3 :       mooseError("You must supply the same number of boundary ids and names parameters");
     186             : 
     187       66343 :     for (unsigned int i = 0; i < ids.size(); ++i)
     188             :     {
     189          30 :       if (seen_it.find(names[i]) != seen_it.end())
     190           3 :         mooseError("The following dynamic boundary name is not unique: " + names[i]);
     191          27 :       mesh->setBoundaryName(ids[i], names[i]);
     192          27 :       seen_it.insert(names[i]);
     193             :     }
     194       66313 :   }
     195             : 
     196      198939 :   if (getParam<bool>("construct_side_list_from_node_list"))
     197         260 :     mesh->getMesh().get_boundary_info().build_side_list_from_node_list();
     198             : 
     199             :   // Here we can override the partitioning for special cases
     200      198939 :   if (getParam<bool>("skip_partitioning"))
     201          84 :     mesh->getMesh().skip_partitioning(getParam<bool>("skip_partitioning"));
     202       66313 : }
     203             : 
     204             : std::string
     205         255 : SetupMeshAction::modifyParamsForUseSplit(InputParameters & moose_object_params) const
     206             : {
     207             :   // Get the split_file extension, if there is one, and use that to decide
     208             :   // between .cpr and .cpa.gz
     209         255 :   auto split_file = _split_file;
     210         255 :   std::string split_file_ext = MooseUtils::getExtension(split_file);
     211             : 
     212             :   // If split_file already has the .cpr or .cpa.gz extension, we go with
     213             :   // that, otherwise we strip off the extension and append ".cpa.gz".
     214         255 :   if (split_file != "" && split_file_ext != "cpr" && split_file_ext != "cpa.gz")
     215         138 :     split_file = MooseUtils::stripExtension(split_file) + ".cpa.gz";
     216             : 
     217         255 :   if (_type != "FileMesh")
     218             :   {
     219         255 :     if (split_file.empty())
     220           0 :       mooseError("Cannot use split mesh for a non-file mesh without specifying --split-file on "
     221             :                  "command line or the Mesh/split_file parameter");
     222             : 
     223         255 :     auto new_pars = FileMesh::validParams();
     224             : 
     225             :     // Keep existing parameters where possible
     226         255 :     new_pars.applyParameters(_moose_object_pars);
     227             : 
     228         765 :     new_pars.set<MeshFileName>("file") = split_file;
     229         510 :     new_pars.set<MooseApp *>(MooseBase::app_param) =
     230         255 :         moose_object_params.get<MooseApp *>(MooseBase::app_param);
     231         255 :     moose_object_params = new_pars;
     232         255 :   }
     233             :   else
     234             :   {
     235           0 :     if (!split_file.empty())
     236           0 :       moose_object_params.set<MeshFileName>("file") = split_file;
     237             :     else
     238           0 :       moose_object_params.set<MeshFileName>("file") =
     239           0 :           MooseUtils::stripExtension(moose_object_params.get<MeshFileName>("file")) + ".cpa.gz";
     240             :   }
     241             : 
     242         510 :   moose_object_params.set<bool>("_is_split") = true;
     243             : 
     244         510 :   return "FileMesh";
     245         255 : }
     246             : 
     247             : void
     248      196078 : SetupMeshAction::act()
     249             : {
     250             :   // Create the mesh object and tell it to build itself
     251      196078 :   if (_current_task == "setup_mesh")
     252             :   {
     253      329590 :     TIME_SECTION("SetupMeshAction::act::setup_mesh", 1, "Setting Up Mesh", true);
     254             : 
     255       65918 :     if (_app.useMasterMesh())
     256         781 :       _mesh = _app.masterMesh()->safeClone();
     257             :     else
     258             :     {
     259      130274 :       const auto & generator_actions = _awh.getActionListByName("add_mesh_generator");
     260             : 
     261             :       // If we trigger any actions that can build MeshGenerators, whether through input file
     262             :       // syntax or through custom actions, change the default type to construct. We can't yet
     263             :       // check whether there are any actual MeshGenerator objects because those are added after
     264             :       // setup_mesh
     265       65137 :       if (!generator_actions.empty())
     266             :       {
     267             :         // Check for whether type has been set or whether for the default type (FileMesh) a file has
     268             :         // been provided
     269      127228 :         if (!_pars.isParamSetByUser("type") && !_moose_object_pars.isParamValid("file"))
     270             :         {
     271       25397 :           _type = "MeshGeneratorMesh";
     272       25397 :           auto original_params = _moose_object_pars;
     273       50794 :           _moose_object_pars = _factory.getValidParams("MeshGeneratorMesh");
     274             : 
     275             :           // Since we changing the type on the fly, we'll have to manually extract parameters again
     276             :           // from the input file object.
     277       25397 :           _app.builder().extractParams(_registered_identifier, _moose_object_pars);
     278       25397 :         }
     279          81 :         else if (!_moose_object_pars.get<bool>("_mesh_generator_mesh"))
     280             :         {
     281             :           // There are cases where a custom action may register the "add_mesh_generator" task, but
     282             :           // may not actually add any mesh generators depending on user input. We don't want to risk
     283             :           // giving false warnings in this case. However, if we triggered the "add_mesh_generator"
     284             :           // task through explicit input file syntax, then it is definitely safe to warn
     285           3 :           for (auto generator_action_ptr : generator_actions)
     286           3 :             if (dynamic_cast<AddMeshGeneratorAction *>(generator_action_ptr))
     287             :             {
     288           3 :               mooseError("Mesh Generators present but the [Mesh] block is set to construct a \"",
     289           3 :                          _type,
     290             :                          "\" mesh, which does not use Mesh Generators in constructing the mesh. ");
     291             :             }
     292             :         }
     293             :       }
     294             : 
     295             :       // switch non-file meshes to be a file-mesh if using a pre-split mesh configuration.
     296       65134 :       if (_use_split)
     297         255 :         _type = modifyParamsForUseSplit(_moose_object_pars);
     298             : 
     299      195366 :       _mesh = _factory.create<MooseMesh>(_type, "mesh", _moose_object_pars);
     300             :     }
     301       65879 :   }
     302             : 
     303      130160 :   else if (_current_task == "set_mesh_base")
     304             :   {
     305      325400 :     TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Setting Mesh", true);
     306             : 
     307       65080 :     if (!_app.useMasterMesh() && !_mesh->hasMeshBase())
     308             :     {
     309             :       // We want to set the MeshBase object to that coming from mesh generators when the following
     310             :       // conditions are met:
     311             :       // 1. We have mesh generators
     312             :       // 2. We are not using the pre-split mesh
     313             :       // 3. We are not: recovering/restarting and we are the master application
     314       88938 :       if (!_app.getMeshGeneratorNames().empty() && !_use_split &&
     315       24639 :           !((_app.isRecovering() || _app.isRestarting()) && _app.isUltimateMaster()))
     316             :       {
     317       23577 :         auto & mesh_generator_system = _app.getMeshGeneratorSystem();
     318             :         auto mesh_base =
     319       23577 :             mesh_generator_system.getSavedMesh(mesh_generator_system.mainMeshGeneratorName());
     320       23577 :         if (_mesh->allowRemoteElementRemoval() != mesh_base->allow_remote_element_removal())
     321           0 :           mooseError("The MooseMesh and libmesh::MeshBase object coming from mesh generators are "
     322             :                      "out of sync with respect to whether remote elements can be deleted");
     323             :         mooseAssert(mesh_base, "Null mesh");
     324       23577 :         _mesh->setMeshBase(std::move(mesh_base));
     325       23577 :       }
     326             :       else
     327             :       {
     328       40722 :         const auto & mg_names = _app.getMeshGeneratorNames();
     329       40722 :         std::vector<bool> use_dm;
     330       42874 :         for (const auto & mg_name : mg_names)
     331        6456 :           if (hasMeshProperty<bool>("use_distributed_mesh", mg_name))
     332         201 :             use_dm.push_back(getMeshProperty<bool>("use_distributed_mesh", mg_name));
     333             : 
     334       40722 :         if (!use_dm.empty())
     335             :         {
     336          67 :           if (std::adjacent_find(use_dm.begin(), use_dm.end(), std::not_equal_to<bool>()) !=
     337         134 :               use_dm.end())
     338           0 :             mooseError("You cannot use mesh generators that set different values of the mesh "
     339             :                        "property 'use_distributed_mesh' within the same simulation.");
     340             : 
     341          67 :           const auto ptype = use_dm.front() ? MooseMesh::ParallelType::DISTRIBUTED
     342          67 :                                             : MooseMesh::ParallelType::REPLICATED;
     343          67 :           _mesh->setParallelType(ptype);
     344             :         }
     345             : 
     346       40722 :         _mesh->setMeshBase(_mesh->buildMeshBaseObject());
     347       40722 :       }
     348             :     }
     349       65080 :   }
     350             : 
     351       65080 :   else if (_current_task == "init_mesh")
     352             :   {
     353      325400 :     TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Initializing Mesh", true);
     354             : 
     355       65080 :     if (_app.useMasterMesh())
     356             :     {
     357         781 :       if (_app.masterDisplacedMesh())
     358           0 :         _displaced_mesh = _app.masterDisplacedMesh()->safeClone();
     359             :     }
     360             :     else
     361             :     {
     362       64299 :       _mesh->init();
     363             : 
     364      197027 :       if (isParamValid("displacements") && getParam<bool>("use_displaced_mesh"))
     365             :       {
     366        2032 :         _displaced_mesh = _mesh->safeClone();
     367        2032 :         _displaced_mesh->isDisplaced(true);
     368        4064 :         _displaced_mesh->getMesh().allow_remote_element_removal(
     369        2032 :             _mesh->getMesh().allow_remote_element_removal());
     370             : 
     371             :         std::vector<std::string> displacements =
     372        4064 :             getParam<std::vector<std::string>>("displacements");
     373        2032 :         if (displacements.size() < _displaced_mesh->dimension())
     374           0 :           mooseError("Number of displacements must be greater than or equal to the dimension of "
     375             :                      "the mesh!");
     376        2032 :       }
     377             : 
     378       64293 :       setupMesh(_mesh.get());
     379             : 
     380       64281 :       if (_displaced_mesh)
     381        2032 :         setupMesh(_displaced_mesh.get());
     382             :     }
     383       65062 :   }
     384      196019 : }

Generated by: LCOV version 1.14