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 : }