LCOV - code coverage report
Current view: top level - src/fvkernels - INSFVMomentumDiffusion.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: #32971 (54bef8) with base c6cf66 Lines: 92 116 79.3 %
Date: 2026-05-29 20:37:52 Functions: 5 5 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 "INSFVMomentumDiffusion.h"
      11             : #include "INSFVRhieChowInterpolator.h"
      12             : #include "NS.h"
      13             : #include "NavierStokesMethods.h"
      14             : #include "SystemBase.h"
      15             : #include "NonlinearSystemBase.h"
      16             : #include "RelationshipManager.h"
      17             : #include "Factory.h"
      18             : #include "libmesh/nonlinear_solver.h"
      19             : 
      20             : registerMooseObject("NavierStokesApp", INSFVMomentumDiffusion);
      21             : 
      22             : InputParameters
      23       18369 : INSFVMomentumDiffusion::validParams()
      24             : {
      25       18369 :   auto params = INSFVFluxKernel::validParams();
      26       18369 :   params += FVDiffusionInterpolationInterface::validParams();
      27       18369 :   params.addRequiredParam<MooseFunctorName>(NS::mu, "The viscosity");
      28       18369 :   params.addClassDescription(
      29             :       "Implements the Laplace form of the viscous stress in the Navier-Stokes equation.");
      30             : 
      31       36738 :   MooseEnum coeff_interp_method("average harmonic", "harmonic");
      32       36738 :   params.addParam<MooseEnum>("mu_interp_method",
      33             :                              coeff_interp_method,
      34             :                              "Switch that can select face interpolation method for the viscosity.");
      35       18369 :   params.set<unsigned short>("ghost_layers") = 2;
      36             : 
      37             :   // We add the relationship manager here, this will select the right number of
      38             :   // ghosting layers depending on the chosen interpolation method
      39       36738 :   params.addRelationshipManager(
      40             :       "ElementSideNeighborLayers",
      41             :       Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC |
      42             :           Moose::RelationshipManagerType::COUPLING,
      43             :       [](const InputParameters & obj_params, InputParameters & rm_params)
      44       21845 :       { FVRelationshipManagerInterface::setRMParamsDiffusion(obj_params, rm_params, 3); });
      45             : 
      46       36738 :   params.addParam<bool>(
      47             :       "complete_expansion",
      48       36738 :       false,
      49             :       "Boolean parameter to use complete momentum expansion is the diffusion term.");
      50       36738 :   params.addParam<bool>("include_isotropic_viscous_stress",
      51       36738 :                         false,
      52             :                         "Add the -(2/3) mu div(u) I term (requires specifying the velocity "
      53             :                         "components via 'u', 'v', 'w'). Only meaningful for "
      54             :                         "weakly-compressible formulations.");
      55       36738 :   params.addParam<MooseFunctorName>("u", "The velocity in the x direction.");
      56       36738 :   params.addParam<MooseFunctorName>("v", "The velocity in the y direction.");
      57       36738 :   params.addParam<MooseFunctorName>("w", "The velocity in the z direction.");
      58       36738 :   params.addParam<bool>(
      59       36738 :       "limit_interpolation", false, "Flag to limit interpolation to positive values.");
      60       36738 :   params.addParam<bool>("newton_solve", false, "Whether a Newton nonlinear solve is being used");
      61       36738 :   params.addParamNamesToGroup("newton_solve", "Advanced");
      62       18369 :   return params;
      63       18369 : }
      64             : 
      65       10021 : INSFVMomentumDiffusion::INSFVMomentumDiffusion(const InputParameters & params)
      66             :   : INSFVFluxKernel(params),
      67             :     FVDiffusionInterpolationInterface(params),
      68       20042 :     _mu(getFunctor<ADReal>(NS::mu)),
      69       10021 :     _mu_interp_method(
      70       20042 :         Moose::FV::selectInterpolationMethod(getParam<MooseEnum>("mu_interp_method"))),
      71       12057 :     _u_var(params.isParamValid("u") ? &getFunctor<ADReal>("u") : nullptr),
      72       12057 :     _v_var(params.isParamValid("v") ? &getFunctor<ADReal>("v") : nullptr),
      73       10021 :     _w_var(params.isParamValid("w") ? &getFunctor<ADReal>("w") : nullptr),
      74       20042 :     _complete_expansion(getParam<bool>("complete_expansion")),
      75       20042 :     _include_isotropic_viscous_stress(getParam<bool>("include_isotropic_viscous_stress")),
      76       20042 :     _limit_interpolation(getParam<bool>("limit_interpolation")),
      77       10021 :     _dim(_subproblem.mesh().dimension()),
      78       40084 :     _newton_solve(getParam<bool>("newton_solve"))
      79             : {
      80       10021 :   if (_complete_expansion && !_u_var)
      81           0 :     paramError("u", "The u velocity must be defined when 'complete_expansion=true'.");
      82             : 
      83       10021 :   if (_complete_expansion && _dim >= 2 && !_v_var)
      84           0 :     paramError("v",
      85             :                "The v velocity must be defined when 'complete_expansion=true'"
      86             :                "and problem dimension is larger or equal to 2.");
      87             : 
      88       10021 :   if (_complete_expansion && _dim >= 3 && !_w_var)
      89           0 :     paramError("w",
      90             :                "The w velocity must be defined when 'complete_expansion=true'"
      91             :                "and problem dimension is larger or equal to three.");
      92             : 
      93       10021 :   if (_include_isotropic_viscous_stress)
      94             :   {
      95           0 :     if (!_complete_expansion)
      96           0 :       paramError("include_isotropic_viscous_stress",
      97             :                  "Complete expansion needs to be enabled to use the isotropic viscous stress!");
      98             : 
      99           0 :     if (!_u_var)
     100           0 :       paramError("include_isotropic_viscous_stress",
     101             :                  "Velocity components must be provided to use the "
     102             :                  "'include_isotropic_viscous_stress' option.");
     103           0 :     if (_dim >= 2 && !_v_var)
     104           0 :       paramError("include_isotropic_viscous_stress",
     105             :                  "Velocity components must be provided to use the "
     106             :                  "'include_isotropic_viscous_stress' option in dimensions >= 2.");
     107           0 :     if (_dim >= 3 && !_w_var)
     108           0 :       paramError("include_isotropic_viscous_stress",
     109             :                  "Velocity components must be provided to use the "
     110             :                  "'include_isotropic_viscous_stress' option in 3D.");
     111             :   }
     112       10021 : }
     113             : 
     114             : ADReal
     115    48239701 : INSFVMomentumDiffusion::computeStrongResidual(const bool populate_a_coeffs)
     116             : {
     117    48239701 :   const Moose::StateArg state = determineState();
     118    48239701 :   const auto dudn = gradUDotNormal(state, _correct_skewness);
     119             :   ADReal face_mu;
     120             : 
     121    48239701 :   if (onBoundary(*_face_info))
     122     4435102 :     face_mu = _mu(makeCDFace(*_face_info), state);
     123             :   else
     124    43804599 :     Moose::FV::interpolate(_mu_interp_method,
     125             :                            face_mu,
     126    43804599 :                            _mu(elemArg(), state),
     127    87609198 :                            _mu(neighborArg(), state),
     128    43804599 :                            *_face_info,
     129             :                            true);
     130             : 
     131             :   // Protecting from negative viscosity at interpolation
     132             :   // to preserve convergence
     133    48239701 :   if (face_mu < 0.0)
     134             :   {
     135         144 :     if (!(_limit_interpolation))
     136             :     {
     137          72 :       mooseDoOnce(mooseWarning(
     138             :           "Negative face viscosity has been encountered. Value ",
     139             :           raw_value(face_mu),
     140             :           " at ",
     141             :           _face_info->faceCentroid(),
     142             :           " limiting it to 0!\nFurther warnings for this issue will be silenced, but the "
     143             :           "occurrences will be recorded through the solution invalidity interface."));
     144          78 :       flagInvalidSolution("Negative face dynamic viscosity has been encountered.");
     145             :     }
     146             :     // Keep face_mu here for sparsity pattern detection
     147         288 :     face_mu = 0 * face_mu;
     148             :   }
     149             : 
     150    48239701 :   if (populate_a_coeffs)
     151             :   {
     152    40024607 :     if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     153             :         _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     154             :     {
     155    40024015 :       const auto dof_number = _face_info->elem().dof_number(_sys.number(), _var.number(), 0);
     156             :       // A gradient is a linear combination of degrees of freedom so it's safe to straight-up index
     157             :       // into the derivatives vector at the dof we care about
     158    40024015 :       _ae = dudn.derivatives()[dof_number];
     159    40024015 :       _ae *= -face_mu;
     160             :     }
     161    40024607 :     if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     162             :         _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     163             :     {
     164    37202853 :       const auto dof_number = _face_info->neighbor().dof_number(_sys.number(), _var.number(), 0);
     165    37202853 :       _an = dudn.derivatives()[dof_number];
     166    37202853 :       _an *= face_mu;
     167             :     }
     168             :   }
     169             : 
     170    48239701 :   ADReal dudn_transpose = 0.0;
     171    48239701 :   ADReal divergence_term = 0.0;
     172    48239701 :   if (_complete_expansion)
     173             :   {
     174             :     // Computing the gradient from coupled variables
     175             :     // Normally, we can do this with `_var.gradient(face, state)` but we will need the transpose
     176             :     // gradient. So, we compute all at once
     177             :     Moose::FaceArg face;
     178     1900408 :     if (onBoundary(*_face_info))
     179      283296 :       face = singleSidedFaceArg();
     180             :     else
     181     1617112 :       face = makeCDFace(*_face_info, _correct_skewness);
     182             : 
     183             :     ADRealTensorValue gradient;
     184     1900408 :     if (_dim == 1)
     185             :     {
     186           0 :       const auto & grad_u = _u_var->gradient(face, state);
     187           0 :       gradient = ADRealTensorValue(grad_u, ADRealVectorValue(0, 0, 0), ADRealVectorValue(0, 0, 0));
     188             :     }
     189     1900408 :     else if (_dim == 2)
     190             :     {
     191     1900408 :       const auto & grad_u = _u_var->gradient(face, state);
     192     1900408 :       const auto & grad_v = _v_var->gradient(face, state);
     193     3800816 :       gradient = ADRealTensorValue(grad_u, grad_v, ADRealVectorValue(0, 0, 0));
     194             :     }
     195             :     else // if (_dim == 3)
     196             :     {
     197           0 :       const auto & grad_u = _u_var->gradient(face, state);
     198           0 :       const auto & grad_v = _v_var->gradient(face, state);
     199           0 :       const auto & grad_w = _w_var->gradient(face, state);
     200           0 :       gradient = ADRealTensorValue(grad_u, grad_v, grad_w);
     201             :     }
     202             : 
     203             :     // Getting transpose of the gradient matrix
     204     1900408 :     const auto gradient_transpose = gradient.transpose();
     205             : 
     206     1900408 :     dudn_transpose += gradient_transpose.row(_index) * _face_info->normal();
     207             : 
     208     1900408 :     if (_include_isotropic_viscous_stress)
     209             :     {
     210             :       libMesh::VectorValue<ADReal> velocity;
     211           0 :       velocity(0) = _u_var ? (*_u_var)(face, state) : ADReal(0);
     212           0 :       velocity(1) = _v_var ? (*_v_var)(face, state) : ADReal(0);
     213           0 :       velocity(2) = _w_var ? (*_w_var)(face, state) : ADReal(0);
     214             : 
     215           0 :       const auto coord_sys = _subproblem.getCoordSystem(_face_info->elem().subdomain_id());
     216             :       unsigned int rz_radial_coord =
     217           0 :           coord_sys == Moose::COORD_RZ ? _subproblem.getAxisymmetricRadialCoord() : 0;
     218             :       divergence_term =
     219           0 :           NS::divergence(gradient, velocity, face.getPoint(), coord_sys, rz_radial_coord);
     220             :     }
     221             :   }
     222             : 
     223    48239701 :   ADReal residual = -face_mu * (dudn + dudn_transpose);
     224    48239701 :   if (_complete_expansion && _include_isotropic_viscous_stress)
     225           0 :     residual += (2.0 / 3.0) * face_mu * divergence_term * _face_info->normal()(_index);
     226             : 
     227    48239701 :   return residual;
     228             : }
     229             : 
     230             : void
     231    70355576 : INSFVMomentumDiffusion::gatherRCData(const FaceInfo & fi)
     232             : {
     233    70355576 :   if (skipForBoundary(fi))
     234             :     return;
     235             : 
     236    68708783 :   _face_info = &fi;
     237    68708783 :   _normal = fi.normal();
     238    68708783 :   _face_type = fi.faceType(std::make_pair(_var.number(), _var.sys().number()));
     239             : 
     240   137417566 :   addResidualAndJacobian(computeStrongResidual(true) * (fi.faceArea() * fi.faceCoord()));
     241             : 
     242    68708783 :   if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     243             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     244   137416182 :     _rc_uo.addToA(&fi.elem(), _index, _ae * (fi.faceArea() * fi.faceCoord()));
     245    68708783 :   if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     246             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     247   194820948 :     _rc_uo.addToA(fi.neighborPtr(), _index, _an * (fi.faceArea() * fi.faceCoord()));
     248             : }
     249             : 
     250             : ADReal
     251    10128594 : INSFVMomentumDiffusion::computeSegregatedContribution()
     252             : {
     253    10128594 :   return computeStrongResidual(false);
     254             : }

Generated by: LCOV version 1.14