https://mooseframework.inl.gov
AddPeriodicBCAction.C
Go to the documentation of this file.
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 "AddPeriodicBCAction.h"
11 
12 // MOOSE includes
13 #include "DisplacedProblem.h"
14 #include "FEProblem.h"
16 #include "GeneratedMesh.h"
17 #include "InputParameters.h"
18 #include "MooseMesh.h"
19 #include "MooseVariableFE.h"
20 #include "NonlinearSystem.h"
21 #include "RelationshipManager.h"
22 
23 #include "libmesh/periodic_boundary.h" // translation PBCs provided by libmesh
24 
25 using namespace libMesh;
26 
27 registerMooseAction("MooseApp", AddPeriodicBCAction, "add_periodic_bc");
28 registerMooseAction("MooseApp", AddPeriodicBCAction, "add_geometric_rm");
29 registerMooseAction("MooseApp", AddPeriodicBCAction, "add_algebraic_rm");
30 
33 {
35  params.addParam<std::vector<std::string>>("auto_direction",
36  "If using a generated mesh, you can "
37  "specify just the dimension(s) you "
38  "want to mark as periodic");
39 
40  params.addParam<BoundaryName>("primary", "Boundary ID associated with the primary boundary.");
41  params.addParam<BoundaryName>("secondary", "Boundary ID associated with the secondary boundary.");
42  params.addParam<RealVectorValue>("translation",
43  "Vector that translates coordinates on the "
44  "primary boundary to coordinates on the "
45  "secondary boundary.");
46  params.addParam<std::vector<std::string>>("transform_func",
47  "Functions that specify the transformation");
48  params.addParam<std::vector<std::string>>("inv_transform_func",
49  "Functions that specify the inverse transformation");
50 
51  params.addParam<std::vector<VariableName>>(
52  "variable", {}, "Variable for the periodic boundary condition");
53  params.addClassDescription("Action that adds periodic boundary conditions");
54  return params;
55 }
56 
58  : Action(params), _mesh(nullptr)
59 {
60  // Check for inconsistent parameters
61  if (isParamValid("auto_direction"))
62  {
63  if (isParamValid("primary") || isParamValid("secondary") || isParamValid("translation") ||
64  isParamValid("transform_func") || isParamValid("inv_transform_func"))
65  paramError(
66  "auto_direction",
67  "Using the automatic periodic boundary detection does not require additional parameters");
68  }
69  else if (!isParamValid("primary") || !isParamValid("secondary"))
70  paramError("primary", "Both a primary and secondary boundary must be specified");
71 }
72 
73 void
75  const std::vector<VariableName> & var_names)
76 {
77  // TODO: multi-system
78  if (_problem->numSolverSystems() > 1)
79  mooseError("Multiple solver systems currently not supported");
80 
81  NonlinearSystemBase & nl = _problem->getNonlinearSystemBase(/*nl_sys_num=*/0);
82  const std::vector<VariableName> * var_names_ptr;
83 
84  // If var_names is empty - then apply this periodic condition to all variables in the system
85  if (var_names.empty())
86  var_names_ptr = &nl.getVariableNames();
87  else
88  var_names_ptr = &var_names;
89 
90  // Helper function to apply periodic BC for a given variable number
91  auto applyPeriodicBC = [&](unsigned int var_num, const std::string & var_name)
92  {
93  p.set_variable(var_num);
96  else
97  mooseInfoRepeated("Periodicity information for variable '" + var_name +
98  "' will only be stored in the system's DoF map, not on the MooseMesh");
99  };
100 
101  // If is an array variable, loop over all of components
102  for (const auto & var_name : *var_names_ptr)
103  {
104  // Exclude scalar variables for which periodic boundary conditions dont make sense
105  if (!nl.hasScalarVariable(var_name))
106  {
107  const auto & var = nl.getVariable(0, var_name);
108  unsigned int var_num = var.number();
109 
110  if (var.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
111  {
112  for (const auto component : make_range(var.count()))
113  applyPeriodicBC(var_num + component, var_name + "_" + std::to_string(component));
114  }
115  else
116  applyPeriodicBC(var_num, var_name);
117  }
118  }
119 }
120 
121 bool
123 {
124  auto displaced_problem = _problem->getDisplacedProblem();
125 
126  if (isParamValid("auto_direction"))
127  {
128  // If we are working with a parallel mesh then we're going to ghost all the boundaries
129  // everywhere because we don't know what we need...
130  if (_mesh->isDistributedMesh())
131  {
132  bool is_orthogonal_mesh = _mesh->detectOrthogonalDimRanges();
133 
134  // If we can't detect the orthogonal dimension ranges for this
135  // Mesh, then auto_direction periodicity isn't going to work.
136  if (!is_orthogonal_mesh)
137  mooseError("Could not detect orthogonal dimension ranges for DistributedMesh.");
138  }
139 
140  std::vector<std::string> auto_dirs = getParam<std::vector<std::string>>("auto_direction");
141 
142  int dim_offset = _mesh->dimension() - 2;
143  for (const auto & dir : auto_dirs)
144  {
145  int component = -1;
146  if (dir == "X" || dir == "x")
147  component = 0;
148  else if (dir == "Y" || dir == "y")
149  {
150  if (dim_offset < 0)
151  mooseError("Cannot wrap 'Y' direction when using a 1D mesh");
152  component = 1;
153  }
154  else if (dir == "Z" || dir == "z")
155  {
156  if (dim_offset <= 0)
157  mooseError("Cannot wrap 'Z' direction when using a 1D or 2D mesh");
158  component = 2;
159  }
160 
161  if (component >= 0)
162  {
163  const std::pair<BoundaryID, BoundaryID> * boundary_ids =
164  _mesh->getPairedBoundaryMapping(component);
165  RealVectorValue v;
166  v(component) = _mesh->dimensionWidth(component);
167  PeriodicBoundary p(v);
168 
169  if (boundary_ids == nullptr)
170  mooseError("Couldn't auto-detect a paired boundary for use with periodic boundary "
171  "conditions in the '" +
172  dir + "' direction");
173 
174  p.myboundary = boundary_ids->first;
175  p.pairedboundary = boundary_ids->second;
176  setPeriodicVars(p, getParam<std::vector<VariableName>>("variable"));
177  auto & eq = _problem->es();
178  for (const auto i : make_range(eq.n_systems()))
179  eq.get_system(i).get_dof_map().add_periodic_boundary(p);
180  if (displaced_problem)
181  {
182  auto & deq = displaced_problem->es();
183  for (const auto i : make_range(deq.n_systems()))
184  deq.get_system(i).get_dof_map().add_periodic_boundary(p);
185  }
186  }
187  }
188  return true;
189  }
190  return false;
191 }
192 
193 void
195 {
196  if (_current_task == "add_geometric_rm")
197  // Tell the mesh to hold off on deleting remote elements because we need to wait for our
198  // periodic boundaries to be added
199  Action::_mesh->allowRemoteElementRemoval(false);
200 
201  if (_current_task == "add_algebraic_rm")
202  {
203  auto rm_params = _factory.getValidParams("ElementSideNeighborLayers");
204 
205  rm_params.set<std::string>("for_whom") = "PeriodicBCs";
206  if (!_mesh)
207  mooseError("We should have added periodic boundaries and consequently we should have set the "
208  "_mesh by now");
209 
210  rm_params.set<MooseMesh *>("mesh") = _mesh;
211  // The default GhostPointNeighbors ghosting functor in libMesh handles the geometric ghosting
212  // of periodic boundaries for us, so we only need to handle the algebraic ghosting here
213  rm_params.set<Moose::RelationshipManagerType>("rm_type") =
215 
216  if (rm_params.areAllRequiredParamsValid())
217  {
218  auto rm_obj = _factory.create<RelationshipManager>(
219  "ElementSideNeighborLayers", "periodic_bc_ghosting_" + name(), rm_params);
220 
221  if (!_app.addRelationshipManager(rm_obj))
222  _factory.releaseSharedObjects(*rm_obj);
223  }
224  else
225  mooseError("Invalid initialization of ElementSideNeighborLayers");
226  }
227 
228  if (_current_task == "add_periodic_bc")
229  {
230  auto & nl = _problem->getNonlinearSystemBase(/*nl_sys_num=*/0);
231  _mesh = &_problem->mesh();
232  auto displaced_problem = _problem->getDisplacedProblem();
233 
235  {
236  // Check that the boundaries exist in the mesh
237  const auto & primary_name = getParam<BoundaryName>("primary");
238  const auto & secondary_name = getParam<BoundaryName>("secondary");
239  if (!MooseMeshUtils::hasBoundaryName(*_mesh, primary_name))
240  paramError("primary", "Boundary '" + primary_name + "' does not exist in the mesh");
241  if (!MooseMeshUtils::hasBoundaryName(*_mesh, secondary_name))
242  paramError("secondary", "Boundary '" + secondary_name + "' does not exist in the mesh");
243 
244  if (_pars.isParamValid("translation"))
245  {
246  RealVectorValue translation = getParam<RealVectorValue>("translation");
247 
248  PeriodicBoundary p(translation);
249  p.myboundary = _mesh->getBoundaryID(primary_name);
250  p.pairedboundary = _mesh->getBoundaryID(secondary_name);
251  setPeriodicVars(p, getParam<std::vector<VariableName>>("variable"));
252 
253  auto & eq = _problem->es();
254  for (const auto i : make_range(eq.n_systems()))
255  eq.get_system(i).get_dof_map().add_periodic_boundary(p);
256  if (displaced_problem)
257  {
258  auto & deq = displaced_problem->es();
259  for (const auto i : make_range(deq.n_systems()))
260  deq.get_system(i).get_dof_map().add_periodic_boundary(p);
261  }
262  }
263  else if (getParam<std::vector<std::string>>("transform_func") != std::vector<std::string>())
264  {
265  std::vector<std::string> inv_fn_names =
266  getParam<std::vector<std::string>>("inv_transform_func");
267  std::vector<std::string> fn_names = getParam<std::vector<std::string>>("transform_func");
268 
269  // If the user provided a forward transformation, they must also provide an inverse -- we
270  // can't form the inverse of an arbitrary function automatically...
271  if (inv_fn_names == std::vector<std::string>())
272  mooseError("You must provide an inv_transform_func for FunctionPeriodicBoundary!");
273 
274  FunctionPeriodicBoundary pb(*_problem, fn_names);
275  pb.myboundary = _mesh->getBoundaryID(primary_name);
276  pb.pairedboundary = _mesh->getBoundaryID(secondary_name);
277  setPeriodicVars(pb, getParam<std::vector<VariableName>>("variable"));
278 
279  FunctionPeriodicBoundary ipb(*_problem, inv_fn_names);
280  ipb.myboundary = _mesh->getBoundaryID(secondary_name); // these are swapped
281  ipb.pairedboundary = _mesh->getBoundaryID(primary_name); // these are swapped
282  setPeriodicVars(ipb, getParam<std::vector<VariableName>>("variable"));
283 
284  // Add the pair of periodic boundaries to the dof map
285  auto & eq = _problem->es();
286  for (const auto i : make_range(eq.n_systems()))
287  eq.get_system(i).get_dof_map().add_periodic_boundary(pb, ipb);
288  if (displaced_problem)
289  {
290  auto & deq = displaced_problem->es();
291  for (const auto i : make_range(deq.n_systems()))
292  deq.get_system(i).get_dof_map().add_periodic_boundary(pb, ipb);
293  }
294  }
295  else
296  {
297  mooseError(
298  "You have to specify either 'auto_direction', 'translation' or 'trans_func' in your "
299  "period boundary section '" +
300  _name + "'");
301  }
302  }
303 
304  // Now make sure that the mesh default ghosting functor has its periodic bcs set
305  // TODO: multi-system
307  nl.dofMap().get_periodic_boundaries());
308  if (displaced_problem)
309  displaced_problem->mesh().getMesh().default_ghosting().set_periodic_boundaries(
310  displaced_problem->solverSys(/*nl_sys_num=*/0).dofMap().get_periodic_boundaries());
311  }
312 }
const InputParameters & _pars
The object&#39;s parameters.
Definition: MooseBase.h:362
This Action adds a periodic boundary to the problem.
std::shared_ptr< DisplacedProblem > displaced_problem
RelationshipManagerType
Main types of Relationship Managers.
Definition: MooseTypes.h:964
const std::string & _name
The name of this class.
Definition: MooseBase.h:359
registerMooseAction("MooseApp", AddPeriodicBCAction, "add_periodic_bc")
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the mesh.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:435
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
Definition: MooseBase.h:384
unsigned int number() const
Get variable number coming from libMesh.
Factory & _factory
The Factory associated with the MooseApp.
Periodic boundary for calculation periodic BC on domains where the translation is given by functions...
boundary_id_type pairedboundary
void mooseInfoRepeated(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
Definition: MooseError.h:408
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
Base class for actions.
Definition: Action.h:33
bool autoTranslationBoundaries()
This function will automatically add the correct translation vectors for each requested dimension whe...
virtual void act() override
Method to add objects to the simulation or perform other setup tasks.
Nonlinear system to be solved.
void set_variable(unsigned int var)
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:99
bool addRelationshipManager(std::shared_ptr< RelationshipManager > relationship_manager)
Transfers ownership of a RelationshipManager to the application for lifetime management.
Definition: MooseApp.C:3024
static InputParameters validParams()
Definition: Action.C:26
virtual std::unique_ptr< Base > create()=0
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3448
AddPeriodicBCAction(const InputParameters &params)
virtual void set_periodic_boundaries(const PeriodicBoundaries *)
virtual unsigned int dimension() const
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition: MooseMesh.C:2928
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
const std::pair< BoundaryID, BoundaryID > * getPairedBoundaryMapping(unsigned int component)
This function attempts to return the paired boundary ids for the given component. ...
Definition: MooseMesh.C:2293
const std::string & _current_task
The current action (even though we have separate instances for each action)
Definition: Action.h:165
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:353
void setPeriodicVars(libMesh::PeriodicBoundaryBase &p, const std::vector< VariableName > &var_names)
bool isRegularOrthogonal()
Getter to query if the mesh was detected to be regular and orthogonal.
Definition: MooseMesh.h:1056
void addPeriodicVariable(unsigned int var_num, BoundaryID primary, BoundaryID secondary)
For "regular orthogonal" meshes, determine if variable var_num is periodic with respect to the primar...
Definition: MooseMesh.C:2217
std::shared_ptr< MooseMesh > & _mesh
Definition: Action.h:167
bool detectOrthogonalDimRanges(Real tol=1e-6)
This routine determines whether the Mesh is a regular orthogonal mesh (i.e.
Definition: MooseMesh.C:1925
RelationshipManagers are used for describing what kinds of non-local resources are needed for an obje...
Real dimensionWidth(unsigned int component) const
Returns the width of the requested dimension.
Definition: MooseMesh.C:2193
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:267
const std::vector< VariableName > & getVariableNames() const
Definition: SystemBase.h:860
static InputParameters validParams()
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...
std::shared_ptr< FEProblemBase > & _problem
Convenience reference to a problem this action works on.
Definition: Action.h:171
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a variable of with specified name.
Definition: SystemBase.C:90
virtual bool hasScalarVariable(const std::string &var_name) const
Definition: SystemBase.C:868
virtual bool isDistributedMesh() const
Returns the final Mesh distribution type.
Definition: MooseMesh.h:1001
GhostingFunctor & default_ghosting()
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
Get the associated BoundaryID for the boundary name.
Definition: MooseMesh.C:1692
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another, i.e.