https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PorousFlowFluidMass.C
Go to the documentation of this file.
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 "PorousFlowFluidMass.h"
11
12#include "MooseVariable.h"
13
14#include "libmesh/quadrature.h"
15
18
19template <bool is_ad>
22{
24 params.addParam<unsigned int>(
25 "fluid_component",
26 0,
27 "The index corresponding to the fluid component that this Postprocessor acts on");
28 params.addRequiredParam<UserObjectName>(
29 "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names.");
30 params.addParam<std::vector<unsigned int>>("phase",
31 {},
32 "The index of the fluid phase that this "
33 "Postprocessor is restricted to. Multiple "
34 "indices can be entered");
35 params.addRangeCheckedParam<Real>("saturation_threshold",
36 1.0,
37 "saturation_threshold >= 0 & saturation_threshold <= 1",
38 "The saturation threshold below which the mass is calculated "
39 "for a specific phase. Default is 1.0. Note: only one "
40 "phase_index can be entered");
41 params.addParam<unsigned int>("kernel_variable_number",
42 0,
43 "The PorousFlow variable number (according to the dictator) of "
44 "the fluid-mass kernel. This is required only in the unusual "
45 "situation where a variety of different finite-element "
46 "interpolation schemes are employed in the simulation");
47 params.addParam<std::string>(
48 "base_name",
49 "For non-mechanically-coupled systems with no TensorMechanics strain calculators, base_name "
50 "need not be set. For mechanically-coupled systems, base_name should be the same base_name "
51 "as given to the TensorMechanics object that computes strain, so that this Postprocessor can "
52 "correctly account for changes in mesh volume. For non-mechanically-coupled systems, "
53 "base_name should not be the base_name of any TensorMechanics strain calculators.");
54 params.set<bool>("use_displaced_mesh") = false;
55 params.suppressParameter<bool>("use_displaced_mesh");
56 params.addClassDescription("Calculates the mass of a fluid component in a region");
57 return params;
58}
59
60template <bool is_ad>
62 : ElementIntegralPostprocessor(parameters),
63
64 _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
65 _fluid_component(getParam<unsigned int>("fluid_component")),
66 _phase_index(getParam<std::vector<unsigned int>>("phase")),
67 _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
68 _has_total_strain(hasMaterialProperty<RankTwoTensor>(_base_name + "total_strain")),
69 _total_strain(_has_total_strain
70 ? &getMaterialProperty<RankTwoTensor>(_base_name + "total_strain")
71 : nullptr),
72 _porosity(getGenericMaterialProperty<Real, is_ad>("PorousFlow_porosity_nodal")),
73 _fluid_density(getGenericMaterialProperty<std::vector<Real>, is_ad>(
74 "PorousFlow_fluid_phase_density_nodal")),
75 _fluid_saturation(
76 getGenericMaterialProperty<std::vector<Real>, is_ad>("PorousFlow_saturation_nodal")),
77 _mass_fraction(getGenericMaterialProperty<std::vector<std::vector<Real>>, is_ad>(
78 "PorousFlow_mass_frac_nodal")),
79 _saturation_threshold(getParam<Real>("saturation_threshold")),
80 _var(getParam<unsigned>("kernel_variable_number") < _dictator.numVariables()
81 ? &_fe_problem.getStandardVariable(
82 _tid,
83 _dictator
84 .getCoupledStandardMooseVars()[getParam<unsigned>("kernel_variable_number")]
85 ->name())
86 : nullptr)
87{
88 const unsigned int num_phases = _dictator.numPhases();
89 const unsigned int num_components = _dictator.numComponents();
90
91 // Check that the number of components entered is not greater than the total number of components
92 if (_fluid_component >= num_components)
94 "fluid_component",
95 "The Dictator proclaims that the number of components in this simulation is ",
96 num_components,
97 " whereas you have used a component index of ",
99 ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
100
101 // Check that the number of phases entered is not more than the total possible phases
102 if (_phase_index.size() > num_phases)
103 paramError("phase",
104 "The Dictator decrees that the number of phases in this simulation is ",
105 num_phases,
106 " but you have entered ",
107 _phase_index.size(),
108 " phases.");
109
110 // Check that kernel_variable_number is OK
111 if (getParam<unsigned>("kernel_variable_number") >= _dictator.numVariables())
112 paramError("kernel_variable_number",
113 "The Dictator pronounces that the number of PorousFlow variables is ",
115 ", however you have used ",
116 getParam<unsigned>("kernel_variable_number"),
117 ". This is an error");
118
119 // Now that we know kernel_variable_number is OK, _var must be OK,
120 // so ensure that reinit is called on _var:
122
123 // Also check that the phase indices entered are not greater than the number of phases
124 // to avoid a segfault. Note that the input parser takes care of negative inputs so we
125 // don't need to guard against them
126 if (!_phase_index.empty())
127 {
128 unsigned int max_phase_num = *std::max_element(_phase_index.begin(), _phase_index.end());
129 if (max_phase_num > num_phases - 1)
130 paramError("phase",
131 "The Dictator proclaims that the phase index ",
132 max_phase_num,
133 " is greater than the largest phase index possible, which is ",
134 num_phases - 1);
135 }
136
137 // Using saturation_threshold only makes sense for a specific phase_index
138 if (_saturation_threshold < 1.0 && _phase_index.size() != 1)
139 paramError("saturation_threshold",
140 "A single phase_index must be entered when prescribing a saturation_threshold");
141
142 // If _phase_index is empty, create vector of all phase numbers to calculate mass over all phases
143 if (_phase_index.empty())
144 for (unsigned int i = 0; i < num_phases; ++i)
145 _phase_index.push_back(i);
146
147 // Error if a strain base_name is provided but doesn't exist
148 if (parameters.isParamSetByUser("base_name") && !_has_total_strain)
149 paramError("base_name", "A strain base_name ", _base_name, " does not exist");
150}
151
152template <bool is_ad>
153Real
155{
156 Real sum = 0;
157
158 // The use of _test in the loops below mean that the
159 // integral is exactly the same as the one computed
160 // by the PorousFlowMassTimeDerivative Kernel. Because that
161 // Kernel is lumped, this Postprocessor also needs to
162 // be lumped. Hence the use of the "nodal" Material
163 // Properties
164 const VariableTestValue & test = _var->phi();
165
166 for (unsigned node = 0; node < test.size(); ++node)
167 {
168 Real nodal_volume = 0.0;
169 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
170 {
171 const Real n_v = _JxW[_qp] * _coord[_qp] * test[node][_qp];
172 if (_has_total_strain)
173 nodal_volume += n_v * (1.0 + (*_total_strain)[_qp].trace());
174 else
175 nodal_volume += n_v;
176 }
177
178 Real mass = 0.0;
179 for (auto ph : _phase_index)
180 {
181 if (MetaPhysicL::raw_value(_fluid_saturation[node][ph]) <= _saturation_threshold)
182 mass += MetaPhysicL::raw_value(_fluid_density[node][ph] * _fluid_saturation[node][ph] *
183 _mass_fraction[node][ph][_fluid_component]);
184 }
185 sum += nodal_volume * MetaPhysicL::raw_value(_porosity[node]) * mass;
186 }
187
188 return sum;
189}
190
191template <bool is_ad>
192Real
197
199template class PorousFlowFluidMassTempl<true>;
registerMooseObject("PorousFlowApp", PorousFlowFluidMass)
const std::string name
Definition Setup.h:21
void ErrorVector unsigned int
static InputParameters validParams()
void suppressParameter(const std::string &name)
bool isParamSetByUser(const std::string &name) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
T & set(const std::string &name, bool quiet_mode=false)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
const InputParameters & parameters() const
void paramError(const std::string &param, Args... args) const
void addMooseVariableDependency(MooseVariableFieldBase *var)
This holds maps between the nonlinear variables used in a PorousFlow simulation and the variable numb...
unsigned int numPhases() const
The number of fluid phases.
unsigned int numVariables() const
The number of PorousFlow variables.
unsigned int numComponents() const
The number of fluid components.
Postprocessor produces the mass of a given fluid component in a region.
static InputParameters validParams()
MooseVariable *const _var
The variable for the corresponding PorousFlowMassTimeDerivative Kernel: this provides test functions.
const PorousFlowDictator & _dictator
PorousFlowDictator UserObject.
virtual Real computeIntegral() override
std::vector< unsigned int > _phase_index
The phase indices that this Postprocessor is restricted to.
virtual Real computeQpIntegral() override
const Real _saturation_threshold
Saturation threshold - only fluid mass at saturations below this are calculated.
const std::string _base_name
base name used in the Tensor Mechanics strain calculator
PorousFlowFluidMassTempl(const InputParameters &parameters)
const unsigned int _fluid_component
The fluid component index that this Postprocessor applies to.
const bool _has_total_strain
Whether there is a Material called _base_name_total_strain.
auto raw_value(const Eigen::Map< T > &in)
VariableShapeValue< true > VariableTestValue