opm-common
GasPvtThermal.hpp
Go to the documentation of this file.
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19  Consult the COPYING file in the top-level source directory of this
20  module for the precise wording of the license and the list of
21  copyright holders.
22 */
27 #ifndef OPM_GAS_PVT_THERMAL_HPP
28 #define OPM_GAS_PVT_THERMAL_HPP
29 
31 
32 #include <cstddef>
33 
34 namespace Opm {
35 
36 class EclipseState;
37 class Schedule;
38 
39 template <class Scalar, bool enableThermal>
40 class GasPvtMultiplexer;
41 
48 template <class Scalar>
50 {
51 public:
52  using IsothermalPvt = GasPvtMultiplexer<Scalar, /*enableThermal=*/false>;
54 
55  GasPvtThermal() = default;
56 
57  GasPvtThermal(IsothermalPvt* isothermalPvt,
58  const std::vector<TabulatedOneDFunction>& gasvisctCurves,
59  const std::vector<Scalar>& viscrefPress,
60  const std::vector<Scalar>& viscRef,
61  const std::vector<Scalar>& gasdentRefTemp,
62  const std::vector<Scalar>& gasdentCT1,
63  const std::vector<Scalar>& gasdentCT2,
64  const std::vector<Scalar>& gasJTRefPres,
65  const std::vector<Scalar>& gasJTC,
66  const std::vector<TabulatedOneDFunction>& internalEnergyCurves,
68  bool enableJouleThomson,
70  bool enableInternalEnergy)
71  : isothermalPvt_(isothermalPvt)
72  , gasvisctCurves_(gasvisctCurves)
73  , viscrefPress_(viscrefPress)
74  , viscRef_(viscRef)
75  , gasdentRefTemp_(gasdentRefTemp)
76  , gasdentCT1_(gasdentCT1)
77  , gasdentCT2_(gasdentCT2)
78  , gasJTRefPres_(gasJTRefPres)
79  , gasJTC_(gasJTC)
80  , internalEnergyCurves_(internalEnergyCurves)
81  , enableThermalDensity_(enableThermalDensity)
82  , enableJouleThomson_(enableJouleThomson)
83  , enableThermalViscosity_(enableThermalViscosity)
84  , enableInternalEnergy_(enableInternalEnergy)
85  { }
86 
87  GasPvtThermal(const GasPvtThermal& data)
88  { *this = data; }
89 
90  ~GasPvtThermal()
91  { delete isothermalPvt_; }
92 
96  void initFromState(const EclipseState& eclState, const Schedule& schedule);
97 
101  void setNumRegions(std::size_t numRegions);
102 
103  void setVapPars(const Scalar par1, const Scalar par2)
104  {
105  isothermalPvt_->setVapPars(par1, par2);
106  }
107 
111  void initEnd()
112  { }
113 
117  bool enableThermalDensity() const
118  { return enableThermalDensity_; }
119 
123  bool enableJouleThomson() const
124  { return enableJouleThomson_; }
125 
130  { return enableThermalViscosity_; }
131 
132  std::size_t numRegions() const
133  { return viscrefPress_.size(); }
134 
138  template <class Evaluation>
139  Evaluation internalEnergy(unsigned regionIdx,
140  const Evaluation& temperature,
141  const Evaluation& pressure,
142  const Evaluation& Rv,
143  [[maybe_unused]] const Evaluation& RvW) const
144  {
145  if (!enableInternalEnergy_) {
146  throw std::runtime_error("Requested the internal energy of gas but it is disabled");
147  }
148 
149  if (!enableJouleThomson_) {
150  // compute the specific internal energy for the specified tempature. We use linear
151  // interpolation here despite the fact that the underlying heat capacities are
152  // piecewise linear (which leads to a quadratic function)
153  return internalEnergyCurves_[regionIdx].eval(temperature, /*extrapolate=*/true);
154  }
155  else {
156  // NB should probably be revisited with adding more or restrict to linear internal energy
157  OpmLog::warning("Experimental code for jouleThomson: simulation will be slower");
158  Evaluation Tref = gasdentRefTemp_[regionIdx];
159  Evaluation Pref = gasJTRefPres_[regionIdx];
160  Scalar JTC = gasJTC_[regionIdx]; // if JTC is default then JTC is calculaited
161  Evaluation Rvw = 0.0;
162 
163  Evaluation invB = inverseFormationVolumeFactor(regionIdx, temperature, pressure, Rv, Rvw);
164  // NB this assumes internalEnergyCurve(0) = 0 derivative should be used add Cp table ??
165  Evaluation Cp = (internalEnergyCurves_[regionIdx].eval(temperature, /*extrapolate=*/true))/temperature;
166  Evaluation density = invB * (gasReferenceDensity(regionIdx) + Rv * rhoRefO_[regionIdx]);
167 
168  Evaluation enthalpyPres;
169  if (JTC != 0) {
170  enthalpyPres = -Cp * JTC * (pressure -Pref);
171  }
172  else if (enableThermalDensity_) {
173  Scalar c1T = gasdentCT1_[regionIdx];
174  Scalar c2T = gasdentCT2_[regionIdx];
175 
176  Evaluation alpha = (c1T + 2 * c2T * (temperature - Tref)) /
177  (1 + c1T *(temperature - Tref) + c2T * (temperature - Tref) * (temperature - Tref));
178 
179  constexpr const int N = 100; // value is experimental
180  Evaluation deltaP = (pressure - Pref)/N;
181  Evaluation enthalpyPresPrev = 0;
182  for (std::size_t i = 0; i < N; ++i) {
183  Evaluation Pnew = Pref + i * deltaP;
184  Evaluation rho = inverseFormationVolumeFactor(regionIdx, temperature, Pnew, Rv, Rvw) *
185  (gasReferenceDensity(regionIdx) + Rv * rhoRefO_[regionIdx]);
186  // see e.g.https://en.wikipedia.org/wiki/Joule-Thomson_effect for a derivation of the Joule-Thomson coeff.
187  Evaluation jouleThomsonCoefficient = -(1.0/Cp) * (1.0 - alpha * temperature)/rho;
188  Evaluation deltaEnthalpyPres = -Cp * jouleThomsonCoefficient * deltaP;
189  enthalpyPres = enthalpyPresPrev + deltaEnthalpyPres;
190  enthalpyPresPrev = enthalpyPres;
191  }
192  }
193  else {
194  throw std::runtime_error("Requested Joule-thomson calculation but thermal "
195  "gas density (GASDENT) is not provided");
196  }
197 
198  Evaluation enthalpy = Cp * (temperature - Tref) + enthalpyPres;
199 
200  return enthalpy - pressure/density;
201  }
202  }
203 
207  template <class Evaluation>
208  Evaluation viscosity(unsigned regionIdx,
209  const Evaluation& temperature,
210  const Evaluation& pressure,
211  const Evaluation& Rv,
212  const Evaluation& Rvw) const
213  {
214  const auto& isothermalMu = isothermalPvt_->viscosity(regionIdx, temperature, pressure, Rv, Rvw);
215  if (!enableThermalViscosity())
216  return isothermalMu;
217 
218  // compute the viscosity deviation due to temperature
219  const auto& muGasvisct = gasvisctCurves_[regionIdx].eval(temperature, /*extrapolate=*/true);
220  return muGasvisct/viscRef_[regionIdx]*isothermalMu;
221  }
222 
226  template <class Evaluation>
227  Evaluation saturatedViscosity(unsigned regionIdx,
228  const Evaluation& temperature,
229  const Evaluation& pressure) const
230  {
231  const auto& isothermalMu = isothermalPvt_->saturatedViscosity(regionIdx, temperature, pressure);
232  if (!enableThermalViscosity())
233  return isothermalMu;
234 
235  // compute the viscosity deviation due to temperature
236  const auto& muGasvisct = gasvisctCurves_[regionIdx].eval(temperature, true);
237  return muGasvisct/viscRef_[regionIdx]*isothermalMu;
238  }
239 
243  template <class Evaluation>
244  Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
245  const Evaluation& temperature,
246  const Evaluation& pressure,
247  const Evaluation& Rv,
248  const Evaluation& /*Rvw*/) const
249  {
250  const Evaluation& Rvw = 0.0;
251  const auto& b =
252  isothermalPvt_->inverseFormationVolumeFactor(regionIdx, temperature,
253  pressure, Rv, Rvw);
254 
255  if (!enableThermalDensity()) {
256  return b;
257  }
258 
259  // we use the same approach as for the for water here, but with the OPM-specific
260  // GASDENT keyword.
261  //
262  // TODO: Since gas is quite a bit more compressible than water, it might be
263  // necessary to make GASDENT to a table keyword. If the current temperature
264  // is relatively close to the reference temperature, the current approach
265  // should be good enough, though.
266  Scalar TRef = gasdentRefTemp_[regionIdx];
267  Scalar cT1 = gasdentCT1_[regionIdx];
268  Scalar cT2 = gasdentCT2_[regionIdx];
269  const Evaluation& Y = temperature - TRef;
270 
271  return b / (1 + (cT1 + cT2 * Y) * Y);
272  }
273 
277  template <class FluidState, class LhsEval = typename FluidState::ValueType>
278  std::pair<LhsEval, LhsEval>
279  inverseFormationVolumeFactorAndViscosity(const FluidState& fluidState, unsigned regionIdx)
280  {
281  auto [b, mu] = isothermalPvt_->inverseFormationVolumeFactorAndViscosity(fluidState, regionIdx);
282  const LhsEval& temperature = decay<LhsEval>(fluidState.temperature(FluidState::gasPhaseIdx));
283  if (enableThermalDensity()) {
284  // we use the same approach as for the for water here, but with the OPM-specific
285  // GASDENT keyword.
286  //
287  // TODO: Since gas is quite a bit more compressible than water, it might be
288  // necessary to make GASDENT to a table keyword. If the current temperature
289  // is relatively close to the reference temperature, the current approach
290  // should be good enough, though.
291  Scalar TRef = gasdentRefTemp_[regionIdx];
292  Scalar cT1 = gasdentCT1_[regionIdx];
293  Scalar cT2 = gasdentCT2_[regionIdx];
294  const LhsEval& Y = temperature - TRef;
295  b /= (1.0 + (cT1 + cT2 * Y) * Y);
296  }
297  if (enableThermalViscosity()) {
298  // compute the viscosity deviation due to temperature
299  const auto& muGasvisct = gasvisctCurves_[regionIdx].eval(temperature, /*extrapolate=*/true);
300  mu *= (muGasvisct / viscRef_[regionIdx]);
301  }
302  return { b, mu };
303  }
304 
308  template <class Evaluation>
309  Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx,
310  const Evaluation& temperature,
311  const Evaluation& pressure) const
312  {
313  const auto& b =
314  isothermalPvt_->saturatedInverseFormationVolumeFactor(regionIdx, temperature, pressure);
315 
316  if (!enableThermalDensity()) {
317  return b;
318  }
319 
320  // we use the same approach as for the for water here, but with the OPM-specific
321  // GASDENT keyword.
322  //
323  // TODO: Since gas is quite a bit more compressible than water, it might be
324  // necessary to make GASDENT to a table keyword. If the current temperature
325  // is relatively close to the reference temperature, the current approach
326  // should be good enough, though.
327  Scalar TRef = gasdentRefTemp_[regionIdx];
328  Scalar cT1 = gasdentCT1_[regionIdx];
329  Scalar cT2 = gasdentCT2_[regionIdx];
330  const Evaluation& Y = temperature - TRef;
331 
332  return b / (1 + (cT1 + cT2 * Y) * Y);
333  }
334 
338  template <class Evaluation>
339  Evaluation saturatedWaterVaporizationFactor(unsigned /*regionIdx*/,
340  const Evaluation& /*temperature*/,
341  const Evaluation& /*pressure*/) const
342  { return 0.0; }
343 
347  template <class Evaluation = Scalar>
348  Evaluation saturatedWaterVaporizationFactor(unsigned /*regionIdx*/,
349  const Evaluation& /*temperature*/,
350  const Evaluation& /*pressure*/,
351  const Evaluation& /*saltConcentration*/) const
352  { return 0.0; }
353 
361  template <class Evaluation>
362  Evaluation saturatedOilVaporizationFactor(unsigned regionIdx,
363  const Evaluation& temperature,
364  const Evaluation& pressure) const
365  { return isothermalPvt_->saturatedOilVaporizationFactor(regionIdx, temperature, pressure); }
366 
374  template <class Evaluation>
375  Evaluation saturatedOilVaporizationFactor(unsigned regionIdx,
376  const Evaluation& temperature,
377  const Evaluation& pressure,
378  const Evaluation& oilSaturation,
379  const Evaluation& maxOilSaturation) const
380  {
381  return isothermalPvt_->saturatedOilVaporizationFactor(regionIdx, temperature,
382  pressure, oilSaturation,
383  maxOilSaturation);
384  }
385 
393  template <class Evaluation>
394  Evaluation saturationPressure(unsigned regionIdx,
395  const Evaluation& temperature,
396  const Evaluation& pressure) const
397  { return isothermalPvt_->saturationPressure(regionIdx, temperature, pressure); }
398 
399  template <class Evaluation>
400  Evaluation diffusionCoefficient(const Evaluation& temperature,
401  const Evaluation& pressure,
402  unsigned compIdx) const
403  {
404  return isothermalPvt_->diffusionCoefficient(temperature, pressure, compIdx);
405  }
406  const IsothermalPvt* isoThermalPvt() const
407  { return isothermalPvt_; }
408 
409  Scalar gasReferenceDensity(unsigned regionIdx) const
410  { return isothermalPvt_->gasReferenceDensity(regionIdx); }
411 
412  Scalar hVap(unsigned regionIdx) const
413  { return this->hVap_[regionIdx]; }
414 
415  const std::vector<TabulatedOneDFunction>& gasvisctCurves() const
416  { return gasvisctCurves_; }
417 
418  const std::vector<Scalar>& viscrefPress() const
419  { return viscrefPress_; }
420 
421  const std::vector<Scalar>& viscRef() const
422  { return viscRef_; }
423 
424  const std::vector<Scalar>& gasdentRefTemp() const
425  { return gasdentRefTemp_; }
426 
427  const std::vector<Scalar>& gasdentCT1() const
428  { return gasdentCT1_; }
429 
430  const std::vector<Scalar>& gasdentCT2() const
431  { return gasdentCT2_; }
432 
433  const std::vector<TabulatedOneDFunction>& internalEnergyCurves() const
434  { return internalEnergyCurves_; }
435 
436  bool enableInternalEnergy() const
437  { return enableInternalEnergy_; }
438 
439  const std::vector<Scalar>& gasJTRefPres() const
440  { return gasJTRefPres_; }
441 
442  const std::vector<Scalar>& gasJTC() const
443  { return gasJTC_; }
444 
445  bool operator==(const GasPvtThermal<Scalar>& data) const;
446 
447  GasPvtThermal<Scalar>& operator=(const GasPvtThermal<Scalar>& data);
448 
449 private:
450  IsothermalPvt* isothermalPvt_{nullptr};
451 
452  // The PVT properties needed for temperature dependence of the viscosity. We need
453  // to store one value per PVT region.
454  std::vector<TabulatedOneDFunction> gasvisctCurves_{};
455  std::vector<Scalar> viscrefPress_{};
456  std::vector<Scalar> viscRef_{};
457 
458  std::vector<Scalar> gasdentRefTemp_{};
459  std::vector<Scalar> gasdentCT1_{};
460  std::vector<Scalar> gasdentCT2_{};
461 
462  std::vector<Scalar> gasJTRefPres_{};
463  std::vector<Scalar> gasJTC_{};
464 
465  std::vector<Scalar> rhoRefO_{};
466  std::vector<Scalar> hVap_{};
467 
468  // piecewise linear curve representing the internal energy of gas
469  std::vector<TabulatedOneDFunction> internalEnergyCurves_{};
470 
471  bool enableThermalDensity_{false};
472  bool enableJouleThomson_{false};
473  bool enableThermalViscosity_{false};
474  bool enableInternalEnergy_{false};
475 };
476 
477 } // namespace Opm
478 
479 #endif
Evaluation saturatedViscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the dynamic viscosity [Pa s] of oil saturated gas given a set of parameters.
Definition: GasPvtMultiplexer.hpp:189
Evaluation saturatedWaterVaporizationFactor(unsigned, const Evaluation &, const Evaluation &) const
Returns the water vaporization factor [m^3/m^3] of the water phase.
Definition: GasPvtThermal.hpp:339
bool enableThermalViscosity() const
Returns true iff the viscosity of the gas phase is temperature dependent.
Definition: GasPvtThermal.hpp:129
Definition: Schedule.hpp:100
Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the formation volume factor [-] of oil saturated gas given a set of parameters.
Definition: GasPvtMultiplexer.hpp:217
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
This class represents the Pressure-Volume-Temperature relations of the gas phase in the black-oil mod...
Definition: GasPvtMultiplexer.hpp:108
Evaluation inverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rv, const Evaluation &Rvw) const
Returns the formation volume factor [-] of the fluid phase.
Definition: GasPvtMultiplexer.hpp:198
Evaluation saturatedViscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the dynamic viscosity [Pa s] of the oil-saturated gas phase given a set of parameters...
Definition: GasPvtThermal.hpp:227
Evaluation saturatedOilVaporizationFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &oilSaturation, const Evaluation &maxOilSaturation) const
Returns the oil vaporization factor [m^3/m^3] of the gas phase.
Definition: GasPvtThermal.hpp:375
void setNumRegions(std::size_t numRegions)
Set the number of PVT-regions considered by this object.
Definition: GasPvtThermal.cpp:191
Definition: EclipseState.hpp:66
Scalar gasReferenceDensity(unsigned regionIdx) const
Return the reference density which are considered by this PVT-object.
Definition: GasPvtMultiplexer.cpp:57
Evaluation internalEnergy(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rv, [[maybe_unused]] const Evaluation &RvW) const
Returns the specific internal energy [J/kg] of gas given a set of parameters.
Definition: GasPvtThermal.hpp:139
Evaluation diffusionCoefficient(const Evaluation &temperature, const Evaluation &pressure, unsigned compIdx) const
Calculate the binary molecular diffusion coefficient for a component in a fluid phase [mol^2 * s / (k...
Definition: GasPvtMultiplexer.hpp:279
Evaluation saturatedOilVaporizationFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the oil vaporization factor [m^3/m^3] of oil saturated gas.
Definition: GasPvtMultiplexer.hpp:226
Evaluation viscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rv, const Evaluation &Rvw) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: GasPvtMultiplexer.hpp:178
bool enableJouleThomson() const
Returns true iff Joule-Thomson effect for the gas phase is active.
Definition: GasPvtThermal.hpp:123
bool enableThermalDensity() const
Returns true iff the density of the gas phase is temperature dependent.
Definition: GasPvtThermal.hpp:117
Evaluation saturatedWaterVaporizationFactor(unsigned, const Evaluation &, const Evaluation &, const Evaluation &) const
Returns the water vaporization factor [m^3/m^3] of water saturated gas.
Definition: GasPvtThermal.hpp:348
Implements a linearly interpolated scalar function that depends on one variable.
void initFromState(const EclipseState &eclState, const Schedule &schedule)
Implement the temperature part of the gas PVT properties.
Definition: GasPvtThermal.cpp:42
Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the formation volume factor [-] of oil-saturated gas.
Definition: GasPvtThermal.hpp:309
Evaluation inverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rv, const Evaluation &) const
Returns the formation volume factor [-] of the fluid phase.
Definition: GasPvtThermal.hpp:244
This class implements temperature dependence of the PVT properties of gas.
Definition: GasPvtThermal.hpp:49
Evaluation saturationPressure(unsigned regionIdx, const Evaluation &temperature, const Evaluation &Rv) const
Returns the saturation pressure of the gas phase [Pa] depending on its mass fraction of the oil compo...
Definition: GasPvtMultiplexer.hpp:270
Evaluation saturatedOilVaporizationFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the oil vaporization factor [m^3/m^3] of the gas phase.
Definition: GasPvtThermal.hpp:362
Implements a linearly interpolated scalar function that depends on one variable.
Definition: Tabulated1DFunction.hpp:50
Evaluation viscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rv, const Evaluation &Rvw) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: GasPvtThermal.hpp:208
std::pair< LhsEval, LhsEval > inverseFormationVolumeFactorAndViscosity(const FluidState &fluidState, unsigned regionIdx)
Returns the formation volume factor [-] and viscosity [Pa s] of the fluid phase.
Definition: GasPvtMultiplexer.hpp:210
Evaluation saturationPressure(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the saturation pressure of the gas phase [Pa].
Definition: GasPvtThermal.hpp:394
void initEnd()
Finish initializing the thermal part of the gas phase PVT properties.
Definition: GasPvtThermal.hpp:111
std::pair< LhsEval, LhsEval > inverseFormationVolumeFactorAndViscosity(const FluidState &fluidState, unsigned regionIdx)
Returns the formation volume factor [-] and viscosity [Pa s] of the fluid phase.
Definition: GasPvtThermal.hpp:279