Tables: Add Structurally Correct Water PVT Output

This commit adds a new public member function

    Tables::addPVTTables(const EclipseState&)

that calls into a new private member function

    Tables::addWaterPVTTables(const EclipseState&)

to create structurally correct TAB vector entries from the PVTW
input table data when water is an active phase in a simulation run.
Specifically, the result array has the columns

    [ Pw, 1/Bw, Cw, 1/(Bw * mu_w), Cw - Cv ]

in which 'Cw' denotes the water compressibility and 'Cv' denotes the
water viscosibility.  Column 4 and 5 follow ECLIPSE 100 conventions.
Number of table rows equal to number of PVT regions.  This result
array differs from the existing Tables::addPVTW() member function in
the treatment of viscosity and viscosibility data.  We have verified
the results with ECLIPSE 100.

At present the function is not called by Flow's INIT file writer.

Add a unit test to exercise the new member function.
This commit is contained in:
Bård Skaflestad 2019-03-28 15:46:41 +01:00
parent c279184229
commit 466341fa0f
3 changed files with 245 additions and 0 deletions

View File

@ -1,4 +1,6 @@
/*
Copyright 2019 Equinor.
Copyright 2017 Statoil ASA.
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
@ -42,6 +44,15 @@ namespace Opm {
void addPVTW(const PvtwTable& pvtwTable);
void addDensity(const DensityTable& density);
/// Add normalised PVT function tables to INIT file's TAB vector.
///
/// \param[in] es Valid \c EclipseState object with accurate RUNSPEC
/// information on active phases and table dimensions ("TABDIMS").
///
/// \param[in] logihead Flag specifications identifying which tables
/// to output.
void addPVTTables(const EclipseState& es);
/// Add normalised saturation function tables to INIT file's TAB
/// vector.
///
@ -101,6 +112,14 @@ namespace Opm {
const bool gas,
const bool oil,
const bool wat);
/// Add water PVT tables (keyword PVTW) to the tabular data (TABDIMS
/// and TAB vectors).
///
/// \param[in] es Valid \c EclipseState object with accurate table
/// dimensions ("TABDIMS" keyword) and an initialised \c
/// TableManager sub-object.
void addWaterPVTTables(const EclipseState& es);
};
/// Emit normalised tabular information (TABDIMS and TAB vectors) to

View File

@ -27,6 +27,7 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/FlatTable.hpp> // PVTW
#include <opm/parser/eclipse/EclipseState/Tables/SgfnTable.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/SgofTable.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/Sof2Table.hpp>
@ -1078,6 +1079,99 @@ namespace { namespace SatFunc {
} // Water
}} // Anonymous::SatFunc
/// Functions to facilitate generating TAB vector entries for tabulated
/// PVT functions.
namespace { namespace PVTFunc {
/// Functions to create linearised, padded, and normalised water PVT
/// output tables from input water PVT function keyword.
namespace Water {
/// Create linearised 'TAB' vector entries of normalised water PVT
/// tables for all PVT function regions from PVTW keyword data.
///
/// \param[in] units Active unit system. Needed to convert SI
/// convention pressure values (Pascal), formation volume factors
/// (Rm3/Sm3), compressibility values (1/Pascal), viscosity
/// values (Pa*s), and viscosibility values (1/Pascal) to
/// declared conventions of the run specification.
///
/// \param[in] pvtw Collection of PVTW tables for all PVT regions.
///
/// \return Linearised 'TAB' vector values for output water PVT
/// tables. A unit-converted, transformed version of the input
/// table \p pvtw. No derivative information added.
std::vector<double>
fromPVTW(const Opm::UnitSystem& units,
const Opm::PvtwTable& pvtw)
{
// Recall: PvtwTable is essentially vector<PVTWRecord> in which
//
// struct PVTWRecord {
// double reference_pressure;
// double volume_factor;
// double compressibility;
// double viscosity;
// double viscosibility;
// };
using M = ::Opm::UnitSystem::measure;
// Columns [ Pw, 1/Bw, Cw, 1/(Bw*mu_w), Cw - Cv ]
//
// Single row per table. No derivatives. Can't reuse
// createPropfuncTable here, so implement the return value
// directly in terms of LinearisedOutputTable.
const auto numTab = pvtw.size();
const auto numPrim = std::size_t{1};
const auto numRows = std::size_t{1};
const auto numCols = std::size_t{5};
auto lintable = ::Opm::LinearisedOutputTable {
numTab, numPrim, numRows, numCols
};
// Note unit hack for compressibility and viscosibility. The
// unit of measurement for these quantities is 1/pressure, but
// the UnitSystem does not define this unit. Work around the
// missing conversion by using *to_si()* rather than *from_si()*
// for those quantities.
const auto uPress = M::pressure;
const auto uRecipFVF = M::water_inverse_formation_volume_factor;
const auto uVisc = M::viscosity;
const auto primID = std::size_t{0};
for (auto tabID = 0*numTab; tabID < numTab; ++tabID) {
const auto& t = pvtw[tabID];
auto iPw = lintable.column(tabID, primID, 0);
auto irecipFvf = lintable.column(tabID, primID, 1);
auto iCw = lintable.column(tabID, primID, 2);
auto irecipFvfVisc = lintable.column(tabID, primID, 3);
auto idiffCwCv = lintable.column(tabID, primID, 4);
*iPw = units.from_si(uPress , t.reference_pressure);
*irecipFvf = units.from_si(uRecipFVF, 1.0 / t.volume_factor);
// Compressibility unit hack here (*to_si()*)
*iCw = units.to_si(uPress, t.compressibility);
*irecipFvfVisc =
units.from_si(uRecipFVF, 1.0 / t.volume_factor)
/ units.from_si(uVisc, t.viscosity);
// Viscosibility unit hack here (*to_si()*)
*idiffCwCv =
units.to_si(uPress, t.compressibility - t.viscosibility);
}
return lintable.getDataDestructively();
}
} // Water
}} // Anonymous::PVTFunc
namespace Opm {
Tables::Tables(const UnitSystem& units0)
@ -1274,6 +1368,13 @@ namespace Opm {
}
}
void Tables::addPVTTables(const EclipseState& es)
{
const auto& phases = es.runspec().phases();
if (phases.active(Phase::WATER)) { this->addWaterPVTTables(es); }
}
void Tables::addSatFunc(const EclipseState& es)
{
const auto& tabMgr = es.getTableManager();
@ -1441,6 +1542,22 @@ namespace Opm {
}
}
void Tables::addWaterPVTTables(const EclipseState& es)
{
const auto& tabMgr = es.getTableManager();
const auto& pvtw = tabMgr.getPvtwTable();
if (pvtw.empty()) {
return;
}
const auto data = PVTFunc::Water::fromPVTW(this->units, pvtw);
this->addData(TABDIMS_IBPVTW_OFFSET_ITEM, data);
this->m_tabdims[TABDIMS_NTPVTW_ITEM] = pvtw.size();
}
void fwrite(const Tables& tables,
ERT::FortIO& fortio)
{

View File

@ -1,4 +1,5 @@
/*
Copyright 2019 Equinor.
Copyright 2016 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
@ -1608,3 +1609,111 @@ BOOST_AUTO_TEST_CASE (Serialize_Family_Two)
}
BOOST_AUTO_TEST_SUITE_END ()
// #####################################################################
BOOST_AUTO_TEST_SUITE (PVTTables)
namespace {
Opm::EclipseState parse(const std::string& rspec,
const std::string& props)
{
return {
Opm::Parser{}.parseString(rspec + R"(GRID
INIT
DXV
10*200 /
DYV
10*200 /
DZV
10*25 /
TOPS
100*2500 /
PORO
1000*0.3 /
PERMX
1000*100 /
COPY
'PERMX' 'PERMY' /
'PERMX' 'PERMZ' /
/
MULTIPLY
'PERMZ' 0.1 /
/
PROPS
)" + props + R"(
END
)") };
}
}
BOOST_AUTO_TEST_SUITE (Water)
BOOST_AUTO_TEST_CASE (PVTW)
{
const auto rspec = std::string { R"(RUNSPEC
DIMENS
10 10 10 /
TITLE
Test PVTW Output
WATER
METRIC
TABDIMS
-- NTSFUN NTPVT NSSFUN NPPVT NTFIP NRPVT
1* 2 1* 4 1* 3
/
)" };
const auto props = std::string { R"(
PVTW
-- Pref Bw(Pref) Cw Vw(Pref) Cv
200 1.23 0.321e-4 0.25 0.654e-3 /
250 0.987 1.234e-5 0.314 0.9876e-5 /
)" };
const auto es = parse(rspec, props);
auto tables = ::Opm::Tables(es.getUnits());
tables.addPVTTables(es);
const auto& tabdims = tables.tabdims();
const auto& tab = tables.tab();
const auto ibpvtw = tabdims[ TABDIMS_IBPVTW_OFFSET_ITEM ] - 1;
const auto ntpvtw = tabdims[ TABDIMS_NTPVTW_ITEM ];
const auto ncol = 5;
BOOST_CHECK_EQUAL(ntpvtw, 2);
const auto pvtw = std::vector<double> {
&tab[ ibpvtw ] + 0,
&tab[ ibpvtw ] + ntpvtw*ncol
};
const auto expect_pvtw = makeTable(5, {
// Pw 1/Bw Cw 1/(Bw*mu_w) Cw - Cv
2.000000000000000e+02, 8.130081300813008e-01, 3.210000000000000e-05, 3.252032520325203e+00, -6.219000000000000e-04,
2.500000000000000e+02, 1.013171225937183e+00, 1.234000000000000e-05, 3.226659955213960e+00, 2.464000000000000e-06,
});
check_is_close(pvtw, expect_pvtw);
}
BOOST_AUTO_TEST_SUITE_END ()
// =====================================================================
BOOST_AUTO_TEST_SUITE_END ()