LCOV - code coverage report
Current view: top level - src/actions - SetupMeshAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 1f9d31 Lines: 157 171 91.8 %
Date: 2025-09-02 20:01:20 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       68128 : SetupMeshAction::validParams()
      28             : {
      29       68128 :   InputParameters params = MooseObjectAction::validParams();
      30      136256 :   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      272512 :   params.addParam<std::string>(
      39             :       "type",
      40             :       "FileMesh",
      41             :       "A string representing the Moose Object that will be built by this Action");
      42             : 
      43      204384 :   params.addParam<bool>("second_order",
      44      136256 :                         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      272512 :   params.addParam<std::vector<SubdomainID>>("block_id", "IDs of the block id/name pairs");
      50      272512 :   params.addParam<std::vector<SubdomainName>>(
      51             :       "block_name", "Names of the block id/name pairs (must correspond with \"block_id\"");
      52             : 
      53      272512 :   params.addParam<std::vector<BoundaryID>>("boundary_id", {}, "IDs of the boundary id/name pairs");
      54      272512 :   params.addParam<std::vector<BoundaryName>>(
      55             :       "boundary_name",
      56             :       {},
      57             :       "Names of the boundary id/name pairs (must correspond with \"boundary_id\"");
      58             : 
      59      204384 :   params.addParam<bool>("construct_side_list_from_node_list",
      60      136256 :                         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      272512 :   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      204384 :   params.addParam<bool>(
      72             :       "use_displaced_mesh",
      73      136256 :       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      272512 :   params.addParam<std::vector<BoundaryName>>(
      78             :       "ghosted_boundaries", {}, "Boundaries to be ghosted if using Nemesis");
      79      272512 :   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      204384 :   params.addParam<unsigned int>(
      86      136256 :       "uniform_refine", 0, "Specify the level of uniform refinement applied to the initial mesh");
      87             : 
      88      272512 :   params.addParam<bool>("skip_deletion_repartition_after_refine",
      89      136256 :                         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      204384 :   params.addParam<bool>("skip_partitioning",
      99      136256 :                         false,
     100             :                         "If true the mesh won't be partitioned. This may cause large load "
     101             :                         "imbalances.");
     102             : 
     103      204384 :   params.addParam<bool>(
     104             :       "use_split",
     105      136256 :       false,
     106             :       "Use split distributed mesh files; is overriden by the --use-split command line option");
     107      272512 :   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      272512 :   params.addParamNamesToGroup("displacements ghosted_boundaries ghosted_boundaries_inflation",
     114             :                               "Advanced");
     115      272512 :   params.addParamNamesToGroup("second_order construct_side_list_from_node_list skip_partitioning",
     116             :                               "Advanced");
     117      272512 :   params.addParamNamesToGroup("block_id block_name boundary_id boundary_name", "Add Names");
     118      204384 :   params.addParamNamesToGroup("use_split split_file", "Split Mesh");
     119             : 
     120       68128 :   return params;
     121           0 : }
     122             : 
     123       67890 : SetupMeshAction::SetupMeshAction(const InputParameters & params)
     124             :   : MooseObjectAction(params),
     125      203594 :     _use_split(getParam<bool>("use_split") || _app.getParam<bool>("use_split")),
     126      271903 :     _split_file(_app.isParamSetByUser("split_file") ? _app.getParam<std::string>("split_file")
     127      338421 :                                                     : getParam<std::string>("split_file"))
     128             : {
     129       67890 : }
     130             : 
     131             : void
     132       68051 : SetupMeshAction::setupMesh(MooseMesh * mesh)
     133             : {
     134      204153 :   if (isParamValid("ghosted_boundaries"))
     135      204153 :     for (const auto & bnd_name : getParam<std::vector<BoundaryName>>("ghosted_boundaries"))
     136           0 :       mesh->addGhostedBoundary(mesh->getBoundaryID(bnd_name));
     137             : 
     138      204153 :   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       68051 :   mesh->ghostGhostedBoundaries();
     146             : 
     147      204153 :   if (getParam<bool>("second_order"))
     148        1312 :     mesh->getMesh().all_second_order(true);
     149             : 
     150             : #ifdef LIBMESH_ENABLE_AMR
     151      136102 :   unsigned int level = getParam<unsigned int>("uniform_refine");
     152             : 
     153             :   // Did they specify extra refinement levels on the command-line?
     154      204153 :   if (_app.isParamSetByUser("refinements"))
     155          90 :     level += _app.getParam<unsigned int>("refinements");
     156             : 
     157      136102 :   mesh->setUniformRefineLevel(level, getParam<bool>("skip_deletion_repartition_after_refine"));
     158             : #endif // LIBMESH_ENABLE_AMR
     159             : 
     160             :   // Add entity names to the mesh
     161      204241 :   if (_pars.isParamValid("block_id") && _pars.isParamValid("block_name"))
     162             :   {
     163          88 :     std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("block_id");
     164          88 :     std::vector<SubdomainName> names = getParam<std::vector<SubdomainName>>("block_name");
     165          44 :     std::set<SubdomainName> seen_it;
     166             : 
     167          44 :     if (ids.size() != names.size())
     168           4 :       mooseError("You must supply the same number of block ids and names parameters");
     169             : 
     170         133 :     for (unsigned int i = 0; i < ids.size(); ++i)
     171             :     {
     172          97 :       if (seen_it.find(names[i]) != seen_it.end())
     173           4 :         mooseError("The following dynamic block name is not unique: " + names[i]);
     174          93 :       seen_it.insert(names[i]);
     175          93 :       mesh->setSubdomainName(ids[i], names[i]);
     176             :     }
     177          36 :   }
     178      340215 :   if (_pars.isParamValid("boundary_id") && _pars.isParamValid("boundary_name"))
     179             :   {
     180      136086 :     std::vector<BoundaryID> ids = getParam<std::vector<BoundaryID>>("boundary_id");
     181      136086 :     std::vector<BoundaryName> names = getParam<std::vector<BoundaryName>>("boundary_name");
     182       68043 :     std::set<SubdomainName> seen_it;
     183             : 
     184       68043 :     if (ids.size() != names.size())
     185           4 :       mooseError("You must supply the same number of boundary ids and names parameters");
     186             : 
     187       68069 :     for (unsigned int i = 0; i < ids.size(); ++i)
     188             :     {
     189          34 :       if (seen_it.find(names[i]) != seen_it.end())
     190           4 :         mooseError("The following dynamic boundary name is not unique: " + names[i]);
     191          30 :       mesh->setBoundaryName(ids[i], names[i]);
     192          30 :       seen_it.insert(names[i]);
     193             :     }
     194       68035 :   }
     195             : 
     196      204105 :   if (getParam<bool>("construct_side_list_from_node_list"))
     197         213 :     mesh->getMesh().get_boundary_info().build_side_list_from_node_list();
     198             : 
     199             :   // Here we can override the partitioning for special cases
     200      204105 :   if (getParam<bool>("skip_partitioning"))
     201          96 :     mesh->getMesh().skip_partitioning(getParam<bool>("skip_partitioning"));
     202       68035 : }
     203             : 
     204             : std::string
     205         294 : 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         294 :   auto split_file = _split_file;
     210         294 :   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         294 :   if (split_file != "" && split_file_ext != "cpr" && split_file_ext != "cpa.gz")
     215         162 :     split_file = MooseUtils::stripExtension(split_file) + ".cpa.gz";
     216             : 
     217         294 :   if (_type != "FileMesh")
     218             :   {
     219         294 :     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         294 :     auto new_pars = FileMesh::validParams();
     224             : 
     225             :     // Keep existing parameters where possible
     226         294 :     new_pars.applyParameters(_moose_object_pars);
     227             : 
     228         882 :     new_pars.set<MeshFileName>("file") = split_file;
     229         588 :     new_pars.set<MooseApp *>(MooseBase::app_param) =
     230         294 :         moose_object_params.get<MooseApp *>(MooseBase::app_param);
     231         294 :     moose_object_params = new_pars;
     232         294 :   }
     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         588 :   moose_object_params.set<bool>("_is_split") = true;
     243             : 
     244         588 :   return "FileMesh";
     245         294 : }
     246             : 
     247             : void
     248      200912 : SetupMeshAction::act()
     249             : {
     250             :   // Create the mesh object and tell it to build itself
     251      200912 :   if (_current_task == "setup_mesh")
     252             :   {
     253      338050 :     TIME_SECTION("SetupMeshAction::act::setup_mesh", 1, "Setting Up Mesh", true);
     254             : 
     255       67610 :     if (_app.useMasterMesh())
     256         849 :       _mesh = _app.masterMesh()->safeClone();
     257             :     else
     258             :     {
     259      133522 :       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       66761 :       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      130640 :         if (!_pars.isParamSetByUser("type") && !_moose_object_pars.isParamValid("file"))
     270             :         {
     271       26074 :           _type = "MeshGeneratorMesh";
     272       26074 :           auto original_params = _moose_object_pars;
     273       52148 :           _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       26074 :           _app.builder().extractParams(_registered_identifier, _moose_object_pars);
     278       26074 :         }
     279          90 :         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           4 :           for (auto generator_action_ptr : generator_actions)
     286           4 :             if (dynamic_cast<AddMeshGeneratorAction *>(generator_action_ptr))
     287             :             {
     288           4 :               mooseError("Mesh Generators present but the [Mesh] block is set to construct a \"",
     289           4 :                          _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       66757 :       if (_use_split)
     297         294 :         _type = modifyParamsForUseSplit(_moose_object_pars);
     298             : 
     299      200223 :       _mesh = _factory.create<MooseMesh>(_type, "mesh", _moose_object_pars);
     300             :     }
     301       67558 :   }
     302             : 
     303      133302 :   else if (_current_task == "set_mesh_base")
     304             :   {
     305      333255 :     TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Setting Mesh", true);
     306             : 
     307       66651 :     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       91010 :       if (!_app.getMeshGeneratorNames().empty() && !_use_split &&
     315       25208 :           !((_app.isRecovering() || _app.isRestarting()) && _app.isUltimateMaster()))
     316             :       {
     317       24290 :         auto & mesh_generator_system = _app.getMeshGeneratorSystem();
     318             :         auto mesh_base =
     319       24290 :             mesh_generator_system.getSavedMesh(mesh_generator_system.mainMeshGeneratorName());
     320       24290 :         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       24290 :         _mesh->setMeshBase(std::move(mesh_base));
     325       24290 :       }
     326             :       else
     327             :       {
     328       41512 :         const auto & mg_names = _app.getMeshGeneratorNames();
     329       41512 :         std::vector<bool> use_dm;
     330       43451 :         for (const auto & mg_name : mg_names)
     331        5817 :           if (hasMeshProperty<bool>("use_distributed_mesh", mg_name))
     332         201 :             use_dm.push_back(getMeshProperty<bool>("use_distributed_mesh", mg_name));
     333             : 
     334       41512 :         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       41512 :         _mesh->setMeshBase(_mesh->buildMeshBaseObject());
     347       41512 :       }
     348             :     }
     349       66651 :   }
     350             : 
     351       66651 :   else if (_current_task == "init_mesh")
     352             :   {
     353      333255 :     TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Initializing Mesh", true);
     354             : 
     355       66651 :     if (_app.useMasterMesh())
     356             :     {
     357         849 :       if (_app.masterDisplacedMesh())
     358           0 :         _displaced_mesh = _app.masterDisplacedMesh()->safeClone();
     359             :     }
     360             :     else
     361             :     {
     362       65802 :       _mesh->init();
     363             : 
     364      201970 :       if (isParamValid("displacements") && getParam<bool>("use_displaced_mesh"))
     365             :       {
     366        2257 :         _displaced_mesh = _mesh->safeClone();
     367        2257 :         _displaced_mesh->isDisplaced(true);
     368        4514 :         _displaced_mesh->getMesh().allow_remote_element_removal(
     369        2257 :             _mesh->getMesh().allow_remote_element_removal());
     370             : 
     371             :         std::vector<std::string> displacements =
     372        4514 :             getParam<std::vector<std::string>>("displacements");
     373        2257 :         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        2257 :       }
     377             : 
     378       65794 :       setupMesh(_mesh.get());
     379             : 
     380       65778 :       if (_displaced_mesh)
     381        2257 :         setupMesh(_displaced_mesh.get());
     382             :     }
     383       66627 :   }
     384      200836 : }

Generated by: LCOV version 1.14