LCOV - code coverage report
Current view: top level - src/actions - AddPeriodicBCAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 90 95 94.7 %
Date: 2026-05-29 20:35:17 Functions: 8 8 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 "AddPeriodicBCAction.h"
      11             : 
      12             : #include "DisplacedProblem.h"
      13             : #include "FEProblem.h"
      14             : #include "MooseMesh.h"
      15             : #include "MooseVariableFE.h"
      16             : #include "NonlinearSystemBase.h"
      17             : #include "RelationshipManager.h"
      18             : 
      19             : #include "libmesh/periodic_boundary.h"
      20             : 
      21             : #include <optional>
      22             : 
      23             : registerMooseAction("MooseApp", AddPeriodicBCAction, "add_periodic_bc");
      24             : registerMooseAction("MooseApp", AddPeriodicBCAction, "add_geometric_rm");
      25             : registerMooseAction("MooseApp", AddPeriodicBCAction, "add_algebraic_rm");
      26             : 
      27             : InputParameters
      28         737 : AddPeriodicBCAction::validParams()
      29             : {
      30         737 :   InputParameters params = Action::validParams();
      31         737 :   params += Moose::PeriodicBCHelper::validParams();
      32             : 
      33        2948 :   params.addParam<std::vector<VariableName>>("variable",
      34             :                                              "Variable(s) to apply periodic boundary conditions "
      35             :                                              "to; if unset, apply to all field variables.");
      36             : 
      37         737 :   params.addClassDescription("Action that adds periodic boundary conditions");
      38             : 
      39         737 :   return params;
      40           0 : }
      41             : 
      42         695 : AddPeriodicBCAction::AddPeriodicBCAction(const InputParameters & params)
      43         695 :   : Action(params), Moose::PeriodicBCHelper(static_cast<const Action &>(*this))
      44             : {
      45         695 :   checkPeriodicParams();
      46         689 : }
      47             : 
      48             : void
      49        2001 : AddPeriodicBCAction::act()
      50             : {
      51        2001 :   if (_current_task == "add_geometric_rm")
      52             :     // Tell the mesh to hold off on deleting remote elements because we need to wait for our
      53             :     // periodic boundaries to be added
      54         689 :     Action::_mesh->allowRemoteElementRemoval(false);
      55             : 
      56        2001 :   if (_current_task == "add_algebraic_rm" && getPeriodicBoundaries().size())
      57             :   {
      58        1896 :     auto rm_params = _factory.getValidParams("ElementSideNeighborLayers");
      59             : 
      60         632 :     rm_params.set<std::string>("for_whom") = "PeriodicBCs";
      61         632 :     if (!_mesh)
      62           0 :       mooseError("We should have added periodic boundaries and consequently we should have set the "
      63             :                  "_mesh by now");
      64             : 
      65        1896 :     rm_params.set<MooseMesh *>("mesh") = _mesh;
      66             :     // The default GhostPointNeighbors ghosting functor in libMesh handles the geometric ghosting
      67             :     // of periodic boundaries for us, so we only need to handle the algebraic ghosting here
      68         632 :     rm_params.set<Moose::RelationshipManagerType>("rm_type") =
      69             :         Moose::RelationshipManagerType::ALGEBRAIC;
      70             : 
      71         632 :     if (rm_params.areAllRequiredParamsValid())
      72             :     {
      73         632 :       auto rm_obj = _factory.create<RelationshipManager>(
      74        1896 :           "ElementSideNeighborLayers", "periodic_bc_ghosting_" + name(), rm_params);
      75             : 
      76         632 :       if (!_app.addRelationshipManager(rm_obj))
      77         182 :         _factory.releaseSharedObjects(*rm_obj);
      78         632 :     }
      79             :     else
      80           0 :       mooseError("Invalid initialization of ElementSideNeighborLayers");
      81         632 :   }
      82             : 
      83        2001 :   if (_current_task == "add_periodic_bc")
      84             :   {
      85         680 :     _mesh = &_problem->mesh();
      86             : 
      87             :     // Set _vars so that variables can be used in onSetupPeriodicBoundary
      88         680 :     _vars = getVariables();
      89             :     mooseAssert(_vars.size(), "Shouldn't run without variables");
      90             : 
      91             :     // Query the helper to determine the periodic boundaries, which will
      92             :     // call onSetupPeriodicBoundary() for every periodic boundary
      93         662 :     setupPeriodicBoundaries(*_problem);
      94             : 
      95         635 :     if (!_mesh->isRegularOrthogonal())
      96             :     {
      97          72 :       std::ostringstream out;
      98          72 :       out << "Periodicity information for the variables\n";
      99         144 :       for (const auto & var_ptr : _vars)
     100          72 :         out << "  - " << var_ptr->name() << "\n";
     101          72 :       out << "will only be stored in the system's DoF map, not on the MooseMesh";
     102          72 :       mooseInfoRepeated(out.str());
     103          72 :     }
     104             :   }
     105        1956 : }
     106             : 
     107             : void
     108         905 : AddPeriodicBCAction::onSetupPeriodicBoundary(libMesh::PeriodicBoundaryBase & p)
     109             : {
     110         905 :   const auto is_regular_orthogonal = _mesh->isRegularOrthogonal();
     111        1811 :   for (const auto & var_ptr : _vars)
     112             :   {
     113         909 :     const auto sys_num = var_ptr->sys().number();
     114        1851 :     for (const auto component : make_range(var_ptr->count()))
     115             :     {
     116         945 :       const auto var_num = var_ptr->number() + component;
     117             : 
     118             :       // Set variable number in PeriodicBoundaryBase object
     119         945 :       p.set_variable(var_num);
     120             : 
     121             :       // Add to MooseMesh to querying variable periodicity
     122         945 :       if (is_regular_orthogonal)
     123         873 :         _mesh->addPeriodicVariable(sys_num, var_num, p.myboundary, p.pairedboundary);
     124             : 
     125             :       // Add to dof maps for algebraic ghosting
     126        1034 :       const auto add_to_dof_map = [&p, &sys_num](auto & problem)
     127        1976 :       { problem.es().get_system(sys_num).get_dof_map().add_periodic_boundary(p); };
     128         942 :       add_to_dof_map(*_problem);
     129         942 :       if (auto displaced_problem = _problem->getDisplacedProblem())
     130         942 :         add_to_dof_map(*displaced_problem);
     131             :     }
     132             :   }
     133         902 : }
     134             : 
     135             : std::vector<const MooseVariableFieldBase *>
     136         680 : AddPeriodicBCAction::getVariables() const
     137             : {
     138         680 :   std::vector<VariableName> var_names;
     139             :   // Variable is set, use it
     140        2040 :   if (isParamValid("variable"))
     141             :   {
     142        1214 :     var_names = getParam<std::vector<VariableName>>("variable");
     143         607 :     if (var_names.empty())
     144           6 :       paramError("variable", "No variables are set to apply periodic boundaries to");
     145        1205 :     for (const auto & var_name : var_names)
     146             :     {
     147         607 :       if (_problem->hasScalarVariable(var_name))
     148           3 :         paramError("variable",
     149           3 :                    "Variable '" + var_name +
     150             :                        "' is a scalar variable and does not support a periodic boundary condition");
     151         604 :       if (!_problem->hasVariable(var_name))
     152           6 :         paramError("variable", "Variable '" + var_name + "' not found");
     153         601 :       if (_problem->getVariable(0, var_name).isFV())
     154           0 :         paramError("variable",
     155           0 :                    "Variable '" + var_name +
     156             :                        "' is a finite volume variable and does not support a periodic boundary "
     157             :                        "condition.");
     158             :     }
     159             :   }
     160             :   // Variable is not set, use all nonlinear variables that are non-scalar and non-FV
     161             :   else
     162             :   {
     163             :     // We can't currently distinguish PeriodicBoundaries objects across
     164             :     // multiple systems so we can't use vars across all systems
     165          73 :     if (_problem->numSolverSystems() > 1)
     166           3 :       mooseError("Parameter 'variable' must be specified when multiple solver systems exist");
     167          70 :     const auto & nl = _problem->getNonlinearSystemBase(0);
     168          70 :     var_names = nl.getVariableNames();
     169          70 :     var_names.erase(std::remove_if(var_names.begin(),
     170             :                                    var_names.end(),
     171          69 :                                    [&nl](const auto & var_name)
     172             :                                    {
     173         138 :                                      return nl.hasScalarVariable(var_name) ||
     174         138 :                                             nl.getVariable(0, var_name).isFV();
     175             :                                    }),
     176          70 :                     var_names.end());
     177          70 :     if (var_names.empty())
     178           3 :       mooseError("There are no variables to apply periodic boundaries to");
     179             :   }
     180             : 
     181             :   // Verify and collect variables
     182         665 :   std::vector<const MooseVariableFieldBase *> vars;
     183         665 :   vars.reserve(var_names.size());
     184         665 :   std::optional<unsigned int> used_sys_num;
     185        1332 :   for (const auto & var_name : var_names)
     186             :   {
     187         670 :     const auto & var = _problem->getVariable(0, var_name);
     188         670 :     const auto sys_num = var.sys().number();
     189             : 
     190             :     // Until we have a way to have separate PeriodicBoundaries objects for each systems,
     191             :     // we can't do these in the same block
     192         670 :     if (used_sys_num && *used_sys_num != sys_num)
     193           6 :       paramError("variable",
     194             :                  "Variables were specified across multiple systems; this is not supported. Use a "
     195             :                  "separate [Periodic/BCs] block for each system.");
     196         667 :     used_sys_num = sys_num;
     197             : 
     198         667 :     vars.push_back(&var);
     199             :   }
     200             : 
     201        1324 :   return vars;
     202         662 : }

Generated by: LCOV version 1.14