LCOV - code coverage report
Current view: top level - src/linearfvkernels - LinearWCNSFVMomentumFlux.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: 9fc4b0 Lines: 161 173 93.1 %
Date: 2025-08-14 10:14:56 Functions: 17 17 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 "LinearWCNSFVMomentumFlux.h"
      11             : #include "MooseLinearVariableFV.h"
      12             : #include "NSFVUtils.h"
      13             : #include "NS.h"
      14             : #include "RhieChowMassFlux.h"
      15             : #include "LinearFVBoundaryCondition.h"
      16             : #include "LinearFVAdvectionDiffusionBC.h"
      17             : 
      18             : registerMooseObject("NavierStokesApp", LinearWCNSFVMomentumFlux);
      19             : 
      20             : InputParameters
      21        2978 : LinearWCNSFVMomentumFlux::validParams()
      22             : {
      23        2978 :   InputParameters params = LinearFVFluxKernel::validParams();
      24        2978 :   params.addClassDescription("Represents the matrix and right hand side contributions of the "
      25             :                              "stress and advection terms of the momentum equation.");
      26        5956 :   params.addRequiredParam<SolverVariableName>("u", "The velocity in the x direction.");
      27        5956 :   params.addParam<SolverVariableName>("v", "The velocity in the y direction.");
      28        5956 :   params.addParam<SolverVariableName>("w", "The velocity in the z direction.");
      29        5956 :   params.addRequiredParam<UserObjectName>(
      30             :       "rhie_chow_user_object",
      31             :       "The rhie-chow user-object which is used to determine the face velocity.");
      32        2978 :   params.addRequiredParam<MooseFunctorName>(NS::mu, "The diffusion coefficient.");
      33        5956 :   MooseEnum momentum_component("x=0 y=1 z=2");
      34        5956 :   params.addRequiredParam<MooseEnum>(
      35             :       "momentum_component",
      36             :       momentum_component,
      37             :       "The component of the momentum equation that this kernel applies to.");
      38        5956 :   params.addParam<bool>(
      39             :       "use_nonorthogonal_correction",
      40        5956 :       true,
      41             :       "If the nonorthogonal correction should be used when computing the normal gradient.");
      42        5956 :   params.addParam<bool>(
      43        5956 :       "use_deviatoric_terms", false, "If deviatoric terms in the stress terms need to be used.");
      44             : 
      45        2978 :   params += Moose::FV::advectedInterpolationParameter();
      46        2978 :   return params;
      47        2978 : }
      48             : 
      49        1579 : LinearWCNSFVMomentumFlux::LinearWCNSFVMomentumFlux(const InputParameters & params)
      50             :   : LinearFVFluxKernel(params),
      51        1579 :     _dim(_subproblem.mesh().dimension()),
      52        1579 :     _mass_flux_provider(getUserObject<RhieChowMassFlux>("rhie_chow_user_object")),
      53        1579 :     _mu(getFunctor<Real>(getParam<MooseFunctorName>(NS::mu))),
      54        3158 :     _use_nonorthogonal_correction(getParam<bool>("use_nonorthogonal_correction")),
      55        3158 :     _use_deviatoric_terms(getParam<bool>("use_deviatoric_terms")),
      56        1579 :     _advected_interp_coeffs(std::make_pair<Real, Real>(0, 0)),
      57        1579 :     _face_mass_flux(0.0),
      58        1579 :     _boundary_normal_factor(1.0),
      59        1579 :     _stress_matrix_contribution(0.0),
      60        1579 :     _stress_rhs_contribution(0.0),
      61        3158 :     _index(getParam<MooseEnum>("momentum_component")),
      62        1579 :     _u_var(dynamic_cast<const MooseLinearVariableFVReal *>(
      63        3158 :         &_fe_problem.getVariable(_tid, getParam<SolverVariableName>("u")))),
      64        1579 :     _v_var(params.isParamValid("v")
      65        3092 :                ? dynamic_cast<const MooseLinearVariableFVReal *>(
      66        6118 :                      &_fe_problem.getVariable(_tid, getParam<SolverVariableName>("v")))
      67             :                : nullptr),
      68        1579 :     _w_var(params.isParamValid("w")
      69        1660 :                ? dynamic_cast<const MooseLinearVariableFVReal *>(
      70        1822 :                      &_fe_problem.getVariable(_tid, getParam<SolverVariableName>("w")))
      71        1579 :                : nullptr)
      72             : {
      73             :   // We only need gradients if the nonorthogonal correction is enabled or when we request the
      74             :   // computation of the deviatoric parts of the stress tensor.
      75        1579 :   if (_use_nonorthogonal_correction || _use_deviatoric_terms)
      76         460 :     _var.computeCellGradients();
      77             : 
      78        1579 :   Moose::FV::setInterpolationMethod(*this, _advected_interp_method, "advected_interp_method");
      79             : 
      80        1579 :   if (!_u_var)
      81           0 :     paramError("u", "the u velocity must be a MooseLinearVariableFVReal.");
      82             : 
      83        1579 :   if (_dim >= 2 && !_v_var)
      84           0 :     paramError("v",
      85             :                "In two or more dimensions, the v velocity must be supplied and it must be a "
      86             :                "MooseLinearVariableFVReal.");
      87             : 
      88        1579 :   if (_dim >= 3 && !_w_var)
      89           0 :     paramError("w",
      90             :                "In three-dimensions, the w velocity must be supplied and it must be a "
      91             :                "MooseLinearVariableFVReal.");
      92        1579 : }
      93             : 
      94             : Real
      95    40800507 : LinearWCNSFVMomentumFlux::computeElemMatrixContribution()
      96             : {
      97    40800507 :   return (computeInternalAdvectionElemMatrixContribution() +
      98    40800507 :           computeInternalStressMatrixContribution()) *
      99    40800507 :          _current_face_area;
     100             : }
     101             : 
     102             : Real
     103    40800507 : LinearWCNSFVMomentumFlux::computeNeighborMatrixContribution()
     104             : {
     105    40800507 :   return (computeInternalAdvectionNeighborMatrixContribution() -
     106    40800507 :           computeInternalStressMatrixContribution()) *
     107    40800507 :          _current_face_area;
     108             : }
     109             : 
     110             : Real
     111    40800507 : LinearWCNSFVMomentumFlux::computeElemRightHandSideContribution()
     112             : {
     113    40800507 :   return computeInternalStressRHSContribution() * _current_face_area;
     114             : }
     115             : 
     116             : Real
     117    40800507 : LinearWCNSFVMomentumFlux::computeNeighborRightHandSideContribution()
     118             : {
     119    40800507 :   return -computeInternalStressRHSContribution() * _current_face_area;
     120             : }
     121             : 
     122             : Real
     123     5332854 : LinearWCNSFVMomentumFlux::computeBoundaryMatrixContribution(const LinearFVBoundaryCondition & bc)
     124             : {
     125             :   const auto * const adv_diff_bc = static_cast<const LinearFVAdvectionDiffusionBC *>(&bc);
     126             :   mooseAssert(adv_diff_bc, "This should be a valid BC!");
     127     5332854 :   return (computeStressBoundaryMatrixContribution(adv_diff_bc) +
     128     5332854 :           computeAdvectionBoundaryMatrixContribution(adv_diff_bc)) *
     129     5332854 :          _current_face_area;
     130             : }
     131             : 
     132             : Real
     133     5332854 : LinearWCNSFVMomentumFlux::computeBoundaryRHSContribution(const LinearFVBoundaryCondition & bc)
     134             : {
     135             :   const auto * const adv_diff_bc = static_cast<const LinearFVAdvectionDiffusionBC *>(&bc);
     136             : 
     137             :   mooseAssert(adv_diff_bc, "This should be a valid BC!");
     138     5332854 :   return (computeStressBoundaryRHSContribution(adv_diff_bc) +
     139     5332854 :           computeAdvectionBoundaryRHSContribution(adv_diff_bc)) *
     140     5332854 :          _current_face_area;
     141             : }
     142             : 
     143             : Real
     144    40800507 : LinearWCNSFVMomentumFlux::computeInternalAdvectionElemMatrixContribution()
     145             : {
     146    40800507 :   return _advected_interp_coeffs.first * _face_mass_flux;
     147             : }
     148             : 
     149             : Real
     150    40800507 : LinearWCNSFVMomentumFlux::computeInternalAdvectionNeighborMatrixContribution()
     151             : {
     152    40800507 :   return _advected_interp_coeffs.second * _face_mass_flux;
     153             : }
     154             : 
     155             : Real
     156    81601014 : LinearWCNSFVMomentumFlux::computeInternalStressMatrixContribution()
     157             : {
     158             :   // If we don't have the value yet, we compute it
     159    81601014 :   if (!_cached_matrix_contribution)
     160             :   {
     161    40800507 :     const auto face_arg = makeCDFace(*_current_face_info);
     162             : 
     163             :     // If we requested nonorthogonal correction, we use the normal component of the
     164             :     // cell to face vector.
     165    40800507 :     const auto d = _use_nonorthogonal_correction
     166    40800507 :                        ? std::abs(_current_face_info->dCN() * _current_face_info->normal())
     167    30881283 :                        : _current_face_info->dCNMag();
     168             : 
     169             :     // Cache the matrix contribution
     170    40800507 :     _stress_matrix_contribution = _mu(face_arg, determineState()) / d;
     171    40800507 :     _cached_matrix_contribution = true;
     172             :   }
     173             : 
     174    81601014 :   return _stress_matrix_contribution;
     175             : }
     176             : 
     177             : Real
     178    81601014 : LinearWCNSFVMomentumFlux::computeInternalStressRHSContribution()
     179             : {
     180             :   // We can have contributions to the right hand side in two occasions:
     181             :   // (1) when we use nonorthogonal correction for the normal gradients
     182             :   // (2) when we request the deviatoric parts of the stress tensor. (needed for space-dependent
     183             :   // viscosities for example)
     184    81601014 :   if (!_cached_rhs_contribution)
     185             :   {
     186             :     // scenario (1), we need to add the nonorthogonal correction. In 1D, we don't have
     187             :     // any correction so we just skip this part
     188    40800507 :     if (_dim > 1 && _use_nonorthogonal_correction)
     189             :     {
     190     9919224 :       const auto face_arg = makeCDFace(*_current_face_info);
     191     9919224 :       const auto state_arg = determineState();
     192             : 
     193             :       // Get the gradients from the adjacent cells
     194     9919224 :       const auto grad_elem = _var.gradSln(*_current_face_info->elemInfo());
     195     9919224 :       const auto & grad_neighbor = _var.gradSln(*_current_face_info->neighborInfo());
     196             : 
     197             :       // Interpolate the two gradients to the face
     198             :       const auto interp_coeffs =
     199     9919224 :           interpCoeffs(Moose::FV::InterpMethod::Average, *_current_face_info, true);
     200             : 
     201             :       const auto correction_vector =
     202             :           _current_face_info->normal() -
     203     9919224 :           1 / (_current_face_info->normal() * _current_face_info->eCN()) *
     204             :               _current_face_info->eCN();
     205             : 
     206             :       // Cache the matrix contribution
     207     9919224 :       _stress_rhs_contribution +=
     208     9919224 :           _mu(face_arg, state_arg) *
     209             :           (interp_coeffs.first * grad_elem + interp_coeffs.second * grad_neighbor) *
     210             :           correction_vector;
     211             :     }
     212             :     // scenario (2), we will have to account for the deviatoric parts of the stress tensor.
     213    40800507 :     if (_use_deviatoric_terms)
     214             :     {
     215             :       // Interpolate the two gradients to the face
     216             :       const auto interp_coeffs =
     217     8372720 :           interpCoeffs(Moose::FV::InterpMethod::Average, *_current_face_info, true);
     218             : 
     219     8372720 :       const auto u_grad_elem = _u_var->gradSln(*_current_face_info->elemInfo());
     220     8372720 :       const auto u_grad_neighbor = _u_var->gradSln(*_current_face_info->neighborInfo());
     221             : 
     222             :       Real trace_elem = 0;
     223             :       Real trace_neighbor = 0;
     224             :       RealVectorValue deviatoric_vector_elem;
     225             :       RealVectorValue deviatoric_vector_neighbor;
     226             : 
     227     8372720 :       deviatoric_vector_elem(0) = u_grad_elem(_index);
     228     8372720 :       deviatoric_vector_neighbor(0) = u_grad_neighbor(_index);
     229     8372720 :       trace_elem += u_grad_elem(0);
     230     8372720 :       trace_neighbor += u_grad_neighbor(0);
     231             : 
     232     8372720 :       const auto face_arg = makeCDFace(*_current_face_info);
     233     8372720 :       const auto state_arg = determineState();
     234             : 
     235     8372720 :       if (_dim > 1)
     236             :       {
     237     8372720 :         const auto v_grad_elem = _v_var->gradSln(*_current_face_info->elemInfo());
     238     8372720 :         const auto v_grad_neighbor = _v_var->gradSln(*_current_face_info->neighborInfo());
     239             : 
     240     8372720 :         deviatoric_vector_elem(1) = v_grad_elem(_index);
     241     8372720 :         deviatoric_vector_neighbor(1) = v_grad_neighbor(_index);
     242     8372720 :         trace_elem += v_grad_elem(1);
     243     8372720 :         trace_neighbor += v_grad_neighbor(1);
     244     8372720 :         if (_dim > 2)
     245             :         {
     246           0 :           const auto w_grad_elem = _w_var->gradSln(*_current_face_info->elemInfo());
     247           0 :           const auto w_grad_neighbor = _w_var->gradSln(*_current_face_info->neighborInfo());
     248             : 
     249           0 :           deviatoric_vector_elem(2) = w_grad_elem(_index);
     250           0 :           deviatoric_vector_neighbor(2) = w_grad_neighbor(_index);
     251           0 :           trace_elem += w_grad_elem(2);
     252           0 :           trace_neighbor += w_grad_neighbor(2);
     253             :         }
     254             :       }
     255     8372720 :       deviatoric_vector_elem(_index) -= 2 / 3 * trace_elem;
     256     8372720 :       deviatoric_vector_neighbor(_index) -= 2 / 3 * trace_neighbor;
     257             : 
     258     8372720 :       _stress_rhs_contribution += _mu(face_arg, state_arg) *
     259             :                                   (interp_coeffs.first * deviatoric_vector_elem +
     260             :                                    interp_coeffs.second * deviatoric_vector_neighbor) *
     261     8372720 :                                   _current_face_info->normal();
     262             :     }
     263    40800507 :     _cached_rhs_contribution = true;
     264             :   }
     265             : 
     266    81601014 :   return _stress_rhs_contribution;
     267             : }
     268             : 
     269             : Real
     270     5332854 : LinearWCNSFVMomentumFlux::computeStressBoundaryMatrixContribution(
     271             :     const LinearFVAdvectionDiffusionBC * bc)
     272             : {
     273     5332854 :   auto grad_contrib = bc->computeBoundaryGradientMatrixContribution();
     274             :   // If the boundary condition does not include the diffusivity contribution then
     275             :   // add it here.
     276     5332854 :   if (!bc->includesMaterialPropertyMultiplier())
     277             :   {
     278     5332854 :     const auto face_arg = singleSidedFaceArg(_current_face_info);
     279     5332854 :     grad_contrib *= _mu(face_arg, determineState());
     280             :   }
     281             : 
     282     5332854 :   return grad_contrib;
     283             : }
     284             : 
     285             : Real
     286     5332854 : LinearWCNSFVMomentumFlux::computeStressBoundaryRHSContribution(
     287             :     const LinearFVAdvectionDiffusionBC * bc)
     288             : {
     289     5332854 :   const auto face_arg = singleSidedFaceArg(_current_face_info);
     290     5332854 :   auto grad_contrib = bc->computeBoundaryGradientRHSContribution();
     291             : 
     292             :   // If the boundary condition does not include the diffusivity contribution then
     293             :   // add it here.
     294     5332854 :   if (!bc->includesMaterialPropertyMultiplier())
     295     5332854 :     grad_contrib *= _mu(face_arg, determineState());
     296             : 
     297             :   // We add the nonorthogonal corrector for the face here. Potential idea: we could do
     298             :   // this in the boundary condition too. For now, however, we keep it like this.
     299     5332854 :   if (_use_nonorthogonal_correction)
     300             :   {
     301             :     // We support internal boundaries as well. In that case we have to decide on which side
     302             :     // of the boundary we are on.
     303      992256 :     const auto elem_info = (_current_face_type == FaceInfo::VarFaceNeighbors::ELEM)
     304      992256 :                                ? _current_face_info->elemInfo()
     305       26976 :                                : _current_face_info->neighborInfo();
     306             : 
     307             :     // Unit vector to the boundary. Unfortunately, we have to recompute it because the value
     308             :     // stored in the face info is only correct for external boundaries
     309      992256 :     const auto e_Cf = _current_face_info->faceCentroid() - elem_info->centroid();
     310             :     const auto correction_vector =
     311      992256 :         _current_face_info->normal() - 1 / (_current_face_info->normal() * e_Cf) * e_Cf;
     312             : 
     313      992256 :     grad_contrib += _mu(face_arg, determineState()) * _var.gradSln(*elem_info) *
     314             :                     _boundary_normal_factor * correction_vector;
     315             :   }
     316             : 
     317     5332854 :   if (_use_deviatoric_terms)
     318             :   {
     319             :     // We might be on a face which is an internal boundary so we want to make sure we
     320             :     // get the gradient from the right side.
     321     1108096 :     const auto elem_info = (_current_face_type == FaceInfo::VarFaceNeighbors::ELEM)
     322     1108096 :                                ? _current_face_info->elemInfo()
     323       16072 :                                : _current_face_info->neighborInfo();
     324             : 
     325     1108096 :     const auto u_grad_elem = _u_var->gradSln(*elem_info);
     326             : 
     327             :     Real trace_elem = 0;
     328             :     RealVectorValue frace_grad_approx;
     329             : 
     330     1108096 :     trace_elem += u_grad_elem(0);
     331     1108096 :     frace_grad_approx(0) = u_grad_elem(_index);
     332             : 
     333     1108096 :     const auto state_arg = determineState();
     334             : 
     335     1108096 :     if (_dim > 1)
     336             :     {
     337     1108096 :       const auto v_grad_elem = _v_var->gradSln(*elem_info);
     338     1108096 :       trace_elem += v_grad_elem(1);
     339     1108096 :       frace_grad_approx(1) = v_grad_elem(_index);
     340             : 
     341     1108096 :       if (_dim > 2)
     342             :       {
     343           0 :         const auto w_grad_elem = _w_var->gradSln(*elem_info);
     344           0 :         trace_elem += w_grad_elem(2);
     345           0 :         frace_grad_approx(2) = w_grad_elem(_index);
     346             :       }
     347             :     }
     348             : 
     349     1108096 :     frace_grad_approx(_index) -= 2 / 3 * trace_elem;
     350             : 
     351             :     // We support internal boundaries too so we have to make sure the normal points always outward
     352     1108096 :     grad_contrib += _mu(face_arg, state_arg) * frace_grad_approx * _boundary_normal_factor *
     353     1108096 :                     _current_face_info->normal();
     354             :   }
     355             : 
     356     5332854 :   return grad_contrib;
     357             : }
     358             : 
     359             : Real
     360     5332854 : LinearWCNSFVMomentumFlux::computeAdvectionBoundaryMatrixContribution(
     361             :     const LinearFVAdvectionDiffusionBC * bc)
     362             : {
     363     5332854 :   const auto boundary_value_matrix_contrib = bc->computeBoundaryValueMatrixContribution();
     364     5332854 :   return boundary_value_matrix_contrib * _face_mass_flux;
     365             : }
     366             : 
     367             : Real
     368     5332854 : LinearWCNSFVMomentumFlux::computeAdvectionBoundaryRHSContribution(
     369             :     const LinearFVAdvectionDiffusionBC * bc)
     370             : {
     371     5332854 :   const auto boundary_value_rhs_contrib = bc->computeBoundaryValueRHSContribution();
     372     5332854 :   return -boundary_value_rhs_contrib * _face_mass_flux;
     373             : }
     374             : 
     375             : void
     376    46133361 : LinearWCNSFVMomentumFlux::setupFaceData(const FaceInfo * face_info)
     377             : {
     378    46133361 :   LinearFVFluxKernel::setupFaceData(face_info);
     379             : 
     380             :   // Multiplier that ensures the normal of the boundary always points outwards, even in cases
     381             :   // when the boundary is within the mesh.
     382    46133361 :   _boundary_normal_factor = (_current_face_type == FaceInfo::VarFaceNeighbors::ELEM) ? 1.0 : -1.0;
     383             : 
     384             :   // Caching the mass flux on the face which will be reused in the advection term's matrix and
     385             :   // right hand side contributions
     386    46133361 :   _face_mass_flux = _mass_flux_provider.getMassFlux(*face_info);
     387             : 
     388             :   // Caching the interpolation coefficients so they will be reused for the matrix and right hand
     389             :   // side terms
     390             :   _advected_interp_coeffs =
     391    46133361 :       interpCoeffs(_advected_interp_method, *_current_face_info, true, _face_mass_flux);
     392             : 
     393             :   // We'll have to set this to zero to make sure that we don't accumulate values over multiple
     394             :   // faces. The matrix contribution should be fine.
     395    46133361 :   _stress_rhs_contribution = 0;
     396    46133361 : }

Generated by: LCOV version 1.14