LCOV - code coverage report
Current view: top level - src/utils - PeriodicBCHelper.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 93 96 96.9 %
Date: 2026-05-29 20:35:17 Functions: 12 12 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 "PeriodicBCHelper.h"
      11             : 
      12             : #include "DisplacedProblem.h"
      13             : #include "FEProblemBase.h"
      14             : #include "FunctionPeriodicBoundary.h"
      15             : #include "MooseObjectAction.h"
      16             : #include "MooseMesh.h"
      17             : 
      18             : #include "libmesh/periodic_boundary.h"
      19             : #include "libmesh/ghost_point_neighbors.h"
      20             : 
      21             : namespace Moose
      22             : {
      23             : InputParameters
      24         737 : PeriodicBCHelper::validParams()
      25             : {
      26         737 :   auto params = emptyInputParameters();
      27             : 
      28        1474 :   const MultiMooseEnum auto_direction("x=0 y=1 z=2");
      29        2948 :   params.addParam<MultiMooseEnum>(
      30             :       "auto_direction",
      31             :       auto_direction,
      32             :       "If using a generated mesh, the dimension(s) you want to mark as periodic.");
      33             : 
      34        2948 :   params.addParam<BoundaryName>("primary", "Boundary associated with the primary boundary.");
      35        2948 :   params.addParam<BoundaryName>("secondary", "Boundary associated with the secondary boundary.");
      36        2948 :   params.addParam<RealVectorValue>("translation",
      37             :                                    "Vector that translates coordinates on the primary boundary to "
      38             :                                    "coordinates on the secondary boundary.");
      39        2948 :   params.addParam<std::vector<std::string>>("transform_func",
      40             :                                             "Functions that specify the transformation");
      41        2211 :   params.addParam<std::vector<std::string>>("inv_transform_func",
      42             :                                             "Functions that specify the inverse transformation");
      43        1474 :   return params;
      44         737 : }
      45             : 
      46         695 : PeriodicBCHelper::PeriodicBCHelper(const Action & action) : _action(action), _params(getParams()) {}
      47             : 
      48             : void
      49         695 : PeriodicBCHelper::checkPeriodicParams() const
      50             : {
      51        2085 :   if (_params.isParamValid("auto_direction"))
      52             :   {
      53        1821 :     for (const auto & param :
      54        2127 :          {"primary", "secondary", "translation", "transform_func", "inv_transform_func"})
      55        4554 :       if (_params.isParamValid(param))
      56           6 :         _params.paramError(param, "Should not be specified along with 'auto_direction'");
      57             :   }
      58        1939 :   else if (!_params.isParamValid("primary") || !_params.isParamValid("secondary"))
      59           3 :     _action.mooseError(
      60             :         "Either 'auto_direction' or both 'primary' and 'secondary' must be specified");
      61         689 : }
      62             : 
      63             : void
      64         662 : PeriodicBCHelper::setupPeriodicBoundaries(FEProblemBase & problem)
      65             : {
      66             :   mooseAssert(_periodic_boundaries.empty(), "Already set");
      67             : 
      68             :   // Setup paired sidesets to be able to call MooseMesh::getPairedBoundaryMapping()
      69         662 :   if (!problem.mesh().hasDetectedPairedSidesets())
      70         538 :     problem.mesh().detectPairedSidesets();
      71             : 
      72        1986 :   if (_params.isParamValid("auto_direction"))
      73         285 :     setupAutoPeriodicBoundaries(problem.mesh());
      74             :   else
      75         377 :     setupManualPeriodicBoundaries(problem);
      76             : 
      77             :   mooseAssert(getPeriodicBoundaries().size(), "Shouldn't run without boundaries");
      78             : 
      79         727 :   const auto add_ghosting = [this](auto & problem)
      80             :   {
      81         727 :     auto & mesh = problem.mesh().getMesh();
      82         727 :     auto functor = std::make_shared<libMesh::GhostPointNeighbors>(mesh);
      83         727 :     functor->set_periodic_boundaries(&getPeriodicBoundaries());
      84         727 :     mesh.add_ghosting_functor(functor);
      85        1362 :   };
      86             : 
      87         635 :   add_ghosting(problem);
      88         635 :   if (const auto displaced_problem = problem.getDisplacedProblem())
      89         635 :     add_ghosting(*displaced_problem);
      90         635 : }
      91             : 
      92             : void
      93         905 : PeriodicBCHelper::addPeriodicBoundary(std::unique_ptr<libMesh::PeriodicBoundaryBase> p)
      94             : {
      95         905 :   onSetupPeriodicBoundary(*p);
      96             : 
      97         902 :   _periodic_boundaries.emplace(p->myboundary, p->clone());
      98         902 :   _periodic_boundaries.emplace(p->pairedboundary, p->clone(libMesh::PeriodicBoundaryBase::INVERSE));
      99         902 : }
     100             : 
     101             : void
     102         285 : PeriodicBCHelper::setupAutoPeriodicBoundaries(MooseMesh & mesh)
     103             : {
     104             :   // If we are working with a parallel mesh then we're going to ghost all the boundaries
     105             :   // everywhere because we don't know what we need...
     106         285 :   if (mesh.isDistributedMesh() && !mesh.detectOrthogonalDimRanges())
     107           0 :     _action.mooseError("Could not detect orthogonal dimension ranges for DistributedMesh.");
     108             : 
     109         831 :   for (const auto & dir : _params.get<MultiMooseEnum>("auto_direction"))
     110             :   {
     111         552 :     const int component = dir.id();
     112         552 :     if (component > (cast_int<int>(mesh.dimension()) - 1))
     113           3 :       _params.paramError("auto_direction",
     114           3 :                          MooseUtils::toLower(dir.name()),
     115             :                          "-dimension component not valid for ",
     116           3 :                          mesh.dimension(),
     117             :                          "D mesh");
     118             : 
     119         549 :     const auto boundary_ids = mesh.getPairedBoundaryMapping(component);
     120         549 :     if (!boundary_ids)
     121           3 :       _params.paramError("auto_direction",
     122             :                          "Couldn't auto-detect a paired boundary in the ",
     123           3 :                          MooseUtils::toLower(dir.name()),
     124             :                          "-direction");
     125             : 
     126         546 :     RealVectorValue v;
     127         546 :     v(component) = mesh.dimensionWidth(component);
     128             : 
     129         546 :     auto p = std::make_unique<libMesh::PeriodicBoundary>(v);
     130         546 :     p->myboundary = boundary_ids->first;
     131         546 :     p->pairedboundary = boundary_ids->second;
     132             : 
     133         546 :     addPeriodicBoundary(std::move(p));
     134         546 :   }
     135         279 : }
     136             : 
     137             : void
     138         377 : PeriodicBCHelper::setupManualPeriodicBoundaries(FEProblemBase & problem)
     139             : {
     140         377 :   auto & mesh = problem.mesh();
     141         377 :   std::unique_ptr<libMesh::PeriodicBoundaryBase> p;
     142             : 
     143        1131 :   if (const auto translation_ptr = _params.queryParam<RealVectorValue>("translation"))
     144         239 :     p = std::make_unique<libMesh::PeriodicBoundary>(*translation_ptr);
     145         414 :   else if (const auto fn_names_ptr = _params.queryParam<std::vector<std::string>>("transform_func"))
     146             :   {
     147             :     const auto inv_fn_names_ptr =
     148         270 :         _params.queryParam<std::vector<std::string>>("inv_transform_func");
     149         135 :     if (!inv_fn_names_ptr)
     150           6 :       _params.paramError("transform_func", "Must also specify 'inv_transform_func'");
     151         132 :     if (fn_names_ptr->size() != mesh.dimension())
     152           6 :       _params.paramError(
     153           3 :           "transform_func", "Must be the size of the mesh dimension ", mesh.dimension());
     154         129 :     if (inv_fn_names_ptr->size() != mesh.dimension())
     155           6 :       _params.paramError(
     156           3 :           "inv_transform_func", "Must be the size of the mesh dimension ", mesh.dimension());
     157             : 
     158         126 :     p = std::make_unique<FunctionPeriodicBoundary>(problem, *fn_names_ptr, *inv_fn_names_ptr);
     159             :   }
     160             :   else
     161           3 :     _action.mooseError(
     162             :         "You need to specify either 'auto_direction', 'translation', or 'transform_func'");
     163             : 
     164         727 :   const auto get_boundary = [this, &mesh](const auto & param) -> BoundaryID
     165             :   {
     166        2181 :     if (const auto name_ptr = _params.queryParam<BoundaryName>(param))
     167             :     {
     168         727 :       if (const auto id = MooseMeshUtils::getBoundaryID(*name_ptr, mesh);
     169         727 :           id != Moose::INVALID_BOUNDARY_ID)
     170         721 :         return id;
     171          12 :       _params.paramError(param, "Boundary '", *name_ptr, "' does not exist in the mesh");
     172             :     }
     173           0 :     _action.mooseError("Parameter '", param, "' is required when 'auto_direction' is not set");
     174         365 :   };
     175         365 :   p->myboundary = get_boundary("primary");
     176         362 :   p->pairedboundary = get_boundary("secondary");
     177             : 
     178         359 :   addPeriodicBoundary(std::move(p));
     179         356 : }
     180             : 
     181             : const InputParameters &
     182         695 : PeriodicBCHelper::getParams() const
     183             : {
     184         695 :   if (const auto moa = dynamic_cast<const MooseObjectAction *>(&_action))
     185           0 :     return moa->getObjectParams();
     186         695 :   return _action.parameters();
     187             : }
     188             : }

Generated by: LCOV version 1.14