LCOV - code coverage report
Current view: top level - src/bcs - PorousFlowOutflowBC.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 145 151 96.0 %
Date: 2025-09-04 07:55:56 Functions: 9 9 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 "PorousFlowOutflowBC.h"
      11             : 
      12             : #include "MooseVariable.h"
      13             : #include "libmesh/string_to_enum.h"
      14             : #include "libmesh/quadrature.h"
      15             : 
      16             : registerMooseObject("PorousFlowApp", PorousFlowOutflowBC);
      17             : 
      18             : InputParameters
      19         383 : PorousFlowOutflowBC::validParams()
      20             : {
      21         383 :   InputParameters params = IntegratedBC::validParams();
      22         766 :   params.addRequiredParam<UserObjectName>(
      23             :       "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names");
      24         766 :   params.addRequiredParam<RealVectorValue>("gravity",
      25             :                                            "Gravitational acceleration vector downwards (m/s^2)");
      26         766 :   MooseEnum flux_type_enum("fluid heat", "fluid");
      27         766 :   params.addParam<MooseEnum>(
      28             :       "flux_type",
      29             :       flux_type_enum,
      30             :       "The type of boundary condition to apply.  'fluid' means this boundary condition will allow "
      31             :       "a fluid component to flow freely from the boundary.  'heat' means this boundary condition "
      32             :       "will allow heat energy to flow freely from the boundary");
      33         766 :   params.addParam<unsigned int>(
      34             :       "mass_fraction_component",
      35         766 :       0,
      36             :       "The index corresponding to a fluid "
      37             :       "component.  If supplied, the residual contribution will be "
      38             :       "multiplied by the mass fraction, corresponding to allowing the "
      39             :       "given mass fraction to flow freely from the boundary.  This is ignored if flux_type = heat");
      40         766 :   params.addParam<bool>("multiply_by_density",
      41         766 :                         true,
      42             :                         "If true, this BC represents mass flux.  If false, it represents volume "
      43             :                         "flux.  User input of this flag is ignored if flux_type = heat as "
      44             :                         "multiply_by_density should always be true in that case");
      45         766 :   params.addParam<bool>(
      46             :       "include_relperm",
      47         766 :       true,
      48             :       "If true, the Darcy flux will include the relative permeability.  If false, the relative "
      49             :       "permeability will not be used, which must only be used for fully-saturated situations "
      50             :       "where there is no notion of relative permeability");
      51         766 :   params.addParam<Real>(
      52             :       "multiplier",
      53         766 :       1.0,
      54             :       "Multiply the flux by this number.  This is mainly used for testing purposes");
      55         766 :   params.addParamNamesToGroup("multiplier", "Advanced");
      56         383 :   params.addClassDescription(
      57             :       "Applies an 'outflow' boundary condition, which allows fluid components or heat energy to "
      58             :       "flow freely out of the boundary as if it weren't there.  This is fully upwinded");
      59         383 :   return params;
      60         383 : }
      61             : 
      62         216 : PorousFlowOutflowBC::PorousFlowOutflowBC(const InputParameters & parameters)
      63             :   : IntegratedBC(parameters),
      64         216 :     _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
      65         216 :     _num_phases(_dictator.numPhases()),
      66         216 :     _perm_derivs(_dictator.usePermDerivs()),
      67         432 :     _flux_type(getParam<MooseEnum>("flux_type").getEnum<FluxTypeChoiceEnum>()),
      68         432 :     _sp(getParam<unsigned>("mass_fraction_component")),
      69         216 :     _multiply_by_density(
      70         398 :         _flux_type == FluxTypeChoiceEnum::FLUID ? getParam<bool>("multiply_by_density") : true),
      71         432 :     _include_relperm(getParam<bool>("include_relperm")),
      72         432 :     _gravity(getParam<RealVectorValue>("gravity")),
      73         432 :     _multiplier(getParam<Real>("multiplier")),
      74         432 :     _grad_p(getMaterialProperty<std::vector<RealGradient>>("PorousFlow_grad_porepressure_qp")),
      75         432 :     _dgrad_p_dgrad_var(getMaterialProperty<std::vector<std::vector<Real>>>(
      76             :         "dPorousFlow_grad_porepressure_qp_dgradvar")),
      77         432 :     _dgrad_p_dvar(getMaterialProperty<std::vector<std::vector<RealGradient>>>(
      78             :         "dPorousFlow_grad_porepressure_qp_dvar")),
      79         432 :     _fluid_density_qp(getMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_qp")),
      80         432 :     _dfluid_density_qp_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
      81             :         "dPorousFlow_fluid_phase_density_qp_dvar")),
      82         432 :     _permeability(getMaterialProperty<RealTensorValue>("PorousFlow_permeability_qp")),
      83         216 :     _dpermeability_dvar(
      84         216 :         getMaterialProperty<std::vector<RealTensorValue>>("dPorousFlow_permeability_qp_dvar")),
      85         432 :     _dpermeability_dgradvar(getMaterialProperty<std::vector<std::vector<RealTensorValue>>>(
      86             :         "dPorousFlow_permeability_qp_dgradvar")),
      87         432 :     _fluid_viscosity(getMaterialProperty<std::vector<Real>>("PorousFlow_viscosity_nodal")),
      88         216 :     _dfluid_viscosity_dvar(
      89         216 :         getMaterialProperty<std::vector<std::vector<Real>>>("dPorousFlow_viscosity_nodal_dvar")),
      90             : 
      91         216 :     _has_density(hasMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_nodal") &&
      92         430 :                  hasMaterialProperty<std::vector<std::vector<Real>>>(
      93             :                      "dPorousFlow_fluid_phase_density_nodal_dvar")),
      94         216 :     _has_mass_fraction(
      95         216 :         hasMaterialProperty<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_nodal") &&
      96         430 :         hasMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
      97             :             "dPorousFlow_mass_frac_nodal_dvar")),
      98         216 :     _has_relperm(hasMaterialProperty<std::vector<Real>>("PorousFlow_relative_permeability_nodal") &&
      99         430 :                  hasMaterialProperty<std::vector<std::vector<Real>>>(
     100             :                      "dPorousFlow_relative_permeability_nodal_dvar")),
     101         216 :     _has_enthalpy(hasMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_enthalpy_nodal") &&
     102         428 :                   hasMaterialProperty<std::vector<std::vector<Real>>>(
     103             :                       "dPorousFlow_fluid_phase_enthalpy_nodal_dvar")),
     104         216 :     _has_thermal_conductivity(
     105         216 :         hasMaterialProperty<RealTensorValue>("PorousFlow_thermal_conductivity_qp") &&
     106         263 :         hasMaterialProperty<std::vector<RealTensorValue>>(
     107             :             "dPorousFlow_thermal_conductivity_qp_dvar")),
     108         430 :     _has_t(hasMaterialProperty<RealGradient>("PorousFlow_grad_temperature_qp") &&
     109         432 :            hasMaterialProperty<std::vector<RealGradient>>("dPorousFlow_grad_temperature_qp_dvar") &&
     110         430 :            hasMaterialProperty<std::vector<Real>>("dPorousFlow_grad_temperature_qp_dgradvar")),
     111             : 
     112         430 :     _fluid_density_node(_has_density ? &getMaterialProperty<std::vector<Real>>(
     113             :                                            "PorousFlow_fluid_phase_density_nodal")
     114             :                                      : nullptr),
     115         430 :     _dfluid_density_node_dvar(_has_density ? &getMaterialProperty<std::vector<std::vector<Real>>>(
     116             :                                                  "dPorousFlow_fluid_phase_density_nodal_dvar")
     117             :                                            : nullptr),
     118         430 :     _relative_permeability(_has_relperm ? &getMaterialProperty<std::vector<Real>>(
     119             :                                               "PorousFlow_relative_permeability_nodal")
     120             :                                         : nullptr),
     121         432 :     _drelative_permeability_dvar(_has_relperm
     122         430 :                                      ? &getMaterialProperty<std::vector<std::vector<Real>>>(
     123             :                                            "dPorousFlow_relative_permeability_nodal_dvar")
     124             :                                      : nullptr),
     125         430 :     _mass_fractions(_has_mass_fraction ? &getMaterialProperty<std::vector<std::vector<Real>>>(
     126             :                                              "PorousFlow_mass_frac_nodal")
     127             :                                        : nullptr),
     128         432 :     _dmass_fractions_dvar(_has_mass_fraction
     129         430 :                               ? &getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
     130             :                                     "dPorousFlow_mass_frac_nodal_dvar")
     131             :                               : nullptr),
     132         428 :     _enthalpy(_has_enthalpy ? &getMaterialPropertyByName<std::vector<Real>>(
     133             :                                   "PorousFlow_fluid_phase_enthalpy_nodal")
     134             :                             : nullptr),
     135         428 :     _denthalpy_dvar(_has_enthalpy ? &getMaterialPropertyByName<std::vector<std::vector<Real>>>(
     136             :                                         "dPorousFlow_fluid_phase_enthalpy_nodal_dvar")
     137             :                                   : nullptr),
     138         263 :     _thermal_conductivity(_has_thermal_conductivity ? &getMaterialProperty<RealTensorValue>(
     139             :                                                           "PorousFlow_thermal_conductivity_qp")
     140             :                                                     : nullptr),
     141         432 :     _dthermal_conductivity_dvar(_has_thermal_conductivity
     142         263 :                                     ? &getMaterialProperty<std::vector<RealTensorValue>>(
     143             :                                           "dPorousFlow_thermal_conductivity_qp_dvar")
     144             :                                     : nullptr),
     145         430 :     _grad_t(_has_t ? &getMaterialProperty<RealGradient>("PorousFlow_grad_temperature_qp")
     146             :                    : nullptr),
     147         430 :     _dgrad_t_dvar(_has_t ? &getMaterialProperty<std::vector<RealGradient>>(
     148             :                                "dPorousFlow_grad_temperature_qp_dvar")
     149             :                          : nullptr),
     150         216 :     _dgrad_t_dgradvar(
     151         430 :         _has_t ? &getMaterialProperty<std::vector<Real>>("dPorousFlow_grad_temperature_qp_dgradvar")
     152         216 :                : nullptr)
     153             : {
     154         216 :   if (_flux_type == FluxTypeChoiceEnum::FLUID && _sp >= _dictator.numComponents())
     155           2 :     paramError("mass_fraction_component",
     156             :                "The Dictator declares that the maximum fluid component index is ",
     157           2 :                _dictator.numComponents() - 1,
     158             :                ", but you have set mass_fraction_component to ",
     159           2 :                _sp,
     160             :                ". Remember that indexing starts at 0. Please be assured that the Dictator has "
     161             :                "noted your error.");
     162             : 
     163         214 :   if (_multiply_by_density && !_has_density)
     164           2 :     mooseError("PorousFlowOutflowBC: You requested to multiply_by_density, but you have no nodal "
     165             :                "fluid density Material");
     166         212 :   if (_include_relperm && !_has_relperm)
     167           2 :     mooseError("PorousFlowOutflowBC: You requested to include the relative permeability, but you "
     168             :                "have no nodal relative permeability Material");
     169         210 :   if (_flux_type == FluxTypeChoiceEnum::FLUID && !_has_mass_fraction)
     170           2 :     mooseError(
     171             :         "PorousFlowOutflowBC: For flux_type = fluid, you need a nodal mass-fraction Material");
     172         208 :   if (_flux_type == FluxTypeChoiceEnum::HEAT && !_has_enthalpy)
     173           2 :     mooseError(
     174             :         "PorousFlowOutflowBC: For flux_type = heat, you need a nodal fluid enthalpy Material");
     175         206 :   if (_flux_type == FluxTypeChoiceEnum::HEAT && !_has_thermal_conductivity)
     176           2 :     mooseError(
     177             :         "PorousFlowOutflowBC: For flux_type = heat, you need a thermal conductivity Material");
     178         204 :   if (_flux_type == FluxTypeChoiceEnum::HEAT && !_has_t)
     179           2 :     mooseError("PorousFlowOutflowBC: For flux_type = heat, you need a temperature Material");
     180         202 : }
     181             : 
     182             : Real
     183      854560 : PorousFlowOutflowBC::computeQpResidual()
     184             : {
     185             :   Real advective_term = 0.0;
     186     1893560 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     187     1039000 :     advective_term -= darcy(ph) * mobility(ph) * prefactor(ph);
     188             : 
     189      854560 :   if (_flux_type == FluxTypeChoiceEnum::FLUID)
     190      615536 :     return _test[_i][_qp] * advective_term * _multiplier;
     191             : 
     192      239024 :   const Real conduction_term = -_normals[_qp] * ((*_thermal_conductivity)[_qp] * (*_grad_t)[_qp]);
     193      239024 :   return _test[_i][_qp] * (conduction_term + advective_term) * _multiplier;
     194             : }
     195             : 
     196             : Real
     197      399452 : PorousFlowOutflowBC::computeQpJacobian()
     198             : {
     199      399452 :   return jac(_var.number());
     200             : }
     201             : 
     202             : Real
     203      414940 : PorousFlowOutflowBC::computeQpOffDiagJacobian(unsigned int jvar)
     204             : {
     205      414940 :   return jac(jvar);
     206             : }
     207             : 
     208             : Real
     209      814392 : PorousFlowOutflowBC::jac(unsigned int jvar) const
     210             : {
     211      814392 :   if (_dictator.notPorousFlowVariable(jvar))
     212             :     return 0.0;
     213      814392 :   const unsigned int pvar = _dictator.porousFlowVariableNum(jvar);
     214             : 
     215             :   // For _i != _j, note:
     216             :   // since the only non-upwinded contribution to the residual is
     217             :   // from Darcy and thermal_conductivity, the only contribution
     218             :   // of the residual at node _i from changing jvar at node _j is through
     219             :   // the derivative of Darcy or thermal_conductivity
     220             : 
     221             :   Real advective_term_prime = 0.0;
     222     1776560 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     223             :   {
     224             :     Real darcyprime =
     225      962168 :         _normals[_qp] *
     226      962168 :         (_permeability[_qp] * (_grad_phi[_j][_qp] * _dgrad_p_dgrad_var[_qp][ph][pvar] +
     227      962168 :                                _dgrad_p_dvar[_qp][ph][pvar] * _phi[_j][_qp] -
     228      962168 :                                _dfluid_density_qp_dvar[_qp][ph][pvar] * _phi[_j][_qp] * _gravity));
     229      962168 :     if (_perm_derivs)
     230             :     {
     231           0 :       darcyprime += _normals[_qp] * (_dpermeability_dvar[_qp][pvar] * _phi[_j][_qp] *
     232           0 :                                      (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity));
     233           0 :       for (const auto i : make_range(Moose::dim))
     234           0 :         darcyprime +=
     235           0 :             _normals[_qp] * (_dpermeability_dgradvar[_qp][i][pvar] * _grad_phi[_j][_qp](i) *
     236           0 :                              (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity));
     237             :     }
     238      962168 :     if (_i != _j)
     239      820892 :       advective_term_prime -= prefactor(ph) * mobility(ph) * darcyprime;
     240             :     else
     241             :     {
     242      141276 :       const Real dar = darcy(ph);
     243             : 
     244      141276 :       Real mob = 1.0 / _fluid_viscosity[_i][ph];
     245             :       Real mobprime =
     246      141276 :           -_dfluid_viscosity_dvar[_i][ph][pvar] / Utility::pow<2>(_fluid_viscosity[_i][ph]);
     247      141276 :       if (_multiply_by_density)
     248             :       {
     249      141276 :         const Real densityprime = (*_dfluid_density_node_dvar)[_i][ph][pvar];
     250      141276 :         mobprime = densityprime * mob + (*_fluid_density_node)[_i][ph] * mobprime;
     251      141276 :         mob *= (*_fluid_density_node)[_i][ph];
     252             :       }
     253      141276 :       if (_include_relperm)
     254             :       {
     255      137376 :         const Real relpermprime = (*_drelative_permeability_dvar)[_i][ph][pvar];
     256      137376 :         mobprime = relpermprime * mob + (*_relative_permeability)[_i][ph] * mobprime;
     257      137376 :         mob *= (*_relative_permeability)[_i][ph];
     258             :       }
     259             : 
     260      141276 :       const Real pre = prefactor(ph);
     261             :       const Real preprime =
     262      141276 :           (_flux_type == FluxTypeChoiceEnum::FLUID ? (*_dmass_fractions_dvar)[_i][ph][_sp][pvar]
     263       44160 :                                                    : (*_denthalpy_dvar)[_i][ph][pvar]);
     264             : 
     265      141276 :       advective_term_prime -= preprime * mob * dar + pre * mobprime * dar + pre * mob * darcyprime;
     266             :     }
     267             :   }
     268      814392 :   if (_flux_type == FluxTypeChoiceEnum::FLUID)
     269      545592 :     return _test[_i][_qp] * advective_term_prime * _multiplier;
     270             : 
     271             :   const Real conduction_term_prime =
     272      268800 :       -_normals[_qp] *
     273      268800 :           ((*_dthermal_conductivity_dvar)[_qp][pvar] * (*_grad_t)[_qp] +
     274      268800 :            (*_thermal_conductivity)[_qp] * (*_dgrad_t_dvar)[_qp][pvar]) *
     275      268800 :           _phi[_j][_qp] -
     276             :       _normals[_qp] *
     277      268800 :           ((*_thermal_conductivity)[_qp] * (*_dgrad_t_dgradvar)[_qp][pvar] * _grad_phi[_j][_qp]);
     278      268800 :   return _test[_i][_qp] * (conduction_term_prime + advective_term_prime) * _multiplier;
     279             : }
     280             : 
     281             : Real
     282     1180276 : PorousFlowOutflowBC::darcy(unsigned ph) const
     283             : {
     284     1180276 :   return _normals[_qp] *
     285     1180276 :          (_permeability[_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity));
     286             : }
     287             : 
     288             : Real
     289     1859892 : PorousFlowOutflowBC::mobility(unsigned ph) const
     290             : {
     291     1859892 :   return (_multiply_by_density ? (*_fluid_density_node)[_i][ph] : 1.0) *
     292     1859892 :          (_include_relperm ? (*_relative_permeability)[_i][ph] : 1.0) / _fluid_viscosity[_i][ph];
     293             : }
     294             : 
     295             : Real
     296     2001168 : PorousFlowOutflowBC::prefactor(unsigned ph) const
     297             : {
     298     2001168 :   return (_flux_type == FluxTypeChoiceEnum::FLUID ? (*_mass_fractions)[_i][ph][_sp]
     299      507824 :                                                   : (*_enthalpy)[_i][ph]);
     300             : }

Generated by: LCOV version 1.14