LCOV - code coverage report
Current view: top level - src/bcs - Q2PPiecewiseLinearSink.C (source / functions) Hit Total Coverage
Test: idaholab/moose richards: #31405 (292dce) with base fef103 Lines: 117 118 99.2 %
Date: 2025-09-04 07:56:35 Functions: 10 10 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 "Q2PPiecewiseLinearSink.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "MooseVariable.h"
      14             : 
      15             : // C++ includes
      16             : #include <iostream>
      17             : 
      18             : registerMooseObject("RichardsApp", Q2PPiecewiseLinearSink);
      19             : 
      20             : InputParameters
      21          55 : Q2PPiecewiseLinearSink::validParams()
      22             : {
      23          55 :   InputParameters params = IntegratedBC::validParams();
      24         110 :   params.addRequiredParam<bool>(
      25             :       "use_mobility",
      26             :       "If true, then fluxes are multiplied by (density*permeability_nn/viscosity), "
      27             :       "where the '_nn' indicates the component normal to the boundary.  In this "
      28             :       "case bare_flux is measured in Pa.s^-1.  This can be used in conjunction "
      29             :       "with use_relperm.");
      30         110 :   params.addRequiredParam<bool>("use_relperm",
      31             :                                 "If true, then fluxes are multiplied by relative "
      32             :                                 "permeability.  This can be used in conjunction "
      33             :                                 "with use_mobility");
      34         110 :   params.addRequiredParam<std::vector<Real>>(
      35             :       "pressures", "Tuple of pressure values.  Must be monotonically increasing.");
      36         110 :   params.addRequiredParam<std::vector<Real>>(
      37             :       "bare_fluxes",
      38             :       "Tuple of flux values (measured in kg.m^-2.s^-1 for use_mobility=false, and "
      39             :       "in Pa.s^-1 if use_mobility=true).  This flux is OUT of the medium: hence "
      40             :       "positive values of flux means this will be a SINK, while negative values "
      41             :       "indicate this flux will be a SOURCE.  A piecewise-linear fit is performed to "
      42             :       "the (pressure,bare_fluxes) pairs to obtain the flux at any arbitrary "
      43             :       "pressure, and the first or last bare_flux values are used if the quad-point "
      44             :       "pressure falls outside this range.");
      45         110 :   params.addParam<FunctionName>("multiplying_fcn",
      46         110 :                                 1.0,
      47             :                                 "If this function is provided, the flux "
      48             :                                 "will be multiplied by this function.  "
      49             :                                 "This is useful for spatially or "
      50             :                                 "temporally varying sinks");
      51         110 :   params.addRequiredParam<UserObjectName>(
      52             :       "fluid_density",
      53             :       "A RichardsDensity UserObject that defines the fluid density as a function of pressure.");
      54         110 :   params.addRequiredParam<UserObjectName>(
      55             :       "fluid_relperm",
      56             :       "A RichardsRelPerm UserObject (eg RichardsRelPermPower) that defines the "
      57             :       "fluid relative permeability as a function of the saturation Variable.");
      58         110 :   params.addRequiredCoupledVar("other_var",
      59             :                                "The other variable in the 2-phase system.  If "
      60             :                                "Variable=porepressure, the other_var=saturation, and "
      61             :                                "vice-versa.");
      62         110 :   params.addRequiredParam<bool>("var_is_porepressure",
      63             :                                 "This flag is needed to correctly calculate the Jacobian entries.  "
      64             :                                 "If set to true, this Sink will extract fluid from the phase with "
      65             :                                 "porepressure as its Variable (usually the liquid phase).  If set "
      66             :                                 "to false, this Sink will extract fluid from the phase with "
      67             :                                 "saturation as its variable (usually the gas phase)");
      68         110 :   params.addRequiredParam<Real>("fluid_viscosity", "The fluid dynamic viscosity");
      69          55 :   params.addClassDescription("Sink of fluid, controlled by (pressure, bare_fluxes) interpolation.  "
      70             :                              "This is for use in Q2P models");
      71          55 :   return params;
      72           0 : }
      73             : 
      74          20 : Q2PPiecewiseLinearSink::Q2PPiecewiseLinearSink(const InputParameters & parameters)
      75             :   : IntegratedBC(parameters),
      76          20 :     _use_mobility(getParam<bool>("use_mobility")),
      77          40 :     _use_relperm(getParam<bool>("use_relperm")),
      78          80 :     _sink_func(getParam<std::vector<Real>>("pressures"),
      79             :                getParam<std::vector<Real>>("bare_fluxes")),
      80          20 :     _m_func(getFunction("multiplying_fcn")),
      81          20 :     _density(getUserObject<RichardsDensity>("fluid_density")),
      82          20 :     _relperm(getUserObject<RichardsRelPerm>("fluid_relperm")),
      83          20 :     _other_var_nodal(coupledDofValues("other_var")),
      84          20 :     _other_var_num(coupled("other_var")),
      85          40 :     _var_is_pp(getParam<bool>("var_is_porepressure")),
      86          40 :     _viscosity(getParam<Real>("fluid_viscosity")),
      87          40 :     _permeability(getMaterialProperty<RealTensorValue>("permeability")),
      88          20 :     _num_nodes(0),
      89          20 :     _pp(0),
      90          20 :     _sat(0),
      91          20 :     _nodal_density(0),
      92          20 :     _dnodal_density_dp(0),
      93          20 :     _nodal_relperm(0),
      94          40 :     _dnodal_relperm_ds(0)
      95             : {
      96          20 : }
      97             : 
      98             : void
      99        1724 : Q2PPiecewiseLinearSink::prepareNodalValues()
     100             : {
     101        1724 :   _num_nodes = _other_var_nodal.size();
     102             : 
     103             :   // set _pp and _sat variables
     104        1724 :   _pp.resize(_num_nodes);
     105        1724 :   _sat.resize(_num_nodes);
     106        1724 :   if (_var_is_pp)
     107             :   {
     108        3134 :     for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
     109             :     {
     110        2544 :       _pp[nodenum] = _var.dofValues()[nodenum];
     111        2544 :       _sat[nodenum] = _other_var_nodal[nodenum];
     112             :     }
     113             :   }
     114             :   else
     115             :   {
     116        5854 :     for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
     117             :     {
     118        4720 :       _pp[nodenum] = _other_var_nodal[nodenum];
     119        4720 :       _sat[nodenum] = _var.dofValues()[nodenum];
     120             :     }
     121             :   }
     122             : 
     123             :   // calculate derived things
     124        1724 :   if (_use_mobility)
     125             :   {
     126        1180 :     _nodal_density.resize(_num_nodes);
     127        1180 :     _dnodal_density_dp.resize(_num_nodes);
     128        6268 :     for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
     129             :     {
     130        5088 :       _nodal_density[nodenum] = _density.density(_pp[nodenum]);
     131        5088 :       _dnodal_density_dp[nodenum] = _density.ddensity(_pp[nodenum]);
     132             :     }
     133             :   }
     134             : 
     135        1724 :   if (_use_relperm)
     136             :   {
     137        1180 :     _nodal_relperm.resize(_num_nodes);
     138        1180 :     _dnodal_relperm_ds.resize(_num_nodes);
     139        6268 :     for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
     140             :     {
     141        5088 :       _nodal_relperm[nodenum] = _relperm.relperm(_sat[nodenum]);
     142        5088 :       _dnodal_relperm_ds[nodenum] = _relperm.drelperm(_sat[nodenum]);
     143             :     }
     144             :   }
     145        1724 : }
     146             : 
     147             : void
     148         983 : Q2PPiecewiseLinearSink::computeResidual()
     149             : {
     150         983 :   prepareNodalValues();
     151         983 :   IntegratedBC::computeResidual();
     152         983 : }
     153             : 
     154             : Real
     155        9784 : Q2PPiecewiseLinearSink::computeQpResidual()
     156             : {
     157             :   Real flux = 0;
     158             :   Real k = 0;
     159             : 
     160        9784 :   flux = _test[_i][_qp] * _sink_func.sample(_pp[_i]);
     161        9784 :   if (_use_mobility)
     162             :   {
     163        7376 :     k = (_permeability[0] * _normals[_qp]) * _normals[_qp]; // assume that _permeability is constant
     164             :                                                             // throughout element so doesn't need to
     165             :                                                             // be upwinded
     166        7376 :     flux *= _nodal_density[_i] * k / _viscosity;
     167             :   }
     168        9784 :   if (_use_relperm)
     169        7376 :     flux *= _nodal_relperm[_i];
     170             : 
     171        9784 :   flux *= _m_func.value(_t, _q_point[_qp]);
     172             : 
     173        9784 :   return flux;
     174             : }
     175             : 
     176             : void
     177         313 : Q2PPiecewiseLinearSink::computeJacobian()
     178             : {
     179         313 :   prepareNodalValues();
     180         313 :   IntegratedBC::computeJacobian();
     181         313 : }
     182             : 
     183             : Real
     184       10912 : Q2PPiecewiseLinearSink::computeQpJacobian()
     185             : {
     186       10912 :   return jac(_var.number());
     187             : }
     188             : 
     189             : void
     190         428 : Q2PPiecewiseLinearSink::computeOffDiagJacobian(const unsigned int jvar)
     191             : {
     192         428 :   prepareNodalValues();
     193         428 :   IntegratedBC::computeOffDiagJacobian(jvar);
     194         428 : }
     195             : 
     196             : Real
     197        7744 : Q2PPiecewiseLinearSink::computeQpOffDiagJacobian(unsigned int jvar)
     198             : {
     199        7744 :   if (jvar == _var.number() || jvar == _other_var_num)
     200        7744 :     return jac(jvar);
     201             : 
     202             :   return 0.0;
     203             : }
     204             : 
     205             : Real
     206       18656 : Q2PPiecewiseLinearSink::jac(unsigned int wrt_num)
     207             : {
     208             :   Real flux = 0;
     209             :   Real deriv = 0;
     210             :   Real k = 0;
     211             :   Real mob = 0;
     212             :   Real mobp = 0;
     213             :   Real phi = 1;
     214             : 
     215       18656 :   if (_i != _j)
     216             :     return 0.0; // residual at node _i only depends on variables at that node
     217             : 
     218        4408 :   flux = _sink_func.sample(_pp[_i]);
     219             : 
     220        4408 :   if (_var_is_pp)
     221             :   {
     222             :     // derivative of the _sink_func
     223        1512 :     if (wrt_num == _var.number())
     224         888 :       deriv = _sink_func.sampleDerivative(_pp[_i]);
     225             :     else
     226             :       deriv = 0;
     227             : 
     228             :     // add derivative of the mobility
     229        1512 :     if (_use_mobility)
     230             :     {
     231        1512 :       k = (_permeability[0] * _normals[_qp]) * _normals[_qp];
     232        1512 :       mob = _nodal_density[_i] * k / _viscosity;
     233        1512 :       if (wrt_num == _var.number())
     234         888 :         mobp = _dnodal_density_dp[_i] * k / _viscosity; // else mobp = 0
     235        1512 :       deriv = mob * deriv + mobp * flux;
     236        1512 :       flux *= mob;
     237             :     }
     238             : 
     239             :     // add derivative of the relperm
     240        1512 :     if (_use_relperm)
     241             :     {
     242        1512 :       if (wrt_num == _other_var_num)
     243         624 :         deriv = _nodal_relperm[_i] * deriv + _dnodal_relperm_ds[_i] * flux;
     244             :       else
     245         888 :         deriv = _nodal_relperm[_i] * deriv;
     246             :     }
     247             :   }
     248             :   else
     249             :   {
     250             :     // derivative of the _sink_func
     251        2896 :     if (wrt_num == _other_var_num)
     252        1184 :       deriv = _sink_func.sampleDerivative(_pp[_i]);
     253             :     else
     254             :       deriv = 0;
     255             : 
     256             :     // add derivative of the mobility
     257        2896 :     if (_use_mobility)
     258             :     {
     259        1512 :       k = (_permeability[0] * _normals[_qp]) * _normals[_qp];
     260        1512 :       mob = _nodal_density[_i] * k / _viscosity;
     261        1512 :       if (wrt_num == _other_var_num)
     262         624 :         mobp = _dnodal_density_dp[_i] * k / _viscosity; // else mobp = 0
     263        1512 :       deriv = mob * deriv + mobp * flux;
     264        1512 :       flux *= mob;
     265             :     }
     266             : 
     267             :     // add derivative of the relperm
     268        2896 :     if (_use_relperm)
     269             :     {
     270        1512 :       if (wrt_num == _var.number())
     271         888 :         deriv = _nodal_relperm[_i] * deriv + _dnodal_relperm_ds[_i] * flux;
     272             :       else
     273         624 :         deriv = _nodal_relperm[_i] * deriv;
     274             :     }
     275             :   }
     276             : 
     277        4408 :   deriv *= _m_func.value(_t, _q_point[_qp]);
     278             : 
     279        4408 :   return _test[_i][_qp] * deriv * phi;
     280             : }

Generated by: LCOV version 1.14