replace the blackoil PVT classes by the ones of opm-material

the opm-material classes are the ones which are now used by
opm-autodiff and this patch makes it much easier to keep the opm-core
and opm-autodiff results consistent. Also, the opm-material classes
seem to be a bit faster than the opm-core ones (see
https://github.com/OPM/opm-autodiff/pull/576)

I ran the usual array of tests with `flow`: SPE1, SPE3, SPE9 and Norne
all produce the same results at the identical runtime (modulo noise)
and also "Model 2" seems to work.
This commit is contained in:
Andreas Lauser
2016-02-15 16:03:30 +01:00
parent 0c05fc4dc0
commit 23088f987f
23 changed files with 882 additions and 4365 deletions

View File

@@ -5,11 +5,22 @@
-- Copyright (C) 2015 Statoil
RUNSPEC
TABDIMS
--ntsfun ntpvt nssfun nppvt ntfip nrpvt ntendp
2 2 33 60 16 60 /
DIMENS
1 1 1 /
GRID
PROPS
DENSITY
859.5 1033.0 0.854 / Justert 22/7
860.04 1033.0 0.853 / Justert 22/7
PVTG

View File

@@ -1,388 +0,0 @@
#include <config.h>
#include <opm/core/props/pvt/PvtConstCompr.hpp>
#include <opm/core/props/pvt/PvtDead.hpp>
#include <opm/core/props/pvt/PvtDeadSpline.hpp>
#include <opm/core/props/pvt/PvtLiveOil.hpp>
#include <opm/core/props/pvt/PvtLiveGas.hpp>
#include <opm/core/props/phaseUsageFromDeck.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/core/props/pvt/BlackoilPvtProperties.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseMode.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
#if HAVE_DYNAMIC_BOOST_TEST
#define BOOST_TEST_DYN_LINK
#endif
#define NVERBOSE // to suppress our messages when throwing
#define BOOST_TEST_MODULE BlackoilFluidTest
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <memory>
#include <iostream>
#include <iterator>
#include <vector>
#include <string>
using namespace Opm;
using namespace std;
std::vector<std::shared_ptr<PvtInterface> > getProps(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState, PhaseUsage phase_usage_){
enum PhaseIndex { Aqua = 0, Liquid = 1, Vapour = 2 };
int samples = 0;
std::shared_ptr<const TableManager> tables = eclipseState->getTableManager();
std::vector<std::shared_ptr<PvtInterface> > props_;
// Set the properties.
props_.resize(phase_usage_.num_phases);
// Water PVT
if (phase_usage_.phase_used[Aqua]) {
if (deck->hasKeyword("PVTW")) {
std::shared_ptr<PvtConstCompr> pvtw(new PvtConstCompr);
pvtw->initFromWater(deck->getKeyword("PVTW"));
props_[phase_usage_.phase_pos[Aqua]] = pvtw;
} else {
// Eclipse 100 default.
props_[phase_usage_.phase_pos[Aqua]].reset(new PvtConstCompr(0.5*Opm::prefix::centi*Opm::unit::Poise));
}
}
// Oil PVT
if (phase_usage_.phase_used[Liquid]) {
const auto& pvdoTables = tables->getPvdoTables();
const auto& pvtoTables = tables->getPvtoTables();
if (!pvdoTables.empty()) {
if (samples > 0) {
std::shared_ptr<PvtDeadSpline> splinePvt(new PvtDeadSpline);
splinePvt->initFromOil(pvdoTables, samples);
props_[phase_usage_.phase_pos[Liquid]] = splinePvt;
} else {
std::shared_ptr<PvtDead> deadPvt(new PvtDead);
deadPvt->initFromOil(pvdoTables);
props_[phase_usage_.phase_pos[Liquid]] = deadPvt;
}
} else if (!pvtoTables.empty()) {
props_[phase_usage_.phase_pos[Liquid]].reset(new PvtLiveOil(pvtoTables));
} else if (deck->hasKeyword("PVCDO")) {
std::shared_ptr<PvtConstCompr> pvcdo(new PvtConstCompr);
pvcdo->initFromOil(deck->getKeyword("PVCDO"));
props_[phase_usage_.phase_pos[Liquid]] = pvcdo;
} else {
OPM_THROW(std::runtime_error, "Input is missing PVDO, PVCDO or PVTO\n");
}
}
// Gas PVT
if (phase_usage_.phase_used[Vapour]) {
const auto& pvdgTables = tables->getPvdgTables();
const auto& pvtgTables = tables->getPvtgTables();
if (!pvdgTables.empty()) {
if (samples > 0) {
std::shared_ptr<PvtDeadSpline> splinePvt(new PvtDeadSpline);
splinePvt->initFromGas(pvdgTables, samples);
props_[phase_usage_.phase_pos[Vapour]] = splinePvt;
} else {
std::shared_ptr<PvtDead> deadPvt(new PvtDead);
deadPvt->initFromGas(pvdgTables);
props_[phase_usage_.phase_pos[Vapour]] = deadPvt;
}
} else if (!pvtgTables.empty()) {
props_[phase_usage_.phase_pos[Vapour]].reset(new PvtLiveGas(pvtgTables));
} else {
OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n");
}
}
return props_;
}
void testmu(const double reltol, int n, int np, const std::vector<int> &pvtTableIdx, std::vector<double> p, std::vector<double> T, std::vector<double> r,std::vector<double> z,
std::vector<std::shared_ptr<PvtInterface> > props_, std::vector<Opm::PhasePresence> condition)
{
std::vector<double> mu(n);
std::vector<double> dmudp(n);
std::vector<double> dmudr(n);
std::vector<double> mu_new(n);
double dmudp_diff;
double dmudr_diff;
double dmudp_diff_u;
double dmudr_diff_u;
// test mu
for (int phase = 0; phase < np; ++phase) {
props_[phase]->mu(n, &pvtTableIdx[0], &p[0], &T[0], &r[0], &condition[0], &mu_new[0], &dmudp[0], &dmudr[0]);
props_[phase]->mu(n, &pvtTableIdx[0], &p[0], &T[0], &z[0], &mu[0]);
dmudp_diff = (mu_new[1]-mu_new[0])/(p[1]-p[0]);
dmudr_diff = (mu_new[2]-mu_new[0])/(r[2]-r[0]);
dmudp_diff_u = (mu_new[4]-mu_new[3])/(p[4]-p[3]);
dmudr_diff_u = (mu_new[5]-mu_new[3])/(r[5]-r[3]);
for (int i = 0; i < n; ++i){
BOOST_CHECK_CLOSE(mu_new[i],mu[i],reltol);
}
// saturated case
BOOST_CHECK_CLOSE(dmudp_diff,dmudp[0],reltol);
BOOST_CHECK_CLOSE(dmudr_diff,dmudr[0],reltol);
// unsaturated case
BOOST_CHECK_CLOSE(dmudp_diff_u,dmudp[3],reltol);
BOOST_CHECK_CLOSE(dmudr_diff_u,dmudr[3],reltol);
}
}
void testb(const double reltol, int n, int np, const std::vector<int> &pvtTableIdx, std::vector<double> p, std::vector<double> T, std::vector<double> r,std::vector<double> z,
std::vector<std::shared_ptr<PvtInterface> > props_, std::vector<Opm::PhasePresence> condition)
{
// test b
std::vector<double> b(n);
std::vector<double> B(n);
std::vector<double> invB(n);
std::vector<double> dinvBdp(n);
std::vector<double> dBdp(n);
std::vector<double> dbdr(n);
std::vector<double> dbdp(n);
double dbdp_diff;
double dbdr_diff;
double dbdp_diff_u;
double dbdr_diff_u;
for (int phase = 0; phase < np; ++phase) {
props_[phase]->b(n, &pvtTableIdx[0], &p[0], &T[0], &r[0], &condition[0], &b[0], &dbdp[0], &dbdr[0]);
props_[phase]->dBdp(n, &pvtTableIdx[0], &p[0], &T[0], &z[0], &B[0], &dBdp[0]);
dbdp_diff = (b[1]-b[0])/(p[1]-p[0]);
dbdr_diff = (b[2]-b[0])/(r[2]-r[0]);
dbdp_diff_u = (b[4]-b[3])/(p[4]-p[3]);
dbdr_diff_u = (b[5]-b[3])/(r[5]-r[3]);
for (int i = 0; i < n; ++i){
invB[i] = 1/B[i];
dinvBdp[i] = -1/pow(B[i],2) * dBdp[i];
}
for (int i = 0; i < n; ++i){
BOOST_CHECK_CLOSE(invB[i],b[i] , reltol);
BOOST_CHECK_CLOSE(dinvBdp[i],dbdp[i] , reltol);
}
// saturated case
BOOST_CHECK_CLOSE(dbdp_diff,dbdp[0], reltol);
BOOST_CHECK_CLOSE(dbdr_diff,dbdr[0], reltol);
// unsaturated case
BOOST_CHECK_CLOSE(dbdp_diff_u,dbdp[3], reltol);
BOOST_CHECK_CLOSE(dbdr_diff_u,dbdr[3], reltol);
}
}
void testrsSat(double reltol, int n, int np, const std::vector<int> &pvtTableIdx, std::vector<double> p, std::vector<std::shared_ptr<PvtInterface> > props_){
// test bublepoint pressure
std::vector<double> rs(n);
std::vector<double> drsdp(n);
double drsdp_diff;
double drsdp_diff_u;
for (int phase = 0; phase < np; ++phase) {
props_[phase] ->rsSat(n, &pvtTableIdx[0], &p[0], &rs[0], &drsdp[0]);
drsdp_diff = (rs[1]-rs[0])/(p[1]-p[0]);
drsdp_diff_u = (rs[4]-rs[3])/(p[4]-p[3]);
// saturated case
BOOST_CHECK_CLOSE(drsdp_diff,drsdp[0], reltol);
// unsaturad case
BOOST_CHECK_CLOSE(drsdp_diff_u,drsdp[3], reltol);
}
}
void testrvSat(double reltol, int n, int np, const std::vector<int> &pvtTableIdx, std::vector<double> p, std::vector<std::shared_ptr<PvtInterface> > props_){
// test rv saturated
std::vector<double> rv(n);
std::vector<double> drvdp(n);
double drvdp_diff;
double drvdp_diff_u;
for (int phase = 0; phase < np; ++phase) {
props_[phase] ->rvSat(n, &pvtTableIdx[0], &p[0], &rv[0], &drvdp[0]);
drvdp_diff = (rv[1]-rv[0])/(p[1]-p[0]);
drvdp_diff_u = (rv[4]-rv[3])/(p[4]-p[3]);
// saturated case
BOOST_CHECK_CLOSE(drvdp_diff,drvdp[0], reltol);
// unsaturad case
BOOST_CHECK_CLOSE(drvdp_diff_u,drvdp[3], reltol);
}
}
BOOST_AUTO_TEST_CASE(test_liveoil)
{
// read eclipse deck
const std::string filename = "liveoil.DATA";
cout << "Reading deck: " << filename << endl;
Opm::ParserPtr parser(new Opm::Parser());
Opm::ParseMode parseMode;
Opm::DeckConstPtr deck(parser->parseFile(filename , parseMode));
Opm::EclipseStateConstPtr eclipseState(new EclipseState(deck, parseMode));
// setup pvt interface
PhaseUsage phase_usage_ = phaseUsageFromDeck(deck);
std::vector<std::shared_ptr<PvtInterface> > props_ = getProps(deck, eclipseState, phase_usage_);
// setup a test case. We will check 6 [p,r] pairs and compare them to both the [p,z] interface and a finite difference
// approximation of the derivatives.
const int n = 6;
const int np = phase_usage_.num_phases;
std::vector<int> pvtRegionIdx(n, 0);
// the relative tolerance in percentage for acceptable difference in values
const double reltolper = 1e-9;
// the relative tolerance in percentage for acceptable difference in values for viscosity
const double reltolpermu = 1e-1;
std::vector<double> p(n);
std::vector<double> T(n, 273.15 + 20);
std::vector<double> r(n);
std::vector<PhasePresence> condition(n);
std::vector<double> z(n * np);
// Used for forward difference calculations
const double h_p = 1e4;
const double h_r = 1;
// saturated
p[0] = 1e7;
p[1] = p[0] + h_p;
p[2] = p[0];
r[0] = 200;
r[1] = 200;
r[2] = 200 + h_r;
condition[0].setFreeGas();
condition[1].setFreeGas();
condition[2].setFreeGas();
// undersaturated
p[3] = p[0];
p[4] = p[1];
p[5] = p[2];
r[3] = 50;
r[4] = 50;
r[5] = 50 +h_r;
// Corresponing z factors, used to compare with the [p,z] interface
for (int i = 0; i < n; ++i) {
z[0+i*np] = 0; z[1+i*np] = 1;
z[2+i*np] = r[i];
}
testmu(reltolpermu, n, np, pvtRegionIdx, p, T, r,z, props_, condition);
testb(reltolper,n,np,pvtRegionIdx,p,T,r,z,props_,condition);
testrsSat(reltolper,n,np,pvtRegionIdx,p,props_);
testrvSat(reltolper,n,np,pvtRegionIdx,p,props_);
}
BOOST_AUTO_TEST_CASE(test_wetgas)
{
// read eclipse deck
const std::string filename = "wetgas.DATA";
cout << "Reading deck: " << filename << endl;
Opm::ParserPtr parser(new Opm::Parser());
Opm::ParseMode parseMode;
Opm::DeckConstPtr deck(parser->parseFile(filename , parseMode));
Opm::EclipseStateConstPtr eclipseState(new EclipseState(deck, parseMode));
// setup pvt interface
PhaseUsage phase_usage_ = phaseUsageFromDeck(deck);
std::vector<std::shared_ptr<PvtInterface> > props_ = getProps(deck,eclipseState,phase_usage_);
// setup a test case. We will check 6 [p,r] pairs and compare them to both the [p,z] interface and a finite difference
// approximation of the derivatives.
const int n = 6;
const int np = phase_usage_.num_phases;
std::vector<int> pvtRegionIdx(n, 0);
// the relative tolerance in percentage for acceptable difference in values
const double reltolper = 1e-9;
// the relative tolerance in percentage for acceptable difference in values for viscosity
const double reltolpermu = 1e-1;
std::vector<double> p(n);
std::vector<double> T(n, 273.15+20);
std::vector<double> r(n);
std::vector<PhasePresence> condition(n);
std::vector<double> z(n * np);
// Used for forward difference calculations
const double h_p = 1e4;
const double h_r = 1e-7;
// saturated
p[0] = 1e7;
p[1] = p[0] + h_p;
p[2] = p[0];
r[0] = 5e-5;
r[1] = 5e-5;
r[2] = 5e-5 + h_r;
condition[0].setFreeOil();
condition[1].setFreeOil();
condition[2].setFreeOil();
// undersaturated
p[3] = p[0];
p[4] = p[1];
p[5] = p[2];
r[3] = 1e-5;
r[4] = 1e-5;
r[5] = 1e-5 +h_r;
// Corresponing z factors, used to compare with the [p,z] interface
for (int i = 0; i < n; ++i) {
z[0+i*np] = 0; z[1+i*np] = r[i];
z[2+i*np] = 1;
}
testmu(reltolpermu, n, np, pvtRegionIdx, p,T, r,z, props_, condition);
testb(reltolper,n,np,pvtRegionIdx,p,T,r,z,props_,condition);
testrsSat(reltolper,n,np,pvtRegionIdx,p,props_);
testrvSat(reltolper,n,np,pvtRegionIdx,p,props_);
}

View File

@@ -39,7 +39,7 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/core/props/pvt/PvtLiveOil.hpp>
#include <opm/material/fluidsystems/blackoilpvt/LiveOilPvt.hpp>
using namespace Opm;
@@ -57,19 +57,9 @@ using namespace Opm;
further semantic meaning.
*/
void check_vectors( const std::vector<double>& v1 , const std::vector<double>& v2) {
double tol = 1e-5;
for (decltype(v1.size()) i = 0; i < v1.size(); i++) {
BOOST_CHECK_CLOSE( v1[i] , v2[i] , tol );
}
}
void verify_norne_oil_pvt_region2(const TableManager& tableManager) {
auto pvtoTables = tableManager.getPvtoTables();
PvtLiveOil oilPvt(pvtoTables);
void verify_norne_oil_pvt_region1(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclState) {
Opm::LiveOilPvt<double> oilPvt;
oilPvt.initFromDeck(deck, eclState);
std::vector<double> rs = {33, 33,
43, 43,
@@ -113,33 +103,37 @@ void verify_norne_oil_pvt_region2(const TableManager& tableManager) {
{
std::vector<int> tableIndex(P.size() , 0);
std::vector<double> mu(P.size());
std::vector<double> dmudp(P.size());
std::vector<double> dmudr(P.size());
std::vector<double> b(P.size());
std::vector<double> dbdp(P.size());
std::vector<double> dbdr(P.size());
// convert the pressures to SI units (bar to Pascal)
for (auto& value : P)
value *= Metric::Pressure;
// convert the gas dissolution factors to SI units
for (auto& value : rs)
value *= Metric::GasDissolutionFactor;
oilPvt.mu( P.size() , tableIndex.data() , P.data() , NULL , rs.data() , mu.data() , dmudp.data() , dmudr.data());
oilPvt.b( P.size() , tableIndex.data() , P.data() , NULL , rs.data() , b.data() , dbdp.data() , dbdr.data());
for (unsigned i = 0; i < P.size(); ++i) {
double mu;
double b;
double RsSat = oilPvt.saturatedGasDissolutionFactor(/*tableIndex=*/0, /*T=*/273.15, P[i]);
if (rs[i] >= RsSat) {
mu = oilPvt.saturatedViscosity(/*tableIndex=*/0, /*T=*/273.15, P[i]);
b = oilPvt.saturatedInverseFormationVolumeFactor(/*tableIndex=*/0, /*T=*/273.15, P[i]);
}
else {
mu = oilPvt.viscosity(/*tableIndex=*/0, /*T=*/273.15, P[i], rs[i]);
b = oilPvt.inverseFormationVolumeFactor(/*tableIndex=*/0, /*T=*/273.15, P[i], rs[i]);
}
check_vectors( mu , mu_expected );
check_vectors( b , b_expected );
BOOST_CHECK_CLOSE( mu , mu_expected[i], 1e-5 );
BOOST_CHECK_CLOSE( b , b_expected[i], 1e-5 );
}
}
}
void verify_norne_oil_pvt_region1(const TableManager& tableManager) {
auto pvtoTables = tableManager.getPvtoTables();
PvtLiveOil oilPvt(pvtoTables);
void verify_norne_oil_pvt_region2(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclState) {
Opm::LiveOilPvt<double> oilPvt;
oilPvt.initFromDeck(deck, eclState);
std::vector<double> rs = {21 , 21,
30 , 30,
@@ -254,50 +248,41 @@ void verify_norne_oil_pvt_region1(const TableManager& tableManager) {
0.57289091037, 0.56019050084,
0.55474601877, 0.55809201119, 0.54526832277};
{
std::vector<int> tableIndex(P.size() , 1);
// convert the pressures to SI units (bar to Pascal)
for (auto& value : P)
value *= Metric::Pressure;
std::vector<double> mu(P.size());
std::vector<double> dmudp(P.size());
std::vector<double> dmudr(P.size());
// convert the gas dissolution factors to SI units
for (auto& value : rs)
value *= Metric::GasDissolutionFactor;
std::vector<double> b(P.size());
std::vector<double> dbdp(P.size());
std::vector<double> dbdr(P.size());
for (unsigned i = 0; i < P.size(); ++i) {
double mu;
double b;
double RsSat = oilPvt.saturatedGasDissolutionFactor(/*tableIndex=*/1, /*T=*/273.15, P[i]);
if (rs[i] >= RsSat) {
mu = oilPvt.saturatedViscosity(/*tableIndex=*/1, /*T=*/273.15, P[i]);
b = oilPvt.saturatedInverseFormationVolumeFactor(/*tableIndex=*/1, /*T=*/273.15, P[i]);
}
else {
mu = oilPvt.viscosity(/*tableIndex=*/1, /*T=*/273.15, P[i], rs[i]);
b = oilPvt.inverseFormationVolumeFactor(/*tableIndex=*/1, /*T=*/273.15, P[i], rs[i]);
}
for (auto& value : P)
value *= Metric::Pressure;
for (auto& value : rs)
value *= Metric::GasDissolutionFactor;
oilPvt.mu( P.size() , tableIndex.data() , P.data() , NULL , rs.data() , mu.data() , dmudp.data() , dmudr.data());
oilPvt.b( P.size() , tableIndex.data() , P.data() , NULL , rs.data() , b.data() , dbdp.data() , dbdr.data());
check_vectors( mu , mu_expected );
check_vectors( b , b_expected );
BOOST_CHECK_CLOSE( mu , mu_expected[i], 1e-5 );
BOOST_CHECK_CLOSE( b , b_expected[i], 1e-5 );
}
}
TableManager loadTables( const std::string& deck_file) {
BOOST_AUTO_TEST_CASE( Test_Norne_PVT) {
Opm::ParseMode parseMode({{ ParseMode::PARSE_RANDOM_SLASH , InputError::IGNORE }});
Opm::ParserPtr parser(new Parser());
std::shared_ptr<const Deck> deck;
deck = parser->parseFile("norne_pvt.data", parseMode);
deck = parser->parseFile(deck_file, parseMode);
return TableManager(*deck);
}
BOOST_AUTO_TEST_CASE( Test_Norne_PVT) {
TableManager tableManager = loadTables( "norne_pvt.data" );
verify_norne_oil_pvt_region1( tableManager );
verify_norne_oil_pvt_region2( tableManager );
Opm::EclipseStateConstPtr eclState(new EclipseState(deck, parseMode));
verify_norne_oil_pvt_region1( deck, eclState );
verify_norne_oil_pvt_region2( deck, eclState );
}