www.mooseframework.org
SetupMeshAction.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
28 {
30  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  params.addParam<std::string>(
39  "type",
40  "FileMesh",
41  "A string representing the Moose Object that will be built by this Action");
42 
43  params.addParam<bool>("second_order",
44  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  params.addParam<std::vector<SubdomainID>>("block_id", "IDs of the block id/name pairs");
50  params.addParam<std::vector<SubdomainName>>(
51  "block_name", "Names of the block id/name pairs (must correspond with \"block_id\"");
52 
53  params.addParam<std::vector<BoundaryID>>("boundary_id", {}, "IDs of the boundary id/name pairs");
54  params.addParam<std::vector<BoundaryName>>(
55  "boundary_name",
56  {},
57  "Names of the boundary id/name pairs (must correspond with \"boundary_id\"");
58 
59  params.addParam<bool>("construct_side_list_from_node_list",
60  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  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  params.addParam<bool>(
72  "use_displaced_mesh",
73  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  params.addParam<std::vector<BoundaryName>>(
78  "ghosted_boundaries", {}, "Boundaries to be ghosted if using Nemesis");
79  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  params.addParam<unsigned int>(
86  "uniform_refine", 0, "Specify the level of uniform refinement applied to the initial mesh");
87 
88  params.addParam<bool>("skip_deletion_repartition_after_refine",
89  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  params.addParam<bool>("skip_partitioning",
99  false,
100  "If true the mesh won't be partitioned. This may cause large load "
101  "imbalances.");
102 
103  params.addParam<bool>(
104  "use_split",
105  false,
106  "Use split distributed mesh files; is overriden by the --use-split command line option");
107  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  params.addParamNamesToGroup("displacements ghosted_boundaries ghosted_boundaries_inflation",
114  "Advanced");
115  params.addParamNamesToGroup("second_order construct_side_list_from_node_list skip_partitioning",
116  "Advanced");
117  params.addParamNamesToGroup("block_id block_name boundary_id boundary_name", "Add Names");
118  params.addParamNamesToGroup("use_split split_file", "Split Mesh");
119 
120  return params;
121 }
122 
124  : MooseObjectAction(params),
125  _use_split(getParam<bool>("use_split") || _app.getParam<bool>("use_split")),
126  _split_file(_app.getParam<std::string>("split_file").size()
127  ? _app.getParam<std::string>("split_file")
128  : getParam<std::string>("split_file"))
129 {
130 }
131 
132 void
134 {
135  if (isParamValid("ghosted_boundaries"))
136  for (const auto & bnd_name : getParam<std::vector<BoundaryName>>("ghosted_boundaries"))
137  mesh->addGhostedBoundary(mesh->getBoundaryID(bnd_name));
138 
139  if (isParamValid("ghosted_boundaries_inflation"))
140  {
141  std::vector<Real> ghosted_boundaries_inflation =
142  getParam<std::vector<Real>>("ghosted_boundaries_inflation");
143  mesh->setGhostedBoundaryInflation(ghosted_boundaries_inflation);
144  }
145 
146  mesh->ghostGhostedBoundaries();
147 
148  if (getParam<bool>("second_order"))
149  mesh->getMesh().all_second_order(true);
150 
151 #ifdef LIBMESH_ENABLE_AMR
152  unsigned int level = getParam<unsigned int>("uniform_refine");
153 
154  // Did they specify extra refinement levels on the command-line?
155  level += _app.getParam<unsigned int>("refinements");
156 
157  mesh->setUniformRefineLevel(level, getParam<bool>("skip_deletion_repartition_after_refine"));
158 #endif // LIBMESH_ENABLE_AMR
159 
160  // Add entity names to the mesh
161  if (_pars.isParamValid("block_id") && _pars.isParamValid("block_name"))
162  {
163  std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("block_id");
164  std::vector<SubdomainName> names = getParam<std::vector<SubdomainName>>("block_name");
165  std::set<SubdomainName> seen_it;
166 
167  if (ids.size() != names.size())
168  mooseError("You must supply the same number of block ids and names parameters");
169 
170  for (unsigned int i = 0; i < ids.size(); ++i)
171  {
172  if (seen_it.find(names[i]) != seen_it.end())
173  mooseError("The following dynamic block name is not unique: " + names[i]);
174  seen_it.insert(names[i]);
175  mesh->setSubdomainName(ids[i], names[i]);
176  }
177  }
178  if (_pars.isParamValid("boundary_id") && _pars.isParamValid("boundary_name"))
179  {
180  std::vector<BoundaryID> ids = getParam<std::vector<BoundaryID>>("boundary_id");
181  std::vector<BoundaryName> names = getParam<std::vector<BoundaryName>>("boundary_name");
182  std::set<SubdomainName> seen_it;
183 
184  if (ids.size() != names.size())
185  mooseError("You must supply the same number of boundary ids and names parameters");
186 
187  for (unsigned int i = 0; i < ids.size(); ++i)
188  {
189  if (seen_it.find(names[i]) != seen_it.end())
190  mooseError("The following dynamic boundary name is not unique: " + names[i]);
191  mesh->setBoundaryName(ids[i], names[i]);
192  seen_it.insert(names[i]);
193  }
194  }
195 
196  if (getParam<bool>("construct_side_list_from_node_list"))
197  mesh->getMesh().get_boundary_info().build_side_list_from_node_list();
198 
199  // Here we can override the partitioning for special cases
200  if (getParam<bool>("skip_partitioning"))
201  mesh->getMesh().skip_partitioning(getParam<bool>("skip_partitioning"));
202 }
203 
204 std::string
206 {
207  // Get the split_file extension, if there is one, and use that to decide
208  // between .cpr and .cpa
209  auto split_file = _split_file;
210  std::string split_file_ext;
211  auto pos = split_file.rfind(".");
212  if (pos != std::string::npos)
213  split_file_ext = split_file.substr(pos + 1, std::string::npos);
214 
215  // If split_file already has the .cpr or .cpa extension, we go with
216  // that, otherwise we strip off the extension and append ".cpr".
217  if (split_file != "" && split_file_ext != "cpr" && split_file_ext != "cpa")
218  split_file = MooseUtils::stripExtension(split_file) + ".cpr";
219 
220  if (_type != "FileMesh")
221  {
222  if (split_file.empty())
223  mooseError("Cannot use split mesh for a non-file mesh without specifying --split-file on "
224  "command line or the Mesh/split_file parameter");
225 
226  auto new_pars = FileMesh::validParams();
227 
228  // Keep existing parameters where possible
229  new_pars.applyParameters(_moose_object_pars);
230 
231  new_pars.set<MeshFileName>("file") = split_file;
232  new_pars.set<MooseApp *>("_moose_app") = moose_object_params.get<MooseApp *>("_moose_app");
233  moose_object_params = new_pars;
234  }
235  else
236  {
237  if (!split_file.empty())
238  moose_object_params.set<MeshFileName>("file") = split_file;
239  else
240  moose_object_params.set<MeshFileName>("file") =
241  MooseUtils::stripExtension(moose_object_params.get<MeshFileName>("file")) + ".cpr";
242  }
243 
244  moose_object_params.set<bool>("_is_split") = true;
245 
246  return "FileMesh";
247 }
248 
249 void
251 {
252  // Create the mesh object and tell it to build itself
253  if (_current_task == "setup_mesh")
254  {
255  TIME_SECTION("SetupMeshAction::act::setup_mesh", 1, "Setting Up Mesh", true);
256 
257  if (_app.masterMesh())
259  else
260  {
261  const auto & generator_actions = _awh.getActionListByName("add_mesh_generator");
262 
263  // If we trigger any actions that can build MeshGenerators, whether through input file
264  // syntax or through custom actions, change the default type to construct. We can't yet
265  // check whether there are any actual MeshGenerator objects because those are added after
266  // setup_mesh
267  if (!generator_actions.empty())
268  {
269  // Check for whether type has been set or whether for the default type (FileMesh) a file has
270  // been provided
271  if (!_pars.isParamSetByUser("type") && !_moose_object_pars.isParamValid("file"))
272  {
273  _type = "MeshGeneratorMesh";
274  auto original_params = _moose_object_pars;
275  _moose_object_pars = _factory.getValidParams("MeshGeneratorMesh");
276 
277  // Since we changing the type on the fly, we'll have to manually extract parameters again
278  // from the input file object.
280  }
281  else if (!_moose_object_pars.get<bool>("_mesh_generator_mesh"))
282  {
283  // There are cases where a custom action may register the "add_mesh_generator" task, but
284  // may not actually add any mesh generators depending on user input. We don't want to risk
285  // giving false warnings in this case. However, if we triggered the "add_mesh_generator"
286  // task through explicit input file syntax, then it is definitely safe to warn
287  for (auto generator_action_ptr : generator_actions)
288  if (dynamic_cast<AddMeshGeneratorAction *>(generator_action_ptr))
289  {
290  mooseWarning("Mesh Generators present but the [Mesh] block is set to construct a \"",
291  _type,
292  "\" mesh, which does not use Mesh Generators in constructing the mesh.");
293  break;
294  }
295  }
296  }
297 
298  // switch non-file meshes to be a file-mesh if using a pre-split mesh configuration.
299  if (_use_split)
301 
303  }
304  }
305 
306  else if (_current_task == "set_mesh_base")
307  {
308 
309  TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Setting Mesh", true);
310 
311  if (!_app.masterMesh() && !_mesh->hasMeshBase())
312  {
313  // We want to set the MeshBase object to that coming from mesh generators when the following
314  // conditions are met:
315  // 1. We have mesh generators
316  // 2. We are not using the pre-split mesh
317  // 3. We are not: recovering/restarting and we are the master application
318  if (!_app.getMeshGeneratorNames().empty() && !_use_split &&
320  {
321  auto & mesh_generator_system = _app.getMeshGeneratorSystem();
322  auto mesh_base =
323  mesh_generator_system.getSavedMesh(mesh_generator_system.mainMeshGeneratorName());
324  if (_mesh->allowRemoteElementRemoval() != mesh_base->allow_remote_element_removal())
325  mooseError("The MooseMesh and libmesh::MeshBase object coming from mesh generators are "
326  "out of sync with respect to whether remote elements can be deleted");
327  mooseAssert(mesh_base, "Null mesh");
328  _mesh->setMeshBase(std::move(mesh_base));
329  }
330  else
331  {
332  const auto & mg_names = _app.getMeshGeneratorNames();
333  std::vector<bool> use_dm;
334  for (const auto & mg_name : mg_names)
335  if (hasMeshProperty<bool>("use_distributed_mesh", mg_name))
336  use_dm.push_back(getMeshProperty<bool>("use_distributed_mesh", mg_name));
337 
338  if (!use_dm.empty())
339  {
340  if (std::adjacent_find(use_dm.begin(), use_dm.end(), std::not_equal_to<bool>()) !=
341  use_dm.end())
342  mooseError("You cannot use mesh generators that set different values of the mesh "
343  "property 'use_distributed_mesh' within the same simulation.");
344 
345  const auto ptype = use_dm.front() ? MooseMesh::ParallelType::DISTRIBUTED
347  _mesh->setParallelType(ptype);
348  }
349 
350  _mesh->setMeshBase(_mesh->buildMeshBaseObject());
351  }
352  }
353  }
354 
355  else if (_current_task == "init_mesh")
356  {
357  TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Initializing Mesh", true);
358 
359  if (_app.masterMesh())
360  {
363  }
364  else
365  {
366  _mesh->init();
367 
368  if (isParamValid("displacements") && getParam<bool>("use_displaced_mesh"))
369  {
370  _displaced_mesh = _mesh->safeClone();
371  _displaced_mesh->isDisplaced(true);
372  _displaced_mesh->getMesh().allow_remote_element_removal(
373  _mesh->getMesh().allow_remote_element_removal());
374 
375  std::vector<std::string> displacements =
376  getParam<std::vector<std::string>>("displacements");
377  if (displacements.size() < _displaced_mesh->dimension())
378  mooseError("Number of displacements must be greater than or equal to the dimension of "
379  "the mesh!");
380  }
381 
382  setupMesh(_mesh.get());
383 
384  if (_displaced_mesh)
385  setupMesh(_displaced_mesh.get());
386  }
387  }
388 }
const std::string _split_file
The split mesh file (if any); comes from either Mesh/split_file or –split-file.
bool isUltimateMaster() const
Whether or not this app is the ultimate master app.
Definition: MooseApp.h:805
ActionWarehouse & _awh
Reference to ActionWarehouse where we store object build by actions.
Definition: Action.h:170
virtual void act() override
Method to add objects to the simulation or perform other setup tasks.
static InputParameters validParams()
std::vector< std::string > getMeshGeneratorNames() const
Definition: MooseApp.h:867
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
static InputParameters validParams()
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
std::shared_ptr< MooseObject > create(const std::string &obj_name, const std::string &name, const InputParameters &parameters, THREAD_ID tid=0, bool print_deprecated=true)
Definition: Factory.C:110
std::unique_ptr< MeshBase > getSavedMesh(const std::string &name)
Get the saved mesh by name.
registerMooseAction("MooseApp", SetupMeshAction, "setup_mesh")
MeshBase & mesh
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Definition: Factory.C:67
Base class for MOOSE-based applications.
Definition: MooseApp.h:73
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::string stripExtension(const std::string &s)
Removes any file extension from the given string s (i.e.
Definition: MooseUtils.C:413
const std::list< Action * > & getActionListByName(const std::string &task) const
Retrieve a constant list of Action pointers associated with the passed in task.
bool isRestarting() const
Whether or not this is a "restart" calculation.
Definition: MooseApp.C:1174
void extractParams(const std::string &prefix, InputParameters &p)
This function attempts to extract values from the input file based on the contents of the passed para...
Definition: Builder.C:917
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Factory & _factory
The Factory associated with the MooseApp.
std::string _registered_identifier
Definition: Action.h:152
Moose::Builder & builder()
Returns a writable reference to the builder.
Definition: MooseApp.h:204
std::shared_ptr< MooseMesh > & _displaced_mesh
Definition: Action.h:176
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
const std::string & _current_task
The current action (even though we have separate instances for each action)
Definition: Action.h:173
const MooseMesh * masterMesh() const
Returns a pointer to the master mesh.
Definition: MooseApp.h:810
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:84
std::string modifyParamsForUseSplit(InputParameters &moose_object_params) const
Modifies the MooseObject&#39;s parameters to build the right type of Mesh when using splits.
SetupMeshAction(const InputParameters &params)
void setupMesh(MooseMesh *mesh)
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was by the user.
const MooseMesh * masterDisplacedMesh() const
Returns a pointer to the master displaced mesh.
Definition: MooseApp.h:815
const T & getParam(const std::string &name)
Retrieve a parameter for the object.
Definition: MooseApp.h:1465
std::shared_ptr< MooseMesh > & _mesh
Definition: Action.h:175
std::string _type
The Object type that is being created.
virtual std::unique_ptr< MooseMesh > safeClone() const =0
A safer version of the clone() method that hands back an allocated object wrapped in a smart pointer...
InputParameters _moose_object_pars
The parameters for the object to be created.
static InputParameters validParams()
Definition: FileMesh.C:25
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
const InputParameters & _pars
Parameters of this object, references the InputParameters stored in the InputParametersWarehouse.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
MeshGeneratorSystem & getMeshGeneratorSystem()
Gets the system that manages the MeshGenerators.
Definition: MooseApp.h:820
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition: MooseApp.C:1168
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
const bool _use_split
Whether or not to use a split mesh; comes from either Mesh/use_split or –use-split.
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another, i.e.