Merge pull request #765 from andlaus/implement_temperature_dependent_density
Implement temperature dependent density
This commit is contained in:
commit
ca9c198368
12 files changed
+1097
-252
No files matched your search
@@ -23,8 +23,6 @@
|
||||
#include <opm/core/props/pvt/PvtInterface.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -47,8 +45,6 @@ namespace Opm
|
||||
{
|
||||
public:
|
||||
PvtConstCompr()
|
||||
: oilvisctTables_(0),
|
||||
watvisctTables_(0)
|
||||
{}
|
||||
|
||||
void initFromWater(Opm::DeckKeywordConstPtr pvtwKeyword)
|
||||
@@ -102,9 +98,7 @@ namespace Opm
|
||||
ref_B_(1, 1.0),
|
||||
comp_(1, 0.0),
|
||||
viscosity_(1, visc),
|
||||
visc_comp_(1, 0.0),
|
||||
oilvisctTables_(0),
|
||||
watvisctTables_(0)
|
||||
visc_comp_(1, 0.0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -125,13 +119,6 @@ namespace Opm
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
double x = -visc_comp_[tableIdx]*(p[i] - ref_press_[tableIdx]);
|
||||
output_mu[i] = viscosity_[tableIdx]/(1.0 + x + 0.5*x*x);
|
||||
|
||||
if (oilvisctTables_ != 0 || watvisctTables_ != 0) {
|
||||
// TODO: temperature dependence
|
||||
OPM_THROW(std::logic_error,
|
||||
"temperature dependent viscosity as a function of z "
|
||||
"is not yet implemented!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +146,7 @@ namespace Opm
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* /*r*/,
|
||||
const PhasePresence* /*cond*/,
|
||||
double* output_mu,
|
||||
@@ -174,46 +161,6 @@ namespace Opm
|
||||
double d = (1.0 + x + 0.5*x*x);
|
||||
output_mu[i] = viscosity_[tableIdx]/d;
|
||||
output_dmudp[i] = (viscosity_[tableIdx]/(d*d))*(1+x) * visc_comp_[tableIdx];
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// this object handles _either_ oil _or_ water
|
||||
assert(watvisctTables_ == 0);
|
||||
|
||||
// temperature dependence of the oil phase
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(tableIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double muRef = -visc_comp_[tableIdx]*(pRef - ref_press_[tableIdx]);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[tableIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
|
||||
if (watvisctTables_ != 0) {
|
||||
// this object handles _either_ oil _or_ water
|
||||
assert(oilvisctTables_ == 0);
|
||||
|
||||
// temperature dependence of the water phase
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(tableIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double muRef = -visc_comp_[tableIdx]*(pRef - ref_press_[tableIdx]);
|
||||
|
||||
double muWatvisct = (*watvisctTables_)[tableIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muWatvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
}
|
||||
std::fill(output_dmudr, output_dmudr + n, 0.0);
|
||||
}
|
||||
@@ -340,22 +287,6 @@ namespace Opm
|
||||
std::fill(output_dRdp, output_dRdp + n, 0.0);
|
||||
}
|
||||
|
||||
/// set the tables which specify the temperature dependence of the oil viscosity
|
||||
void setOilvisctTables(const std::vector<Opm::OilvisctTable>& oilvisctTables,
|
||||
DeckKeywordConstPtr viscrefKeyword)
|
||||
{
|
||||
oilvisctTables_ = &oilvisctTables;
|
||||
viscrefKeyword_ = viscrefKeyword;
|
||||
}
|
||||
|
||||
/// set the tables which specify the temperature dependence of the water viscosity
|
||||
void setWatvisctTables(const std::vector<Opm::WatvisctTable>& watvisctTables,
|
||||
DeckKeywordConstPtr viscrefKeyword)
|
||||
{
|
||||
watvisctTables_ = &watvisctTables;
|
||||
viscrefKeyword_ = viscrefKeyword;
|
||||
}
|
||||
|
||||
private:
|
||||
int getTableIndex_(const int* pvtTableIdx, int cellIdx) const
|
||||
{
|
||||
@@ -371,10 +302,6 @@ namespace Opm
|
||||
std::vector<double> comp_;
|
||||
std::vector<double> viscosity_;
|
||||
std::vector<double> visc_comp_;
|
||||
|
||||
const std::vector<Opm::OilvisctTable>* oilvisctTables_;
|
||||
const std::vector<Opm::WatvisctTable>* watvisctTables_;
|
||||
DeckKeywordConstPtr viscrefKeyword_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -123,20 +123,13 @@ namespace Opm
|
||||
double tempInvB = b_[regionIdx](p[i]);
|
||||
double tempInvBmu = inverseBmu_[regionIdx](p[i]);
|
||||
output_mu[i] = tempInvB / tempInvBmu;
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// TODO: temperature dependence
|
||||
OPM_THROW(std::logic_error,
|
||||
"temperature dependent viscosity as a function of z "
|
||||
"is not yet implemented!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PvtDead::mu(const int n,
|
||||
const int* pvtTableIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* /*r*/,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
@@ -150,24 +143,6 @@ namespace Opm
|
||||
output_mu[i] = tempInvB / tempInvBmu;
|
||||
output_dmudp[i] = (tempInvBmu * b_[regionIdx].derivative(p[i])
|
||||
- tempInvB * inverseBmu_[regionIdx].derivative(p[i])) / (tempInvBmu * tempInvBmu);
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// temperature dependence of the oil phase
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(regionIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double muRef = b_[regionIdx](pRef)/inverseBmu_[regionIdx](pRef);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[regionIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
|
||||
}
|
||||
std::fill(output_dmudr, output_dmudr + n, 0.0);
|
||||
|
||||
@@ -176,7 +151,7 @@ namespace Opm
|
||||
void PvtDead::mu(const int n,
|
||||
const int* pvtTableIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* /*r*/,
|
||||
const PhasePresence* /*cond*/,
|
||||
double* output_mu,
|
||||
@@ -192,23 +167,6 @@ namespace Opm
|
||||
output_dmudp[i] = (tempInvBmu * b_[regionIdx].derivative(p[i])
|
||||
- tempInvB * inverseBmu_[regionIdx].derivative(p[i]))
|
||||
/ (tempInvBmu * tempInvBmu);
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// temperature dependence of the oil phase
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(regionIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double muRef = b_[regionIdx](pRef)/inverseBmu_[regionIdx](pRef);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[regionIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
}
|
||||
std::fill(output_dmudr, output_dmudr + n, 0.0);
|
||||
|
||||
|
||||
@@ -44,11 +44,7 @@ namespace Opm
|
||||
class PvtDead : public PvtInterface
|
||||
{
|
||||
public:
|
||||
PvtDead()
|
||||
{
|
||||
// by default, specify no temperature dependence of the PVT properties
|
||||
oilvisctTables_ = 0;
|
||||
}
|
||||
PvtDead() {};
|
||||
|
||||
void initFromOil(const std::vector<Opm::PvdoTable>& pvdoTables);
|
||||
void initFromGas(const std::vector<Opm::PvdgTable>& pvdgTables);
|
||||
@@ -154,15 +150,6 @@ namespace Opm
|
||||
const double* z,
|
||||
double* output_R,
|
||||
double* output_dRdp) const;
|
||||
|
||||
/// set the tables which specify the temperature dependence of the oil viscosity
|
||||
void setOilvisctTables(const std::vector<Opm::OilvisctTable>& oilvisctTables,
|
||||
DeckKeywordConstPtr viscrefKeyword)
|
||||
{
|
||||
oilvisctTables_ = &oilvisctTables;
|
||||
viscrefKeyword_ = viscrefKeyword;
|
||||
}
|
||||
|
||||
private:
|
||||
int getTableIndex_(const int* pvtTableIdx, int cellIdx) const
|
||||
{
|
||||
@@ -176,9 +163,6 @@ namespace Opm
|
||||
std::vector<NonuniformTableLinear<double> > b_;
|
||||
std::vector<NonuniformTableLinear<double> > viscosity_;
|
||||
std::vector<NonuniformTableLinear<double> > inverseBmu_;
|
||||
|
||||
const std::vector<Opm::OilvisctTable>* oilvisctTables_;
|
||||
DeckKeywordConstPtr viscrefKeyword_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -36,10 +36,7 @@ namespace Opm
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
PvtDeadSpline::PvtDeadSpline()
|
||||
{
|
||||
// by default, specify no temperature dependence of the PVT properties
|
||||
oilvisctTables_ = 0;
|
||||
}
|
||||
{}
|
||||
|
||||
void PvtDeadSpline::initFromOil(const std::vector<Opm::PvdoTable>& pvdoTables,
|
||||
int numSamples)
|
||||
@@ -123,7 +120,7 @@ namespace Opm
|
||||
void PvtDeadSpline::mu(const int n,
|
||||
const int* pvtTableIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* /*r*/,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
@@ -134,23 +131,6 @@ namespace Opm
|
||||
int regionIdx = getTableIndex_(pvtTableIdx, i);
|
||||
output_mu[i] = viscosity_[regionIdx](p[i]);
|
||||
output_dmudp[i] = viscosity_[regionIdx].derivative(p[i]);
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// temperature dependence of the oil phase
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(regionIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double muRef = viscosity_[regionIdx](pRef);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[regionIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
}
|
||||
std::fill(output_dmudr, output_dmudr + n, 0.0);
|
||||
}
|
||||
@@ -158,7 +138,7 @@ namespace Opm
|
||||
void PvtDeadSpline::mu(const int n,
|
||||
const int* pvtTableIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* /*r*/,
|
||||
const PhasePresence* /*cond*/,
|
||||
double* output_mu,
|
||||
@@ -171,23 +151,6 @@ namespace Opm
|
||||
int regionIdx = getTableIndex_(pvtTableIdx, i);
|
||||
output_mu[i] = viscosity_[regionIdx](p[i]);
|
||||
output_dmudp[i] = viscosity_[regionIdx].derivative(p[i]);
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// temperature dependence of the oil phase
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(regionIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double muRef = viscosity_[regionIdx](pRef);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[regionIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
}
|
||||
std::fill(output_dmudr, output_dmudr + n, 0.0);
|
||||
}
|
||||
|
||||
@@ -148,15 +148,6 @@ namespace Opm
|
||||
const double* z,
|
||||
double* output_R,
|
||||
double* output_dRdp) const;
|
||||
|
||||
/// set the tables which specify the temperature dependence of the oil viscosity
|
||||
void setOilvisctTables(const std::vector<Opm::OilvisctTable>& oilvisctTables,
|
||||
DeckKeywordConstPtr viscrefKeyword)
|
||||
{
|
||||
oilvisctTables_ = &oilvisctTables;
|
||||
viscrefKeyword_ = viscrefKeyword;
|
||||
}
|
||||
|
||||
private:
|
||||
int getTableIndex_(const int* pvtTableIdx, int cellIdx) const
|
||||
{
|
||||
@@ -169,9 +160,6 @@ namespace Opm
|
||||
// table per PVT region.
|
||||
std::vector<UniformTableLinear<double> > b_;
|
||||
std::vector<UniformTableLinear<double> > viscosity_;
|
||||
|
||||
const std::vector<Opm::OilvisctTable>* oilvisctTables_;
|
||||
DeckKeywordConstPtr viscrefKeyword_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -114,9 +114,6 @@ namespace Opm
|
||||
double inverseBMu = miscible_gas(p[i], z + num_phases_*i, getTableIndex_(pvtRegionIdx, i), 3, false);
|
||||
|
||||
output_mu[i] = inverseB / inverseBMu;
|
||||
|
||||
// temperature dependence: Since E100 does not implement temperature
|
||||
// dependence of gas viscosity, we skip it here as well...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,8 +162,6 @@ namespace Opm
|
||||
output_dmudr[i] = (inverseBMu * dinverseBdr - inverseB * dinverseBmudr)
|
||||
/ (inverseBMu * inverseBMu);
|
||||
|
||||
// temperature dependence: Since E100 does not implement temperature
|
||||
// dependence of gas viscosity, we skip it here as well...
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,9 +36,6 @@ namespace Opm
|
||||
//-------------------------------------------------------------------------
|
||||
PvtLiveOil::PvtLiveOil(const std::vector<Opm::PvtoTable>& pvtoTables)
|
||||
{
|
||||
// by default, specify no temperature dependence of the PVT properties
|
||||
oilvisctTables_ = 0;
|
||||
|
||||
int numTables = pvtoTables.size();
|
||||
saturated_oil_table_.resize(numTables);
|
||||
undersat_oil_tables_.resize(numTables);
|
||||
@@ -152,20 +149,13 @@ namespace Opm
|
||||
|
||||
output_mu[i] = inverseB / inverseBMu;
|
||||
}
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// TODO: temperature dependence
|
||||
OPM_THROW(std::logic_error,
|
||||
"temperature dependent viscosity as a function of z "
|
||||
"is not yet implemented!");
|
||||
}
|
||||
}
|
||||
|
||||
/// Viscosity and its p and r derivatives as a function of p, T and r.
|
||||
void PvtLiveOil::mu(const int n,
|
||||
const int* pvtTableIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* r,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
@@ -193,32 +183,14 @@ namespace Opm
|
||||
output_dmudr[i] = (inverseBMu * dinverseBdr - inverseB * dinverseBmudr)
|
||||
/ (inverseBMu * inverseBMu);
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// temperature dependence
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(tableIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double rsRef = viscrefRecord->getItem("REFERENCE_RS")->getSIDouble(0);
|
||||
double muRef = miscible_oil(pRef, rsRef, tableIdx, 3, 0)/miscible_oil(pRef, rsRef, tableIdx, 1, 0);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[tableIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Viscosity and its p and r derivatives as a function of p, T and r.
|
||||
void PvtLiveOil::mu(const int n,
|
||||
const int* pvtTableIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* /*T*/,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_mu,
|
||||
@@ -248,24 +220,6 @@ namespace Opm
|
||||
output_dmudr[i] = (inverseBMu * dinverseBdr - inverseB * dinverseBmudr)
|
||||
/ (inverseBMu * inverseBMu);
|
||||
|
||||
|
||||
if (oilvisctTables_ != 0) {
|
||||
// temperature dependence
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword_->getRecord(tableIdx);
|
||||
double pRef = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
double rsRef = viscrefRecord->getItem("REFERENCE_RS")->getSIDouble(0);
|
||||
double muRef = miscible_oil(pRef, rsRef, tableIdx, 3, 0)/miscible_oil(pRef, rsRef, tableIdx, 1, 0);
|
||||
|
||||
double muOilvisct = (*oilvisctTables_)[tableIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
|
||||
// TODO (?): derivative of oil viscosity w.r.t. temperature.
|
||||
// probably requires a healthy portion of if-spaghetti
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,4 +645,5 @@ namespace Opm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
@@ -142,14 +142,6 @@ namespace Opm
|
||||
double* output_R,
|
||||
double* output_dRdp) const;
|
||||
|
||||
/// set the tables which specify the temperature dependence of the oil viscosity
|
||||
void setOilvisctTables(const std::vector<Opm::OilvisctTable>& oilvisctTables,
|
||||
DeckKeywordConstPtr viscrefKeyword)
|
||||
{
|
||||
oilvisctTables_ = &oilvisctTables;
|
||||
viscrefKeyword_ = viscrefKeyword;
|
||||
}
|
||||
|
||||
private:
|
||||
int getTableIndex_(const int* pvtTableIdx, int cellIdx) const
|
||||
{
|
||||
@@ -187,9 +179,6 @@ namespace Opm
|
||||
// store one table per PVT region.
|
||||
std::vector<std::vector<std::vector<double> > > saturated_oil_table_;
|
||||
std::vector<std::vector<std::vector<std::vector<double> > > > undersat_oil_tables_;
|
||||
|
||||
const std::vector<Opm::OilvisctTable>* oilvisctTables_;
|
||||
DeckKeywordConstPtr viscrefKeyword_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
Copyright 2015 Andreas Lauser
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef OPM_THERMAL_GAS_PVT_WRAPPER_HPP
|
||||
#define OPM_THERMAL_GAS_PVT_WRAPPER_HPP
|
||||
|
||||
#include <opm/core/props/pvt/PvtInterface.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// Class which wraps another (i.e., isothermal) PVT object into one which adds
|
||||
/// temperature dependence of gas
|
||||
class ThermalGasPvtWrapper : public PvtInterface
|
||||
{
|
||||
public:
|
||||
ThermalGasPvtWrapper()
|
||||
{}
|
||||
|
||||
|
||||
/// extract the quantities needed specify the temperature dependence of the gas
|
||||
/// viscosity and density from the deck
|
||||
void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt,
|
||||
Opm::DeckConstPtr deck,
|
||||
Opm::EclipseStateConstPtr eclipseState)
|
||||
{
|
||||
isothermalPvt_ = isothermalPvt;
|
||||
|
||||
int numRegions;
|
||||
if (deck->hasKeyword("PVTG"))
|
||||
numRegions = eclipseState->getPvtgTables().size();
|
||||
else if (deck->hasKeyword("PVDG"))
|
||||
numRegions = eclipseState->getPvdgTables().size();
|
||||
else
|
||||
OPM_THROW(std::runtime_error, "Gas phase was not initialized using a known way");
|
||||
|
||||
// viscosity
|
||||
if (deck->hasKeyword("GASVISCT")) {
|
||||
gasvisctTables_ = &eclipseState->getGasvisctTables();
|
||||
assert(gasvisctTables_->size() == numRegions);
|
||||
|
||||
gasCompIdx_ = deck->getKeyword("GCOMPIDX")->getRecord(0)->getItem("GAS_COMPONENT_INDEX")->getInt(0) - 1;
|
||||
gasvisctColumnName_ = "Viscosity"+std::to_string(static_cast<long long>(gasCompIdx_));
|
||||
}
|
||||
|
||||
// density
|
||||
if (deck->hasKeyword("TREF")) {
|
||||
tref_ = deck->getKeyword("TREF")->getRecord(0)->getItem("TEMPERATURE")->getSIDouble(0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_mu) const
|
||||
{
|
||||
if (gasvisctTables_)
|
||||
// TODO: temperature dependence for viscosity depending on z
|
||||
OPM_THROW(std::runtime_error,
|
||||
"temperature dependent viscosity as a function of z "
|
||||
"is not yet implemented!");
|
||||
|
||||
// compute the isothermal viscosity
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, z, output_mu);
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
double* output_dmudr) const
|
||||
{
|
||||
if (gasvisctTables_ != 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// temperature dependence of the gas phase. this assumes that the gas
|
||||
// component index has been set properly, and it also looses the
|
||||
// pressure dependence of gas. (This does not make much sense, but it
|
||||
// seems to be what the documentation for the GASVISCT keyword in the
|
||||
// RM says.)
|
||||
int regionIdx = getPvtRegionIndex_(pvtRegionIdx, i);
|
||||
double muGasvisct = (*gasvisctTables_)[regionIdx].evaluate(gasvisctColumnName_, T[i]);
|
||||
|
||||
output_mu[i] = muGasvisct;
|
||||
output_dmudp[i] = 0.0;
|
||||
output_dmudr[i] = 0.0;
|
||||
|
||||
// TODO (?): derivative of gas viscosity w.r.t. temperature.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// compute the isothermal viscosity and its derivatives
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, r, output_mu, output_dmudp, output_dmudr);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
double* output_dmudr) const
|
||||
{
|
||||
if (gasvisctTables_ != 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// temperature dependence of the gas phase. this assumes that the gas
|
||||
// component index has been set properly, and it also looses the
|
||||
// pressure dependence of gas. (This does not make much sense, but it
|
||||
// seems to be what the documentation for the GASVISCT keyword in the
|
||||
// RM says.)
|
||||
int regionIdx = getPvtRegionIndex_(pvtRegionIdx, i);
|
||||
double muGasvisct = (*gasvisctTables_)[regionIdx].evaluate(gasvisctColumnName_, T[i]);
|
||||
|
||||
output_mu[i] = muGasvisct;
|
||||
output_dmudp[i] = 0.0;
|
||||
output_dmudr[i] = 0.0;
|
||||
|
||||
// TODO (?): derivative of gas viscosity w.r.t. temperature.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// compute the isothermal viscosity and its derivatives
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, r, cond, output_mu, output_dmudp, output_dmudr);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void B(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_B) const
|
||||
{
|
||||
// isothermal case
|
||||
isothermalPvt_->B(n, pvtRegionIdx, p, T, z, output_B);
|
||||
|
||||
if (tref_ > 0.0) {
|
||||
// the Eclipse TD/RM do not explicitly specify the relation of the gas
|
||||
// density and the temperature, but equation (69.49) (for Eclipse 2011.1)
|
||||
// implies that the temperature dependence of the gas phase is rho(T, p) =
|
||||
// rho(tref_, p)/tref_*T ...
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = tref_/T[i];
|
||||
output_B[i] *= alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void dBdp(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_B,
|
||||
double* output_dBdp) const
|
||||
{
|
||||
isothermalPvt_->dBdp(n, pvtRegionIdx, p, T, z, output_B, output_dBdp);
|
||||
|
||||
if (tref_ > 0.0) {
|
||||
// the Eclipse TD/RM do not explicitly specify the relation of the gas
|
||||
// density and the temperature, but equation (69.49) (for Eclipse 2011.1)
|
||||
// implies that the temperature dependence of the gas phase is rho(T, p) =
|
||||
// rho(tref_, p)/tref_*T ...
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = tref_/T[i];
|
||||
output_B[i] *= alpha;
|
||||
output_dBdp[i] *= alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void b(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
double* output_b,
|
||||
double* output_dbdp,
|
||||
double* output_dbdr) const
|
||||
{
|
||||
isothermalPvt_->b(n, pvtRegionIdx, p, T, r, output_b, output_dbdp, output_dbdr);
|
||||
|
||||
if (tref_ > 0.0) {
|
||||
// the Eclipse TD/RM do not explicitly specify the relation of the gas
|
||||
// density and the temperature, but equation (69.49) (for Eclipse 2011.1)
|
||||
// implies that the temperature dependence of the gas phase is rho(T, p) =
|
||||
// rho(tref_, p)/tref_*T ...
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = T[i]/tref_;
|
||||
output_b[i] *= alpha;
|
||||
output_dbdp[i] *= alpha;
|
||||
output_dbdr[i] *= alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void b(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_b,
|
||||
double* output_dbdp,
|
||||
double* output_dbdr) const
|
||||
{
|
||||
isothermalPvt_->b(n, pvtRegionIdx, p, T, r, cond, output_b, output_dbdp, output_dbdr);
|
||||
|
||||
if (tref_ > 0.0) {
|
||||
// the Eclipse TD/RM do not explicitly specify the relation of the gas
|
||||
// density and the temperature, but equation (69.49) (for Eclipse 2011.1)
|
||||
// implies that the temperature dependence of the gas phase is rho(T, p) =
|
||||
// rho(tref_, p)/tref_*T ...
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = T[i]/tref_;
|
||||
output_b[i] *= alpha;
|
||||
output_dbdp[i] *= alpha;
|
||||
output_dbdr[i] *= alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void rsSat(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
double* output_rsSat,
|
||||
double* output_drsSatdp) const
|
||||
{
|
||||
isothermalPvt_->rsSat(n, pvtRegionIdx, p, output_rsSat, output_drsSatdp);
|
||||
}
|
||||
|
||||
virtual void rvSat(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
double* output_rvSat,
|
||||
double* output_drvSatdp) const
|
||||
{
|
||||
isothermalPvt_->rvSat(n, pvtRegionIdx, p, output_rvSat, output_drvSatdp);
|
||||
}
|
||||
|
||||
virtual void R(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* z,
|
||||
double* output_R) const
|
||||
{
|
||||
isothermalPvt_->R(n, pvtRegionIdx, p, z, output_R);
|
||||
}
|
||||
|
||||
virtual void dRdp(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* z,
|
||||
double* output_R,
|
||||
double* output_dRdp) const
|
||||
{
|
||||
isothermalPvt_->dRdp(n, pvtRegionIdx, p, z, output_R, output_dRdp);
|
||||
}
|
||||
|
||||
private:
|
||||
int getPvtRegionIndex_(const int* pvtRegionIdx, int cellIdx) const
|
||||
{
|
||||
if (!pvtRegionIdx)
|
||||
return 0;
|
||||
return pvtRegionIdx[cellIdx];
|
||||
}
|
||||
|
||||
// the PVT propertied for the isothermal case
|
||||
std::shared_ptr<const PvtInterface> isothermalPvt_;
|
||||
|
||||
// The PVT properties needed for temperature dependence of the viscosity. We need
|
||||
// to store one value per PVT region.
|
||||
const std::vector<Opm::GasvisctTable>* gasvisctTables_;
|
||||
std::string gasvisctColumnName_;
|
||||
int gasCompIdx_;
|
||||
|
||||
// The PVT properties needed for temperature dependence of the density.
|
||||
double tref_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
Copyright 2015 Andreas Lauser
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_THERMAL_OIL_PVT_WRAPPER_HPP
|
||||
#define OPM_THERMAL_OIL_PVT_WRAPPER_HPP
|
||||
|
||||
#include <opm/core/props/pvt/PvtInterface.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// Class which wraps another (i.e., isothermal) PVT object into one which adds
|
||||
/// temperature dependence of oil
|
||||
class ThermalOilPvtWrapper : public PvtInterface
|
||||
{
|
||||
public:
|
||||
ThermalOilPvtWrapper()
|
||||
{}
|
||||
|
||||
|
||||
/// set the tables which specify the temperature dependence of the oil viscosity
|
||||
void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt,
|
||||
Opm::DeckConstPtr deck,
|
||||
Opm::EclipseStateConstPtr eclipseState)
|
||||
{
|
||||
isothermalPvt_ = isothermalPvt;
|
||||
|
||||
int numRegions;
|
||||
if (deck->hasKeyword("PVTO"))
|
||||
numRegions = eclipseState->getPvtoTables().size();
|
||||
else if (deck->hasKeyword("PVDO"))
|
||||
numRegions = eclipseState->getPvdoTables().size();
|
||||
else if (deck->hasKeyword("PVCDO"))
|
||||
numRegions = deck->getKeyword("PVCDO")->size();
|
||||
else
|
||||
OPM_THROW(std::runtime_error, "Oil phase was not initialized using a known way");
|
||||
|
||||
// viscosity
|
||||
if (deck->hasKeyword("VISCREF")) {
|
||||
oilvisctTables_ = &eclipseState->getOilvisctTables();
|
||||
Opm::DeckKeywordConstPtr viscrefKeyword = deck->getKeyword("VISCREF");
|
||||
|
||||
assert(oilvisctTables_->size() == numRegions);
|
||||
assert(viscrefKeyword->size() == numRegions);
|
||||
|
||||
viscrefPress_.resize(numRegions);
|
||||
viscrefRs_.resize(numRegions);
|
||||
muRef_.resize(numRegions);
|
||||
for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
|
||||
DeckRecordConstPtr viscrefRecord = viscrefKeyword->getRecord(regionIdx);
|
||||
viscrefPress_[regionIdx] = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
viscrefRs_[regionIdx] = viscrefRecord->getItem("REFERENCE_RS")->getSIDouble(0);
|
||||
|
||||
// temperature used to calculate the reference viscosity [K]. the
|
||||
// value does not really matter if the underlying PVT object really
|
||||
// is isothermal...
|
||||
double Tref = 273.15 + 20;
|
||||
|
||||
// compute the reference viscosity using the isothermal PVT object.
|
||||
double tmp1, tmp2;
|
||||
isothermalPvt_->mu(1,
|
||||
®ionIdx,
|
||||
&viscrefPress_[regionIdx],
|
||||
&Tref,
|
||||
&viscrefRs_[regionIdx],
|
||||
&muRef_[regionIdx],
|
||||
&tmp1,
|
||||
&tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
// quantities required for density. note that we just always use the values
|
||||
// for the first EOS. (since EOS != PVT region.)
|
||||
tref_ = 0.0;
|
||||
if (deck->hasKeyword("THERMEX1")) {
|
||||
oilCompIdx_ = deck->getKeyword("OCOMPIDX")->getRecord(0)->getItem("OIL_COMPONENT_INDEX")->getInt(0) - 1;
|
||||
|
||||
// always use the values of the first EOS
|
||||
tref_ = deck->getKeyword("TREF")->getRecord(0)->getItem("TEMPERATURE")->getSIDouble(oilCompIdx_);
|
||||
pref_ = deck->getKeyword("PREF")->getRecord(0)->getItem("PRESSURE")->getSIDouble(oilCompIdx_);
|
||||
cref_ = deck->getKeyword("CREF")->getRecord(0)->getItem("COMPRESSIBILITY")->getSIDouble(oilCompIdx_);
|
||||
thermex1_ = deck->getKeyword("THERMEX1")->getRecord(0)->getItem("EXPANSION_COEFF")->getSIDouble(oilCompIdx_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_mu) const
|
||||
{
|
||||
if (oilvisctTables_)
|
||||
// TODO: temperature dependence for viscosity depending on z
|
||||
OPM_THROW(std::runtime_error,
|
||||
"temperature dependent viscosity as a function of z "
|
||||
"is not yet implemented!");
|
||||
|
||||
// compute the isothermal viscosity
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, z, output_mu);
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
double* output_dmudr) const
|
||||
{
|
||||
// compute the isothermal viscosity and its derivatives
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, r, output_mu, output_dmudp, output_dmudr);
|
||||
|
||||
if (!oilvisctTables_)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// temperature dependence
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int regionIdx = getPvtRegionIndex_(pvtRegionIdx, i);
|
||||
|
||||
// calculate the viscosity of the isothermal keyword for the reference
|
||||
// pressure given by the VISCREF keyword.
|
||||
double muRef = muRef_[regionIdx];
|
||||
|
||||
// compute the viscosity deviation due to temperature
|
||||
double muOilvisct = (*oilvisctTables_)[regionIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
// TODO (?): derivative of viscosity w.r.t. temperature.
|
||||
}
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
double* output_dmudr) const
|
||||
{
|
||||
// compute the isothermal viscosity and its derivatives
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, r, cond, output_mu, output_dmudp, output_dmudr);
|
||||
|
||||
if (!oilvisctTables_)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// temperature dependence
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int regionIdx = getPvtRegionIndex_(pvtRegionIdx, i);
|
||||
|
||||
// calculate the viscosity of the isothermal keyword for the reference
|
||||
// pressure given by the VISCREF keyword.
|
||||
double muRef = muRef_[regionIdx];
|
||||
|
||||
// compute the viscosity deviation due to temperature
|
||||
double muOilvisct = (*oilvisctTables_)[regionIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muOilvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
// TODO (?): derivative of viscosity w.r.t. temperature.
|
||||
}
|
||||
}
|
||||
|
||||
virtual void B(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_B) const
|
||||
{
|
||||
// isothermal case
|
||||
isothermalPvt_->B(n, pvtRegionIdx, p, T, z, output_B);
|
||||
|
||||
if (thermex1_ <= 0.0)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// deal with the temperature dependence of the oil phase. we use equation
|
||||
// (3.208) from the Eclipse 2011.1 Reference Manual, but we calculate rho_ref
|
||||
// using the isothermal keyword instead of using the value for the
|
||||
// components, so the oil compressibility is already dealt with there. Note
|
||||
// that we only do the part for the oil component here, the part for
|
||||
// dissolved gas is ignored so far.
|
||||
double cT1 = thermex1_;
|
||||
double TRef = tref_;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = (1 + cT1*(T[i] - TRef));
|
||||
output_B[i] *= alpha;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void dBdp(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_B,
|
||||
double* output_dBdp) const
|
||||
{
|
||||
isothermalPvt_->dBdp(n, pvtRegionIdx, p, T, z, output_B, output_dBdp);
|
||||
|
||||
if (thermex1_ <= 0.0)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// deal with the temperature dependence of the oil phase. we use equation
|
||||
// (3.208) from the Eclipse 2011.1 Reference Manual, but we calculate rho_ref
|
||||
// using the isothermal keyword instead of using the value for the
|
||||
// components, so the oil compressibility is already dealt with there. Note
|
||||
// that we only do the part for the oil component here, the part for
|
||||
// dissolved gas is ignored so far.
|
||||
double cT1 = thermex1_;
|
||||
double TRef = tref_;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = (1 + cT1*(T[i] - TRef));
|
||||
output_B[i] *= alpha;
|
||||
output_dBdp[i] *= alpha;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void b(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
double* output_b,
|
||||
double* output_dbdp,
|
||||
double* output_dbdr) const
|
||||
{
|
||||
isothermalPvt_->b(n, pvtRegionIdx, p, T, r, output_b, output_dbdp, output_dbdr);
|
||||
|
||||
if (thermex1_ <= 0.0)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// deal with the temperature dependence of the oil phase. we use equation
|
||||
// (3.208) from the Eclipse 2011.1 Reference Manual, but we calculate rho_ref
|
||||
// using the isothermal keyword instead of using the value for the
|
||||
// components, so the oil compressibility is already dealt with there. Note
|
||||
// that we only do the part for the oil component here, the part for
|
||||
// dissolved gas is ignored so far.
|
||||
double cT1 = thermex1_;
|
||||
double TRef = tref_;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = 1.0/(1 + cT1*(T[i] - TRef));
|
||||
output_b[i] *= alpha;
|
||||
output_dbdp[i] *= alpha;
|
||||
output_dbdr[i] *= alpha;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void b(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_b,
|
||||
double* output_dbdp,
|
||||
double* output_dbdr) const
|
||||
{
|
||||
isothermalPvt_->b(n, pvtRegionIdx, p, T, r, cond, output_b, output_dbdp, output_dbdr);
|
||||
|
||||
if (thermex1_ <= 0.0)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// deal with the temperature dependence of the oil phase. we use equation
|
||||
// (3.208) from the Eclipse 2011.1 Reference Manual, but we calculate rho_ref
|
||||
// using the isothermal keyword instead of using the value for the
|
||||
// components, so the oil compressibility is already dealt with there. Note
|
||||
// that we only do the part for the oil component here, the part for
|
||||
// dissolved gas is ignored so far.
|
||||
double cT1 = thermex1_;
|
||||
double TRef = tref_;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double alpha = 1.0/(1 + cT1*(T[i] - TRef));
|
||||
output_b[i] *= alpha;
|
||||
output_dbdp[i] *= alpha;
|
||||
output_dbdr[i] *= alpha;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void rsSat(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
double* output_rsSat,
|
||||
double* output_drsSatdp) const
|
||||
{
|
||||
isothermalPvt_->rsSat(n, pvtRegionIdx, p, output_rsSat, output_drsSatdp);
|
||||
}
|
||||
|
||||
virtual void rvSat(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
double* output_rvSat,
|
||||
double* output_drvSatdp) const
|
||||
{
|
||||
isothermalPvt_->rvSat(n, pvtRegionIdx, p, output_rvSat, output_drvSatdp);
|
||||
}
|
||||
|
||||
virtual void R(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* z,
|
||||
double* output_R) const
|
||||
{
|
||||
isothermalPvt_->R(n, pvtRegionIdx, p, z, output_R);
|
||||
}
|
||||
|
||||
virtual void dRdp(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* z,
|
||||
double* output_R,
|
||||
double* output_dRdp) const
|
||||
{
|
||||
isothermalPvt_->dRdp(n, pvtRegionIdx, p, z, output_R, output_dRdp);
|
||||
}
|
||||
|
||||
private:
|
||||
int getPvtRegionIndex_(const int* pvtRegionIdx, int cellIdx) const
|
||||
{
|
||||
if (!pvtRegionIdx)
|
||||
return 0;
|
||||
return pvtRegionIdx[cellIdx];
|
||||
}
|
||||
|
||||
// the PVT propertied for the isothermal case
|
||||
std::shared_ptr<const PvtInterface> isothermalPvt_;
|
||||
|
||||
// The PVT properties needed for temperature dependence of the viscosity. We need
|
||||
// to store one value per PVT region.
|
||||
std::vector<double> viscrefPress_;
|
||||
std::vector<double> viscrefRs_;
|
||||
std::vector<double> muRef_;
|
||||
|
||||
const std::vector<Opm::OilvisctTable>* oilvisctTables_;
|
||||
|
||||
// The PVT properties needed for temperature dependence of the density. This is
|
||||
// specified as one value per EOS in the manual, but we unconditionally use the
|
||||
// expansion coefficient of the first EOS...
|
||||
int oilCompIdx_;
|
||||
double tref_;
|
||||
double pref_;
|
||||
double cref_;
|
||||
double thermex1_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Copyright 2015 Andreas Lauser
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_THERMAL_WATER_PVT_WRAPPER_HPP
|
||||
#define OPM_THERMAL_WATER_PVT_WRAPPER_HPP
|
||||
|
||||
#include <opm/core/props/pvt/PvtInterface.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// Class which wraps another (i.e., isothermal) PVT object into one which adds
|
||||
/// temperature dependence of water
|
||||
class ThermalWaterPvtWrapper : public PvtInterface
|
||||
{
|
||||
public:
|
||||
ThermalWaterPvtWrapper()
|
||||
{}
|
||||
|
||||
|
||||
/// set the tables which specify the temperature dependence of the water viscosity
|
||||
void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt,
|
||||
Opm::DeckConstPtr deck,
|
||||
Opm::EclipseStateConstPtr eclipseState)
|
||||
{
|
||||
isothermalPvt_ = isothermalPvt;
|
||||
watvisctTables_ = 0;
|
||||
|
||||
// stuff which we need to get from the PVTW keyword
|
||||
Opm::DeckKeywordConstPtr pvtwKeyword = deck->getKeyword("PVTW");
|
||||
int numRegions = pvtwKeyword->size();
|
||||
pvtwRefPress_.resize(numRegions);
|
||||
pvtwRefB_.resize(numRegions);
|
||||
pvtwCompressibility_.resize(numRegions);
|
||||
pvtwViscosity_.resize(numRegions);
|
||||
pvtwViscosibility_.resize(numRegions);
|
||||
for (int regionIdx = 0; regionIdx < numRegions; ++ regionIdx) {
|
||||
Opm::DeckRecordConstPtr pvtwRecord = pvtwKeyword->getRecord(regionIdx);
|
||||
pvtwRefPress_[regionIdx] = pvtwRecord->getItem("P_REF")->getSIDouble(0);
|
||||
pvtwRefB_[regionIdx] = pvtwRecord->getItem("WATER_VOL_FACTOR")->getSIDouble(0);
|
||||
pvtwViscosity_[regionIdx] = pvtwRecord->getItem("WATER_VISCOSITY")->getSIDouble(0);
|
||||
pvtwViscosibility_[regionIdx] = pvtwRecord->getItem("WATER_VISCOSIBILITY")->getSIDouble(0);
|
||||
}
|
||||
|
||||
// quantities required for the temperature dependence of the viscosity
|
||||
// (basically we expect well-behaved VISCREF and WATVISCT keywords.)
|
||||
if (deck->hasKeyword("VISCREF")) {
|
||||
watvisctTables_ = &eclipseState->getWatvisctTables();
|
||||
Opm::DeckKeywordConstPtr viscrefKeyword = deck->getKeyword("VISCREF");
|
||||
|
||||
assert(watvisctTables_->size() == numRegions);
|
||||
assert(viscrefKeyword->size() == numRegions);
|
||||
|
||||
viscrefPress_.resize(numRegions);
|
||||
for (int regionIdx = 0; regionIdx < numRegions; ++ regionIdx) {
|
||||
Opm::DeckRecordConstPtr viscrefRecord = viscrefKeyword->getRecord(regionIdx);
|
||||
|
||||
viscrefPress_[regionIdx] = viscrefRecord->getItem("REFERENCE_PRESSURE")->getSIDouble(0);
|
||||
}
|
||||
}
|
||||
|
||||
// quantities required for the temperature dependence of the density
|
||||
if (deck->hasKeyword("WATDENT")) {
|
||||
DeckKeywordConstPtr watdentKeyword = deck->getKeyword("WATDENT");
|
||||
|
||||
assert(watdentKeyword->size() == numRegions);
|
||||
|
||||
watdentRefTemp_.resize(numRegions);
|
||||
watdentCT1_.resize(numRegions);
|
||||
watdentCT2_.resize(numRegions);
|
||||
for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
|
||||
Opm::DeckRecordConstPtr watdentRecord = watdentKeyword->getRecord(regionIdx);
|
||||
|
||||
watdentRefTemp_[regionIdx] = watdentRecord->getItem("REFERENCE_TEMPERATURE")->getSIDouble(0);
|
||||
watdentCT1_[regionIdx] = watdentRecord->getItem("EXPANSION_COEFF_LINEAR")->getSIDouble(0);
|
||||
watdentCT2_[regionIdx] = watdentRecord->getItem("EXPANSION_COEFF_QUADRATIC")->getSIDouble(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_mu) const
|
||||
{
|
||||
if (watvisctTables_)
|
||||
// TODO: temperature dependence for viscosity depending on z
|
||||
OPM_THROW(std::runtime_error,
|
||||
"temperature dependent viscosity as a function of z "
|
||||
"is not yet implemented!");
|
||||
|
||||
// compute the isothermal viscosity
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, z, output_mu);
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
double* output_dmudr) const
|
||||
{
|
||||
// compute the isothermal viscosity and its derivatives
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, r, output_mu, output_dmudp, output_dmudr);
|
||||
|
||||
if (!watvisctTables_)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// temperature dependence
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
|
||||
// calculate the viscosity of the isothermal keyword for the reference
|
||||
// pressure given by the VISCREF keyword.
|
||||
double x = -pvtwViscosibility_[tableIdx]*(viscrefPress_[tableIdx] - pvtwRefPress_[tableIdx]);
|
||||
double muRef = pvtwViscosity_[tableIdx]/(1.0 + x + 0.5*x*x);
|
||||
|
||||
// compute the viscosity deviation due to temperature
|
||||
double muWatvisct = (*watvisctTables_)[tableIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muWatvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
// TODO (?): derivative of viscosity w.r.t. temperature.
|
||||
}
|
||||
}
|
||||
|
||||
virtual void mu(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_mu,
|
||||
double* output_dmudp,
|
||||
double* output_dmudr) const
|
||||
{
|
||||
// compute the isothermal viscosity and its derivatives
|
||||
isothermalPvt_->mu(n, pvtRegionIdx, p, T, r, cond, output_mu, output_dmudp, output_dmudr);
|
||||
|
||||
if (!watvisctTables_)
|
||||
// isothermal case
|
||||
return;
|
||||
|
||||
// temperature dependence
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
|
||||
// calculate the viscosity of the isothermal keyword for the reference
|
||||
// pressure given by the VISCREF keyword.
|
||||
double x = -pvtwViscosibility_[tableIdx]*(viscrefPress_[tableIdx] - pvtwRefPress_[tableIdx]);
|
||||
double muRef = pvtwViscosity_[tableIdx]/(1.0 + x + 0.5*x*x);
|
||||
|
||||
// compute the viscosity deviation due to temperature
|
||||
double muWatvisct = (*watvisctTables_)[tableIdx].evaluate("Viscosity", T[i]);
|
||||
double alpha = muWatvisct/muRef;
|
||||
|
||||
output_mu[i] *= alpha;
|
||||
output_dmudp[i] *= alpha;
|
||||
output_dmudr[i] *= alpha;
|
||||
// TODO (?): derivative of viscosity w.r.t. temperature.
|
||||
}
|
||||
}
|
||||
|
||||
virtual void B(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_B) const
|
||||
{
|
||||
if (watdentRefTemp_.empty()) {
|
||||
// isothermal case
|
||||
isothermalPvt_->B(n, pvtRegionIdx, p, T, z, output_B);
|
||||
return;
|
||||
}
|
||||
|
||||
// This changes how the water density depends on pressure compared to what's
|
||||
// used for the PVTW keyword, but it seems to be what Eclipse does. For
|
||||
// details, see the documentation for the WATDENT keyword in the Eclipse RM.
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
double BwRef = pvtwRefB_[tableIdx];
|
||||
double TRef = watdentRefTemp_[tableIdx];
|
||||
double X = pvtwCompressibility_[tableIdx]*(p[i] - pvtwRefPress_[tableIdx]);
|
||||
double cT1 = watdentCT1_[tableIdx];
|
||||
double cT2 = watdentCT2_[tableIdx];
|
||||
double Y = T[i] - TRef;
|
||||
double Bw = BwRef*(1 - X)*(1 + cT1*Y + cT2*Y*Y);
|
||||
output_B[i] = Bw;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void dBdp(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* z,
|
||||
double* output_B,
|
||||
double* output_dBdp) const
|
||||
{
|
||||
if (watdentRefTemp_.empty()) {
|
||||
// isothermal case
|
||||
isothermalPvt_->dBdp(n, pvtRegionIdx, p, T, z, output_B, output_dBdp);
|
||||
return;
|
||||
}
|
||||
|
||||
// This changes how the water density depends on pressure. This is awkward,
|
||||
// but it seems to be what Eclipse does. See the documentation for the
|
||||
// WATDENT keyword in the Eclipse RM
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
double BwRef = pvtwRefB_[tableIdx];
|
||||
double TRef = watdentRefTemp_[tableIdx];
|
||||
double X = pvtwCompressibility_[tableIdx]*(p[i] - pvtwRefPress_[tableIdx]);
|
||||
double cT1 = watdentCT1_[tableIdx];
|
||||
double cT2 = watdentCT2_[tableIdx];
|
||||
double Y = T[i] - TRef;
|
||||
double Bw = BwRef*(1 - X)*(1 + cT1*Y + cT2*Y*Y);
|
||||
output_B[i] = Bw;
|
||||
}
|
||||
|
||||
std::fill(output_dBdp, output_dBdp + n, 0.0);
|
||||
}
|
||||
|
||||
virtual void b(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
double* output_b,
|
||||
double* output_dbdp,
|
||||
double* output_dbdr) const
|
||||
{
|
||||
if (watdentRefTemp_.empty()) {
|
||||
// isothermal case
|
||||
isothermalPvt_->b(n, pvtRegionIdx, p, T, r, output_b, output_dbdp, output_dbdr);
|
||||
return;
|
||||
}
|
||||
|
||||
// This changes how the water density depends on pressure. This is awkward,
|
||||
// but it seems to be what Eclipse does. See the documentation for the
|
||||
// WATDENT keyword in the Eclipse RM
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
double BwRef = pvtwRefB_[tableIdx];
|
||||
double TRef = watdentRefTemp_[tableIdx];
|
||||
double X = pvtwCompressibility_[tableIdx]*(p[i] - pvtwRefPress_[tableIdx]);
|
||||
double cT1 = watdentCT1_[tableIdx];
|
||||
double cT2 = watdentCT2_[tableIdx];
|
||||
double Y = T[i] - TRef;
|
||||
double Bw = BwRef*(1 - X)*(1 + cT1*Y + cT2*Y*Y);
|
||||
output_b[i] = 1.0/Bw;
|
||||
}
|
||||
|
||||
std::fill(output_dbdp, output_dbdp + n, 0.0);
|
||||
std::fill(output_dbdr, output_dbdr + n, 0.0);
|
||||
}
|
||||
|
||||
virtual void b(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* T,
|
||||
const double* r,
|
||||
const PhasePresence* cond,
|
||||
double* output_b,
|
||||
double* output_dbdp,
|
||||
double* output_dbdr) const
|
||||
{
|
||||
if (watdentRefTemp_.empty()) {
|
||||
// isothermal case
|
||||
isothermalPvt_->b(n, pvtRegionIdx, p, T, r, cond, output_b, output_dbdp, output_dbdr);
|
||||
return;
|
||||
}
|
||||
|
||||
// This changes pressure dependence of the water density, but it seems to be
|
||||
// what Eclipse does. See the documentation for the WATDENT keyword in the
|
||||
// Eclipse RM
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int tableIdx = getTableIndex_(pvtRegionIdx, i);
|
||||
double BwRef = pvtwRefB_[tableIdx];
|
||||
double TRef = watdentRefTemp_[tableIdx];
|
||||
double X = pvtwCompressibility_[tableIdx]*(p[i] - pvtwRefPress_[tableIdx]);
|
||||
double cT1 = watdentCT1_[tableIdx];
|
||||
double cT2 = watdentCT2_[tableIdx];
|
||||
double Y = T[i] - TRef;
|
||||
double Bw = BwRef*(1 - X)*(1 + cT1*Y + cT2*Y*Y);
|
||||
output_b[i] = 1.0/Bw;
|
||||
}
|
||||
|
||||
std::fill(output_dbdp, output_dbdp + n, 0.0);
|
||||
std::fill(output_dbdr, output_dbdr + n, 0.0);
|
||||
|
||||
}
|
||||
|
||||
virtual void rsSat(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
double* output_rsSat,
|
||||
double* output_drsSatdp) const
|
||||
{
|
||||
isothermalPvt_->rsSat(n, pvtRegionIdx, p, output_rsSat, output_drsSatdp);
|
||||
}
|
||||
|
||||
virtual void rvSat(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
double* output_rvSat,
|
||||
double* output_drvSatdp) const
|
||||
{
|
||||
isothermalPvt_->rvSat(n, pvtRegionIdx, p, output_rvSat, output_drvSatdp);
|
||||
}
|
||||
|
||||
virtual void R(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* z,
|
||||
double* output_R) const
|
||||
{
|
||||
isothermalPvt_->R(n, pvtRegionIdx, p, z, output_R);
|
||||
}
|
||||
|
||||
virtual void dRdp(const int n,
|
||||
const int* pvtRegionIdx,
|
||||
const double* p,
|
||||
const double* z,
|
||||
double* output_R,
|
||||
double* output_dRdp) const
|
||||
{
|
||||
isothermalPvt_->dRdp(n, pvtRegionIdx, p, z, output_R, output_dRdp);
|
||||
}
|
||||
|
||||
private:
|
||||
int getTableIndex_(const int* pvtTableIdx, int cellIdx) const
|
||||
{
|
||||
if (!pvtTableIdx)
|
||||
return 0;
|
||||
return pvtTableIdx[cellIdx];
|
||||
}
|
||||
|
||||
// the PVT propertied for the isothermal case
|
||||
std::shared_ptr<const PvtInterface> isothermalPvt_;
|
||||
|
||||
// The PVT properties needed for temperature dependence. We need to store one
|
||||
// value per PVT region.
|
||||
std::vector<double> viscrefPress_;
|
||||
|
||||
std::vector<double> watdentRefTemp_;
|
||||
std::vector<double> watdentCT1_;
|
||||
std::vector<double> watdentCT2_;
|
||||
|
||||
std::vector<double> pvtwRefPress_;
|
||||
std::vector<double> pvtwRefB_;
|
||||
std::vector<double> pvtwCompressibility_;
|
||||
std::vector<double> pvtwViscosity_;
|
||||
std::vector<double> pvtwViscosibility_;
|
||||
|
||||
const std::vector<Opm::WatvisctTable>* watvisctTables_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user