LCOV - code coverage report
Current view: top level - src/userobjects - RichardsSUPGstandard.C (source / functions) Hit Total Coverage
Test: idaholab/moose richards: #31405 (292dce) with base fef103 Lines: 76 77 98.7 %
Date: 2025-09-04 07:56:35 Functions: 14 14 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 "RichardsSUPGstandard.h"
      11             : #include "libmesh/utility.h"
      12             : 
      13             : registerMooseObject("RichardsApp", RichardsSUPGstandard);
      14             : 
      15             : InputParameters
      16         578 : RichardsSUPGstandard::validParams()
      17             : {
      18         578 :   InputParameters params = RichardsSUPG::validParams();
      19        1156 :   params.addRequiredRangeCheckedParam<Real>(
      20             :       "p_SUPG",
      21             :       "p_SUPG > 0",
      22             :       "SUPG pressure.  This parameter controls the strength of the "
      23             :       "upwinding.  This parameter must be positive.  If you need to track "
      24             :       "advancing fronts in a problem, then set to less than your expected "
      25             :       "range of pressures in your unsaturated zone.  Otherwise, set "
      26             :       "larger, and then minimal upwinding will occur and convergence will "
      27             :       "typically be good.  If you need no SUPG, it is more efficient not "
      28             :       "to use this UserObject.");
      29         578 :   params.addClassDescription(
      30             :       "Standard SUPG relationships for Richards flow based on Appendix A of      TJR Hughes, M "
      31             :       "Mallet and A Mizukami ``A new finite element formulation for computational fluid dynamics:: "
      32             :       "II. Behond SUPG'' Computer Methods in Applied Mechanics and Engineering 54 (1986) 341--355");
      33         578 :   return params;
      34           0 : }
      35             : 
      36         285 : RichardsSUPGstandard::RichardsSUPGstandard(const InputParameters & parameters)
      37         570 :   : RichardsSUPG(parameters), _p_SUPG(getParam<Real>("p_SUPG"))
      38             : {
      39         285 : }
      40             : 
      41             : RealVectorValue
      42     6278018 : RichardsSUPGstandard::velSUPG(RealTensorValue perm,
      43             :                               RealVectorValue gradp,
      44             :                               Real density,
      45             :                               RealVectorValue gravity) const
      46             : {
      47     6278018 :   return -perm * (gradp - density * gravity); // points in direction of info propagation
      48             : }
      49             : 
      50             : RealTensorValue
      51     6278018 : RichardsSUPGstandard::dvelSUPG_dgradp(RealTensorValue perm) const
      52             : {
      53     6278018 :   return -perm;
      54             : }
      55             : 
      56             : RealVectorValue
      57     6278018 : RichardsSUPGstandard::dvelSUPG_dp(RealTensorValue perm,
      58             :                                   Real density_prime,
      59             :                                   RealVectorValue gravity) const
      60             : {
      61     6278018 :   return perm * density_prime * gravity;
      62             : }
      63             : 
      64             : Real
      65    18700854 : RichardsSUPGstandard::cosh_relation(Real alpha) const
      66             : {
      67    18700854 :   if (alpha >= 5.0 || alpha <= -5.0)
      68    12450507 :     return ((alpha > 0.0) ? 1.0 : -1.0) - 1.0 / alpha; // prevents overflows
      69     6250347 :   else if (alpha == 0)
      70             :     return 0.0;
      71     6250347 :   return 1.0 / std::tanh(alpha) - 1.0 / alpha;
      72             : }
      73             : 
      74             : Real
      75    12467236 : RichardsSUPGstandard::cosh_relation_prime(Real alpha) const
      76             : {
      77    12467236 :   if (alpha >= 5.0 || alpha <= -5.0)
      78     8300338 :     return 1.0 / (alpha * alpha); // prevents overflows
      79     4166898 :   else if (alpha == 0)
      80             :     return 1.0 / 3.0;
      81     4166898 :   return 1.0 - Utility::pow<2>(std::cosh(alpha) / std::sinh(alpha)) + 1.0 / (alpha * alpha);
      82             : }
      83             : 
      84             : // the following is physically 2*velocity/element_length
      85             : RealVectorValue
      86     6278018 : RichardsSUPGstandard::bb(RealVectorValue vel,
      87             :                          int dimen,
      88             :                          RealVectorValue xi_prime,
      89             :                          RealVectorValue eta_prime,
      90             :                          RealVectorValue zeta_prime) const
      91             : {
      92             :   RealVectorValue b;
      93     6278018 :   b(0) = xi_prime * vel;
      94     6278018 :   if (dimen >= 2)
      95     3612740 :     b(1) = eta_prime * vel;
      96     3612740 :   if (dimen == 3)
      97     1748844 :     b(2) = zeta_prime * vel;
      98     6278018 :   return b;
      99             : }
     100             : 
     101             : // following is d(bb*bb)/d(gradp)
     102             : RealVectorValue
     103     6278018 : RichardsSUPGstandard::dbb2_dgradp(RealVectorValue vel,
     104             :                                   RealTensorValue dvel_dgradp,
     105             :                                   RealVectorValue xi_prime,
     106             :                                   RealVectorValue eta_prime,
     107             :                                   RealVectorValue zeta_prime) const
     108             : {
     109             :   // if dvel_dgradp is symmetric so transpose is probably a waste of time
     110     6278018 :   return 2.0 * ((xi_prime * vel) * (dvel_dgradp.transpose() * xi_prime) +
     111     6278018 :                 (eta_prime * vel) * (dvel_dgradp.transpose() * eta_prime) +
     112     6278018 :                 (zeta_prime * vel) * (dvel_dgradp.transpose() * zeta_prime));
     113             : }
     114             : 
     115             : // following is d(bb*bb)/d(p)
     116             : Real
     117     6278018 : RichardsSUPGstandard::dbb2_dp(RealVectorValue vel,
     118             :                               RealVectorValue dvel_dp,
     119             :                               RealVectorValue xi_prime,
     120             :                               RealVectorValue eta_prime,
     121             :                               RealVectorValue zeta_prime) const
     122             : {
     123             :   return 2.0 *
     124     6278018 :          ((xi_prime * vel) * (dvel_dp * xi_prime) + (eta_prime * vel) * (dvel_dp * eta_prime) +
     125     6278018 :           (zeta_prime * vel) * (dvel_dp * zeta_prime));
     126             : }
     127             : 
     128             : Real
     129     6278018 : RichardsSUPGstandard::tauSUPG(RealVectorValue vel, Real traceperm, RealVectorValue b) const
     130             : {
     131             :   // vel = velocity, b = bb
     132     6278018 :   Real norm_v = vel.norm();
     133     6278018 :   Real norm_b = b.norm(); // Hughes et al investigate infinity-norm and 2-norm.  i just use 2-norm
     134             :                           // here.   norm_b ~ 2|a|/ele_length_in_direction_of_a
     135             : 
     136     6278018 :   if (norm_b == 0)
     137             :     return 0.0; // Only way for norm_b=0 is for zero ele size, or vel=0.  Either way we don't have
     138             :                 // to upwind.
     139             : 
     140     6233618 :   Real h = 2.0 * norm_v / norm_b; // h is a measure of the element length in the "a" direction
     141     6233618 :   Real alpha = 0.5 * norm_v * h / (traceperm * _p_SUPG); // this is the Peclet number
     142             : 
     143     6233618 :   const Real xi_tilde = RichardsSUPGstandard::cosh_relation(alpha);
     144             : 
     145     6233618 :   return xi_tilde / norm_b;
     146             : }
     147             : 
     148             : RealVectorValue
     149     6278018 : RichardsSUPGstandard::dtauSUPG_dgradp(RealVectorValue vel,
     150             :                                       RealTensorValue dvel_dgradp,
     151             :                                       Real traceperm,
     152             :                                       RealVectorValue b,
     153             :                                       RealVectorValue db2_dgradp) const
     154             : {
     155     6278018 :   Real norm_vel = vel.norm();
     156     6278018 :   if (norm_vel == 0)
     157             :     return RealVectorValue();
     158             : 
     159     6234218 :   RealVectorValue norm_vel_dgradp(dvel_dgradp * vel / norm_vel);
     160             : 
     161     6234218 :   Real norm_b = b.norm();
     162     6234218 :   if (norm_b == 0)
     163             :     return RealVectorValue();
     164             :   RealVectorValue norm_b_dgradp = db2_dgradp / 2.0 / norm_b;
     165             : 
     166     6233618 :   Real h = 2 * norm_vel / norm_b; // h is a measure of the element length in the "a" direction
     167             :   RealVectorValue h_dgradp(2 * norm_vel_dgradp / norm_b -
     168             :                            2.0 * norm_vel * norm_b_dgradp / norm_b / norm_b);
     169             : 
     170     6233618 :   Real alpha = 0.5 * norm_vel * h / traceperm / _p_SUPG; // this is the Peclet number
     171             :   RealVectorValue alpha_dgradp =
     172             :       0.5 * (norm_vel_dgradp * h + norm_vel * h_dgradp) / traceperm / _p_SUPG;
     173             : 
     174     6233618 :   Real xi_tilde = RichardsSUPGstandard::cosh_relation(alpha);
     175     6233618 :   Real xi_tilde_prime = RichardsSUPGstandard::cosh_relation_prime(alpha);
     176             :   RealVectorValue xi_tilde_dgradp = xi_tilde_prime * alpha_dgradp;
     177             : 
     178             :   RealVectorValue tau_dgradp =
     179     6233618 :       xi_tilde_dgradp / norm_b - xi_tilde * norm_b_dgradp / (norm_b * norm_b);
     180             : 
     181     6233618 :   return tau_dgradp;
     182             : }
     183             : 
     184             : Real
     185     6278018 : RichardsSUPGstandard::dtauSUPG_dp(RealVectorValue vel,
     186             :                                   RealVectorValue dvel_dp,
     187             :                                   Real traceperm,
     188             :                                   RealVectorValue b,
     189             :                                   Real db2_dp) const
     190             : {
     191     6278018 :   Real norm_vel = vel.norm();
     192     6278018 :   if (norm_vel == 0.0)
     193             :     return 0.0; // this deriv is not necessarily correct, but i can't see a better thing to do
     194             : 
     195     6234218 :   Real norm_vel_dp = dvel_dp * vel / norm_vel;
     196             : 
     197     6234218 :   Real norm_b = b.norm();
     198     6234218 :   if (norm_b == 0)
     199             :     return 0.0; // this deriv is not necessarily correct, but i can't see a better thing to do
     200     6233618 :   Real norm_b_dp = db2_dp / (2.0 * norm_b);
     201             : 
     202     6233618 :   Real h = 2.0 * norm_vel / norm_b; // h is a measure of the element length in the "a" direction
     203     6233618 :   Real h_dp = 2.0 * norm_vel_dp / norm_b - 2.0 * norm_vel * norm_b_dp / (norm_b * norm_b);
     204             : 
     205     6233618 :   Real alpha = 0.5 * norm_vel * h / (traceperm * _p_SUPG); // this is the Peclet number
     206     6233618 :   Real alpha_dp = 0.5 * (norm_vel_dp * h + norm_vel * h_dp) / (traceperm * _p_SUPG);
     207             : 
     208     6233618 :   Real xi_tilde = RichardsSUPGstandard::cosh_relation(alpha);
     209     6233618 :   Real xi_tilde_prime = RichardsSUPGstandard::cosh_relation_prime(alpha);
     210     6233618 :   Real xi_tilde_dp = xi_tilde_prime * alpha_dp;
     211             : 
     212             :   // Real tau = xi_tilde/norm_b;
     213     6233618 :   const Real tau_dp = xi_tilde_dp / norm_b - xi_tilde * norm_b_dp / (norm_b * norm_b);
     214             : 
     215     6233618 :   return tau_dp;
     216             : }
     217             : 
     218             : bool
     219     8034169 : RichardsSUPGstandard::SUPG_trivial() const
     220             : {
     221     8034169 :   return false;
     222             : }

Generated by: LCOV version 1.14