LCOV - code coverage report
Current view: top level - src/base - NavierStokesMethods.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: 9fc4b0 Lines: 88 128 68.8 %
Date: 2025-08-14 10:14:56 Functions: 12 16 75.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 "NavierStokesMethods.h"
      11             : #include "MooseError.h"
      12             : #include "libmesh/vector_value.h"
      13             : #include "NS.h"
      14             : 
      15             : namespace NS
      16             : {
      17             : int
      18           0 : delta(unsigned int i, unsigned int j)
      19             : {
      20           0 :   if (i == j)
      21             :     return 1;
      22             :   else
      23           0 :     return 0;
      24             : }
      25             : 
      26             : int
      27           0 : computeSign(const Real & a)
      28             : {
      29           0 :   return a > 0 ? 1 : (a < 0 ? -1 : 0);
      30             : }
      31             : 
      32             : unsigned int
      33           0 : getIndex(const Real & p, const std::vector<Real> & bounds)
      34             : {
      35           0 :   if (p < bounds.front() || p > bounds.back())
      36           0 :     mooseError("Point exceeds bounds of domain!");
      37             : 
      38           0 :   for (unsigned int i = 1; i < bounds.size(); ++i)
      39           0 :     if (p <= bounds[i])
      40           0 :       return i - 1;
      41             : 
      42           0 :   return bounds.size() - 2;
      43             : }
      44             : 
      45             : Real
      46      356838 : reynoldsPropertyDerivative(
      47             :     const Real & Re, const Real & rho, const Real & mu, const Real & drho, const Real & dmu)
      48             : {
      49      356838 :   return Re * (drho / std::max(rho, 1e-6) - dmu / std::max(mu, 1e-8));
      50             : }
      51             : 
      52             : Real
      53      356838 : prandtlPropertyDerivative(const Real & mu,
      54             :                           const Real & cp,
      55             :                           const Real & k,
      56             :                           const Real & dmu,
      57             :                           const Real & dcp,
      58             :                           const Real & dk)
      59             : {
      60      356838 :   return (k * (mu * dcp + cp * dmu) - mu * cp * dk) / std::max(k * k, 1e-8);
      61             : }
      62             : 
      63             : template <typename T>
      64             : T
      65     1208304 : findUStar(const T & mu, const T & rho, const T & u, const Real dist)
      66             : {
      67             :   // usually takes about 3-4 iterations
      68             :   constexpr int MAX_ITERS{50};
      69             :   constexpr Real REL_TOLERANCE{1e-6};
      70             : 
      71             :   // Check inputs
      72             :   mooseAssert(mu > 0, "Need a strictly positive viscosity");
      73             :   mooseAssert(rho > 0, "Need a strictly positive density");
      74             :   mooseAssert(u > 0, "Need a strictly positive velocity");
      75             :   mooseAssert(dist > 0, "Need a strictly positive wall distance");
      76             : 
      77      678144 :   const T nu = mu / rho;
      78             : 
      79             :   // Wall-function linearized guess
      80             :   const Real a_c = 1 / NS::von_karman_constant;
      81     2798784 :   const T b_c = 1.0 / NS::von_karman_constant * (std::log(NS::E_turb_constant * dist / mu) + 1.0);
      82             :   const T & c_c = u;
      83             : 
      84             :   /// This is important to reduce the number of nonlinear iterations
      85     2798784 :   T u_star = std::max(1e-20, (-b_c + std::sqrt(std::pow(b_c, 2) + 4.0 * a_c * c_c)) / (2.0 * a_c));
      86             : 
      87             :   // Newton-Raphson method to solve for u_star (friction velocity).
      88     4774622 :   for (int i = 0; i < MAX_ITERS; ++i)
      89             :   {
      90     6843162 :     T residual =
      91     2706082 :         u_star / NS::von_karman_constant * std::log(NS::E_turb_constant * u_star * dist / nu) - u;
      92     6843162 :     T deriv = (1.0 + std::log(NS::E_turb_constant * u_star * dist / nu)) / NS::von_karman_constant;
      93     4774622 :     T new_u_star = std::max(1e-20, u_star - residual / deriv);
      94             : 
      95             :     Real rel_err =
      96     4774622 :         std::abs(MetaPhysicL::raw_value(new_u_star - u_star) / MetaPhysicL::raw_value(new_u_star));
      97             : 
      98     2068540 :     u_star = new_u_star;
      99     4774622 :     if (rel_err < REL_TOLERANCE)
     100     1208304 :       return u_star;
     101             :   }
     102             : 
     103           0 :   mooseException("Could not find the wall friction velocity (mu: ",
     104             :                  mu,
     105             :                  " rho: ",
     106             :                  rho,
     107             :                  " velocity: ",
     108             :                  u,
     109             :                  " wall distance: ",
     110             :                  dist,
     111             :                  ")");
     112             : }
     113             : template Real findUStar<Real>(const Real & mu, const Real & rho, const Real & u, const Real dist);
     114             : template ADReal
     115             : findUStar<ADReal>(const ADReal & mu, const ADReal & rho, const ADReal & u, const Real dist);
     116             : 
     117             : template <typename T>
     118             : T
     119     1078536 : findyPlus(const T & mu, const T & rho, const T & u, const Real dist)
     120             : {
     121             :   // Fixed point iteration method to find y_plus
     122             :   // It should take 3 or 4 iterations
     123             :   constexpr int MAX_ITERS{10};
     124             :   constexpr Real REL_TOLERANCE{1e-2};
     125             : 
     126             :   // Check inputs
     127             :   mooseAssert(mu > 0, "Need a strictly positive viscosity");
     128             :   mooseAssert(u > 0, "Need a strictly positive velocity");
     129             :   mooseAssert(rho > 0, "Need a strictly positive density");
     130             :   mooseAssert(dist > 0, "Need a strictly positive wall distance");
     131             : 
     132             :   Real yPlusLast = 0.0;
     133     1078536 :   T yPlus = dist * u * rho / mu; // Assign initial value to laminar
     134     1078536 :   const Real rev_yPlusLam = 1.0 / MetaPhysicL::raw_value(yPlus);
     135     1078536 :   const T kappa_time_Re = NS::von_karman_constant * u * dist / (mu / rho);
     136             :   unsigned int iters = 0;
     137             : 
     138             :   do
     139             :   {
     140             :     yPlusLast = MetaPhysicL::raw_value(yPlus);
     141             :     // Negative y plus does not make sense
     142     3238375 :     yPlus = std::max(NS::min_y_plus, yPlus);
     143     3997262 :     yPlus = (kappa_time_Re + yPlus) / (1.0 + std::log(NS::E_turb_constant * yPlus));
     144     3238375 :   } while (std::abs(rev_yPlusLam * (MetaPhysicL::raw_value(yPlus) - yPlusLast)) > REL_TOLERANCE &&
     145             :            ++iters < MAX_ITERS);
     146             : 
     147     1078536 :   return std::max(NS::min_y_plus, yPlus);
     148             : }
     149             : template Real findyPlus<Real>(const Real & mu, const Real & rho, const Real & u, Real dist);
     150             : template ADReal
     151             : findyPlus<ADReal>(const ADReal & mu, const ADReal & rho, const ADReal & u, Real dist);
     152             : 
     153             : template <typename T>
     154             : T
     155    81772228 : computeSpeed(const libMesh::VectorValue<T> & velocity)
     156             : {
     157             :   // if the velocity is zero, then the norm function call fails because AD tries to calculate the
     158             :   // derivatives which causes a divide by zero - because d/dx(sqrt(f(x))) = 1/2/sqrt(f(x))*df/dx.
     159             :   // So add a bit of noise (based on hitchhiker's guide to the galaxy's meaning of life number) to
     160             :   // avoid this failure mode.
     161    81772228 :   return isZero(velocity) ? 1e-42 : velocity.norm();
     162             : }
     163             : template Real computeSpeed<Real>(const libMesh::VectorValue<Real> & velocity);
     164             : template ADReal computeSpeed<ADReal>(const libMesh::VectorValue<ADReal> & velocity);
     165             : 
     166             : template <typename T>
     167             : T
     168      807880 : computeShearStrainRateNormSquared(const Moose::Functor<T> & u,
     169             :                                   const Moose::Functor<T> * v,
     170             :                                   const Moose::Functor<T> * w,
     171             :                                   const Moose::ElemArg & elem_arg,
     172             :                                   const Moose::StateArg & state)
     173             : {
     174      807880 :   const auto & grad_u = u.gradient(elem_arg, state);
     175      807880 :   const T Sij_xx = 2.0 * grad_u(0);
     176           0 :   T Sij_xy = 0.0;
     177           0 :   T Sij_xz = 0.0;
     178           0 :   T Sij_yy = 0.0;
     179           0 :   T Sij_yz = 0.0;
     180           0 :   T Sij_zz = 0.0;
     181             : 
     182           0 :   const T grad_xx = grad_u(0);
     183           0 :   T grad_xy = 0.0;
     184           0 :   T grad_xz = 0.0;
     185           0 :   T grad_yx = 0.0;
     186           0 :   T grad_yy = 0.0;
     187           0 :   T grad_yz = 0.0;
     188           0 :   T grad_zx = 0.0;
     189           0 :   T grad_zy = 0.0;
     190           0 :   T grad_zz = 0.0;
     191             : 
     192      807880 :   T trace = Sij_xx / 3.0;
     193             : 
     194      807880 :   if (v) // dim >= 2
     195             :   {
     196      807880 :     const auto & grad_v = (*v).gradient(elem_arg, state);
     197      807880 :     Sij_xy = grad_u(1) + grad_v(0);
     198      807880 :     Sij_yy = 2.0 * grad_v(1);
     199             : 
     200           0 :     grad_xy = grad_u(1);
     201           0 :     grad_yx = grad_v(0);
     202           0 :     grad_yy = grad_v(1);
     203             : 
     204      807880 :     trace += Sij_yy / 3.0;
     205             : 
     206      807880 :     if (w) // dim >= 3
     207             :     {
     208           0 :       const auto & grad_w = (*w).gradient(elem_arg, state);
     209             : 
     210           0 :       Sij_xz = grad_u(2) + grad_w(0);
     211           0 :       Sij_yz = grad_v(2) + grad_w(1);
     212           0 :       Sij_zz = 2.0 * grad_w(2);
     213             : 
     214           0 :       grad_xz = grad_u(2);
     215           0 :       grad_yz = grad_v(2);
     216           0 :       grad_zx = grad_w(0);
     217           0 :       grad_zy = grad_w(1);
     218           0 :       grad_zz = grad_w(2);
     219             : 
     220           0 :       trace += Sij_zz / 3.0;
     221             :     }
     222             :   }
     223             : 
     224      807880 :   return (Sij_xx - trace) * grad_xx + Sij_xy * grad_xy + Sij_xz * grad_xz + Sij_xy * grad_yx +
     225      807880 :          (Sij_yy - trace) * grad_yy + Sij_yz * grad_yz + Sij_xz * grad_zx + Sij_yz * grad_zy +
     226      807880 :          (Sij_zz - trace) * grad_zz;
     227             : }
     228             : template Real computeShearStrainRateNormSquared<Real>(const Moose::Functor<Real> & u,
     229             :                                                       const Moose::Functor<Real> * v,
     230             :                                                       const Moose::Functor<Real> * w,
     231             :                                                       const Moose::ElemArg & elem_arg,
     232             :                                                       const Moose::StateArg & state);
     233             : template ADReal computeShearStrainRateNormSquared<ADReal>(const Moose::Functor<ADReal> & u,
     234             :                                                           const Moose::Functor<ADReal> * v,
     235             :                                                           const Moose::Functor<ADReal> * w,
     236             :                                                           const Moose::ElemArg & elem_arg,
     237             :                                                           const Moose::StateArg & state);
     238             : 
     239             : /// Bounded element maps for wall treatment
     240             : void
     241       18243 : getWallBoundedElements(const std::vector<BoundaryName> & wall_boundary_names,
     242             :                        const FEProblemBase & fe_problem,
     243             :                        const SubProblem & subproblem,
     244             :                        const std::set<SubdomainID> & block_ids,
     245             :                        std::unordered_set<const Elem *> & wall_bounded)
     246             : {
     247             : 
     248             :   wall_bounded.clear();
     249       18243 :   const auto wall_boundary_ids = subproblem.mesh().getBoundaryIDs(wall_boundary_names);
     250             : 
     251     6089940 :   for (const auto & elem : fe_problem.mesh().getMesh().active_element_ptr_range())
     252             :   {
     253     3026727 :     if (block_ids.find(elem->subdomain_id()) != block_ids.end())
     254    15098355 :       for (const auto i_side : elem->side_index_range())
     255             :       {
     256    12078684 :         const auto & side_bnds = subproblem.mesh().getBoundaryIDs(elem, i_side);
     257    34131940 :         for (const auto & wall_id : wall_boundary_ids)
     258             :         {
     259    23553162 :           for (const auto side_id : side_bnds)
     260     1499906 :             if (side_id == wall_id)
     261             :               wall_bounded.insert(elem);
     262             :         }
     263    12078684 :       }
     264       18243 :   }
     265       18243 : }
     266             : 
     267             : /// Bounded element face distances for wall treatment
     268             : void
     269        4941 : getWallDistance(const std::vector<BoundaryName> & wall_boundary_name,
     270             :                 const FEProblemBase & fe_problem,
     271             :                 const SubProblem & subproblem,
     272             :                 const std::set<SubdomainID> & block_ids,
     273             :                 std::map<const Elem *, std::vector<Real>> & dist_map)
     274             : {
     275             :   dist_map.clear();
     276             : 
     277     1697412 :   for (const auto & elem : fe_problem.mesh().getMesh().active_element_ptr_range())
     278      843765 :     if (block_ids.find(elem->subdomain_id()) != block_ids.end())
     279     4208745 :       for (const auto i_side : elem->side_index_range())
     280             :       {
     281     3366996 :         const auto & side_bnds = subproblem.mesh().getBoundaryIDs(elem, i_side);
     282    12936736 :         for (const auto & name : wall_boundary_name)
     283             :         {
     284     9569740 :           const auto wall_id = subproblem.mesh().getBoundaryID(name);
     285    10214457 :           for (const auto side_id : side_bnds)
     286      644717 :             if (side_id == wall_id)
     287             :             {
     288             :               // The list below stores the face infos with respect to their owning elements,
     289             :               // depending on the block restriction we might encounter situations where the
     290             :               // element outside of the block owns the face info.
     291      173957 :               const auto & neighbor = elem->neighbor_ptr(i_side);
     292      173957 :               const auto elem_has_fi = Moose::FV::elemHasFaceInfo(*elem, neighbor);
     293      173957 :               const auto & elem_for_fi = elem_has_fi ? elem : neighbor;
     294         336 :               const auto side = elem_has_fi ? i_side : neighbor->which_neighbor_am_i(elem);
     295             : 
     296      173957 :               const FaceInfo * const fi = subproblem.mesh().faceInfo(elem_for_fi, side);
     297             :               const auto & elem_centroid =
     298      173957 :                   elem_has_fi ? fi->elemCentroid() : fi->neighborCentroid();
     299      173957 :               const Real dist = std::abs((elem_centroid - fi->faceCentroid()) * fi->normal());
     300      173957 :               dist_map[elem].push_back(dist);
     301             :             }
     302             :         }
     303     3371937 :       }
     304        4941 : }
     305             : 
     306             : /// Face arguments to wall-bounded faces for wall treatment
     307             : void
     308        4941 : getElementFaceArgs(const std::vector<BoundaryName> & wall_boundary_name,
     309             :                    const FEProblemBase & fe_problem,
     310             :                    const SubProblem & subproblem,
     311             :                    const std::set<SubdomainID> & block_ids,
     312             :                    std::map<const Elem *, std::vector<const FaceInfo *>> & face_info_map)
     313             : {
     314             :   face_info_map.clear();
     315             : 
     316     1697412 :   for (const auto & elem : fe_problem.mesh().getMesh().active_element_ptr_range())
     317      843765 :     if (block_ids.find(elem->subdomain_id()) != block_ids.end())
     318     4208745 :       for (const auto i_side : elem->side_index_range())
     319             :       {
     320     3366996 :         const auto & side_bnds = subproblem.mesh().getBoundaryIDs(elem, i_side);
     321    12936736 :         for (const auto & name : wall_boundary_name)
     322             :         {
     323     9569740 :           const auto wall_id = subproblem.mesh().getBoundaryID(name);
     324    10214457 :           for (const auto side_id : side_bnds)
     325      644717 :             if (side_id == wall_id)
     326             :             {
     327             :               // The list below stores the face infos with respect to their owning elements,
     328             :               // depending on the block restriction we might encounter situations where the
     329             :               // element outside of the block owns the face info.
     330      173957 :               const auto & neighbor = elem->neighbor_ptr(i_side);
     331      173957 :               const auto elem_has_fi = Moose::FV::elemHasFaceInfo(*elem, neighbor);
     332      173957 :               const auto & elem_for_fi = elem_has_fi ? elem : neighbor;
     333         336 :               const auto side = elem_has_fi ? i_side : neighbor->which_neighbor_am_i(elem);
     334             : 
     335      173957 :               const FaceInfo * const fi = subproblem.mesh().faceInfo(elem_for_fi, side);
     336      173957 :               face_info_map[elem].push_back(fi);
     337             :             }
     338             :         }
     339     3371937 :       }
     340        4941 : }
     341             : }

Generated by: LCOV version 1.14