LCOV - code coverage report
Current view: top level - src/linearfvkernels - LinearFVDiffusion.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 89 95 93.7 %
Date: 2026-05-29 20:35:17 Functions: 13 13 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 "LinearFVDiffusion.h"
      11             : #include "Assembly.h"
      12             : #include "SubProblem.h"
      13             : #include "LinearFVAdvectionDiffusionBC.h"
      14             : 
      15             : registerMooseObject("MooseApp", LinearFVDiffusion);
      16             : 
      17             : InputParameters
      18        4151 : LinearFVDiffusion::validParams()
      19             : {
      20        4151 :   InputParameters params = LinearFVFluxKernel::validParams();
      21        8302 :   params.addClassDescription("Represents the matrix and right hand side contributions of a "
      22             :                              "diffusion term in a partial differential equation.");
      23       12453 :   params.addParam<bool>(
      24             :       "use_nonorthogonal_correction",
      25        8302 :       true,
      26             :       "If the nonorthogonal correction should be used when computing the normal gradient.");
      27       16604 :   params.addParam<MooseFunctorName>("diffusion_coeff", 1.0, "The diffusion coefficient.");
      28       12453 :   params.addParam<InterpolationMethodName>(
      29             :       "coeff_interp_method",
      30             :       "Optional finite volume interpolation method used to compute a face-centered diffusion "
      31             :       "coefficient. If omitted, the functor is evaluated directly on the face.");
      32        4151 :   return params;
      33           0 : }
      34             : 
      35         545 : LinearFVDiffusion::LinearFVDiffusion(const InputParameters & params)
      36             :   : LinearFVFluxKernel(params),
      37             :     FVInterpolationMethodInterface(this),
      38         545 :     _diffusion_coeff(getFunctor<Real>("diffusion_coeff")),
      39        1090 :     _coeff_interp_method(isParamValid("coeff_interp_method")
      40         545 :                              ? &getFVFaceInterpolationMethod(
      41             :                                    getParam<InterpolationMethodName>("coeff_interp_method"))
      42             :                              : nullptr),
      43        1090 :     _use_nonorthogonal_correction(getParam<bool>("use_nonorthogonal_correction")),
      44         545 :     _flux_matrix_contribution(0.0),
      45         545 :     _flux_rhs_contribution(0.0),
      46         545 :     _cached_face_diffusivity(false),
      47         545 :     _face_diffusivity(0.0)
      48             : {
      49         545 :   if (_use_nonorthogonal_correction)
      50         348 :     _var.computeCellGradients();
      51         545 : }
      52             : 
      53             : Real
      54      946323 : LinearFVDiffusion::faceDiffusivity() const
      55             : {
      56      946323 :   if (!_cached_face_diffusivity)
      57             :   {
      58             :     mooseAssert(_current_face_type == FaceInfo::VarFaceNeighbors::BOTH,
      59             :                 "faceDiffusivity() is only valid for two-sided internal faces.");
      60             : 
      61      521659 :     const auto state = determineState();
      62             : 
      63      521659 :     if (_coeff_interp_method)
      64           0 :       _face_diffusivity =
      65           0 :           _coeff_interp_method->interpolate(_diffusion_coeff, *_current_face_info, state);
      66             :     else
      67      521659 :       _face_diffusivity = _diffusion_coeff(makeCDFace(*_current_face_info), state);
      68             : 
      69      521659 :     _cached_face_diffusivity = true;
      70             :   }
      71             : 
      72      946323 :   return _face_diffusivity;
      73             : }
      74             : 
      75             : void
      76      578015 : LinearFVDiffusion::setupFaceData(const FaceInfo * face_info)
      77             : {
      78      578015 :   LinearFVFluxKernel::setupFaceData(face_info);
      79      578015 :   _cached_face_diffusivity = false;
      80      578015 : }
      81             : 
      82             : void
      83         565 : LinearFVDiffusion::initialSetup()
      84             : {
      85        2083 :   for (const auto bc : _var.getBoundaryConditionMap())
      86        1518 :     if (!dynamic_cast<const LinearFVAdvectionDiffusionBC *>(bc.second))
      87           0 :       mooseError(
      88           0 :           bc.second->type(), " is not a compatible boundary condition with ", this->type(), "!");
      89         565 : }
      90             : 
      91             : Real
      92      521659 : LinearFVDiffusion::computeElemMatrixContribution()
      93             : {
      94      521659 :   return computeFluxMatrixContribution();
      95             : }
      96             : 
      97             : Real
      98      521659 : LinearFVDiffusion::computeNeighborMatrixContribution()
      99             : {
     100      521659 :   return -computeFluxMatrixContribution();
     101             : }
     102             : 
     103             : Real
     104      521659 : LinearFVDiffusion::computeElemRightHandSideContribution()
     105             : {
     106      521659 :   return computeFluxRHSContribution();
     107             : }
     108             : 
     109             : Real
     110      521659 : LinearFVDiffusion::computeNeighborRightHandSideContribution()
     111             : {
     112      521659 :   return -computeFluxRHSContribution();
     113             : }
     114             : 
     115             : Real
     116     1043318 : LinearFVDiffusion::computeFluxMatrixContribution()
     117             : {
     118             :   // If we don't have the value yet, we compute it
     119     1043318 :   if (!_cached_matrix_contribution)
     120             :   {
     121             :     // If we requested nonorthogonal correction, we use the normal component of the
     122             :     // cell to face vector.
     123      521659 :     const auto d = _use_nonorthogonal_correction
     124      521659 :                        ? std::abs(_current_face_info->dCN() * _current_face_info->normal())
     125       96995 :                        : _current_face_info->dCNMag();
     126             : 
     127             :     // Cache the matrix contribution
     128      521659 :     _flux_matrix_contribution = faceDiffusivity() / d * _current_face_area;
     129      521659 :     _cached_matrix_contribution = true;
     130             :   }
     131             : 
     132     1043318 :   return _flux_matrix_contribution;
     133             : }
     134             : 
     135             : Real
     136     1043318 : LinearFVDiffusion::computeFluxRHSContribution()
     137             : {
     138             :   // We only have contributions on the right hand side from internal faces
     139             :   // if the nonorthogonal correction is enabled.
     140     1043318 :   if (_use_nonorthogonal_correction && !_cached_rhs_contribution)
     141             :   {
     142      424664 :     const auto state = determineState();
     143             : 
     144             :     // Get the gradients from the adjacent cells
     145      424664 :     const auto grad_elem = _var.gradSln(*_current_face_info->elemInfo(), state);
     146      424664 :     const auto & grad_neighbor = _var.gradSln(*_current_face_info->neighborInfo(), state);
     147             : 
     148             :     // Interpolate the two gradients to the face
     149             :     const auto interp_coeffs =
     150      424664 :         interpCoeffs(Moose::FV::InterpMethod::Average, *_current_face_info, true);
     151             : 
     152             :     // Compute correction vector. Potential optimization: this only depends on the geometry
     153             :     // so we can cache it in FaceInfo at some point.
     154             :     const auto correction_vector =
     155      424664 :         _current_face_info->normal() -
     156      849328 :         1 / (_current_face_info->normal() * _current_face_info->eCN()) * _current_face_info->eCN();
     157             : 
     158             :     // Cache the matrix contribution
     159      424664 :     _flux_rhs_contribution =
     160      424664 :         faceDiffusivity() *
     161      849328 :         (interp_coeffs.first * grad_elem + interp_coeffs.second * grad_neighbor) *
     162      424664 :         correction_vector * _current_face_area;
     163      424664 :     _cached_rhs_contribution = true;
     164             :   }
     165             : 
     166     1043318 :   return _flux_rhs_contribution;
     167             : }
     168             : 
     169             : Real
     170       50516 : LinearFVDiffusion::computeBoundaryMatrixContribution(const LinearFVBoundaryCondition & bc)
     171             : {
     172       50516 :   const auto * const diff_bc = static_cast<const LinearFVAdvectionDiffusionBC *>(&bc);
     173             :   mooseAssert(diff_bc, "This should be a valid BC!");
     174             : 
     175       50516 :   auto grad_contrib = diff_bc->computeBoundaryGradientMatrixContribution() * _current_face_area;
     176             :   // If the boundary condition does not include the diffusivity contribution then
     177             :   // add it here.
     178       50516 :   if (!diff_bc->includesMaterialPropertyMultiplier())
     179             :   {
     180       37247 :     const auto face_arg = singleSidedFaceArg(_current_face_info);
     181       37247 :     grad_contrib *= _diffusion_coeff(face_arg, determineState());
     182             :   }
     183             : 
     184       50516 :   return grad_contrib;
     185             : }
     186             : 
     187             : Real
     188       50516 : LinearFVDiffusion::computeBoundaryRHSContribution(const LinearFVBoundaryCondition & bc)
     189             : {
     190       50516 :   const auto * const diff_bc = static_cast<const LinearFVAdvectionDiffusionBC *>(&bc);
     191             :   mooseAssert(diff_bc, "This should be a valid BC!");
     192             : 
     193       50516 :   const auto face_arg = singleSidedFaceArg(_current_face_info);
     194       50516 :   const auto state = determineState();
     195       50516 :   auto grad_contrib = diff_bc->computeBoundaryGradientRHSContribution() * _current_face_area;
     196             : 
     197             :   // If the boundary condition does not include the diffusivity contribution then
     198             :   // add it here.
     199       50516 :   if (!diff_bc->includesMaterialPropertyMultiplier())
     200       37247 :     grad_contrib *= _diffusion_coeff(face_arg, state);
     201             : 
     202             :   // We add the nonorthogonal corrector for the face here. Potential idea: we could do
     203             :   // this in the boundary condition too. For now, however, we keep it like this.
     204             :   // This should only be used for BCs where the gradient of the value is computed and
     205             :   // not prescribed.
     206             : 
     207       50516 :   if (_use_nonorthogonal_correction && diff_bc->useBoundaryGradientExtrapolation())
     208             :   {
     209             :     // We support internal boundaries as well. In that case we have to decide on which side
     210             :     // of the boundary we are on.
     211       28645 :     const auto elem_info = (_current_face_type == FaceInfo::VarFaceNeighbors::ELEM)
     212       28645 :                                ? _current_face_info->elemInfo()
     213           0 :                                : _current_face_info->neighborInfo();
     214       28645 :     const Real boundary_normal_multiplier =
     215       28645 :         (_current_face_type == FaceInfo::VarFaceNeighbors::ELEM) ? 1.0 : -1.0;
     216             : 
     217             :     // Unit vector to the boundary. Unfortunately, we have to recompute it because the value
     218             :     // stored in the face info is only correct for external boundaries
     219       28645 :     const auto e_Cf = _current_face_info->faceCentroid() - elem_info->centroid();
     220             :     const auto correction_vector =
     221       28645 :         _current_face_info->normal() - 1 / (_current_face_info->normal() * e_Cf) * e_Cf;
     222             : 
     223       28645 :     grad_contrib += _diffusion_coeff(face_arg, state) * _var.gradSln(*elem_info, state) *
     224       28645 :                     boundary_normal_multiplier * correction_vector * _current_face_area;
     225             :   }
     226             : 
     227       50516 :   return grad_contrib;
     228             : }

Generated by: LCOV version 1.14