LCOV - code coverage report
Current view: top level - src/fvkernels - INSFVMomentumAdvection.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: ba1ead Lines: 127 134 94.8 %
Date: 2025-08-13 06:50:25 Functions: 11 16 68.8 %
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 "INSFVMomentumAdvection.h"
      11             : #include "NS.h"
      12             : #include "FVUtils.h"
      13             : #include "INSFVRhieChowInterpolator.h"
      14             : #include "SystemBase.h"
      15             : #include "NSFVUtils.h"
      16             : 
      17             : registerMooseObject("NavierStokesApp", INSFVMomentumAdvection);
      18             : 
      19             : InputParameters
      20       79316 : INSFVMomentumAdvection::uniqueParams()
      21             : {
      22       79316 :   auto params = emptyInputParameters();
      23      158632 :   params.addParam<Real>(
      24             :       "characteristic_speed",
      25             :       "The characteristic speed. For porous medium simulations, this characteristic speed should "
      26             :       "correspond to the superficial velocity, not the interstitial.");
      27       79316 :   return params;
      28           0 : }
      29             : 
      30             : std::vector<std::string>
      31        1621 : INSFVMomentumAdvection::listOfCommonParams()
      32             : {
      33        1621 :   return {"characteristic_speed"};
      34             : }
      35             : 
      36             : InputParameters
      37       32294 : INSFVMomentumAdvection::validParams()
      38             : {
      39       32294 :   InputParameters params = INSFVAdvectionKernel::validParams();
      40       32294 :   params += INSFVMomentumResidualObject::validParams();
      41       32294 :   params += INSFVMomentumAdvection::uniqueParams();
      42       32294 :   params.addRequiredParam<MooseFunctorName>(NS::density, "Density functor");
      43       32294 :   params.addClassDescription("Object for advecting momentum, e.g. rho*u");
      44       32294 :   return params;
      45           0 : }
      46             : 
      47       16938 : INSFVMomentumAdvection::INSFVMomentumAdvection(const InputParameters & params)
      48             :   : INSFVAdvectionKernel(params),
      49             :     INSFVMomentumResidualObject(*this),
      50       33876 :     _rho(getFunctor<ADReal>(NS::density)),
      51       33876 :     _approximate_as(isParamValid("characteristic_speed")),
      52       35084 :     _cs(_approximate_as ? getParam<Real>("characteristic_speed") : 0)
      53             : {
      54       16938 : }
      55             : 
      56             : void
      57       22644 : INSFVMomentumAdvection::initialSetup()
      58             : {
      59       22644 :   INSFVAdvectionKernel::initialSetup();
      60             : 
      61       22644 :   _rho_u = std::make_unique<PiecewiseByBlockLambdaFunctor<ADReal>>(
      62             :       "rho_u",
      63   386123466 :       [this](const auto & r, const auto & t) -> ADReal
      64   386078178 :       { return _rho(r, t) * _var(r, t) / epsilon()(r, t); },
      65       67932 :       std::set<ExecFlagType>({EXEC_ALWAYS}),
      66             :       _mesh,
      67       22644 :       this->blockIDs());
      68       45288 : }
      69             : 
      70             : ADReal
      71           0 : INSFVMomentumAdvection::computeQpResidual()
      72             : {
      73           0 :   mooseError("Should never be called");
      74             : }
      75             : 
      76             : void
      77   190408499 : INSFVMomentumAdvection::computeResidualsAndAData(const FaceInfo & fi)
      78             : {
      79             :   mooseAssert(!skipForBoundary(fi),
      80             :               "We shouldn't get in here if we're supposed to skip for a boundary");
      81             : 
      82   190408499 :   _face_info = &fi;
      83   190408499 :   _normal = fi.normal();
      84   190408499 :   _face_type = fi.faceType(std::make_pair(_var.number(), _var.sys().number()));
      85   190408499 :   const auto state = determineState();
      86             : 
      87             :   using namespace Moose::FV;
      88             : 
      89   190408499 :   const bool correct_skewness = _advected_interp_method == InterpMethod::SkewCorrectedAverage;
      90   190408499 :   const bool on_boundary = onBoundary(fi);
      91             : 
      92   190408499 :   _elem_residual = 0, _neighbor_residual = 0, _ae = 0, _an = 0;
      93             : 
      94   190408499 :   const auto v_face = velocity();
      95   190408499 :   const auto vdotn = _normal * v_face;
      96             : 
      97   190408499 :   if (on_boundary)
      98             :   {
      99     3249594 :     const auto ssf = singleSidedFaceArg();
     100     3249594 :     const Elem * const sided_elem = ssf.face_side;
     101     3249594 :     const auto dof_number = sided_elem->dof_number(_sys.number(), _var.number(), 0);
     102     3249594 :     const auto rho_face = _rho(ssf, state);
     103     3249594 :     const auto eps_face = epsilon()(ssf, state);
     104     3249594 :     const auto u_face = _var(ssf, state);
     105     3249594 :     const Real d_u_face_d_dof = u_face.derivatives()[dof_number];
     106     3249594 :     const auto coeff = vdotn * rho_face / eps_face;
     107             : 
     108     3249594 :     if (sided_elem == fi.elemPtr())
     109             :     {
     110     3249094 :       _ae = coeff * d_u_face_d_dof;
     111     3249094 :       _elem_residual = coeff * u_face;
     112     3249094 :       if (_approximate_as)
     113       12960 :         _ae = _cs / fi.elem().n_sides() * rho_face / eps_face;
     114             :     }
     115             :     else
     116             :     {
     117        1000 :       _an = -coeff * d_u_face_d_dof;
     118        1000 :       _neighbor_residual = -coeff * u_face;
     119         500 :       if (_approximate_as)
     120           0 :         _an = _cs / fi.neighborPtr()->n_sides() * rho_face / eps_face;
     121             :     }
     122             :   }
     123             :   else // we are an internal fluid flow face
     124             :   {
     125   187158905 :     const bool elem_is_upwind = MetaPhysicL::raw_value(v_face) * _normal > 0;
     126   187158905 :     const auto & limiter_time = _subproblem.isTransient()
     127   187158905 :                                     ? Moose::StateArg(1, Moose::SolutionIterationType::Time)
     128             :                                     : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear);
     129   187158905 :     const Moose::FaceArg advected_face_arg{&fi,
     130   187158905 :                                            limiterType(_advected_interp_method),
     131             :                                            elem_is_upwind,
     132             :                                            correct_skewness,
     133             :                                            nullptr,
     134   187158905 :                                            &limiter_time};
     135   187158905 :     if (const auto [is_jump, eps_elem_face, eps_neighbor_face] =
     136   187158905 :             NS::isPorosityJumpFace(epsilon(), fi, state);
     137   187158905 :         is_jump)
     138             :     {
     139             :       // For a weakly compressible formulation, the density should not depend on pressure and
     140             :       // consequently the density should not be impacted by the pressure jump that occurs at a
     141             :       // porosity jump. Consequently we will allow evaluation of the density using both upstream and
     142             :       // downstream information
     143       31176 :       const auto rho_face = _rho(advected_face_arg, state);
     144             : 
     145             :       // We set the + and - sides of the superficial velocity equal to the interpolated value
     146       31176 :       const auto & var_elem_face = v_face(_index);
     147             :       const auto & var_neighbor_face = v_face(_index);
     148             : 
     149       31176 :       const auto elem_dof_number = fi.elem().dof_number(_sys.number(), _var.number(), 0);
     150       31176 :       const auto neighbor_dof_number = fi.neighbor().dof_number(_sys.number(), _var.number(), 0);
     151             : 
     152       62352 :       const auto d_var_elem_face_d_elem_dof = var_elem_face.derivatives()[elem_dof_number];
     153             :       const auto d_var_neighbor_face_d_neighbor_dof =
     154       31176 :           var_neighbor_face.derivatives()[neighbor_dof_number];
     155             : 
     156             :       // We allow a discontintuity in the advective momentum flux at the jump face. Mainly the
     157             :       // advective flux is:
     158             :       // elem side:
     159             :       // rho * v_superficial / eps_elem * v_superficial = rho * v_interstitial_elem * v_superficial
     160             :       // neighbor side:
     161             :       // rho * v_superficial / eps_neigh * v_superficial = rho * v_interstitial_neigh *
     162             :       // v_superficial
     163       31176 :       const auto elem_coeff = vdotn * rho_face / eps_elem_face;
     164       31176 :       const auto neighbor_coeff = vdotn * rho_face / eps_neighbor_face;
     165       31176 :       _ae = elem_coeff * d_var_elem_face_d_elem_dof;
     166       31176 :       _elem_residual = elem_coeff * var_elem_face;
     167       62352 :       _an = -neighbor_coeff * d_var_neighbor_face_d_neighbor_dof;
     168       62352 :       _neighbor_residual = -neighbor_coeff * var_neighbor_face;
     169       31176 :       if (_approximate_as)
     170             :       {
     171           0 :         _ae = _cs / fi.elem().n_sides() * rho_face / eps_elem_face;
     172           0 :         _an = _cs / fi.neighborPtr()->n_sides() * rho_face / eps_elem_face;
     173             :       }
     174             :     }
     175             :     else
     176             :     {
     177             :       const auto [interp_coeffs, advected] =
     178   187127729 :           interpCoeffsAndAdvected(*_rho_u, advected_face_arg, state);
     179             : 
     180   187127729 :       const auto elem_arg = elemArg();
     181   187127729 :       const auto neighbor_arg = neighborArg();
     182             : 
     183   187127729 :       const auto rho_elem = _rho(elem_arg, state), rho_neighbor = _rho(neighbor_arg, state);
     184   187127729 :       const auto eps_elem = epsilon()(elem_arg, state),
     185   187127729 :                  eps_neighbor = epsilon()(neighbor_arg, state);
     186   187127729 :       const auto var_elem = advected.first / rho_elem * eps_elem,
     187   187127729 :                  var_neighbor = advected.second / rho_neighbor * eps_neighbor;
     188             : 
     189   187127729 :       _ae = vdotn * rho_elem / eps_elem * interp_coeffs.first;
     190             :       // Minus sign because we apply a minus sign to the residual in computeResidual
     191   374255458 :       _an = -vdotn * rho_neighbor / eps_neighbor * interp_coeffs.second;
     192             : 
     193   187127729 :       _elem_residual = _ae * var_elem - _an * var_neighbor;
     194   187127729 :       _neighbor_residual = -_elem_residual;
     195             : 
     196   187127729 :       if (_approximate_as)
     197             :       {
     198    12631840 :         _ae = _cs / fi.elem().n_sides() * rho_elem / eps_elem;
     199    18947760 :         _an = _cs / fi.neighborPtr()->n_sides() * rho_neighbor / eps_neighbor;
     200             :       }
     201             :     }
     202             :   }
     203             : 
     204   190408499 :   _ae *= fi.faceArea() * fi.faceCoord();
     205   190408499 :   _an *= fi.faceArea() * fi.faceCoord();
     206   190408499 :   _elem_residual *= fi.faceArea() * fi.faceCoord();
     207   190408499 :   _neighbor_residual *= fi.faceArea() * fi.faceCoord();
     208   190408499 : }
     209             : 
     210             : void
     211    54298192 : INSFVMomentumAdvection::computeResidual(const FaceInfo & fi)
     212             : {
     213    54298192 :   if (skipForBoundary(fi))
     214             :     return;
     215             : 
     216    50911248 :   computeResidualsAndAData(fi);
     217             : 
     218    50911248 :   if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     219             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     220             :   {
     221             :     // residual contribution of this kernel to the elem element
     222    50911098 :     prepareVectorTag(_assembly, _var.number());
     223    50911098 :     _local_re(0) = MetaPhysicL::raw_value(_elem_residual);
     224    50911098 :     accumulateTaggedLocalResidual();
     225             :   }
     226             : 
     227    50911248 :   if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     228             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     229             :   {
     230             :     // residual contribution of this kernel to the neighbor element
     231    50118768 :     prepareVectorTagNeighbor(_assembly, _var.number());
     232    50118768 :     _local_re(0) = MetaPhysicL::raw_value(_neighbor_residual);
     233    50118768 :     accumulateTaggedLocalResidual();
     234             :   }
     235             : }
     236             : 
     237             : void
     238    54883210 : INSFVMomentumAdvection::computeJacobian(const FaceInfo & fi)
     239             : {
     240    54883210 :   if (skipForBoundary(fi))
     241             :     return;
     242             : 
     243    49773844 :   computeResidualsAndAData(fi);
     244             : 
     245    49773844 :   if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     246             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     247             :   {
     248             :     mooseAssert(_var.dofIndices().size() == 1, "We're currently built to use CONSTANT MONOMIALS");
     249             : 
     250    49773744 :     addResidualsAndJacobian(_assembly,
     251    99547488 :                             std::array<ADReal, 1>{{_elem_residual}},
     252             :                             _var.dofIndices(),
     253    49773744 :                             _var.scalingFactor());
     254             :   }
     255             : 
     256    49773844 :   if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     257             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     258             :   {
     259             :     mooseAssert((_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR) ==
     260             :                     (_var.dofIndices().size() == 0),
     261             :                 "If the variable is only defined on the neighbor hand side of the face, then that "
     262             :                 "means it should have no dof indices on the elem element. Conversely if "
     263             :                 "the variable is defined on both sides of the face, then it should have a non-zero "
     264             :                 "number of degrees of freedom on the elem element");
     265             : 
     266             :     mooseAssert(_var.dofIndicesNeighbor().size() == 1,
     267             :                 "We're currently built to use CONSTANT MONOMIALS");
     268             : 
     269    48692456 :     addResidualsAndJacobian(_assembly,
     270    97384912 :                             std::array<ADReal, 1>{{_neighbor_residual}},
     271             :                             _var.dofIndicesNeighbor(),
     272    48692456 :                             _var.scalingFactor());
     273             :   }
     274             : }
     275             : 
     276             : void
     277    95771881 : INSFVMomentumAdvection::gatherRCData(const FaceInfo & fi)
     278             : {
     279    95771881 :   if (skipForBoundary(fi))
     280             :     return;
     281             : 
     282    89865391 :   const auto saved_velocity_interp_method = _velocity_interp_method;
     283    89865391 :   _velocity_interp_method = Moose::FV::InterpMethod::Average;
     284             :   // Fill-in the coefficients _ae and _an
     285    89865391 :   computeResidualsAndAData(fi);
     286    89865391 :   _velocity_interp_method = saved_velocity_interp_method;
     287             : 
     288    89865391 :   if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
     289             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     290    89865141 :     _rc_uo.addToA(&fi.elem(), _index, _ae);
     291    89865391 :   if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
     292             :       _face_type == FaceInfo::VarFaceNeighbors::BOTH)
     293   176950954 :     _rc_uo.addToA(fi.neighborPtr(), _index, _an);
     294             : }

Generated by: LCOV version 1.14