opm-common
WaterPvtThermal.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_WATER_PVT_THERMAL_HPP
28 #define OPM_WATER_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, bool enableBrine>
40 class WaterPvtMultiplexer;
41 
48 template <class Scalar, bool enableBrine>
50 {
51 public:
53  using IsothermalPvt = WaterPvtMultiplexer<Scalar, /*enableThermal=*/false, enableBrine>;
54 
55  WaterPvtThermal() = default;
56 
57  WaterPvtThermal(IsothermalPvt* isothermalPvt,
58  const std::vector<Scalar>& viscrefPress,
59  const std::vector<Scalar>& watdentRefTemp,
60  const std::vector<Scalar>& watdentCT1,
61  const std::vector<Scalar>& watdentCT2,
62  const std::vector<Scalar>& watJTRefPres,
63  const std::vector<Scalar>& watJTC,
64  const std::vector<Scalar>& pvtwRefPress,
65  const std::vector<Scalar>& pvtwRefB,
66  const std::vector<Scalar>& pvtwCompressibility,
67  const std::vector<Scalar>& pvtwViscosity,
68  const std::vector<Scalar>& pvtwViscosibility,
69  const std::vector<Scalar>& referenceSaltConcentration,
70  const std::vector<TabulatedOneDFunction>& watvisctCurves,
71  const std::vector<TabulatedOneDFunction>& internalEnergyCurves,
73  bool enableJouleThomson,
75  bool enableInternalEnergy,
76  bool enableBrineViscosity)
77  : isothermalPvt_(isothermalPvt)
78  , viscrefPress_(viscrefPress)
79  , watdentRefTemp_(watdentRefTemp)
80  , watdentCT1_(watdentCT1)
81  , watdentCT2_(watdentCT2)
82  , watJTRefPres_(watJTRefPres)
83  , watJTC_(watJTC)
84  , pvtwRefPress_(pvtwRefPress)
85  , pvtwRefB_(pvtwRefB)
86  , pvtwCompressibility_(pvtwCompressibility)
87  , pvtwViscosity_(pvtwViscosity)
88  , pvtwViscosibility_(pvtwViscosibility)
89  , referenceSaltConcentration_(referenceSaltConcentration)
90  , watvisctCurves_(watvisctCurves)
91  , internalEnergyCurves_(internalEnergyCurves)
92  , enableThermalDensity_(enableThermalDensity)
93  , enableJouleThomson_(enableJouleThomson)
94  , enableThermalViscosity_(enableThermalViscosity)
95  , enableInternalEnergy_(enableInternalEnergy)
96  , enableBrineViscosity_(enableBrineViscosity)
97  { }
98 
99  WaterPvtThermal(const WaterPvtThermal& data)
100  { *this = data; }
101 
102  ~WaterPvtThermal()
103  { delete isothermalPvt_; }
104 
108  void initFromState(const EclipseState& eclState, const Schedule& schedule);
109 
113  void setNumRegions(std::size_t numRegions);
114 
115  void setVapPars(const Scalar par1, const Scalar par2)
116  {
117  isothermalPvt_->setVapPars(par1, par2);
118  }
119 
123  void initEnd()
124  { }
125 
129  bool enableThermalDensity() const
130  { return enableThermalDensity_; }
131 
135  bool enableJouleThomson() const
136  { return enableJouleThomson_; }
137 
142  { return enableThermalViscosity_; }
143 
144  Scalar hVap(unsigned regionIdx) const
145  { return this->hVap_[regionIdx]; }
146 
147  std::size_t numRegions() const
148  { return pvtwRefPress_.size(); }
149 
153  template <class Evaluation>
154  Evaluation internalEnergy(unsigned regionIdx,
155  const Evaluation& temperature,
156  const Evaluation& pressure,
157  const Evaluation& Rsw,
158  const Evaluation& saltconcentration) const
159  {
160  if (!enableInternalEnergy_) {
161  throw std::runtime_error("Requested the internal energy of water but it is disabled");
162  }
163 
164  if (!enableJouleThomson_) {
165  // compute the specific internal energy for the specified tempature. We use linear
166  // interpolation here despite the fact that the underlying heat capacities are
167  // piecewise linear (which leads to a quadratic function)
168  return internalEnergyCurves_[regionIdx].eval(temperature, /*extrapolate=*/true);
169  }
170  else {
171  Evaluation Tref = watdentRefTemp_[regionIdx];
172  Evaluation Pref = watJTRefPres_[regionIdx];
173  Scalar JTC = watJTC_[regionIdx]; // if JTC is default then JTC is calculated
174 
175  Evaluation invB = inverseFormationVolumeFactor(regionIdx, temperature, pressure, Rsw, saltconcentration);
176  Evaluation Cp = internalEnergyCurves_[regionIdx].eval(temperature, /*extrapolate=*/true)/temperature;
177  Evaluation density = invB * waterReferenceDensity(regionIdx);
178 
179  Evaluation enthalpyPres;
180  if (JTC != 0) {
181  enthalpyPres = -Cp * JTC * (pressure - Pref);
182  }
183  else if (enableThermalDensity_) {
184  Scalar c1T = watdentCT1_[regionIdx];
185  Scalar c2T = watdentCT2_[regionIdx];
186 
187  Evaluation alpha = (c1T + 2 * c2T * (temperature - Tref)) /
188  (1 + c1T *(temperature - Tref) + c2T * (temperature - Tref) * (temperature - Tref));
189 
190  constexpr const int N = 100; // value is experimental
191  Evaluation deltaP = (pressure - Pref) / N;
192  Evaluation enthalpyPresPrev = 0;
193  for (std::size_t i = 0; i < N; ++i) {
194  Evaluation Pnew = Pref + i * deltaP;
195  Evaluation rho = inverseFormationVolumeFactor(regionIdx, temperature,
196  Pnew, Rsw, saltconcentration) *
197  waterReferenceDensity(regionIdx);
198  Evaluation jouleThomsonCoefficient = -(1.0 / Cp) * (1.0 - alpha * temperature) / rho;
199  Evaluation deltaEnthalpyPres = -Cp * jouleThomsonCoefficient * deltaP;
200  enthalpyPres = enthalpyPresPrev + deltaEnthalpyPres;
201  enthalpyPresPrev = enthalpyPres;
202  }
203  }
204  else {
205  throw std::runtime_error("Requested Joule-thomson calculation but "
206  "thermal water density (WATDENT) is not provided");
207  }
208 
209  Evaluation enthalpy = Cp * (temperature - Tref) + enthalpyPres;
210 
211  return enthalpy - pressure/density;
212  }
213  }
214 
218  template <class Evaluation>
219  Evaluation viscosity(unsigned regionIdx,
220  const Evaluation& temperature,
221  const Evaluation& pressure,
222  const Evaluation& Rsw,
223  const Evaluation& saltconcentration) const
224  {
225  const auto& isothermalMu = isothermalPvt_->viscosity(regionIdx, temperature,
226  pressure, Rsw, saltconcentration);
227  if (!enableThermalViscosity()) {
228  return isothermalMu;
229  }
230 
231  const auto& muWatvisct = watvisctCurves_[regionIdx].eval(temperature, true);
232  if (enableBrineViscosity()) {
233  auto muRef = isothermalPvt_->viscosity(regionIdx, temperature, Evaluation(viscrefPress_[regionIdx]), Rsw, Evaluation(referenceSaltConcentration_[regionIdx]));
234  return isothermalMu * muWatvisct / muRef;
235  } else {
236  Scalar x = -pvtwViscosibility_[regionIdx] * (viscrefPress_[regionIdx] - pvtwRefPress_[regionIdx]);
237  Scalar muRef = pvtwViscosity_[regionIdx] / (1.0 + x + 0.5 * x * x);
238  return isothermalMu * muWatvisct / muRef;
239  }
240  }
241 
245  template <class Evaluation>
246  Evaluation saturatedViscosity(unsigned regionIdx,
247  const Evaluation& temperature,
248  const Evaluation& pressure,
249  const Evaluation& saltconcentration) const
250  {
251  const auto& isothermalMu = isothermalPvt_->saturatedViscosity(regionIdx, temperature,
252  pressure, saltconcentration);
253  if (!enableThermalViscosity()) {
254  return isothermalMu;
255  }
256 
257  Scalar x = -pvtwViscosibility_[regionIdx] * (viscrefPress_[regionIdx] -
258  pvtwRefPress_[regionIdx]);
259  Scalar muRef = pvtwViscosity_[regionIdx] / (1.0 + x + 0.5 * x * x);
260 
261  // compute the viscosity deviation due to temperature
262  const auto& muWatvisct = watvisctCurves_[regionIdx].eval(temperature, true);
263  return isothermalMu * muWatvisct / muRef;
264  }
265 
269  template <class Evaluation>
270  Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx,
271  const Evaluation& temperature,
272  const Evaluation& pressure,
273  const Evaluation& saltconcentration) const
274  {
275  Evaluation Rsw = 0.0;
276  return inverseFormationVolumeFactor(regionIdx, temperature, pressure,
277  Rsw, saltconcentration);
278  }
282  template <class Evaluation>
283  Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
284  const Evaluation& temperature,
285  const Evaluation& pressure,
286  const Evaluation& Rsw,
287  const Evaluation& saltconcentration) const
288  {
289  if (!enableThermalDensity()) {
290  return isothermalPvt_->inverseFormationVolumeFactor(regionIdx, temperature,
291  pressure, Rsw, saltconcentration);
292  }
293 
294  Scalar BwRef = pvtwRefB_[regionIdx];
295  Scalar TRef = watdentRefTemp_[regionIdx];
296  const Evaluation& X = pvtwCompressibility_[regionIdx] * (pressure -
297  pvtwRefPress_[regionIdx]);
298  Scalar cT1 = watdentCT1_[regionIdx];
299  Scalar cT2 = watdentCT2_[regionIdx];
300  const Evaluation& Y = temperature - TRef;
301 
302  // this is inconsistent with the density calculation of water in the isothermal
303  // case (it misses the quadratic pressure term), but it is the equation given in
304  // the documentation.
305  return 1.0 / (((1 - X) * (1 + cT1 * Y + cT2 * Y * Y)) * BwRef);
306  }
307 
311  template <class FluidState, class LhsEval = typename FluidState::ValueType>
312  std::pair<LhsEval, LhsEval>
313  inverseFormationVolumeFactorAndViscosity(const FluidState& fluidState, unsigned regionIdx)
314  {
315  auto [b, mu] = isothermalPvt_->inverseFormationVolumeFactorAndViscosity(fluidState, regionIdx);
316  const LhsEval& pressure = decay<LhsEval>(fluidState.pressure(FluidState::waterPhaseIdx));
317  const LhsEval& temperature = decay<LhsEval>(fluidState.temperature(FluidState::waterPhaseIdx));
318  if (enableThermalDensity()) {
319  Scalar BwRef = pvtwRefB_[regionIdx];
320  Scalar TRef = watdentRefTemp_[regionIdx];
321  const LhsEval X = pvtwCompressibility_[regionIdx] * (pressure - pvtwRefPress_[regionIdx]);
322  Scalar cT1 = watdentCT1_[regionIdx];
323  Scalar cT2 = watdentCT2_[regionIdx];
324  const LhsEval Y = temperature - TRef;
325  // this is inconsistent with the density calculation of water in the isothermal
326  // case (it misses the quadratic pressure term), but it is the equation given in
327  // the documentation.
328  // Note assignment to 'b', not multiplying the isothermal 'b' by a factor!
329  b = 1.0 / (((1 - X) * (1 + cT1 * Y + cT2 * Y * Y)) * BwRef);
330  }
331  if (enableThermalViscosity()) {
332  Scalar x = -pvtwViscosibility_[regionIdx] * (viscrefPress_[regionIdx] - pvtwRefPress_[regionIdx]);
333  Scalar muRef = pvtwViscosity_[regionIdx] / (1.0 + x + 0.5 * x * x);
334  // compute the viscosity deviation due to temperature
335  const auto muWatvisct = watvisctCurves_[regionIdx].eval(temperature, true);
336  // Split operations to get same order of operations as in the viscosity() function.
337  mu *= muWatvisct;
338  mu /= muRef;
339  }
340  return { b, mu };
341  }
342 
350  template <class Evaluation>
351  Evaluation saturationPressure(unsigned /*regionIdx*/,
352  const Evaluation& /*temperature*/,
353  const Evaluation& /*Rs*/,
354  const Evaluation& /*saltconcentration*/) const
355  { return 0.0; /* this is dead water, so there isn't any meaningful saturation pressure! */ }
356 
360  template <class Evaluation>
361  Evaluation saturatedGasDissolutionFactor(unsigned /*regionIdx*/,
362  const Evaluation& /*temperature*/,
363  const Evaluation& /*pressure*/,
364  const Evaluation& /*saltconcentration*/) const
365  { return 0.0; /* this is dead water! */ }
366 
367  template <class Evaluation>
368  Evaluation diffusionCoefficient(const Evaluation& /*temperature*/,
369  const Evaluation& /*pressure*/,
370  unsigned /*compIdx*/,
371  unsigned /*regionIdx*/ = 0) const
372  {
373  throw std::runtime_error("Not implemented: The PVT model does not provide "
374  "a diffusionCoefficient()");
375  }
376 
377  const IsothermalPvt* isoThermalPvt() const
378  { return isothermalPvt_; }
379 
380  Scalar waterReferenceDensity(unsigned regionIdx) const
381  { return isothermalPvt_->waterReferenceDensity(regionIdx); }
382 
383  const std::vector<Scalar>& viscrefPress() const
384  { return viscrefPress_; }
385 
386  const std::vector<Scalar>& watdentRefTemp() const
387  { return watdentRefTemp_; }
388 
389  const std::vector<Scalar>& watdentCT1() const
390  { return watdentCT1_; }
391 
392  const std::vector<Scalar>& watdentCT2() const
393  { return watdentCT2_; }
394 
395  const std::vector<Scalar>& pvtwRefPress() const
396  { return pvtwRefPress_; }
397 
398  const std::vector<Scalar>& pvtwRefB() const
399  { return pvtwRefB_; }
400 
401  const std::vector<Scalar>& pvtwCompressibility() const
402  { return pvtwCompressibility_; }
403 
404  const std::vector<Scalar>& pvtwViscosity() const
405  { return pvtwViscosity_; }
406 
407  const std::vector<Scalar>& pvtwViscosibility() const
408  { return pvtwViscosibility_; }
409 
410  const std::vector<Scalar>& referenceSaltConcentration() const
411  { return referenceSaltConcentration_; }
412 
413  const std::vector<TabulatedOneDFunction>& watvisctCurves() const
414  { return watvisctCurves_; }
415 
416  const std::vector<TabulatedOneDFunction>& internalEnergyCurves() const
417  { return internalEnergyCurves_; }
418 
419  bool enableInternalEnergy() const
420  { return enableInternalEnergy_; }
421 
422  bool enableBrineViscosity() const
423  { return enableBrineViscosity_; }
424 
425  const std::vector<Scalar>& watJTRefPres() const
426  { return watJTRefPres_; }
427 
428  const std::vector<Scalar>& watJTC() const
429  { return watJTC_; }
430 
431  bool operator==(const WaterPvtThermal<Scalar, enableBrine>& data) const;
432 
433  WaterPvtThermal<Scalar, enableBrine>&
434  operator=(const WaterPvtThermal<Scalar, enableBrine>& data);
435 
436 private:
437  IsothermalPvt* isothermalPvt_{nullptr};
438 
439  // The PVT properties needed for temperature dependence. We need to store one
440  // value per PVT region.
441  std::vector<Scalar> viscrefPress_{};
442 
443  std::vector<Scalar> watdentRefTemp_{};
444  std::vector<Scalar> watdentCT1_{};
445  std::vector<Scalar> watdentCT2_{};
446 
447  std::vector<Scalar> watJTRefPres_{};
448  std::vector<Scalar> watJTC_{};
449 
450  std::vector<Scalar> pvtwRefPress_{};
451  std::vector<Scalar> pvtwRefB_{};
452  std::vector<Scalar> pvtwCompressibility_{};
453  std::vector<Scalar> pvtwViscosity_{};
454  std::vector<Scalar> pvtwViscosibility_{};
455  std::vector<Scalar> referenceSaltConcentration_{};
456 
457  std::vector<TabulatedOneDFunction> watvisctCurves_{};
458 
459  // piecewise linear curve representing the internal energy of water
460  std::vector<TabulatedOneDFunction> internalEnergyCurves_{};
461  std::vector<Scalar> hVap_{};
462 
463  bool enableThermalDensity_{false};
464  bool enableJouleThomson_{false};
465  bool enableThermalViscosity_{false};
466  bool enableInternalEnergy_{false};
467  bool enableBrineViscosity_{false};
468 };
469 
470 } // namespace Opm
471 
472 #endif
Evaluation saturationPressure(unsigned, const Evaluation &, const Evaluation &, const Evaluation &) const
Returns the saturation pressure of the water phase [Pa] depending on its mass fraction of the gas com...
Definition: WaterPvtThermal.hpp:351
This class implements temperature dependence of the PVT properties of water.
Definition: WaterPvtThermal.hpp:49
Evaluation internalEnergy(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rsw, const Evaluation &saltconcentration) const
Returns the specific internal energy [J/kg] of water given a set of parameters.
Definition: WaterPvtThermal.hpp:154
std::pair< LhsEval, LhsEval > inverseFormationVolumeFactorAndViscosity(const FluidState &fluidState, unsigned regionIdx)
Returns the formation volume factor [-] and viscosity [Pa s] of the fluid phase.
Definition: WaterPvtMultiplexer.hpp:195
Evaluation inverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rsw, const Evaluation &saltconcentration) const
Returns the formation volume factor [-] of the fluid phase.
Definition: WaterPvtMultiplexer.hpp:181
Evaluation viscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rsw, const Evaluation &saltconcentration) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: WaterPvtThermal.hpp:219
Definition: Schedule.hpp:100
Evaluation saturatedViscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &saltconcentration) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: WaterPvtThermal.hpp:246
Evaluation viscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rsw, const Evaluation &saltconcentration) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: WaterPvtMultiplexer.hpp:151
Evaluation inverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rsw, const Evaluation &saltconcentration) const
Returns the formation volume factor [-] of the fluid phase.
Definition: WaterPvtThermal.hpp:283
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
void initEnd()
Finish initializing the thermal part of the water phase PVT properties.
Definition: WaterPvtThermal.hpp:123
Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &saltconcentration) const
Returns the formation volume factor [-] of the fluid phase.
Definition: WaterPvtThermal.hpp:270
Definition: EclipseState.hpp:66
std::pair< LhsEval, LhsEval > inverseFormationVolumeFactorAndViscosity(const FluidState &fluidState, unsigned regionIdx)
Returns the formation volume factor [-] and viscosity [Pa s] of the fluid phase.
Definition: WaterPvtThermal.hpp:313
Evaluation saturatedGasDissolutionFactor(unsigned, const Evaluation &, const Evaluation &, const Evaluation &) const
Returns the gas dissolution factor [m^3/m^3] of the water phase.
Definition: WaterPvtThermal.hpp:361
This class represents the Pressure-Volume-Temperature relations of the water phase in the black-oil m...
Definition: ConstantCompressibilityBrinePvt.hpp:39
bool enableThermalDensity() const
Returns true iff the density of the water phase is temperature dependent.
Definition: WaterPvtThermal.hpp:129
void setNumRegions(std::size_t numRegions)
Set the number of PVT-regions considered by this object.
Definition: WaterPvtThermal.cpp:198
Implements a linearly interpolated scalar function that depends on one variable.
bool enableJouleThomson() const
Returns true iff Joule-Thomson effect for the water phase is active.
Definition: WaterPvtThermal.hpp:135
bool enableThermalViscosity() const
Returns true iff the viscosity of the water phase is temperature dependent.
Definition: WaterPvtThermal.hpp:141
void initFromState(const EclipseState &eclState, const Schedule &schedule)
Implement the temperature part of the water PVT properties.
Definition: WaterPvtThermal.cpp:41
Implements a linearly interpolated scalar function that depends on one variable.
Definition: Tabulated1DFunction.hpp:50
Scalar waterReferenceDensity(unsigned regionIdx) const
Return the reference density which are considered by this PVT-object.
Definition: WaterPvtMultiplexer.cpp:109
Evaluation saturatedViscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &saltconcentration) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: WaterPvtMultiplexer.hpp:169