LCOV - code coverage report
Current view: top level - src/fvkernels - WCNSFV2PMomentumAdvectionSlip.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: ba1ead Lines: 78 106 73.6 %
Date: 2025-08-13 06:50:25 Functions: 3 3 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 "WCNSFV2PMomentumAdvectionSlip.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", WCNSFV2PMomentumAdvectionSlip);
      18             : 
      19             : InputParameters
      20         164 : WCNSFV2PMomentumAdvectionSlip::validParams()
      21             : {
      22         164 :   InputParameters params = INSFVMomentumAdvection::validParams();
      23         164 :   params.addClassDescription(
      24             :       "Computes the slip velocity advection kernel for two-phase mixture model.");
      25         328 :   params.addRequiredParam<MooseFunctorName>("u_slip", "The slip velocity in the x direction.");
      26         328 :   params.addParam<MooseFunctorName>("v_slip", "The slip velocity in the y direction.");
      27         328 :   params.addParam<MooseFunctorName>("w_slip", "The slip velocity in the z direction.");
      28         328 :   params.addRequiredParam<MooseFunctorName>("rho_d", "Dispersed phase density.");
      29         328 :   params.addParam<MooseFunctorName>("fd", 0.0, "Fraction dispersed phase.");
      30         328 :   params.renameParam("fd", "fraction_dispersed", "");
      31         164 :   params.setDocString(NS::density, "Main phase (not dispersed) density functor");
      32             : 
      33         164 :   return params;
      34           0 : }
      35             : 
      36          88 : WCNSFV2PMomentumAdvectionSlip::WCNSFV2PMomentumAdvectionSlip(const InputParameters & params)
      37             :   : INSFVMomentumAdvection(params),
      38          88 :     _rho_d(getFunctor<ADReal>("rho_d")),
      39          88 :     _dim(_subproblem.mesh().dimension()),
      40         176 :     _u_slip(getFunctor<ADReal>("u_slip")),
      41         352 :     _v_slip(isParamValid("v_slip") ? &getFunctor<ADReal>("v_slip") : nullptr),
      42         176 :     _w_slip(isParamValid("w_slip") ? &getFunctor<ADReal>("w_slip") : nullptr),
      43         264 :     _fd(getFunctor<ADReal>("fd"))
      44             : {
      45          88 :   if (_dim >= 2 && !_v_slip)
      46           0 :     mooseError("In two or more dimensions, the v_slip velocity must be supplied using the 'v_slip' "
      47             :                "parameter");
      48          88 :   if (_dim >= 3 && !_w_slip)
      49           0 :     mooseError(
      50             :         "In three dimensions, the w_slip velocity must be supplied using the 'w_slip' parameter");
      51          88 : }
      52             : 
      53             : void
      54      141984 : WCNSFV2PMomentumAdvectionSlip::computeResidualsAndAData(const FaceInfo & fi)
      55             : {
      56             :   mooseAssert(!skipForBoundary(fi),
      57             :               "We shouldn't get in here if we're supposed to skip for a boundary");
      58             : 
      59             :   constexpr Real offset = 1e-15;
      60      141984 :   _face_info = &fi;
      61      141984 :   _normal = fi.normal();
      62      283968 :   _face_type = fi.faceType(std::make_pair(_var.number(), _var.sys().number()));
      63      141984 :   const auto state = determineState();
      64             : 
      65             :   using namespace Moose::FV;
      66             : 
      67      141984 :   const bool correct_skewness = _advected_interp_method == InterpMethod::SkewCorrectedAverage;
      68      141984 :   const bool on_boundary = onBoundary(fi);
      69             : 
      70      141984 :   _elem_residual = 0, _neighbor_residual = 0, _ae = 0, _an = 0;
      71             : 
      72             :   Moose::FaceArg face_arg;
      73      141984 :   if (on_boundary)
      74       14688 :     face_arg = singleSidedFaceArg();
      75             :   else
      76      127296 :     face_arg = Moose::FaceArg{
      77             :         &fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr};
      78             : 
      79             :   ADRealVectorValue u_slip_vel_vec;
      80      141984 :   if (_dim == 1)
      81           0 :     u_slip_vel_vec(0) = _u_slip(face_arg, state);
      82      141984 :   if (_dim == 2)
      83      283968 :     u_slip_vel_vec = ADRealVectorValue(_u_slip(face_arg, state), (*_v_slip)(face_arg, state), 0.0);
      84      141984 :   if (_dim == 3)
      85           0 :     u_slip_vel_vec = ADRealVectorValue(
      86           0 :         _u_slip(face_arg, state), (*_v_slip)(face_arg, state), (*_w_slip)(face_arg, state));
      87             : 
      88      141984 :   const auto rho_mix = _rho(face_arg, state) +
      89      141984 :                        (_rho_d(face_arg, state) - _rho(face_arg, state)) * _fd(face_arg, state);
      90             : 
      91      141984 :   const auto vdotn = _normal * u_slip_vel_vec;
      92             : 
      93      141984 :   if (on_boundary)
      94             :   {
      95       14688 :     const auto ssf = singleSidedFaceArg();
      96       14688 :     const Elem * const sided_elem = ssf.face_side;
      97       14688 :     const auto dof_number = sided_elem->dof_number(_sys.number(), _var.number(), 0);
      98       14688 :     const auto rho_face = rho_mix;
      99       14688 :     const auto eps_face = epsilon()(ssf, state);
     100       14688 :     const auto u_face = _var(ssf, state);
     101       14688 :     const Real d_u_face_d_dof = u_face.derivatives()[dof_number];
     102       14688 :     const auto coeff = vdotn * rho_face / eps_face;
     103             : 
     104       14688 :     if (sided_elem == fi.elemPtr())
     105             :     {
     106       14688 :       _ae = coeff * d_u_face_d_dof;
     107       14688 :       _elem_residual = coeff * u_face;
     108       14688 :       if (_approximate_as)
     109           0 :         _ae = _cs / fi.elem().n_sides() * rho_face / eps_face;
     110             :     }
     111             :     else
     112             :     {
     113           0 :       _an = -coeff * d_u_face_d_dof;
     114           0 :       _neighbor_residual = -coeff * u_face;
     115           0 :       if (_approximate_as)
     116           0 :         _an = _cs / fi.neighborPtr()->n_sides() * rho_face / eps_face;
     117             :     }
     118             :   }
     119             :   else // we are an internal fluid flow face
     120             :   {
     121      127296 :     const bool elem_is_upwind = MetaPhysicL::raw_value(u_slip_vel_vec) * _normal > 0;
     122      127296 :     const Moose::FaceArg advected_face_arg{&fi,
     123      127296 :                                            limiterType(_advected_interp_method),
     124             :                                            elem_is_upwind,
     125             :                                            correct_skewness,
     126             :                                            nullptr,
     127      127296 :                                            nullptr};
     128      127296 :     if (const auto [is_jump, eps_elem_face, eps_neighbor_face] =
     129      127296 :             NS::isPorosityJumpFace(epsilon(), fi, state);
     130      127296 :         is_jump)
     131             :     {
     132             :       // For a weakly compressible formulation, the density should not depend on pressure and
     133             :       // consequently the density should not be impacted by the pressure jump that occurs at a
     134             :       // porosity jump. Consequently we will allow evaluation of the density using both upstream and
     135             :       // downstream information
     136             :       const auto rho_face =
     137           0 :           _rho_d(advected_face_arg, state) - _rho(advected_face_arg, state) + offset;
     138             : 
     139             :       // We set the + and - sides of the superficial velocity equal to the interpolated value
     140           0 :       const auto & var_elem_face = u_slip_vel_vec(_index);
     141             :       const auto & var_neighbor_face = u_slip_vel_vec(_index);
     142             : 
     143           0 :       const auto elem_dof_number = fi.elem().dof_number(_sys.number(), _var.number(), 0);
     144           0 :       const auto neighbor_dof_number = fi.neighbor().dof_number(_sys.number(), _var.number(), 0);
     145             : 
     146           0 :       const auto d_var_elem_face_d_elem_dof = var_elem_face.derivatives()[elem_dof_number];
     147             :       const auto d_var_neighbor_face_d_neighbor_dof =
     148           0 :           var_neighbor_face.derivatives()[neighbor_dof_number];
     149             : 
     150             :       // We allow a discontintuity in the advective momentum flux at the jump face. Mainly the
     151             :       // advective flux is:
     152             :       // elem side:
     153             :       // rho * v_superficial / eps_elem * v_superficial = rho * v_interstitial_elem * v_superficial
     154             :       // neighbor side:
     155             :       // rho * v_superficial / eps_neigh * v_superficial = rho * v_interstitial_neigh *
     156             :       // v_superficial
     157           0 :       const auto elem_coeff = vdotn * rho_face / eps_elem_face;
     158           0 :       const auto neighbor_coeff = vdotn * rho_face / eps_neighbor_face;
     159           0 :       _ae = elem_coeff * d_var_elem_face_d_elem_dof;
     160           0 :       _elem_residual = elem_coeff * var_elem_face;
     161           0 :       _an = -neighbor_coeff * d_var_neighbor_face_d_neighbor_dof;
     162           0 :       _neighbor_residual = -neighbor_coeff * var_neighbor_face;
     163           0 :       if (_approximate_as)
     164             :       {
     165           0 :         _ae = _cs / fi.elem().n_sides() * rho_face / eps_elem_face;
     166           0 :         _an = _cs / fi.neighborPtr()->n_sides() * rho_face / eps_elem_face;
     167             :       }
     168             :     }
     169             :     else
     170             :     {
     171             :       const auto [interp_coeffs, advected] =
     172      127296 :           interpCoeffsAndAdvected(*_rho_u, advected_face_arg, state);
     173             : 
     174      127296 :       const auto elem_arg = elemArg();
     175      127296 :       const auto neighbor_arg = neighborArg();
     176             : 
     177      127296 :       const auto rho_elem = _rho_d(elem_arg, state) - _rho(elem_arg, state) + offset;
     178      127296 :       const auto rho_neighbor = _rho_d(neighbor_arg, state) - _rho(neighbor_arg, state) + offset;
     179      127296 :       const auto eps_elem = epsilon()(elem_arg, state),
     180      127296 :                  eps_neighbor = epsilon()(neighbor_arg, state);
     181      127296 :       const auto var_elem = advected.first / rho_elem * eps_elem,
     182      127296 :                  var_neighbor = advected.second / rho_neighbor * eps_neighbor;
     183             : 
     184      127296 :       _ae = vdotn * rho_elem / eps_elem * interp_coeffs.first;
     185             :       // Minus sign because we apply a minus sign to the residual in computeResidual
     186      254592 :       _an = -vdotn * rho_neighbor / eps_neighbor * interp_coeffs.second;
     187             : 
     188      127296 :       _elem_residual = _ae * var_elem - _an * var_neighbor;
     189      127296 :       _neighbor_residual = -_elem_residual;
     190             : 
     191      127296 :       if (_approximate_as)
     192             :       {
     193           0 :         _ae = _cs / fi.elem().n_sides() * rho_elem / eps_elem;
     194           0 :         _an = _cs / fi.neighborPtr()->n_sides() * rho_neighbor / eps_neighbor;
     195             :       }
     196             :     }
     197             :   }
     198             : 
     199      141984 :   _ae *= fi.faceArea() * fi.faceCoord();
     200      141984 :   _an *= fi.faceArea() * fi.faceCoord();
     201      141984 :   _elem_residual *= fi.faceArea() * fi.faceCoord();
     202      141984 :   _neighbor_residual *= fi.faceArea() * fi.faceCoord();
     203      141984 : }

Generated by: LCOV version 1.14