opm-common
Loading...
Searching...
No Matches
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
34namespace Opm {
35
36#if HAVE_ECL_INPUT
37class EclipseState;
38class Schedule;
39#endif
40
41template <class Scalar, bool enableThermal, bool enableBrine>
43
50template <class Scalar, bool enableBrine>
51class WaterPvtThermal
52{
53public:
54 using TabulatedOneDFunction = Tabulated1DFunction<Scalar>;
55 using IsothermalPvt = WaterPvtMultiplexer<Scalar, /*enableThermal=*/false, enableBrine>;
56
57 WaterPvtThermal() = default;
58
59 WaterPvtThermal(IsothermalPvt* isothermalPvt,
60 const std::vector<Scalar>& viscrefPress,
61 const std::vector<Scalar>& watdentRefTemp,
62 const std::vector<Scalar>& watdentCT1,
63 const std::vector<Scalar>& watdentCT2,
64 const std::vector<Scalar>& watJTRefPres,
65 const std::vector<Scalar>& watJTC,
66 const std::vector<Scalar>& pvtwRefPress,
67 const std::vector<Scalar>& pvtwRefB,
68 const std::vector<Scalar>& pvtwCompressibility,
69 const std::vector<Scalar>& pvtwViscosity,
70 const std::vector<Scalar>& pvtwViscosibility,
71 const std::vector<TabulatedOneDFunction>& watvisctCurves,
72 const std::vector<TabulatedOneDFunction>& internalEnergyCurves,
76 bool enableInternalEnergy)
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 , watvisctCurves_(watvisctCurves)
90 , internalEnergyCurves_(internalEnergyCurves)
91 , enableThermalDensity_(enableThermalDensity)
92 , enableJouleThomson_(enableJouleThomson)
93 , enableThermalViscosity_(enableThermalViscosity)
94 , enableInternalEnergy_(enableInternalEnergy)
95 { }
96
97 WaterPvtThermal(const WaterPvtThermal& data)
98 { *this = data; }
99
100 ~WaterPvtThermal()
101 { delete isothermalPvt_; }
102
103#if HAVE_ECL_INPUT
107 void initFromState(const EclipseState& eclState, const Schedule& schedule);
108#endif // HAVE_ECL_INPUT
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
130 { return enableThermalDensity_; }
131
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 Scalar x = -pvtwViscosibility_[regionIdx] * (viscrefPress_[regionIdx] -
232 pvtwRefPress_[regionIdx]);
233 Scalar muRef = pvtwViscosity_[regionIdx] / (1.0 + x + 0.5 * x * x);
234
235 // compute the viscosity deviation due to temperature
236 const auto& muWatvisct = watvisctCurves_[regionIdx].eval(temperature, true);
237 return isothermalMu * muWatvisct / muRef;
238 }
239
243 template <class Evaluation>
244 Evaluation saturatedViscosity(unsigned regionIdx,
245 const Evaluation& temperature,
246 const Evaluation& pressure,
247 const Evaluation& saltconcentration) const
248 {
249 const auto& isothermalMu = isothermalPvt_->saturatedViscosity(regionIdx, temperature,
250 pressure, saltconcentration);
251 if (!enableThermalViscosity()) {
252 return isothermalMu;
253 }
254
255 Scalar x = -pvtwViscosibility_[regionIdx] * (viscrefPress_[regionIdx] -
256 pvtwRefPress_[regionIdx]);
257 Scalar muRef = pvtwViscosity_[regionIdx] / (1.0 + x + 0.5 * x * x);
258
259 // compute the viscosity deviation due to temperature
260 const auto& muWatvisct = watvisctCurves_[regionIdx].eval(temperature, true);
261 return isothermalMu * muWatvisct / muRef;
262 }
263
267 template <class Evaluation>
268 Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx,
269 const Evaluation& temperature,
270 const Evaluation& pressure,
271 const Evaluation& saltconcentration) const
272 {
273 Evaluation Rsw = 0.0;
274 return inverseFormationVolumeFactor(regionIdx, temperature, pressure,
275 Rsw, saltconcentration);
276 }
277
280 template <class Evaluation>
281 Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
282 const Evaluation& temperature,
283 const Evaluation& pressure,
284 const Evaluation& Rsw,
285 const Evaluation& saltconcentration) const
286 {
287 if (!enableThermalDensity()) {
288 return isothermalPvt_->inverseFormationVolumeFactor(regionIdx, temperature,
289 pressure, Rsw, saltconcentration);
290 }
291
292 Scalar BwRef = pvtwRefB_[regionIdx];
293 Scalar TRef = watdentRefTemp_[regionIdx];
294 const Evaluation& X = pvtwCompressibility_[regionIdx] * (pressure -
295 pvtwRefPress_[regionIdx]);
296 Scalar cT1 = watdentCT1_[regionIdx];
297 Scalar cT2 = watdentCT2_[regionIdx];
298 const Evaluation& Y = temperature - TRef;
299
300 // this is inconsistent with the density calculation of water in the isothermal
301 // case (it misses the quadratic pressure term), but it is the equation given in
302 // the documentation.
303 return 1.0 / (((1 - X) * (1 + cT1 * Y + cT2 * Y * Y)) * BwRef);
304 }
305
309 template <class FluidState, class LhsEval = typename FluidState::Scalar>
310 std::pair<LhsEval, LhsEval>
311 inverseFormationVolumeFactorAndViscosity(const FluidState& fluidState, unsigned regionIdx)
312 {
313 auto [b, mu] = isothermalPvt_->inverseFormationVolumeFactorAndViscosity(fluidState, regionIdx);
314 const LhsEval& pressure = decay<LhsEval>(fluidState.pressure(FluidState::waterPhaseIdx));
315 const LhsEval& temperature = decay<LhsEval>(fluidState.temperature(FluidState::waterPhaseIdx));
316 if (enableThermalDensity()) {
317 Scalar BwRef = pvtwRefB_[regionIdx];
318 Scalar TRef = watdentRefTemp_[regionIdx];
319 const LhsEval X = pvtwCompressibility_[regionIdx] * (pressure - pvtwRefPress_[regionIdx]);
320 Scalar cT1 = watdentCT1_[regionIdx];
321 Scalar cT2 = watdentCT2_[regionIdx];
322 const LhsEval Y = temperature - TRef;
323 // this is inconsistent with the density calculation of water in the isothermal
324 // case (it misses the quadratic pressure term), but it is the equation given in
325 // the documentation.
326 // Note assignment to 'b', not multiplying the isothermal 'b' by a factor!
327 b = 1.0 / (((1 - X) * (1 + cT1 * Y + cT2 * Y * Y)) * BwRef);
328 }
330 Scalar x = -pvtwViscosibility_[regionIdx] * (viscrefPress_[regionIdx] - pvtwRefPress_[regionIdx]);
331 Scalar muRef = pvtwViscosity_[regionIdx] / (1.0 + x + 0.5 * x * x);
332 // compute the viscosity deviation due to temperature
333 const auto muWatvisct = watvisctCurves_[regionIdx].eval(temperature, true);
334 // Split operations to get same order of operations as in the viscosity() function.
335 mu *= muWatvisct;
336 mu /= muRef;
337 }
338 return { b, mu };
339 }
340
348 template <class Evaluation>
349 Evaluation saturationPressure(unsigned /*regionIdx*/,
350 const Evaluation& /*temperature*/,
351 const Evaluation& /*Rs*/,
352 const Evaluation& /*saltconcentration*/) const
353 { return 0.0; /* this is dead water, so there isn't any meaningful saturation pressure! */ }
354
358 template <class Evaluation>
359 Evaluation saturatedGasDissolutionFactor(unsigned /*regionIdx*/,
360 const Evaluation& /*temperature*/,
361 const Evaluation& /*pressure*/,
362 const Evaluation& /*saltconcentration*/) const
363 { return 0.0; /* this is dead water! */ }
364
365 template <class Evaluation>
366 Evaluation diffusionCoefficient(const Evaluation& /*temperature*/,
367 const Evaluation& /*pressure*/,
368 unsigned /*compIdx*/) const
369 {
370 throw std::runtime_error("Not implemented: The PVT model does not provide "
371 "a diffusionCoefficient()");
372 }
373
374 const IsothermalPvt* isoThermalPvt() const
375 { return isothermalPvt_; }
376
377 Scalar waterReferenceDensity(unsigned regionIdx) const
378 { return isothermalPvt_->waterReferenceDensity(regionIdx); }
379
380 const std::vector<Scalar>& viscrefPress() const
381 { return viscrefPress_; }
382
383 const std::vector<Scalar>& watdentRefTemp() const
384 { return watdentRefTemp_; }
385
386 const std::vector<Scalar>& watdentCT1() const
387 { return watdentCT1_; }
388
389 const std::vector<Scalar>& watdentCT2() const
390 { return watdentCT2_; }
391
392 const std::vector<Scalar>& pvtwRefPress() const
393 { return pvtwRefPress_; }
394
395 const std::vector<Scalar>& pvtwRefB() const
396 { return pvtwRefB_; }
397
398 const std::vector<Scalar>& pvtwCompressibility() const
399 { return pvtwCompressibility_; }
400
401 const std::vector<Scalar>& pvtwViscosity() const
402 { return pvtwViscosity_; }
403
404 const std::vector<Scalar>& pvtwViscosibility() const
405 { return pvtwViscosibility_; }
406
407 const std::vector<TabulatedOneDFunction>& watvisctCurves() const
408 { return watvisctCurves_; }
409
410 const std::vector<TabulatedOneDFunction>& internalEnergyCurves() const
411 { return internalEnergyCurves_; }
412
413 bool enableInternalEnergy() const
414 { return enableInternalEnergy_; }
415
416 const std::vector<Scalar>& watJTRefPres() const
417 { return watJTRefPres_; }
418
419 const std::vector<Scalar>& watJTC() const
420 { return watJTC_; }
421
422 bool operator==(const WaterPvtThermal<Scalar, enableBrine>& data) const;
423
424 WaterPvtThermal<Scalar, enableBrine>&
425 operator=(const WaterPvtThermal<Scalar, enableBrine>& data);
426
427private:
428 IsothermalPvt* isothermalPvt_{nullptr};
429
430 // The PVT properties needed for temperature dependence. We need to store one
431 // value per PVT region.
432 std::vector<Scalar> viscrefPress_{};
433
434 std::vector<Scalar> watdentRefTemp_{};
435 std::vector<Scalar> watdentCT1_{};
436 std::vector<Scalar> watdentCT2_{};
437
438 std::vector<Scalar> watJTRefPres_{};
439 std::vector<Scalar> watJTC_{};
440
441 std::vector<Scalar> pvtwRefPress_{};
442 std::vector<Scalar> pvtwRefB_{};
443 std::vector<Scalar> pvtwCompressibility_{};
444 std::vector<Scalar> pvtwViscosity_{};
445 std::vector<Scalar> pvtwViscosibility_{};
446
447 std::vector<TabulatedOneDFunction> watvisctCurves_{};
448
449 // piecewise linear curve representing the internal energy of water
450 std::vector<TabulatedOneDFunction> internalEnergyCurves_{};
451 std::vector<Scalar> hVap_{};
452
453 bool enableThermalDensity_{false};
454 bool enableJouleThomson_{false};
455 bool enableThermalViscosity_{false};
456 bool enableInternalEnergy_{false};
457};
458
459} // namespace Opm
460
461#endif
Implements a linearly interpolated scalar function that depends on one variable.
Definition EclipseState.hpp:62
Definition Schedule.hpp:101
Implements a linearly interpolated scalar function that depends on one variable.
Definition Tabulated1DFunction.hpp:51
This class represents the Pressure-Volume-Temperature relations of the water phase in the black-oil m...
Definition WaterPvtMultiplexer.hpp:90
Scalar waterReferenceDensity(unsigned regionIdx) const
Return the reference density which are considered by this PVT-object.
Definition WaterPvtMultiplexer.cpp:111
bool enableThermalViscosity() const
Returns true iff the viscosity of the water phase is temperature dependent.
Definition WaterPvtThermal.hpp:141
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:349
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
void initEnd()
Finish initializing the thermal part of the water phase PVT properties.
Definition WaterPvtThermal.hpp:123
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:281
bool enableThermalDensity() const
Returns true iff the density of the water phase is temperature dependent.
Definition WaterPvtThermal.hpp:129
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:359
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
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:268
bool enableJouleThomson() const
Returns true iff Joule-Thomson effect for the water phase is active.
Definition WaterPvtThermal.hpp:135
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:244
void setNumRegions(std::size_t numRegions)
Set the number of PVT-regions considered by this object.
Definition WaterPvtThermal.cpp:185
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:311
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition Exceptions.hpp:30