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 : }