LCOV - code coverage report
Current view: top level - src/materials - PorousFlowHystereticInfo.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #32971 (54bef8) with base c6cf66 Lines: 71 75 94.7 %
Date: 2026-05-29 20:38:56 Functions: 6 6 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 "PorousFlowHystereticInfo.h"
      11             : 
      12             : registerMooseObject("PorousFlowApp", PorousFlowHystereticInfo);
      13             : 
      14             : InputParameters
      15        3900 : PorousFlowHystereticInfo::validParams()
      16             : {
      17        3900 :   InputParameters params = PorousFlowHystereticCapillaryPressure::validParams();
      18        7800 :   params.addCoupledVar("pc_var",
      19             :                        0,
      20             :                        "Variable that represents capillary pressure.  Depending on info_required, "
      21             :                        "this may not be used to compute the info");
      22        7800 :   params.addRequiredCoupledVar(
      23             :       "sat_var",
      24             :       "Variable that represent liquid saturation.  This is always needed to "
      25             :       "ensure the hysteretic order is computed correctly");
      26             :   MooseEnum property_enum("pc sat sat_given_pc dS_dPc_err dPc_dS_err d2S_dPc2_err d2Pc_dS2_err",
      27        7800 :                           "pc");
      28        7800 :   params.addParam<MooseEnum>(
      29             :       "info_required",
      30             :       property_enum,
      31             :       "The type of information required.  pc: capillary pressure given the saturation (pc_var is "
      32             :       "not used in this case).  sat: given the liquid saturation, compute the capillary pressure, "
      33             :       "then invert the relationship to yield liquid saturation again (pc_var is not used in this "
      34             :       "case).  This is useful to understand the non-invertibility of the hysteretic relationships. "
      35             :       " sat_given_pc: given the capillary pressure, compute the saturation.  dS_dPc_err: relative "
      36             :       "error in d(sat)/d(pc) calculation, ie (S(Pc + fd_eps) - S(Pc - fd_eps))/(2 * eps * S'(Pc)) "
      37             :       "- 1, where S' is the coded derivative (Pc is computed from sat in this case: pc_var is not "
      38             :       "used).  This is useful for checking derivatives.  dPc_dS_err: relative error in "
      39             :       "d(pc)/d(sat) calculation, ie (Pc(S + fd_eps) - Pc(S - fd_eps)) / (2 * eps * Pc'(S)) - 1, "
      40             :       "where Pc' is the coded derative (pc_var is not used in this case).  d2S_dPc2_err: relative "
      41             :       "error in d^2(sat)/d(pc)^2 (Pc is computed from sat in this case: pc_var is not used).  "
      42             :       "d2Pc_dS2_err: relative error in d^2(pc)/d(sat)^2.");
      43        7800 :   params.addParam<Real>(
      44             :       "fd_eps",
      45        7800 :       1E-8,
      46             :       "Small quantity used in computing the finite-difference approximations to derivatives");
      47        3900 :   params.addClassDescription(
      48             :       "This Material computes capillary pressure or saturation, etc.  It is primarily "
      49             :       "of use when users desire to compute hysteretic quantities such as capillary pressure for "
      50             :       "visualisation purposes.  The "
      51             :       "result is written into PorousFlow_hysteretic_info_nodal or "
      52             :       "PorousFlow_hysteretic_info_qp (depending on the at_nodes flag).  It "
      53             :       "does not "
      54             :       "compute porepressure and should not be used in simulations that employ "
      55             :       "PorousFlow*PhaseHys* "
      56             :       "Materials.");
      57        3900 :   return params;
      58        3900 : }
      59             : 
      60        3000 : PorousFlowHystereticInfo::PorousFlowHystereticInfo(const InputParameters & parameters)
      61             :   : PorousFlowHystereticCapillaryPressure(parameters),
      62           0 :     _pc(_nodal_material ? declareProperty<Real>("PorousFlow_hysteretic_capillary_pressure_nodal")
      63        6000 :                         : declareProperty<Real>("PorousFlow_hysteretic_capillary_pressure_qp")),
      64        3000 :     _info(_nodal_material ? declareProperty<Real>("PorousFlow_hysteretic_info_nodal")
      65        6000 :                           : declareProperty<Real>("PorousFlow_hysteretic_info_qp")),
      66        6000 :     _pc_val(_nodal_material ? coupledDofValues("pc_var") : coupledValue("pc_var")),
      67        6000 :     _sat_val(_nodal_material ? coupledDofValues("sat_var") : coupledValue("sat_var")),
      68        6000 :     _fd_eps(getParam<Real>("fd_eps")),
      69        9000 :     _info_enum(getParam<MooseEnum>("info_required").getEnum<InfoTypeEnum>())
      70             : {
      71             :   // note that _num_phases must be positive, otherwise get a problem with using
      72             :   // PorousFlowHysteresisOrder, so _num_phases > 0 needn't be checked here
      73        3000 : }
      74             : 
      75             : void
      76      204750 : PorousFlowHystereticInfo::initQpStatefulProperties()
      77             : {
      78      204750 :   PorousFlowHystereticCapillaryPressure::initQpStatefulProperties();
      79      204750 :   _saturation[_qp][0] = _sat_val[_qp];
      80      204750 :   _pc[_qp] = capillaryPressureQp(_sat_val[_qp]);
      81      204750 :   computeQpInfo();
      82      204750 : }
      83             : 
      84             : void
      85      446616 : PorousFlowHystereticInfo::computeQpProperties()
      86             : {
      87      446616 :   PorousFlowHystereticCapillaryPressure::computeQpProperties();
      88      446616 :   _saturation[_qp][0] = _sat_val[_qp];
      89      446616 :   _pc[_qp] = capillaryPressureQp(_sat_val[_qp]);
      90      446616 :   computeQpInfo();
      91      446616 : }
      92             : 
      93             : void
      94      651366 : PorousFlowHystereticInfo::computeQpInfo()
      95             : {
      96      651366 :   switch (_info_enum)
      97             :   {
      98      192986 :     case InfoTypeEnum::PC:
      99      192986 :       _info[_qp] = capillaryPressureQp(_sat_val[_qp]);
     100      192986 :       break;
     101      133660 :     case InfoTypeEnum::SAT:
     102             :     {
     103      133660 :       const Real pc = capillaryPressureQp(_sat_val[_qp]);
     104      133660 :       _info[_qp] = liquidSaturationQp(pc);
     105      133660 :       break;
     106             :     }
     107           0 :     case InfoTypeEnum::SAT_GIVEN_PC:
     108           0 :       _info[_qp] = liquidSaturationQp(_pc_val[_qp]);
     109           0 :       break;
     110       81180 :     case InfoTypeEnum::DS_DPC_ERR:
     111             :     {
     112       81180 :       const Real pc = capillaryPressureQp(_sat_val[_qp]);
     113             :       const Real fd =
     114       81180 :           0.5 * (liquidSaturationQp(pc + _fd_eps) - liquidSaturationQp(pc - _fd_eps)) / _fd_eps;
     115       81180 :       _info[_qp] = relativeError(fd, dliquidSaturationQp(pc));
     116       81180 :       break;
     117             :     }
     118       81180 :     case InfoTypeEnum::DPC_DS_ERR:
     119             :     {
     120       81180 :       const Real fd = 0.5 *
     121       81180 :                       (capillaryPressureQp(_sat_val[_qp] + _fd_eps) -
     122       81180 :                        capillaryPressureQp(_sat_val[_qp] - _fd_eps)) /
     123       81180 :                       _fd_eps;
     124       81180 :       _info[_qp] = relativeError(fd, dcapillaryPressureQp(_sat_val[_qp]));
     125       81180 :       break;
     126             :     }
     127       81180 :     case InfoTypeEnum::D2S_DPC2_ERR:
     128             :     {
     129       81180 :       const Real pc = capillaryPressureQp(_sat_val[_qp]);
     130             :       const Real fd =
     131       81180 :           0.5 * (dliquidSaturationQp(pc + _fd_eps) - dliquidSaturationQp(pc - _fd_eps)) / _fd_eps;
     132       81180 :       _info[_qp] = relativeError(fd, d2liquidSaturationQp(pc));
     133       81180 :       break;
     134             :     }
     135       81180 :     case InfoTypeEnum::D2PC_DS2_ERR:
     136             :     {
     137       81180 :       const Real fd = 0.5 *
     138       81180 :                       (dcapillaryPressureQp(_sat_val[_qp] + _fd_eps) -
     139       81180 :                        dcapillaryPressureQp(_sat_val[_qp] - _fd_eps)) /
     140       81180 :                       _fd_eps;
     141       81180 :       _info[_qp] = relativeError(fd, d2capillaryPressureQp(_sat_val[_qp]));
     142       81180 :       break;
     143             :     }
     144             :   }
     145      651366 : }
     146             : 
     147             : Real
     148      324720 : PorousFlowHystereticInfo::relativeError(Real finite_difference, Real hand_coded)
     149             : {
     150      324720 :   if (finite_difference == 0.0 && hand_coded == 0.0)
     151             :     return 0.0;
     152      308074 :   else if (finite_difference > 0.0 && hand_coded == 0.0)
     153             :     return std::numeric_limits<Real>::max();
     154      308074 :   else if (finite_difference < 0.0 && hand_coded == 0.0)
     155             :     return std::numeric_limits<Real>::min();
     156      299300 :   return finite_difference / hand_coded - 1.0;
     157             : }

Generated by: LCOV version 1.14