LCOV - code coverage report
Current view: top level - src/interfacekernels - InterfaceKernel.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 8601ad Lines: 181 228 79.4 %
Date: 2025-07-18 13:27:08 Functions: 16 20 80.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 "InterfaceKernel.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "Assembly.h"
      14             : #include "MooseVariableFE.h"
      15             : #include "SystemBase.h"
      16             : #include "AuxiliarySystem.h"
      17             : #include "FEProblemBase.h"
      18             : 
      19             : #include "libmesh/quadrature.h"
      20             : 
      21             : template <typename T>
      22             : InputParameters
      23      101402 : InterfaceKernelTempl<T>::validParams()
      24             : {
      25      101402 :   InputParameters params = InterfaceKernelBase::validParams();
      26             :   if (std::is_same<T, Real>::value)
      27       87095 :     params.registerBase("InterfaceKernel");
      28             :   else if (std::is_same<T, RealVectorValue>::value)
      29       14307 :     params.registerBase("VectorInterfaceKernel");
      30             :   else
      31             :     ::mooseError("unsupported InterfaceKernelTempl specialization");
      32      101402 :   return params;
      33           0 : }
      34             : 
      35             : template <typename T>
      36         807 : InterfaceKernelTempl<T>::InterfaceKernelTempl(const InputParameters & parameters)
      37             :   : InterfaceKernelBase(parameters),
      38             :     NeighborMooseVariableInterface<T>(this,
      39             :                                       false,
      40             :                                       Moose::VarKindType::VAR_SOLVER,
      41             :                                       std::is_same<T, Real>::value
      42             :                                           ? Moose::VarFieldType::VAR_FIELD_STANDARD
      43             :                                           : Moose::VarFieldType::VAR_FIELD_VECTOR),
      44        1614 :     _var(*this->mooseVariable()),
      45         807 :     _normals(_assembly.normals()),
      46         807 :     _u(_is_implicit ? _var.sln() : _var.slnOld()),
      47         807 :     _grad_u(_is_implicit ? _var.gradSln() : _var.gradSlnOld()),
      48         807 :     _phi(_assembly.phiFace(_var)),
      49         807 :     _grad_phi(_assembly.gradPhiFace(_var)),
      50         807 :     _test(_var.phiFace()),
      51         807 :     _grad_test(_var.gradPhiFace()),
      52         807 :     _neighbor_var(*getVarHelper<MooseVariableFE<T>>("neighbor_var", 0)),
      53         807 :     _neighbor_value(_is_implicit ? _neighbor_var.slnNeighbor() : _neighbor_var.slnOldNeighbor()),
      54         807 :     _grad_neighbor_value(_neighbor_var.gradSlnNeighbor()),
      55         807 :     _phi_neighbor(_assembly.phiFaceNeighbor(_neighbor_var)),
      56         807 :     _grad_phi_neighbor(_assembly.gradPhiFaceNeighbor(_neighbor_var)),
      57         807 :     _test_neighbor(_neighbor_var.phiFaceNeighbor()),
      58         807 :     _grad_test_neighbor(_neighbor_var.gradPhiFaceNeighbor()),
      59        1614 :     _same_system(_var.sys().number() == _neighbor_var.sys().number())
      60             : {
      61             :   // Neighbor variable dependency is added by
      62             :   // NeighborCoupleableMooseVariableDependencyIntermediateInterface
      63         807 :   addMooseVariableDependency(this->mooseVariable());
      64             : 
      65         807 :   if (!parameters.isParamValid("boundary"))
      66           0 :     mooseError(
      67             :         "In order to use an interface kernel, you must specify a boundary where it will live.");
      68             : 
      69         807 :   if (parameters.isParamSetByUser("save_in"))
      70             :   {
      71          26 :     if (_save_in_strings.size() != _save_in_var_side.size())
      72           0 :       mooseError("save_in and save_in_var_side must be the same length");
      73             :     else
      74             :     {
      75          78 :       for (unsigned i = 0; i < _save_in_strings.size(); ++i)
      76             :       {
      77          52 :         MooseVariable * var = &_subproblem.getStandardVariable(_tid, _save_in_strings[i]);
      78             : 
      79          52 :         if (_sys.hasVariable(_save_in_strings[i]))
      80           0 :           mooseError("Trying to use solution variable " + _save_in_strings[i] +
      81           0 :                      " as a save_in variable in " + name());
      82             : 
      83          52 :         if (_save_in_var_side[i] == "m")
      84             :         {
      85          26 :           if (var->feType() != _var.feType())
      86           0 :             mooseError(
      87           0 :                 "Error in " + name() +
      88             :                 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
      89             :                 "and the fe_type of the the primary side nonlinear "
      90             :                 "variable this interface kernel object is acting on.");
      91          26 :           _primary_save_in_residual_variables.push_back(var);
      92             :         }
      93             :         else
      94             :         {
      95          26 :           if (var->feType() != _neighbor_var.feType())
      96           0 :             mooseError(
      97           0 :                 "Error in " + name() +
      98             :                 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
      99             :                 "and the fe_type of the the secondary side nonlinear "
     100             :                 "variable this interface kernel object is acting on.");
     101          26 :           _secondary_save_in_residual_variables.push_back(var);
     102             :         }
     103             : 
     104          52 :         var->sys().addVariableToZeroOnResidual(_save_in_strings[i]);
     105          52 :         addMooseVariableDependency(var);
     106             :       }
     107             :     }
     108             :   }
     109             : 
     110         807 :   _has_primary_residuals_saved_in = _primary_save_in_residual_variables.size() > 0;
     111         807 :   _has_secondary_residuals_saved_in = _secondary_save_in_residual_variables.size() > 0;
     112             : 
     113         807 :   if (parameters.isParamSetByUser("diag_save_in"))
     114             :   {
     115          26 :     if (_diag_save_in_strings.size() != _diag_save_in_var_side.size())
     116           0 :       mooseError("diag_save_in and diag_save_in_var_side must be the same length");
     117             :     else
     118             :     {
     119          78 :       for (unsigned i = 0; i < _diag_save_in_strings.size(); ++i)
     120             :       {
     121          52 :         MooseVariable * var = &_subproblem.getStandardVariable(_tid, _diag_save_in_strings[i]);
     122             : 
     123          52 :         if (_sys.hasVariable(_diag_save_in_strings[i]))
     124           0 :           mooseError("Trying to use solution variable " + _diag_save_in_strings[i] +
     125           0 :                      " as a save_in variable in " + name());
     126             : 
     127          52 :         if (_diag_save_in_var_side[i] == "m")
     128             :         {
     129          26 :           if (var->feType() != _var.feType())
     130           0 :             mooseError(
     131           0 :                 "Error in " + name() +
     132             :                 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
     133             :                 "and the fe_type of the the primary side nonlinear "
     134             :                 "variable this interface kernel object is acting on.");
     135          26 :           _primary_save_in_jacobian_variables.push_back(var);
     136             :         }
     137             :         else
     138             :         {
     139          26 :           if (var->feType() != _neighbor_var.feType())
     140           0 :             mooseError(
     141           0 :                 "Error in " + name() +
     142             :                 ". There is a mismatch between the fe_type of the save-in Auxiliary variable "
     143             :                 "and the fe_type of the the secondary side nonlinear "
     144             :                 "variable this interface kernel object is acting on.");
     145          26 :           _secondary_save_in_jacobian_variables.push_back(var);
     146             :         }
     147             : 
     148          52 :         var->sys().addVariableToZeroOnJacobian(_diag_save_in_strings[i]);
     149          52 :         addMooseVariableDependency(var);
     150             :       }
     151             :     }
     152             :   }
     153             : 
     154         807 :   _has_primary_jacobians_saved_in = _primary_save_in_jacobian_variables.size() > 0;
     155         807 :   _has_secondary_jacobians_saved_in = _secondary_save_in_jacobian_variables.size() > 0;
     156         807 : }
     157             : 
     158             : template <typename T>
     159             : void
     160      146690 : InterfaceKernelTempl<T>::computeElemNeighResidual(Moose::DGResidualType type)
     161             : {
     162             :   bool is_elem;
     163      146690 :   if (type == Moose::Element)
     164       73401 :     is_elem = true;
     165             :   else
     166       73289 :     is_elem = false;
     167             : 
     168      146690 :   const TemplateVariableTestValue & test_space = is_elem ? _test : _test_neighbor;
     169             : 
     170      146690 :   if (is_elem)
     171       73401 :     prepareVectorTag(_assembly, _var.number());
     172             :   else
     173       73289 :     prepareVectorTagNeighbor(_assembly, _neighbor_var.number());
     174             : 
     175      682868 :   for (_qp = 0; _qp < _qrule->n_points(); _qp++)
     176             :   {
     177      536178 :     initQpResidual(type);
     178     6856198 :     for (_i = 0; _i < test_space.size(); _i++)
     179     6320020 :       _local_re(_i) += _JxW[_qp] * _coord[_qp] * computeQpResidual(type);
     180             :   }
     181             : 
     182      146690 :   accumulateTaggedLocalResidual();
     183             : 
     184             :   // To save the diagonal of the Jacobian
     185      146690 :   if (_has_primary_residuals_saved_in && is_elem)
     186             :   {
     187          32 :     Threads::spin_mutex::scoped_lock lock(_resid_vars_mutex);
     188          64 :     for (const auto & var : _primary_save_in_residual_variables)
     189             :     {
     190          32 :       var->sys().solution().add_vector(_local_re, var->dofIndices());
     191             :     }
     192          32 :   }
     193      146658 :   else if (_has_secondary_residuals_saved_in && !is_elem)
     194             :   {
     195          32 :     Threads::spin_mutex::scoped_lock lock(_resid_vars_mutex);
     196          64 :     for (const auto & var : _secondary_save_in_residual_variables)
     197          32 :       var->sys().solution().add_vector(_local_re, var->dofIndicesNeighbor());
     198          32 :   }
     199      146690 : }
     200             : 
     201             : template <typename T>
     202             : void
     203       73525 : InterfaceKernelTempl<T>::computeResidual()
     204             : {
     205             :   // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
     206             :   // associated only with the lower-dimensional geometric entity that is the boundary between two
     207             :   // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
     208             :   // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
     209             :   // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
     210             :   // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
     211             :   // to execute in the former case. In the future we should remove this and add some kind of "block"
     212             :   // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
     213             :   // this return
     214      147002 :   if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
     215       73477 :       !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
     216          48 :     return;
     217             : 
     218       73477 :   precalculateResidual();
     219             : 
     220             :   // Compute the residual for this element
     221       73477 :   computeElemNeighResidual(Moose::Element);
     222             : 
     223             :   // Compute the residual for the neighbor
     224             :   // This also prevents computing a residual if the neighbor variable is auxiliary
     225       73477 :   if (_same_system)
     226       73365 :     computeElemNeighResidual(Moose::Neighbor);
     227             : }
     228             : 
     229             : template <typename T>
     230             : void
     231       32576 : InterfaceKernelTempl<T>::computeElemNeighJacobian(Moose::DGJacobianType type)
     232             : {
     233       32576 :   const TemplateVariableTestValue & test_space =
     234       32576 :       (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
     235       32576 :   const TemplateVariableTestValue & loc_phi =
     236       32576 :       (type == Moose::ElementElement || type == Moose::NeighborElement) ? _phi : _phi_neighbor;
     237             : 
     238             :   unsigned int ivar, jvar;
     239             : 
     240       32576 :   switch (type)
     241             :   {
     242        9644 :     case Moose::ElementElement:
     243        9644 :       ivar = jvar = _var.number();
     244        9644 :       break;
     245        6664 :     case Moose::ElementNeighbor:
     246        6664 :       ivar = _var.number(), jvar = _neighbor_var.number();
     247        6664 :       break;
     248        6664 :     case Moose::NeighborElement:
     249        6664 :       ivar = _neighbor_var.number(), jvar = _var.number();
     250        6664 :       break;
     251        9604 :     case Moose::NeighborNeighbor:
     252        9604 :       ivar = _neighbor_var.number(), jvar = _neighbor_var.number();
     253        9604 :       break;
     254           0 :     default:
     255           0 :       mooseError("Unknown DGJacobianType ", type);
     256             :   }
     257             : 
     258       32576 :   if (type == Moose::ElementElement)
     259        9644 :     prepareMatrixTag(_assembly, ivar, jvar);
     260             :   else
     261       22932 :     prepareMatrixTagNeighbor(_assembly, ivar, jvar, type);
     262             : 
     263      109052 :   for (_qp = 0; _qp < _qrule->n_points(); _qp++)
     264             :   {
     265       76476 :     initQpJacobian(type);
     266      589860 :     for (_i = 0; _i < test_space.size(); _i++)
     267     5446472 :       for (_j = 0; _j < loc_phi.size(); _j++)
     268     4933088 :         _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpJacobian(type);
     269             :   }
     270             : 
     271       32576 :   accumulateTaggedLocalMatrix();
     272             : 
     273             :   // To save the diagonal of the Jacobian
     274       32576 :   if (_has_primary_jacobians_saved_in && type == Moose::ElementElement)
     275             :   {
     276          16 :     auto rows = _local_ke.m();
     277          16 :     DenseVector<Number> diag(rows);
     278          48 :     for (decltype(rows) i = 0; i < rows; i++)
     279          32 :       diag(i) = _local_ke(i, i);
     280             : 
     281          16 :     Threads::spin_mutex::scoped_lock lock(_jacoby_vars_mutex);
     282          32 :     for (const auto & var : _primary_save_in_jacobian_variables)
     283          16 :       var->sys().solution().add_vector(diag, var->dofIndices());
     284          16 :   }
     285       32560 :   else if (_has_secondary_jacobians_saved_in && type == Moose::NeighborNeighbor)
     286             :   {
     287          16 :     auto rows = _local_ke.m();
     288          16 :     DenseVector<Number> diag(rows);
     289          48 :     for (decltype(rows) i = 0; i < rows; i++)
     290          32 :       diag(i) = _local_ke(i, i);
     291             : 
     292          16 :     Threads::spin_mutex::scoped_lock lock(_jacoby_vars_mutex);
     293          32 :     for (const auto & var : _secondary_save_in_jacobian_variables)
     294          16 :       var->sys().solution().add_vector(diag, var->dofIndicesNeighbor());
     295          16 :   }
     296       32576 : }
     297             : 
     298             : template <typename T>
     299             : void
     300        2956 : InterfaceKernelTempl<T>::computeJacobian()
     301             : {
     302             :   // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
     303             :   // associated only with the lower-dimensional geometric entity that is the boundary between two
     304             :   // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
     305             :   // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
     306             :   // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
     307             :   // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
     308             :   // to execute in the former case. In the future we should remove this and add some kind of "block"
     309             :   // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
     310             :   // this return
     311        5912 :   if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
     312        2956 :       !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
     313           0 :     return;
     314             : 
     315        2956 :   precalculateJacobian();
     316             : 
     317        2956 :   computeElemNeighJacobian(Moose::ElementElement);
     318        2956 :   if (_same_system)
     319        2940 :     computeElemNeighJacobian(Moose::NeighborNeighbor);
     320             : }
     321             : 
     322             : template <typename T>
     323             : void
     324           0 : InterfaceKernelTempl<T>::computeOffDiagElemNeighJacobian(Moose::DGJacobianType type,
     325             :                                                          unsigned int jvar)
     326             : {
     327           0 :   const TemplateVariableTestValue & test_space =
     328           0 :       (type == Moose::ElementElement || type == Moose::ElementNeighbor) ? _test : _test_neighbor;
     329           0 :   const TemplateVariableTestValue & loc_phi =
     330           0 :       (type == Moose::ElementElement || type == Moose::NeighborElement) ? _phi : _phi_neighbor;
     331             : 
     332             :   unsigned int ivar;
     333             : 
     334           0 :   if (type == Moose::ElementElement || type == Moose::ElementNeighbor)
     335           0 :     ivar = _var.number();
     336             :   else
     337           0 :     ivar = _neighbor_var.number();
     338             : 
     339           0 :   if (type == Moose::ElementElement)
     340           0 :     prepareMatrixTag(_assembly, ivar, jvar);
     341             :   else
     342           0 :     prepareMatrixTagNeighbor(_assembly, ivar, jvar, type);
     343             : 
     344             :   // Prevent calling of Jacobian computation if jvar doesn't lie in the current block
     345           0 :   if ((_local_ke.m() == test_space.size()) && (_local_ke.n() == loc_phi.size()))
     346           0 :     for (_qp = 0; _qp < _qrule->n_points(); _qp++)
     347             :     {
     348           0 :       initQpOffDiagJacobian(type, jvar);
     349           0 :       for (_i = 0; _i < test_space.size(); _i++)
     350           0 :         for (_j = 0; _j < loc_phi.size(); _j++)
     351           0 :           _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpOffDiagJacobian(type, jvar);
     352             :     }
     353             : 
     354           0 :   accumulateTaggedLocalMatrix();
     355           0 : }
     356             : 
     357             : template <typename T>
     358             : void
     359       13497 : InterfaceKernelTempl<T>::computeElementOffDiagJacobian(unsigned int jvar)
     360             : {
     361             :   // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
     362             :   // associated only with the lower-dimensional geometric entity that is the boundary between two
     363             :   // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
     364             :   // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
     365             :   // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
     366             :   // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
     367             :   // to execute in the former case. In the future we should remove this and add some kind of "block"
     368             :   // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
     369             :   // this return
     370       26930 :   if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
     371       13433 :       !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
     372          64 :     return;
     373             : 
     374       13433 :   bool is_jvar_not_interface_var = true;
     375       13433 :   if (jvar == _var.number())
     376             :   {
     377        6732 :     precalculateJacobian();
     378        6732 :     computeElemNeighJacobian(Moose::ElementElement);
     379        6732 :     is_jvar_not_interface_var = false;
     380             :   }
     381       13433 :   if (jvar == _neighbor_var.number() && _same_system)
     382             :   {
     383        6708 :     precalculateJacobian();
     384        6708 :     computeElemNeighJacobian(Moose::ElementNeighbor);
     385        6708 :     is_jvar_not_interface_var = false;
     386             :   }
     387             : 
     388       13433 :   if (is_jvar_not_interface_var)
     389             :   {
     390           0 :     precalculateOffDiagJacobian(jvar);
     391           0 :     computeOffDiagElemNeighJacobian(Moose::ElementElement, jvar);
     392           0 :     computeOffDiagElemNeighJacobian(Moose::ElementNeighbor, jvar);
     393             :   }
     394             : }
     395             : 
     396             : template <typename T>
     397             : void
     398       13473 : InterfaceKernelTempl<T>::computeNeighborOffDiagJacobian(unsigned int jvar)
     399             : {
     400             :   // in the gmsh mesh format (at least in the version 2 format) the "sideset" physical entities are
     401             :   // associated only with the lower-dimensional geometric entity that is the boundary between two
     402             :   // higher-dimensional element faces. It does not have a sidedness to it like the exodus format
     403             :   // does. Consequently we may naively try to execute an interface kernel twice, one time where _var
     404             :   // has dofs on _current_elem *AND* _neighbor_var has dofs on _neighbor_elem, and the other time
     405             :   // where _var has dofs on _neighbor_elem and _neighbor_var has dofs on _current_elem. We only want
     406             :   // to execute in the former case. In the future we should remove this and add some kind of "block"
     407             :   // awareness to interface kernels to avoid all the unnecessary reinit that happens before we hit
     408             :   // this return
     409       26882 :   if (!_var.activeOnSubdomain(_current_elem->subdomain_id()) ||
     410       13409 :       !_neighbor_var.activeOnSubdomain(_neighbor_elem->subdomain_id()))
     411          64 :     return;
     412             : 
     413             :   // We don't care about any contribution to the neighbor Jacobian rows if it's not in the system
     414             :   // we are currently working with (the variable's system)
     415       13409 :   if (!_same_system)
     416           0 :     return;
     417             : 
     418       13409 :   bool is_jvar_not_interface_var = true;
     419       13409 :   if (jvar == _var.number())
     420             :   {
     421        6708 :     precalculateJacobian();
     422        6708 :     computeElemNeighJacobian(Moose::NeighborElement);
     423        6708 :     is_jvar_not_interface_var = false;
     424             :   }
     425       13409 :   if (jvar == _neighbor_var.number())
     426             :   {
     427        6708 :     precalculateJacobian();
     428        6708 :     computeElemNeighJacobian(Moose::NeighborNeighbor);
     429        6708 :     is_jvar_not_interface_var = false;
     430             :   }
     431             : 
     432       13409 :   if (is_jvar_not_interface_var)
     433             :   {
     434           0 :     precalculateOffDiagJacobian(jvar);
     435           0 :     computeOffDiagElemNeighJacobian(Moose::NeighborElement, jvar);
     436           0 :     computeOffDiagElemNeighJacobian(Moose::NeighborNeighbor, jvar);
     437             :   }
     438             : }
     439             : 
     440             : template <typename T>
     441             : void
     442          62 : InterfaceKernelTempl<T>::computeResidualAndJacobian()
     443             : {
     444          62 :   computeResidual();
     445             : 
     446          62 :   if (!isImplicit())
     447           0 :     return;
     448             : 
     449         238 :   for (const auto & [ivariable, jvariable] : _fe_problem.couplingEntries(_tid, _sys.number()))
     450             :   {
     451         176 :     if (ivariable->isFV())
     452           0 :       continue;
     453             : 
     454         176 :     const unsigned int ivar = ivariable->number();
     455         176 :     const unsigned int jvar = jvariable->number();
     456             : 
     457         176 :     prepareShapes(jvar);
     458         176 :     prepareNeighborShapes(jvar);
     459             : 
     460         176 :     if (_var.number() == ivar)
     461         100 :       computeElementOffDiagJacobian(jvar);
     462             : 
     463         176 :     if (_same_system)
     464         152 :       if (_neighbor_var.number() == ivar)
     465          76 :         computeNeighborOffDiagJacobian(jvar);
     466             :   }
     467             : }
     468             : 
     469             : // Explicitly instantiates the two versions of the InterfaceKernelTempl class
     470             : template class InterfaceKernelTempl<Real>;
     471             : template class InterfaceKernelTempl<RealVectorValue>;

Generated by: LCOV version 1.14