LCOV - code coverage report
Current view: top level - src/fvkernels - INSFVMomentumDiffusion.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: 853d1f Lines: 84 93 90.3 %
Date: 2025-10-25 20:01:59 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       31833 : INSFVMomentumDiffusion::validParams()
      24             : {
      25       31833 :   auto params = INSFVFluxKernel::validParams();
      26       31833 :   params += FVDiffusionInterpolationInterface::validParams();
      27       31833 :   params.addRequiredParam<MooseFunctorName>(NS::mu, "The viscosity");
      28       31833 :   params.addClassDescription(
      29             :       "Implements the Laplace form of the viscous stress in the Navier-Stokes equation.");
      30             : 
      31       63666 :   MooseEnum coeff_interp_method("average harmonic", "harmonic");
      32       63666 :   params.addParam<MooseEnum>("mu_interp_method",
      33             :                              coeff_interp_method,
      34             :                              "Switch that can select face interpolation method for the viscosity.");
      35       31833 :   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       63666 :   params.addRelationshipManager(
      40             :       "ElementSideNeighborLayers",
      41             :       Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC |
      42             :           Moose::RelationshipManagerType::COUPLING,
      43             :       [](const InputParameters & obj_params, InputParameters & rm_params)
      44       36782 :       { FVRelationshipManagerInterface::setRMParamsDiffusion(obj_params, rm_params, 3); });
      45             : 
      46       63666 :   params.addParam<bool>(
      47             :       "complete_expansion",
      48       63666 :       false,
      49             :       "Boolean parameter to use complete momentum expansion is the diffusion term.");
      50       63666 :   params.addParam<MooseFunctorName>("u", "The velocity in the x direction.");
      51       63666 :   params.addParam<MooseFunctorName>("v", "The velocity in the y direction.");
      52       63666 :   params.addParam<MooseFunctorName>("w", "The velocity in the z direction.");
      53       63666 :   params.addParam<bool>(
      54       63666 :       "limit_interpolation", false, "Flag to limit interpolation to positive values.");
      55       63666 :   params.addParam<bool>("newton_solve", false, "Whether a Newton nonlinear solve is being used");
      56       63666 :   params.addParamNamesToGroup("newton_solve", "Advanced");
      57       31833 :   return params;
      58       31833 : }
      59             : 
      60       17703 : INSFVMomentumDiffusion::INSFVMomentumDiffusion(const InputParameters & params)
      61             :   : INSFVFluxKernel(params),
      62             :     FVDiffusionInterpolationInterface(params),
      63       35406 :     _mu(getFunctor<ADReal>(NS::mu)),
      64       17703 :     _mu_interp_method(
      65       35406 :         Moose::FV::selectInterpolationMethod(getParam<MooseEnum>("mu_interp_method"))),
      66       21307 :     _u_var(params.isParamValid("u") ? &getFunctor<ADReal>("u") : nullptr),
      67       21307 :     _v_var(params.isParamValid("v") ? &getFunctor<ADReal>("v") : nullptr),
      68       17703 :     _w_var(params.isParamValid("w") ? &getFunctor<ADReal>("w") : nullptr),
      69       35406 :     _complete_expansion(getParam<bool>("complete_expansion")),
      70       35406 :     _limit_interpolation(getParam<bool>("limit_interpolation")),
      71       17703 :     _dim(_subproblem.mesh().dimension()),
      72       70812 :     _newton_solve(getParam<bool>("newton_solve"))
      73             : {
      74       17703 :   if (_complete_expansion && !_u_var)
      75           0 :     paramError("u", "The u velocity must be defined when 'complete_expansion=true'.");
      76             : 
      77       17703 :   if (_complete_expansion && _dim >= 2 && !_v_var)
      78           0 :     paramError("v",
      79             :                "The v velocity must be defined when 'complete_expansion=true'"
      80             :                "and problem dimension is larger or equal to 2.");
      81             : 
      82       17703 :   if (_complete_expansion && _dim >= 3 && !_w_var)
      83           0 :     paramError("w",
      84             :                "The w velocity must be defined when 'complete_expansion=true'"
      85             :                "and problem dimension is larger or equal to three.");
      86       17703 : }
      87             : 
      88             : ADReal
      89    68449200 : INSFVMomentumDiffusion::computeStrongResidual(const bool populate_a_coeffs)
      90             : {
      91    68449200 :   const Moose::StateArg state = determineState();
      92    68449200 :   const auto dudn = gradUDotNormal(state, _correct_skewness);
      93             :   ADReal face_mu;
      94             : 
      95    68449200 :   if (onBoundary(*_face_info))
      96     6238108 :     face_mu = _mu(makeCDFace(*_face_info), state);
      97             :   else
      98    62211092 :     Moose::FV::interpolate(_mu_interp_method,
      99             :                            face_mu,
     100    62211092 :                            _mu(elemArg(), state),
     101   124422184 :                            _mu(neighborArg(), state),
     102    62211092 :                            *_face_info,
     103             :                            true);
     104             : 
     105             :   // Protecting from negative viscosity at interpolation
     106             :   // to preserve convergence
     107    68449200 :   if (face_mu < 0.0)
     108             :   {
     109         216 :     if (!(_limit_interpolation))
     110             :     {
     111         108 :       mooseDoOnce(mooseWarning(
     112             :           "Negative face viscosity has been encountered. Value ",
     113             :           raw_value(face_mu),
     114             :           " at ",
     115             :           _face_info->faceCentroid(),
     116             :           " limiting it to 0!\nFurther warnings for this issue will be silenced, but the "
     117             :           "occurrences will be recorded through the solution invalidity interface."));
     118         117 :       flagInvalidSolution("Negative face dynamic viscosity has been encountered.");
     119             :     }
     120             :     // Keep face_mu here for sparsity pattern detection
     121         432 :     face_mu = 0 * face_mu;
     122             :   }
     123             : 
     124    68449200 :   if (populate_a_coeffs)
     125             :   {
     126    56940936 :     if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     127             :         _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     128             :     {
     129    56940126 :       const auto dof_number = _face_info->elem().dof_number(_sys.number(), _var.number(), 0);
     130             :       // A gradient is a linear combination of degrees of freedom so it's safe to straight-up index
     131             :       // into the derivatives vector at the dof we care about
     132    56940126 :       _ae = dudn.derivatives()[dof_number];
     133    56940126 :       _ae *= -face_mu;
     134             :     }
     135    56940936 :     if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     136             :         _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     137             :     {
     138    53060493 :       const auto dof_number = _face_info->neighbor().dof_number(_sys.number(), _var.number(), 0);
     139    53060493 :       _an = dudn.derivatives()[dof_number];
     140    53060493 :       _an *= face_mu;
     141             :     }
     142             :   }
     143             : 
     144    68449200 :   ADReal dudn_transpose = 0.0;
     145    68449200 :   if (_complete_expansion)
     146             :   {
     147             :     // Computing the gradient from coupled variables
     148             :     // Normally, we can do this with `_var.gradient(face, state)` but we will need the transpose
     149             :     // gradient. So, we compute all at once
     150             :     Moose::FaceArg face;
     151     2642440 :     if (onBoundary(*_face_info))
     152      399840 :       face = singleSidedFaceArg();
     153             :     else
     154     2242600 :       face = makeCDFace(*_face_info, _correct_skewness);
     155             : 
     156             :     ADRealTensorValue gradient;
     157     2642440 :     if (_dim == 1)
     158             :     {
     159           0 :       const auto & grad_u = _u_var->gradient(face, state);
     160           0 :       gradient = ADRealTensorValue(grad_u, ADRealVectorValue(0, 0, 0), ADRealVectorValue(0, 0, 0));
     161             :     }
     162     2642440 :     else if (_dim == 2)
     163             :     {
     164     2642440 :       const auto & grad_u = _u_var->gradient(face, state);
     165     2642440 :       const auto & grad_v = _v_var->gradient(face, state);
     166     5284880 :       gradient = ADRealTensorValue(grad_u, grad_v, ADRealVectorValue(0, 0, 0));
     167             :     }
     168             :     else // if (_dim == 3)
     169             :     {
     170           0 :       const auto & grad_u = _u_var->gradient(face, state);
     171           0 :       const auto & grad_v = _v_var->gradient(face, state);
     172           0 :       const auto & grad_w = _w_var->gradient(face, state);
     173           0 :       gradient = ADRealTensorValue(grad_u, grad_v, grad_w);
     174             :     }
     175             : 
     176             :     // Getting transpose of the gradient matrix
     177     2642440 :     const auto gradient_transpose = gradient.transpose();
     178             : 
     179     2642440 :     dudn_transpose += gradient_transpose.row(_index) * _face_info->normal();
     180             :   }
     181             : 
     182   136898400 :   return -face_mu * (dudn + dudn_transpose);
     183             : }
     184             : 
     185             : void
     186    96803677 : INSFVMomentumDiffusion::gatherRCData(const FaceInfo & fi)
     187             : {
     188    96803677 :   if (skipForBoundary(fi))
     189             :     return;
     190             : 
     191    94598988 :   _face_info = &fi;
     192    94598988 :   _normal = fi.normal();
     193    94598988 :   _face_type = fi.faceType(std::make_pair(_var.number(), _var.sys().number()));
     194             : 
     195   189197976 :   addResidualAndJacobian(computeStrongResidual(true) * (fi.faceArea() * fi.faceCoord()));
     196             : 
     197    94598988 :   if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     198             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     199   189196116 :     _rc_uo.addToA(&fi.elem(), _index, _ae * (fi.faceArea() * fi.faceCoord()));
     200    94598988 :   if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     201             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     202   268096299 :     _rc_uo.addToA(fi.neighborPtr(), _index, _an * (fi.faceArea() * fi.faceCoord()));
     203             : }
     204             : 
     205             : ADReal
     206    13803684 : INSFVMomentumDiffusion::computeSegregatedContribution()
     207             : {
     208    13803684 :   return computeStrongResidual(false);
     209             : }

Generated by: LCOV version 1.14