LCOV - code coverage report
Current view: top level - src/fviks - FVInterfaceKernel.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 117 128 91.4 %
Date: 2025-07-17 01:28:37 Functions: 11 14 78.6 %
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 "FVInterfaceKernel.h"
      11             : #include "FEProblemBase.h"
      12             : #include "SystemBase.h"
      13             : #include "MooseVariableFV.h"
      14             : #include "Assembly.h"
      15             : 
      16             : InputParameters
      17       57690 : FVInterfaceKernel::validParams()
      18             : {
      19       57690 :   InputParameters params = MooseObject::validParams();
      20       57690 :   params += BoundaryRestrictableRequired::validParams();
      21       57690 :   params += SetupInterface::validParams();
      22       57690 :   params += FunctionInterface::validParams();
      23       57690 :   params += DistributionInterface::validParams();
      24       57690 :   params += UserObjectInterface::validParams();
      25       57690 :   params += TransientInterface::validParams();
      26       57690 :   params += PostprocessorInterface::validParams();
      27       57690 :   params += VectorPostprocessorInterface::validParams();
      28       57690 :   params += GeometricSearchInterface::validParams();
      29       57690 :   params += MeshChangedInterface::validParams();
      30       57690 :   params += TaggingInterface::validParams();
      31       57690 :   params += NeighborCoupleableMooseVariableDependencyIntermediateInterface::validParams();
      32       57690 :   params += TwoMaterialPropertyInterface::validParams();
      33       57690 :   params += ADFunctorInterface::validParams();
      34             : 
      35       57690 :   params.addRequiredParam<std::vector<SubdomainName>>(
      36             :       "subdomain1", "The subdomains on the 1st side of the boundary.");
      37       57690 :   params.addRequiredParam<std::vector<SubdomainName>>(
      38             :       "subdomain2", "The subdomains on the 2nd side of the boundary.");
      39       57690 :   params.addRequiredParam<NonlinearVariableName>(
      40             :       "variable1", "The name of the first variable that this interface kernel applies to");
      41       57690 :   params.addParam<NonlinearVariableName>(
      42             :       "variable2",
      43             :       "The name of the second variable that this interface kernel applies to. If not supplied, "
      44             :       "variable1 will be used.");
      45      173070 :   params.addParam<bool>("use_displaced_mesh",
      46      115380 :                         false,
      47             :                         "Whether or not this object should use the "
      48             :                         "displaced mesh for computation.  Note that "
      49             :                         "in the case this is true but no "
      50             :                         "displacements are provided in the Mesh block "
      51             :                         "the undisplaced mesh will still be used.");
      52             : 
      53       57690 :   params.addParam<unsigned short>("ghost_layers", 1, "The number of layers of elements to ghost.");
      54      173070 :   params.addParam<bool>("use_point_neighbors",
      55      115380 :                         false,
      56             :                         "Whether to use point neighbors, which introduces additional ghosting to "
      57             :                         "that used for simple face neighbors.");
      58       57690 :   params.addParamNamesToGroup("ghost_layers use_point_neighbors", "Parallel ghosting");
      59             : 
      60             :   // FV Interface Kernels always need one layer of ghosting because the elements
      61             :   // on each side of the interface may be on different MPI ranks, but we still
      62             :   // need to access them as a pair to compute the numerical face flux.
      63       57690 :   params.addRelationshipManager(
      64             :       "ElementSideNeighborLayers",
      65             :       Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC |
      66             :           Moose::RelationshipManagerType::COUPLING,
      67           0 :       [](const InputParameters & obj_params, InputParameters & rm_params)
      68             :       {
      69         915 :         rm_params.set<unsigned short>("layers") = obj_params.get<unsigned short>("ghost_layers");
      70         915 :         rm_params.set<bool>("use_point_neighbors") = obj_params.get<bool>("use_point_neighbors");
      71         915 :       });
      72             : 
      73       57690 :   params.addParamNamesToGroup("use_displaced_mesh", "Advanced");
      74       57690 :   params.addCoupledVar("displacements", "The displacements");
      75       57690 :   params.declareControllable("enable");
      76       57690 :   params.registerBase("FVInterfaceKernel");
      77       57690 :   params.registerSystemAttributeName("FVInterfaceKernel");
      78       57690 :   params.set<bool>("_residual_object") = true;
      79       57690 :   return params;
      80           0 : }
      81             : 
      82         331 : FVInterfaceKernel::FVInterfaceKernel(const InputParameters & parameters)
      83             :   : MooseObject(parameters),
      84             :     BoundaryRestrictableRequired(this, false),
      85             :     SetupInterface(this),
      86             :     FunctionInterface(this),
      87             :     DistributionInterface(this),
      88             :     UserObjectInterface(this),
      89             :     TransientInterface(this),
      90             :     PostprocessorInterface(this),
      91             :     VectorPostprocessorInterface(this),
      92             :     GeometricSearchInterface(this),
      93             :     MeshChangedInterface(parameters),
      94             :     TaggingInterface(this),
      95             :     NeighborCoupleableMooseVariableDependencyIntermediateInterface(
      96             :         this, /*nodal=*/false, /*neighbor_nodal=*/false, /*is_fv=*/true),
      97             :     TwoMaterialPropertyInterface(this, Moose::EMPTY_BLOCK_IDS, boundaryIDs()),
      98             :     ADFunctorInterface(this),
      99         331 :     _tid(getParam<THREAD_ID>("_tid")),
     100         331 :     _subproblem(*getCheckedPointerParam<SubProblem *>("_subproblem")),
     101         662 :     _var1(_subproblem.getVariable(_tid, getParam<NonlinearVariableName>("variable1"))
     102         331 :               .sys()
     103         331 :               .getFVVariable<Real>(_tid, getParam<NonlinearVariableName>("variable1"))),
     104         662 :     _var2(_subproblem
     105         331 :               .getVariable(_tid,
     106         662 :                            isParamValid("variable2") ? getParam<NonlinearVariableName>("variable2")
     107         404 :                                                      : getParam<NonlinearVariableName>("variable1"))
     108         331 :               .sys()
     109         331 :               .getFVVariable<Real>(_tid,
     110         662 :                                    isParamValid("variable2")
     111         662 :                                        ? getParam<NonlinearVariableName>("variable2")
     112         404 :                                        : getParam<NonlinearVariableName>("variable1"))),
     113         331 :     _assembly(_subproblem.assembly(_tid, _var1.sys().number())),
     114         662 :     _mesh(_subproblem.mesh())
     115             : {
     116         331 :   if (getParam<bool>("use_displaced_mesh"))
     117           0 :     paramError("use_displaced_mesh", "FV interface kernels do not yet support displaced mesh");
     118             : 
     119         331 :   _subproblem.haveADObjects(true);
     120         331 :   addMooseVariableDependency(&_var1);
     121         331 :   addMooseVariableDependency(&_var2);
     122             : 
     123         662 :   for (const auto & sub_name : getParam<std::vector<SubdomainName>>("subdomain1"))
     124         331 :     _subdomain1.insert(_mesh.getSubdomainID(sub_name));
     125         662 :   for (const auto & sub_name : getParam<std::vector<SubdomainName>>("subdomain2"))
     126         331 :     _subdomain2.insert(_mesh.getSubdomainID(sub_name));
     127             : 
     128         331 :   if (!_var1.hasBlocks(_subdomain1))
     129           4 :     paramError("variable1",
     130             :                "variable1 does not exist on all the blocks specified by the subdomain1 parameter");
     131         327 :   if (!_var2.hasBlocks(_subdomain2))
     132             :   {
     133           8 :     const bool var2_provided = isParamValid("variable2");
     134           8 :     const std::string var_name = var2_provided ? "variable2" : "variable1";
     135           8 :     paramError(var_name,
     136             :                var_name,
     137             :                " does not exist on all the blocks specified by the subdomain2 parameter",
     138             :                var2_provided ? ""
     139             :                              : ".\nNote that you did not provide the variable2 parameter, "
     140             :                                "so variable1 was implicitly used on subdomain2");
     141           0 :   }
     142         319 : }
     143             : 
     144             : void
     145       13816 : FVInterfaceKernel::setupData(const FaceInfo & fi)
     146             : {
     147       13816 :   _face_info = &fi;
     148       13816 :   _normal = fi.normal();
     149       13816 :   _elem_is_one = _subdomain1.find(fi.elem().subdomain_id()) != _subdomain1.end();
     150             : 
     151             : #ifndef NDEBUG
     152             :   const auto ft1 = fi.faceType(std::make_pair(_var1.number(), _var1.sys().number()));
     153             :   const auto ft2 = fi.faceType(std::make_pair(_var2.number(), _var2.sys().number()));
     154             :   constexpr auto ft_both = FaceInfo::VarFaceNeighbors::BOTH;
     155             :   constexpr auto ft_elem = FaceInfo::VarFaceNeighbors::ELEM;
     156             :   constexpr auto ft_neigh = FaceInfo::VarFaceNeighbors::NEIGHBOR;
     157             :   mooseAssert(
     158             :       (_elem_is_one && (ft1 == ft_elem || ft1 == ft_both) && (ft2 == ft_neigh || ft2 == ft_both)) ||
     159             :           (!_elem_is_one && (ft1 == ft_neigh || ft1 == ft_both) &&
     160             :            (ft2 == ft_elem || ft2 == ft_both)),
     161             :       "Face type was not recognized. Check that the specified boundaries are interfaces.");
     162             : #endif
     163       13816 : }
     164             : 
     165             : void
     166       11284 : FVInterfaceKernel::addResidual(const Real resid, const unsigned int var_num, const bool neighbor)
     167             : {
     168       11284 :   neighbor ? prepareVectorTagNeighbor(_assembly, var_num) : prepareVectorTag(_assembly, var_num);
     169       11284 :   _local_re(0) = resid;
     170       11284 :   accumulateTaggedLocalResidual();
     171       11284 : }
     172             : 
     173             : void
     174           0 : FVInterfaceKernel::addJacobian(const ADReal & resid,
     175             :                                const dof_id_type dof_index,
     176             :                                const Real scaling_factor)
     177             : {
     178           0 :   addJacobian(_assembly,
     179           0 :               std::array<ADReal, 1>{{resid}},
     180           0 :               std::array<dof_id_type, 1>{{dof_index}},
     181             :               scaling_factor);
     182           0 : }
     183             : 
     184             : void
     185        8784 : FVInterfaceKernel::computeResidual(const FaceInfo & fi)
     186             : {
     187        8784 :   setupData(fi);
     188             : 
     189        8784 :   const auto r = MetaPhysicL::raw_value(fi.faceArea() * fi.faceCoord() * computeQpResidual());
     190             : 
     191             :   // If the two variables belong to two different nonlinear systems, we only contribute to the one
     192             :   // which is being assembled right now
     193             :   mooseAssert(_var1.sys().number() == _subproblem.currentNlSysNum(),
     194             :               "The interface kernel should contribute to the system which variable1 belongs to!");
     195        8784 :   addResidual(_elem_is_one ? r : -r, _var1.number(), _elem_is_one ? false : true);
     196        8784 :   if (_var1.sys().number() == _var2.sys().number())
     197        2296 :     addResidual(_elem_is_one ? -r : r, _var2.number(), _elem_is_one ? true : false);
     198        8784 : }
     199             : 
     200             : void
     201          40 : FVInterfaceKernel::computeResidualAndJacobian(const FaceInfo & fi)
     202             : {
     203          40 :   computeJacobian(fi);
     204          40 : }
     205             : 
     206             : void
     207        4744 : FVInterfaceKernel::computeJacobian(const FaceInfo & fi)
     208             : {
     209        4744 :   setupData(fi);
     210             : 
     211        4744 :   const auto r = fi.faceArea() * fi.faceCoord() * computeQpResidual();
     212             : 
     213             :   // If the two variables belong to two different nonlinear systems, we only contribute to the one
     214             :   // which is being assembled right now
     215             :   mooseAssert(_var1.sys().number() == _subproblem.currentNlSysNum(),
     216             :               "The interface kernel should contribute to the system which variable1 belongs to!");
     217       14232 :   addResidualsAndJacobian(_assembly,
     218        4744 :                           std::array<ADReal, 1>{{_elem_is_one ? r : -r}},
     219        4744 :                           _elem_is_one ? _var1.dofIndices() : _var1.dofIndicesNeighbor(),
     220        4744 :                           _var1.scalingFactor());
     221        4744 :   if (_var1.sys().number() == _var2.sys().number())
     222        4512 :     addResidualsAndJacobian(_assembly,
     223        1504 :                             std::array<ADReal, 1>{{_elem_is_one ? -r : r}},
     224        1504 :                             _elem_is_one ? _var2.dofIndicesNeighbor() : _var2.dofIndices(),
     225        1504 :                             _var2.scalingFactor());
     226       10992 : }
     227             : 
     228             : Moose::ElemArg
     229       13528 : FVInterfaceKernel::elemArg(const bool correct_skewness) const
     230             : {
     231       13528 :   return {_face_info->elemPtr(), correct_skewness};
     232             : }
     233             : 
     234             : Moose::ElemArg
     235       13528 : FVInterfaceKernel::neighborArg(const bool correct_skewness) const
     236             : {
     237       13528 :   return {_face_info->neighborPtr(), correct_skewness};
     238             : }
     239             : 
     240             : Moose::FaceArg
     241         224 : FVInterfaceKernel::singleSidedFaceArg(const MooseVariableFV<Real> & variable,
     242             :                                       const FaceInfo * fi,
     243             :                                       const Moose::FV::LimiterType limiter_type,
     244             :                                       const bool correct_skewness,
     245             :                                       const Moose::StateArg * state_limiter) const
     246             : {
     247         224 :   if (!fi)
     248         224 :     fi = _face_info;
     249             : 
     250         224 :   const bool defined_on_elem_side = variable.hasBlocks(fi->elem().subdomain_id());
     251         224 :   bool defined_on_neighbor_side = false;
     252         224 :   if (fi->neighborPtr())
     253         224 :     defined_on_neighbor_side = variable.hasBlocks(fi->neighbor().subdomain_id());
     254             : 
     255          77 :   const Elem * const elem = defined_on_elem_side && defined_on_neighbor_side
     256         448 :                                 ? nullptr
     257         147 :                                 : (defined_on_elem_side ? fi->elemPtr() : fi->neighborPtr());
     258             : 
     259         224 :   return {fi, limiter_type, true, correct_skewness, elem, state_limiter};
     260             : }
     261             : 
     262             : bool
     263           0 : FVInterfaceKernel::hasFaceSide(const FaceInfo &, bool) const
     264             : {
     265             :   // Our default interface kernel treats elem and neighbor sides equivalently so we will assume for
     266             :   // now that we will happily consume functor evaluations on either side of a face and any
     267             :   // interpolation between said evaluations
     268           0 :   return true;
     269             : }

Generated by: LCOV version 1.14