LCOV - code coverage report
Current view: top level - src/userobjects - PorousFlowCapillaryPressure.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 93 94 98.9 %
Date: 2025-09-04 07:55:56 Functions: 20 20 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 "PorousFlowCapillaryPressure.h"
      11             : 
      12             : InputParameters
      13       11411 : PorousFlowCapillaryPressure::validParams()
      14             : {
      15       11411 :   InputParameters params = DiscreteElementUserObject::validParams();
      16       34233 :   params.addRangeCheckedParam<Real>(
      17             :       "sat_lr",
      18       22822 :       0.0,
      19             :       "sat_lr >= 0 & sat_lr < 1",
      20             :       "Liquid residual saturation.  Must be between 0 and 1. Default is 0");
      21       34233 :   params.addRangeCheckedParam<Real>("pc_max",
      22       22822 :                                     1.0e9,
      23             :                                     "pc_max > 0",
      24             :                                     "Maximum capillary pressure (Pa). Must be > 0. Default is 1e9");
      25       22822 :   params.addParam<bool>("log_extension",
      26       22822 :                         true,
      27             :                         "Use a logarithmic extension for low saturation to avoid capillary "
      28             :                         "pressure going to infinity. Default is true.  Set to false if your "
      29             :                         "capillary pressure depends on spatially-dependent variables other than "
      30             :                         "saturation, as the log-extension C++ code for this case has yet to be "
      31             :                         "implemented");
      32       11411 :   params.addClassDescription("Capillary pressure base class");
      33       11411 :   return params;
      34           0 : }
      35             : 
      36        6251 : PorousFlowCapillaryPressure::PorousFlowCapillaryPressure(const InputParameters & parameters)
      37             :   : DiscreteElementUserObject(parameters),
      38        6251 :     _sat_lr(getParam<Real>("sat_lr")),
      39        6251 :     _dseff_ds(1.0 / (1.0 - _sat_lr)),
      40       12502 :     _log_ext(getParam<bool>("log_extension")),
      41       12502 :     _pc_max(getParam<Real>("pc_max")),
      42        6251 :     _sat_ext(0.0),
      43        6251 :     _pc_ext(0.0),
      44        6251 :     _slope_ext(0.0),
      45        6251 :     _log10(std::log(10.0))
      46             : {
      47        6251 : }
      48             : 
      49             : void
      50        6020 : PorousFlowCapillaryPressure::initialSetup()
      51             : {
      52             :   // If _log_ext = true, calculate the saturation where the the logarithmic
      53             :   // extension meets the raw capillary pressure curve.
      54        6020 :   if (_log_ext)
      55             :   {
      56        3974 :     _sat_ext = extensionSaturation();
      57        3974 :     _pc_ext = capillaryPressure(_sat_ext);
      58        3974 :     _slope_ext = (std::log10(_pc_ext) - std::log10(_pc_max)) / _sat_ext;
      59             :   }
      60        6020 : }
      61             : 
      62             : Real
      63     4808132 : PorousFlowCapillaryPressure::capillaryPressure(Real saturation, unsigned qp) const
      64             : {
      65     4808132 :   if (_log_ext && saturation < _sat_ext)
      66        9782 :     return capillaryPressureLogExt(saturation);
      67             :   else
      68     4798350 :     return capillaryPressureCurve(saturation, qp);
      69             : }
      70             : 
      71             : ADReal
      72     1678597 : PorousFlowCapillaryPressure::capillaryPressure(const ADReal & saturation, unsigned qp) const
      73             : {
      74     1678597 :   const Real Pc = capillaryPressure(saturation.value(), qp);
      75     1678597 :   const Real dPc_ds = dCapillaryPressure(saturation.value(), qp);
      76             : 
      77     1678597 :   ADReal result = Pc;
      78     1678597 :   result.derivatives() = saturation.derivatives() * dPc_ds;
      79             : 
      80     1678597 :   return result;
      81             : }
      82             : 
      83             : Real
      84     4064334 : PorousFlowCapillaryPressure::dCapillaryPressure(Real saturation, unsigned qp) const
      85             : {
      86     4064334 :   if (_log_ext && saturation < _sat_ext)
      87        9038 :     return dCapillaryPressureLogExt(saturation);
      88             :   else
      89     4055296 :     return dCapillaryPressureCurve(saturation, qp);
      90             : }
      91             : 
      92             : ADReal
      93       34060 : PorousFlowCapillaryPressure::dCapillaryPressure(const ADReal & saturation, unsigned qp) const
      94             : {
      95       34060 :   const Real dPc = dCapillaryPressure(saturation.value(), qp);
      96       34060 :   const Real d2Pc_ds2 = d2CapillaryPressure(saturation.value(), qp);
      97             : 
      98       34060 :   ADReal result = dPc;
      99       34060 :   result.derivatives() = saturation.derivatives() * d2Pc_ds2;
     100             : 
     101       34060 :   return result;
     102             : }
     103             : 
     104             : Real
     105     1527761 : PorousFlowCapillaryPressure::d2CapillaryPressure(Real saturation, unsigned qp) const
     106             : {
     107     1527761 :   if (_log_ext && saturation < _sat_ext)
     108        7062 :     return d2CapillaryPressureLogExt(saturation);
     109             :   else
     110     1520699 :     return d2CapillaryPressureCurve(saturation, qp);
     111             : }
     112             : 
     113             : Real
     114     3313820 : PorousFlowCapillaryPressure::effectiveSaturationFromSaturation(Real saturation) const
     115             : {
     116     3313820 :   return (saturation - _sat_lr) / (1.0 - _sat_lr);
     117             : }
     118             : 
     119             : Real
     120    47852275 : PorousFlowCapillaryPressure::saturation(Real pc, unsigned qp) const
     121             : {
     122    47852275 :   return effectiveSaturation(pc, qp) * (1.0 - _sat_lr) + _sat_lr;
     123             : }
     124             : 
     125             : ADReal
     126      355173 : PorousFlowCapillaryPressure::saturation(const ADReal & pc, unsigned qp) const
     127             : {
     128      355173 :   const Real s = effectiveSaturation(pc.value(), qp) * (1.0 - _sat_lr) + _sat_lr;
     129      355173 :   const Real ds_dpc = dEffectiveSaturation(pc.value(), qp) * (1.0 - _sat_lr);
     130             : 
     131      355173 :   ADReal result = s;
     132      355173 :   result.derivatives() = pc.derivatives() * ds_dpc;
     133             : 
     134      355173 :   return result;
     135             : }
     136             : 
     137             : Real
     138    46651921 : PorousFlowCapillaryPressure::dSaturation(Real pc, unsigned qp) const
     139             : {
     140    46651921 :   return dEffectiveSaturation(pc, qp) * (1.0 - _sat_lr);
     141             : }
     142             : 
     143             : ADReal
     144      353642 : PorousFlowCapillaryPressure::dSaturation(const ADReal & pc, unsigned qp) const
     145             : {
     146      353642 :   const Real ds = dEffectiveSaturation(pc.value(), qp) * (1.0 - _sat_lr);
     147      353642 :   const Real d2s_dpc2 = d2EffectiveSaturation(pc.value(), qp) * (1.0 - _sat_lr);
     148             : 
     149      353642 :   ADReal result = ds;
     150      353642 :   result.derivatives() = pc.derivatives() * d2s_dpc2;
     151             : 
     152      353642 :   return result;
     153             : }
     154             : 
     155             : Real
     156    23137461 : PorousFlowCapillaryPressure::d2Saturation(Real pc, unsigned qp) const
     157             : {
     158    23137461 :   return d2EffectiveSaturation(pc, qp) * (1.0 - _sat_lr);
     159             : }
     160             : 
     161             : Real
     162        9782 : PorousFlowCapillaryPressure::capillaryPressureLogExt(Real saturation) const
     163             : {
     164        9782 :   return _pc_ext * std::pow(10.0, _slope_ext * (saturation - _sat_ext));
     165             : }
     166             : 
     167             : Real
     168        9038 : PorousFlowCapillaryPressure::dCapillaryPressureLogExt(Real saturation) const
     169             : {
     170        9038 :   return _pc_ext * _slope_ext * _log10 * std::pow(10.0, _slope_ext * (saturation - _sat_ext));
     171             : }
     172             : 
     173             : Real
     174        7062 : PorousFlowCapillaryPressure::d2CapillaryPressureLogExt(Real saturation) const
     175             : {
     176        7062 :   return _pc_ext * _slope_ext * _slope_ext * _log10 * _log10 *
     177        7062 :          std::pow(10.0, _slope_ext * (saturation - _sat_ext));
     178             : }
     179             : 
     180             : Real
     181        3974 : PorousFlowCapillaryPressure::extensionSaturation() const
     182             : {
     183             :   // Initial guess for saturation where extension matches curve
     184        3974 :   Real sat = _sat_lr + 0.01;
     185             : 
     186             :   // Calculate the saturation where the extension matches the derivative of the
     187             :   // raw capillary pressure curve
     188             :   const unsigned int max_its = 20;
     189             :   const Real nr_tol = 1.0e-8;
     190             :   unsigned int iter = 0;
     191             : 
     192       10368 :   while (std::abs(interceptFunction(sat)) > nr_tol)
     193             :   {
     194        6394 :     sat = sat - interceptFunction(sat) / interceptFunctionDeriv(sat);
     195             : 
     196        6394 :     iter++;
     197        6394 :     if (iter > max_its)
     198             :       break;
     199             :   }
     200             : 
     201        3974 :   return sat;
     202             : }
     203             : 
     204             : Real
     205       16762 : PorousFlowCapillaryPressure::interceptFunction(Real saturation) const
     206             : {
     207       16762 :   Real pc = capillaryPressureCurve(saturation);
     208       16762 :   Real dpc = dCapillaryPressureCurve(saturation);
     209             : 
     210       16762 :   return std::log10(pc) - saturation * dpc / (_log10 * pc) - std::log10(_pc_max);
     211             : }
     212             : 
     213             : Real
     214        6394 : PorousFlowCapillaryPressure::interceptFunctionDeriv(Real saturation) const
     215             : {
     216        6394 :   Real pc = capillaryPressureCurve(saturation);
     217        6394 :   Real dpc = dCapillaryPressureCurve(saturation);
     218        6394 :   Real d2pc = d2CapillaryPressureCurve(saturation);
     219             : 
     220        6394 :   return saturation * (dpc * dpc / pc - d2pc) / (_log10 * pc);
     221             : }

Generated by: LCOV version 1.14