LCOV - code coverage report
Current view: top level - src/materials - PorousFlowHystereticInfo.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 71 75 94.7 %
Date: 2025-09-04 07:55: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        8500 : PorousFlowHystereticInfo::validParams()
      16             : {
      17        8500 :   InputParameters params = PorousFlowHystereticCapillaryPressure::validParams();
      18       17000 :   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       17000 :   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       17000 :                           "pc");
      28       17000 :   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       17000 :   params.addParam<Real>(
      44             :       "fd_eps",
      45       17000 :       1E-8,
      46             :       "Small quantity used in computing the finite-difference approximations to derivatives");
      47        8500 :   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        8500 :   return params;
      58        8500 : }
      59             : 
      60        6600 : PorousFlowHystereticInfo::PorousFlowHystereticInfo(const InputParameters & parameters)
      61             :   : PorousFlowHystereticCapillaryPressure(parameters),
      62           0 :     _pc(_nodal_material ? declareProperty<Real>("PorousFlow_hysteretic_capillary_pressure_nodal")
      63       13200 :                         : declareProperty<Real>("PorousFlow_hysteretic_capillary_pressure_qp")),
      64        6600 :     _info(_nodal_material ? declareProperty<Real>("PorousFlow_hysteretic_info_nodal")
      65       13200 :                           : declareProperty<Real>("PorousFlow_hysteretic_info_qp")),
      66       13200 :     _pc_val(_nodal_material ? coupledDofValues("pc_var") : coupledValue("pc_var")),
      67       13200 :     _sat_val(_nodal_material ? coupledDofValues("sat_var") : coupledValue("sat_var")),
      68       13200 :     _fd_eps(getParam<Real>("fd_eps")),
      69       19800 :     _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        6600 : }
      74             : 
      75             : void
      76      330750 : PorousFlowHystereticInfo::initQpStatefulProperties()
      77             : {
      78      330750 :   PorousFlowHystereticCapillaryPressure::initQpStatefulProperties();
      79      330750 :   _saturation[_qp][0] = _sat_val[_qp];
      80      330750 :   _pc[_qp] = capillaryPressureQp(_sat_val[_qp]);
      81      330750 :   computeQpInfo();
      82      330750 : }
      83             : 
      84             : void
      85      638424 : PorousFlowHystereticInfo::computeQpProperties()
      86             : {
      87      638424 :   PorousFlowHystereticCapillaryPressure::computeQpProperties();
      88      638424 :   _saturation[_qp][0] = _sat_val[_qp];
      89      638424 :   _pc[_qp] = capillaryPressureQp(_sat_val[_qp]);
      90      638424 :   computeQpInfo();
      91      638424 : }
      92             : 
      93             : void
      94      969174 : PorousFlowHystereticInfo::computeQpInfo()
      95             : {
      96      969174 :   switch (_info_enum)
      97             :   {
      98      287194 :     case InfoTypeEnum::PC:
      99      287194 :       _info[_qp] = capillaryPressureQp(_sat_val[_qp]);
     100      287194 :       break;
     101      198860 :     case InfoTypeEnum::SAT:
     102             :     {
     103      198860 :       const Real pc = capillaryPressureQp(_sat_val[_qp]);
     104      198860 :       _info[_qp] = liquidSaturationQp(pc);
     105      198860 :       break;
     106             :     }
     107           0 :     case InfoTypeEnum::SAT_GIVEN_PC:
     108           0 :       _info[_qp] = liquidSaturationQp(_pc_val[_qp]);
     109           0 :       break;
     110      120780 :     case InfoTypeEnum::DS_DPC_ERR:
     111             :     {
     112      120780 :       const Real pc = capillaryPressureQp(_sat_val[_qp]);
     113             :       const Real fd =
     114      120780 :           0.5 * (liquidSaturationQp(pc + _fd_eps) - liquidSaturationQp(pc - _fd_eps)) / _fd_eps;
     115      120780 :       _info[_qp] = relativeError(fd, dliquidSaturationQp(pc));
     116      120780 :       break;
     117             :     }
     118      120780 :     case InfoTypeEnum::DPC_DS_ERR:
     119             :     {
     120      120780 :       const Real fd = 0.5 *
     121      120780 :                       (capillaryPressureQp(_sat_val[_qp] + _fd_eps) -
     122      120780 :                        capillaryPressureQp(_sat_val[_qp] - _fd_eps)) /
     123      120780 :                       _fd_eps;
     124      120780 :       _info[_qp] = relativeError(fd, dcapillaryPressureQp(_sat_val[_qp]));
     125      120780 :       break;
     126             :     }
     127      120780 :     case InfoTypeEnum::D2S_DPC2_ERR:
     128             :     {
     129      120780 :       const Real pc = capillaryPressureQp(_sat_val[_qp]);
     130             :       const Real fd =
     131      120780 :           0.5 * (dliquidSaturationQp(pc + _fd_eps) - dliquidSaturationQp(pc - _fd_eps)) / _fd_eps;
     132      120780 :       _info[_qp] = relativeError(fd, d2liquidSaturationQp(pc));
     133      120780 :       break;
     134             :     }
     135      120780 :     case InfoTypeEnum::D2PC_DS2_ERR:
     136             :     {
     137      120780 :       const Real fd = 0.5 *
     138      120780 :                       (dcapillaryPressureQp(_sat_val[_qp] + _fd_eps) -
     139      120780 :                        dcapillaryPressureQp(_sat_val[_qp] - _fd_eps)) /
     140      120780 :                       _fd_eps;
     141      120780 :       _info[_qp] = relativeError(fd, d2capillaryPressureQp(_sat_val[_qp]));
     142      120780 :       break;
     143             :     }
     144             :   }
     145      969174 : }
     146             : 
     147             : Real
     148      483120 : PorousFlowHystereticInfo::relativeError(Real finite_difference, Real hand_coded)
     149             : {
     150      483120 :   if (finite_difference == 0.0 && hand_coded == 0.0)
     151             :     return 0.0;
     152      458354 :   else if (finite_difference > 0.0 && hand_coded == 0.0)
     153             :     return std::numeric_limits<Real>::max();
     154      458354 :   else if (finite_difference < 0.0 && hand_coded == 0.0)
     155             :     return std::numeric_limits<Real>::min();
     156      445300 :   return finite_difference / hand_coded - 1.0;
     157             : }

Generated by: LCOV version 1.14