From 9a955e29d0b96d01a5d8bc245b2b7e2433a884c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Sun, 15 Oct 2017 20:55:08 -0500 Subject: [PATCH 1/7] Table Output: Switch to One-Based Offset Indices This is needed for compatibility with Fortran and external software that reads the .INIT file. --- opm/output/eclipse/Tables.cpp | 2 +- tests/test_Tables.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/opm/output/eclipse/Tables.cpp b/opm/output/eclipse/Tables.cpp index d4ea284..5068b76 100644 --- a/opm/output/eclipse/Tables.cpp +++ b/opm/output/eclipse/Tables.cpp @@ -35,7 +35,7 @@ namespace Opm { void Tables::addData( size_t offset_index, const std::vector& new_data) { - this->tabdims[ offset_index ] = this->data.size(); + this->tabdims[ offset_index ] = this->data.size() + 1; this->data.insert( this->data.end() , new_data.begin() , new_data.end()); this->tabdims[ TABDIMS_TAB_SIZE_ITEM ] = this->data.size(); } diff --git a/tests/test_Tables.cpp b/tests/test_Tables.cpp index cd6bad0..9058812 100644 --- a/tests/test_Tables.cpp +++ b/tests/test_Tables.cpp @@ -90,8 +90,8 @@ BOOST_AUTO_TEST_CASE(Test_PVTX) { BOOST_CHECK_EQUAL( ecl_kw_get_size( tab ) , ecl_kw_iget_int( tabdims , TABDIMS_TAB_SIZE_ITEM )); /* PVTO */ { - int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTO_OFFSET_ITEM ); - int rs_offset = ecl_kw_iget_int( tabdims , TABDIMS_JBPVTO_OFFSET_ITEM ); + int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTO_OFFSET_ITEM ) - 1; + int rs_offset = ecl_kw_iget_int( tabdims , TABDIMS_JBPVTO_OFFSET_ITEM ) - 1; int column_stride = ecl_kw_iget_int( tabdims , TABDIMS_NRPVTO_ITEM ) * ecl_kw_iget_int( tabdims , TABDIMS_NPPVTO_ITEM ) * ecl_kw_iget_int( tabdims , TABDIMS_NTPVTO_ITEM ); BOOST_CHECK_EQUAL( 2, ecl_kw_iget_int( tabdims , TABDIMS_NRPVTO_ITEM ) ); @@ -113,8 +113,8 @@ BOOST_AUTO_TEST_CASE(Test_PVTX) { /* PVTG */ { - int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTG_OFFSET_ITEM ); - int pg_offset = ecl_kw_iget_int( tabdims , TABDIMS_JBPVTG_OFFSET_ITEM ); + int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTG_OFFSET_ITEM ) - 1; + int pg_offset = ecl_kw_iget_int( tabdims , TABDIMS_JBPVTG_OFFSET_ITEM ) - 1; int column_stride = ecl_kw_iget_int( tabdims , TABDIMS_NRPVTG_ITEM ) * ecl_kw_iget_int( tabdims , TABDIMS_NPPVTG_ITEM ) * ecl_kw_iget_int( tabdims , TABDIMS_NTPVTG_ITEM ); BOOST_CHECK_EQUAL( 2, ecl_kw_iget_int( tabdims , TABDIMS_NRPVTG_ITEM ) ); @@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(Test_PVTX) { /* PVTW */ { - int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTW_OFFSET_ITEM ); + int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTW_OFFSET_ITEM ) - 1; int column_stride = ecl_kw_iget_int( tabdims , TABDIMS_NTPVTW_ITEM ); BOOST_CHECK( ecl_kw_get_size( tab ) >= (offset + column_stride * 5 )); @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(Test_PVTX) { // Density { - int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBDENS_OFFSET_ITEM ); + int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBDENS_OFFSET_ITEM ) - 1; int column_stride = ecl_kw_iget_int( tabdims , TABDIMS_NTDENS_ITEM ); BOOST_CHECK( ecl_kw_get_size( tab ) >= (offset + column_stride * 3 )); BOOST_CHECK_CLOSE( 859.5 , ecl_kw_iget_double( tab , offset ) , 1e-6 ); From c3cb94823b98190ce13e1428b0ef089cc13c42fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Wed, 15 Nov 2017 18:04:55 +0100 Subject: [PATCH 2/7] Table Output: Don't Store ECL Keywords Internally This commit switches the internal implementation of the 'tab' and 'tabdims' vectors from being a mix of ECL keyword structures and std::vector<>s to being purely std::vector<>s. We remove the fwrite() member function and rather reimplement the feature in terms of new query member functions const std::vector& tabdims() const const std::vector& tab() const that return read-only references to internal data members. --- opm/output/eclipse/EclipseIO.cpp | 2 +- opm/output/eclipse/Tables.cpp | 108 +++++++++++++++++++------------ opm/output/eclipse/Tables.hpp | 40 +++++++++--- tests/test_Tables.cpp | 2 +- 4 files changed, 100 insertions(+), 52 deletions(-) diff --git a/opm/output/eclipse/EclipseIO.cpp b/opm/output/eclipse/EclipseIO.cpp index f176899..a6e8579 100644 --- a/opm/output/eclipse/EclipseIO.cpp +++ b/opm/output/eclipse/EclipseIO.cpp @@ -313,7 +313,7 @@ void EclipseIO::Impl::writeINITFile( const data::Solution& simProps, std::mapes.getTableManager().getPvtgTables() ); tables.addPVTW( this->es.getTableManager().getPvtwTable() ); tables.addDensity( this->es.getTableManager().getDensityTable( ) ); - tables.fwrite( fortio ); + fwrite(tables, fortio); } // Write all integer field properties from the input deck. diff --git a/opm/output/eclipse/Tables.cpp b/opm/output/eclipse/Tables.cpp index 5068b76..75c0da7 100644 --- a/opm/output/eclipse/Tables.cpp +++ b/opm/output/eclipse/Tables.cpp @@ -25,19 +25,32 @@ #include +#include +#include +#include +#include +#include + namespace Opm { - Tables::Tables( const UnitSystem& units_ ) : - units( units_ ), - tabdims( "TABDIMS" , TABDIMS_SIZE ) + Tables::Tables(const UnitSystem& units) + : units_ (units) + , tabdims_(TABDIMS_SIZE, 0) { + // Initialize subset of base pointers and dimensions to 1 to honour + // requirements of TABDIMS protocol. The magic constant 59 is + // derived from the file-formats documentation. + std::fill_n(std::begin(this->tabdims_), 59, 1); } + void Tables::addData(const std::size_t offset_index, + const std::vector& new_data) + { + this->tabdims_[ offset_index ] = this->data_.size() + 1; + + this->data_.insert(this->data_.end(), new_data.begin(), new_data.end()); - void Tables::addData( size_t offset_index, const std::vector& new_data) { - this->tabdims[ offset_index ] = this->data.size() + 1; - this->data.insert( this->data.end() , new_data.begin() , new_data.end()); - this->tabdims[ TABDIMS_TAB_SIZE_ITEM ] = this->data.size(); + this->tabdims_[ TABDIMS_TAB_SIZE_ITEM ] = this->data_.size(); } @@ -72,9 +85,9 @@ namespace Opm { { const double default_value = 2e20; PvtxDims dims = tableDims( pvtoTables ); - this->tabdims[ TABDIMS_NTPVTO_ITEM ] = dims.num_tables; - this->tabdims[ TABDIMS_NRPVTO_ITEM ] = dims.outer_size; - this->tabdims[ TABDIMS_NPPVTO_ITEM ] = dims.inner_size; + this->tabdims_[ TABDIMS_NTPVTO_ITEM ] = dims.num_tables; + this->tabdims_[ TABDIMS_NRPVTO_ITEM ] = dims.outer_size; + this->tabdims_[ TABDIMS_NPPVTO_ITEM ] = dims.inner_size; { std::vector pvtoData( dims.data_size , default_value ); @@ -94,9 +107,9 @@ namespace Opm { for (size_t row = 0; row < p.size(); row++) { size_t data_index = row + composition_stride * composition_index + table_stride * table_index; - pvtoData[ data_index ] = units.from_si( UnitSystem::measure::pressure, p[row]); + pvtoData[ data_index ] = this->units_.from_si( UnitSystem::measure::pressure, p[row]); pvtoData[ data_index + column_stride ] = 1.0 / bo[row]; - pvtoData[ data_index + 2*column_stride] = units.from_si( UnitSystem::measure::viscosity , mu[row]) / bo[row]; + pvtoData[ data_index + 2*column_stride] = this->units_.from_si( UnitSystem::measure::viscosity , mu[row]) / bo[row]; } composition_index++; } @@ -115,19 +128,17 @@ namespace Opm { table_index++; } - addData( TABDIMS_IBPVTO_OFFSET_ITEM , pvtoData ); - addData( TABDIMS_JBPVTO_OFFSET_ITEM , rs_values ); + this->addData( TABDIMS_IBPVTO_OFFSET_ITEM , pvtoData ); + this->addData( TABDIMS_JBPVTO_OFFSET_ITEM , rs_values ); } } - - void Tables::addPVTG( const std::vector& pvtgTables) { const double default_value = -2e20; PvtxDims dims = tableDims( pvtgTables ); - this->tabdims[ TABDIMS_NTPVTG_ITEM ] = dims.num_tables; - this->tabdims[ TABDIMS_NRPVTG_ITEM ] = dims.outer_size; - this->tabdims[ TABDIMS_NPPVTG_ITEM ] = dims.inner_size; + this->tabdims_[ TABDIMS_NTPVTG_ITEM ] = dims.num_tables; + this->tabdims_[ TABDIMS_NRPVTG_ITEM ] = dims.outer_size; + this->tabdims_[ TABDIMS_NPPVTG_ITEM ] = dims.inner_size; { std::vector pvtgData( dims.data_size , default_value ); @@ -147,10 +158,11 @@ namespace Opm { for (size_t row = 0; row < col0.size(); row++) { size_t data_index = row + composition_stride * composition_index + table_stride * table_index; - pvtgData[ data_index ] = units.from_si( UnitSystem::measure::gas_oil_ratio, col0[row]); - pvtgData[ data_index + column_stride ] = units.from_si( UnitSystem::measure::gas_oil_ratio, col1[row]); - pvtgData[ data_index + 2*column_stride] = units.from_si( UnitSystem::measure::viscosity , col2[row]); + pvtgData[ data_index ] = this->units_.from_si( UnitSystem::measure::gas_oil_ratio, col0[row]); + pvtgData[ data_index + column_stride ] = this->units_.from_si( UnitSystem::measure::gas_oil_ratio, col1[row]); + pvtgData[ data_index + 2*column_stride] = this->units_.from_si( UnitSystem::measure::viscosity , col2[row]); } + composition_index++; } @@ -158,13 +170,15 @@ namespace Opm { const auto& sat_table = table.getSaturatedTable(); const auto& p = sat_table.getColumn("PG"); for (size_t index = 0; index < p.size(); index++) - p_values[index + table_index * dims.outer_size ] = units.from_si( UnitSystem::measure::pressure , p[index]); + p_values[index + table_index * dims.outer_size ] = + this->units_.from_si( UnitSystem::measure::pressure , p[index]); } + table_index++; } - addData( TABDIMS_IBPVTG_OFFSET_ITEM , pvtgData ); - addData( TABDIMS_JBPVTG_OFFSET_ITEM , p_values ); + this->addData( TABDIMS_IBPVTG_OFFSET_ITEM , pvtgData ); + this->addData( TABDIMS_JBPVTG_OFFSET_ITEM , p_values ); } } @@ -175,13 +189,13 @@ namespace Opm { const size_t num_columns = pvtwTable[0].size; std::vector pvtwData( pvtwTable.size() * num_columns , default_value); - this->tabdims[ TABDIMS_NTPVTW_ITEM ] = pvtwTable.size(); + this->tabdims_[ TABDIMS_NTPVTW_ITEM ] = pvtwTable.size(); for (size_t table_num = 0; table_num < pvtwTable.size(); table_num++) { const auto& record = pvtwTable[table_num]; - pvtwData[ table_num * num_columns ] = units.from_si( UnitSystem::measure::pressure , record.reference_pressure); + pvtwData[ table_num * num_columns ] = this->units_.from_si( UnitSystem::measure::pressure , record.reference_pressure); pvtwData[ table_num * num_columns + 1] = 1.0 / record.volume_factor; - pvtwData[ table_num * num_columns + 2] = units.to_si( UnitSystem::measure::pressure, record.compressibility); - pvtwData[ table_num * num_columns + 3] = record.volume_factor / units.from_si( UnitSystem::measure::viscosity , record.viscosity); + pvtwData[ table_num * num_columns + 2] = this->units_.to_si( UnitSystem::measure::pressure, record.compressibility); + pvtwData[ table_num * num_columns + 3] = record.volume_factor / this->units_.from_si( UnitSystem::measure::viscosity , record.viscosity); // The last column should contain information about @@ -191,7 +205,7 @@ namespace Opm { // pvtwData[ table_num * num_columns + 4] = record.viscosibility; } - addData( TABDIMS_IBPVTW_OFFSET_ITEM , pvtwData ); + this->addData( TABDIMS_IBPVTW_OFFSET_ITEM , pvtwData ); } } @@ -202,25 +216,39 @@ namespace Opm { const size_t num_columns = density[0].size; std::vector densityData( density.size() * num_columns , default_value); - this->tabdims[ TABDIMS_NTDENS_ITEM ] = density.size(); + this->tabdims_[ TABDIMS_NTDENS_ITEM ] = density.size(); for (size_t table_num = 0; table_num < density.size(); table_num++) { const auto& record = density[table_num]; - densityData[ table_num * num_columns ] = units.from_si( UnitSystem::measure::density , record.oil); - densityData[ table_num * num_columns + 1] = units.from_si( UnitSystem::measure::density , record.water); - densityData[ table_num * num_columns + 2] = units.from_si( UnitSystem::measure::density , record.gas); + densityData[ table_num * num_columns ] = this->units_.from_si( UnitSystem::measure::density , record.oil); + densityData[ table_num * num_columns + 1] = this->units_.from_si( UnitSystem::measure::density , record.water); + densityData[ table_num * num_columns + 2] = this->units_.from_si( UnitSystem::measure::density , record.gas); } - addData( TABDIMS_IBDENS_OFFSET_ITEM , densityData ); + this->addData( TABDIMS_IBDENS_OFFSET_ITEM , densityData ); } } - void Tables::fwrite( ERT::FortIO& fortio ) const + const std::vector& Tables::tabdims() const + { + return this->tabdims_; + } + + const std::vector& Tables::tab() const + { + return this->data_; + } + + void fwrite(const Tables& tables, + ERT::FortIO& fortio) { - tabdims.fwrite( fortio ); { - ERT::EclKW tab( "TAB" , this->data ); - tab.fwrite( fortio ); + ERT::EclKW tabdims("TABDIMS", tables.tabdims()); + tabdims.fwrite(fortio); } - } + { + ERT::EclKW tab("TAB", tables.tab()); + tab.fwrite(fortio); + } + } } diff --git a/opm/output/eclipse/Tables.hpp b/opm/output/eclipse/Tables.hpp index d2a3aa1..c65b2b2 100644 --- a/opm/output/eclipse/Tables.hpp +++ b/opm/output/eclipse/Tables.hpp @@ -35,20 +35,40 @@ namespace Opm { class Tables { public: - explicit Tables( const UnitSystem& units_); - void fwrite( ERT::FortIO& fortio ) const; - void addPVTO( const std::vector& pvtoTables); - void addPVTG( const std::vector& pvtgTables); - void addPVTW( const PvtwTable& pvtwTable); - void addDensity( const DensityTable& density); + explicit Tables( const UnitSystem& units); + + void addPVTO(const std::vector& pvtoTables); + void addPVTG(const std::vector& pvtgTables); + void addPVTW(const PvtwTable& pvtwTable); + void addDensity(const DensityTable& density); + + /// Acquire read-only reference to internal TABDIMS vector. + const std::vector& tabdims() const; + + /// Acquire read-only reference to internal TAB vector. + const std::vector& tab() const; private: - void addData( size_t offset_index , const std::vector& new_data); + const UnitSystem& units_; + std::vector tabdims_; + std::vector data_; - const UnitSystem& units; - ERT::EclKW tabdims; - std::vector data; + void addData(const std::size_t offset_index, + const std::vector& new_data); }; + + /// Emit normalised tabular information (TABDIMS and TAB vectors) to + /// ECL-like result set file (typically INIT file). + /// + /// \param[in,out] fortio ECL-like result set file. Typically + /// corresponds to a preopened stream attached to the INIT file. + /// + /// \param[in] tables Collection of normalised tables. Its \code + /// tabdims() \endcode and \code tab() \endcode vectors will be + /// emitted to \p fortio as ECL keywords "TABDIMS" and "TAB", + /// respectively. + void fwrite(const Tables& tables, + ERT::FortIO& fortio); } diff --git a/tests/test_Tables.cpp b/tests/test_Tables.cpp index 9058812..10361fc 100644 --- a/tests/test_Tables.cpp +++ b/tests/test_Tables.cpp @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(Test_PVTX) { tables.addDensity( cfg.es.getTableManager().getDensityTable( ) ); { ERT::FortIO f("TEST.INIT" , std::fstream::out); - tables.fwrite( f ); + fwrite(tables, f); } From 81d64c7182b020d8bf42be24bfea755e3f854011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Fri, 3 Nov 2017 00:32:05 -0500 Subject: [PATCH 3/7] Table Output: Add Facility to Simplify Indexing Details This commit introduces a new helper class, LinearisedOutputTable, that is oriented towards managing tabular data such as the PVT or saturation functions in an ECL result set (typically, .INIT file). The class knows about row padding and the column oriented nature of Fortran-like tables. While here, and in anticipation of adding output of tabulated saturation functions, also provide a mechanism for calculating slopes of piecewise linear interpolants. The ECL format stipulates that function derivatives be output along with the actual table data for most functions. --- .gitignore | 23 + CMakeLists_files.cmake | 3 + opm/output/eclipse/LinearisedOutputTable.cpp | 101 +++ opm/output/eclipse/LinearisedOutputTable.hpp | 168 +++++ tests/test_LinearisedOutputTable.cpp | 631 +++++++++++++++++++ 5 files changed, 926 insertions(+) create mode 100644 .gitignore create mode 100644 opm/output/eclipse/LinearisedOutputTable.cpp create mode 100644 opm/output/eclipse/LinearisedOutputTable.hpp create mode 100644 tests/test_LinearisedOutputTable.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87ddd66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Editor autosave files +*~ +*.swp + +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so +*.dylib + +# Compiled Static libraries +*.lai +*.la +*.a + +# Mac OS X debug info +*.dSYM + +# emacs directory setting: +.dir-locals.el diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 335c98d..10bf95b 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -8,6 +8,7 @@ list( APPEND MAIN_SOURCE_FILES opm/test_util/EclFilesComparator.cpp opm/output/eclipse/EclipseGridInspector.cpp opm/output/eclipse/EclipseIO.cpp + opm/output/eclipse/LinearisedOutputTable.cpp opm/output/eclipse/RestartIO.cpp opm/output/eclipse/Summary.cpp opm/output/eclipse/Tables.cpp @@ -25,6 +26,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/output/eclipse/EclipseGridInspector.hpp opm/output/eclipse/EclipseIOUtil.hpp opm/output/eclipse/EclipseIO.hpp + opm/output/eclipse/LinearisedOutputTable.hpp opm/output/eclipse/RestartIO.hpp opm/output/eclipse/RestartValue.hpp opm/output/eclipse/Summary.hpp @@ -52,6 +54,7 @@ list (APPEND TEST_SOURCE_FILES tests/test_compareSummary.cpp tests/test_EclFilesComparator.cpp tests/test_EclipseIO.cpp + tests/test_LinearisedOutputTable.cpp tests/test_Restart.cpp tests/test_RFT.cpp tests/test_Summary.cpp diff --git a/opm/output/eclipse/LinearisedOutputTable.cpp b/opm/output/eclipse/LinearisedOutputTable.cpp new file mode 100644 index 0000000..0b9e924 --- /dev/null +++ b/opm/output/eclipse/LinearisedOutputTable.cpp @@ -0,0 +1,101 @@ +#include + +#include +#include +#include +#include + +Opm::LinearisedOutputTable:: +LinearisedOutputTable(const std::size_t numTables, + const std::size_t numPrimary, + const std::size_t numRows, + const std::size_t numCols) + : data_ (numTables * numPrimary * numRows * numCols, 1.0e20) + , numTables_ (numTables) + , numPrimary_(numPrimary) + , numRows_ (numRows) +{} + +std::vector::iterator +Opm::LinearisedOutputTable::column(const std::size_t tableID, + const std::size_t primID, + const std::size_t colID) +{ + // Table format: numRows_ * numPrimary_ * numTables_ values for first + // column (ID == 0), followed by same number of entries for second + // column &c. + const auto offset = + 0 + this->numRows_*(primID + this->numPrimary_*(tableID + this->numTables_*colID)); + + assert (offset + this->numRows_ <= this->data_.size()); + + return this->data_.begin() + offset; +} + +const std::vector& +Opm::LinearisedOutputTable::getData() const +{ + return this->data_; +} + +std::vector +Opm::LinearisedOutputTable::getDataDestructively() +{ + return std::move(this->data_); +} + +// --------------------------------------------------------------------- + +void +Opm::DifferentiateOutputTable::calcSlopes(const std::size_t nDep, + const Descriptor& desc, + LinearisedOutputTable& table) +{ + if ((nDep == 0) || (desc.numActRows < 2)) { + // No dependent columns or too few rows to compute any derivatives. + // Likely to be user error. Can't do anything here. + return; + } + + auto x = table.column(desc.tableID, desc.primID, 0); + + using colIT = decltype(x); + + auto y = std::vector{}; y .reserve(nDep); + auto dy = std::vector{}; dy.reserve(nDep); + auto y0 = std::vector(nDep); + auto y1 = y0; + for (auto j = 0*nDep; j < nDep; ++j) { + y .push_back(table.column(desc.tableID, desc.primID, j + 1 + 0*nDep)); + dy.push_back(table.column(desc.tableID, desc.primID, j + 1 + 1*nDep)); + + y1[j] = *y.back(); ++y.back(); + } + + using std::swap; + + auto x1 = *x; ++x; auto x0 = 0 * x1; + + // Recall: Number of slope intervals one less than number of active + // table rows. + for (auto n = desc.numActRows - 1, i = 0*n; i < n; ++i) { + // Save previous right-hand point as this left-hand point, clear + // space for new right-hand point. + swap(x0, x1); x1 = *x; ++x; + swap(y0, y1); + + const auto dx = x1 - x0; + + for (auto j = 0*nDep; j < nDep; ++j) { + y1[j] = *y[j]; + + const auto delta = y1[j] - y0[j]; + + // Choice for dx==0 somewhat debatable. + *dy[j] = (std::abs(dx) > 0.0) ? (delta / dx) : 0.0; + + // Advance column iterators; + ++y[j]; ++dy[j]; + } + } +} diff --git a/opm/output/eclipse/LinearisedOutputTable.hpp b/opm/output/eclipse/LinearisedOutputTable.hpp new file mode 100644 index 0000000..1cda47c --- /dev/null +++ b/opm/output/eclipse/LinearisedOutputTable.hpp @@ -0,0 +1,168 @@ +/* + Copyright 2017 Statoil ASA. + + 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 . +*/ + +#ifndef LINEARISED_OUTPUT_TABLE_HPP_INCLUDED +#define LINEARISED_OUTPUT_TABLE_HPP_INCLUDED + +#include +#include + +namespace Opm { + + /// Manage tables of column data, possibly with sub-tables, all with + /// equal number of rows (i.e., with padding), and possibly with + /// multiple tables pertaining to multiple subsets (i.e., cell regions). + /// + /// Mainly intended for use with the output facility for tabular data. + class LinearisedOutputTable + { + public: + /// Constructor. + /// + /// \param[in] numTables Number of tables managed by internal + /// buffer. Typically corresponds to maximum value of a region + /// ID vector such as SATNUM, IMBNUM, or PVTNUM. + /// + /// \param[in] numPrimary Number of primary look-up keys for the + /// tabular data managed by the internal buffer. Mostly relevant + /// (i.e., greater than one) for miscible oil ("PVTO") or + /// miscible gas ("PVTG") tables and typically corresponds to the + /// number of Rs/Rv entries from the TABDIMS keyword. + /// + /// \param[in] numRows Number of rows in each sub-table + /// corresponding to a single primary look-up key. Typically the + /// number of nodes (e.g., NSSFUN or NPPVT) of the corresponding + /// input keyword. + /// + /// \param[in] numCols Number of columns in each sub-table (and main + /// table). Typically 5. + LinearisedOutputTable(const std::size_t numTables, + const std::size_t numPrimary, + const std::size_t numRows, + const std::size_t numCols); + + /// Retrieve iterator to start of \c numRows (contiguous) column + /// elements of a particular sub-table of a particular main table. + /// + /// \param[in] tableID Numeric ID of main table for which to + /// retrieve a column. Must be strictly less than \c numTables + /// constructor argument. + /// + /// \param[in] primID Numeric ID of primary look-up key (sub-table) + /// for which to retrieve a column. Must be strictly less than + /// \c numPrimary constructor argument. + /// + /// \param[in] colID Numeric ID of column to be retrieved from + /// particular sub-table of particular main table. Must be + /// strictly less than \c numCols constructor argument. + /// + /// \return Iterator to start of contiguous column elements. + std::vector::iterator + column(const std::size_t tableID, + const std::size_t primID, + const std::size_t colID); + + /// Read-only access to internal data buffer. + /// + /// Mostly to support outputting all table data to external storage. + const std::vector& getData() const; + + /// Destructive access to internal data buffer. + /// + /// Mostly to support outputting all table data to external storage. + /// + /// \return \code std::move() \endcode of the internal data buffer. + std::vector getDataDestructively(); + + private: + /// Internal buffer for tabular data. + std::vector data_; + + /// Number of tables managed by \c data_. + std::size_t numTables_; + + /// Number of primary look-up keys/sub-tables in \c data_. + std::size_t numPrimary_; + + /// Number of rows per sub-table in \c data_. + std::size_t numRows_; + }; + + /// Apply piecewise linear differentiation (i.e., compute slopes) on a + /// set of dependent variables in a linearised output table. + /// + namespace DifferentiateOutputTable { + /// Columnar data differentantiation table request. + /// + /// Refers to the sub-table with a specific primary ID within a + /// specific table of a \c LinearisedOutputTable. + struct Descriptor { + /// Table ID--usually corresponds to the region ID of a + /// tabulated function pertaining to a specific region of a + /// simulation model. + std::size_t tableID{ 0 }; + + /// Primary ID--nontrivial (\c != 0) only for miscible PVT + /// tables for oil or gas in which case this entry refers to a + /// particular dissolved gas-oil ratio (Rs) or gas pressure + /// (Pg) node. + std::size_t primID{ 0 }; + + /// Number of active rows in this subtable. + std::size_t numActRows{ 0 }; + }; + + /// Apply piecewise linear differentiation (i.e., compute slopes) on + /// a set of dependent variables in a linearised output table. + /// + /// Assumes that the independent variable is stored in the first + /// column (column ID zero). + /// + /// \param[in] numDependent Number of dependent variables. Usually + /// one or two. Dependent variables are assumed to be stored in + /// columns one through \p numDependent. + /// + /// \param[in] desc Columnar data differentantiation table request. + /// Must refer to a particular sub-table of the linearised output + /// table. + /// + /// \param[in,out] table Linearised output table. On input, column + /// zero contains the independent variable in each of \code + /// numActRows.size() \endcode sub-tables and columns one through + /// \p numDependent contain the dependent variables. On output, + /// columns \code numDependent + 1 \endcode through \code 2 * + /// numDependent \endcode contain the slopes of the dependent + /// variables. + /// + /// In partcular, column \code numDependent + j \endcode for + /// \code j = 1..numDependent \endcode contains the derivatives + /// of column \c j with respect to column zero. We define the + /// slopes as + /// \code + /// s(i,j) = (c(i + 1, j) - c(i,j)) / (c(i + 1, 0) - c(i,0)) + /// \endcode + /// for all \code i = 0 .. numActRows[k] - 2 \endcode (in table + /// \p k). + void calcSlopes(const std::size_t numDependent, + const Descriptor& desc, + LinearisedOutputTable& table); + } // DifferentiateOutputTable +} // Opm + +#endif // LINEARISED_OUTPUT_TABLE_HPP_INCLUDED diff --git a/tests/test_LinearisedOutputTable.cpp b/tests/test_LinearisedOutputTable.cpp new file mode 100644 index 0000000..06df163 --- /dev/null +++ b/tests/test_LinearisedOutputTable.cpp @@ -0,0 +1,631 @@ +/* + Copyright 2017 Statoil ASA. + + 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 . +*/ + +#if defined(HAVE_CONFIG_H) +#include +#endif // defined(HAVE_CONFIG_H) + +#if HAVE_DYNAMIC_BOOST_TEST +#define BOOST_TEST_DYN_LINK +#endif + +#define NVERBOSE + +#define BOOST_TEST_MODULE TEST_LINEARISEDOUTPUTTABLE + +#include + +#include + +#include +#include +#include + +namespace { + template + void check_is_close(const Collection1& c1, const Collection2& c2) + { + BOOST_REQUIRE_EQUAL(c1.size(), c2.size()); + + if (! c1.empty()) { + auto i1 = c1.begin(), e1 = c1.end(); + auto i2 = c2.begin(); + + for (; i1 != e1; ++i1, ++i2) { + BOOST_CHECK_CLOSE(*i1, *i2, 1.0e-10); + } + } + } + + std::vector + makeTable(const std::size_t ncol, + std::initializer_list data) + { + auto result = std::vector(data.size(), 0.0); + const auto nrows = data.size() / ncol; + + auto di = std::begin(data); + for (auto i = 0*nrows; i < nrows; ++i) { + for (auto j = 0*ncol; j < ncol; ++j, ++di) { + result[i + j*nrows] = *di; + } + } + + return result; + } + + std::vector spe1_swof() + { + return makeTable(4, { + 0.12, 0, 1, 0, // 0 + 0.18, 4.64876033057851E-008, 1, 0, // 1 + 0.24, 0.000000186, 0.997, 0, // 2 + 0.3 , 4.18388429752066E-007, 0.98, 0, // 3 + 0.36, 7.43801652892562E-007, 0.7, 0, // 4 + 0.42, 1.16219008264463E-006, 0.35, 0, // 5 + 0.48, 1.67355371900826E-006, 0.2, 0, // 6 + 0.54, 2.27789256198347E-006, 0.09, 0, // 7 + 0.6 , 2.97520661157025E-006, 0.021, 0, // 8 + 0.66, 3.7654958677686E-006, 0.01, 0, // 9 + 0.72, 4.64876033057851E-006, 0.001, 0, // 10 + 0.78, 0.000005625, 0.0001, 0, // 11 + 0.84, 6.69421487603306E-006, 0, 0, // 12 + 0.91, 8.05914256198347E-006, 0, 0, // 13 + 1 , 0.00001, 0, 0, }); // 14 + } + + std::vector norne_pvto_1_1_incl_der() + { + return makeTable(5, { + 5.00e+01, 9.040365230755323e-01, 7.661326466741799e-01, 2.000000000000000e+20, 2.000000000000000e+20, + 7.50e+01, 9.077375549181221e-01, 7.279370929575959e-01, 1.480412737035941e-04, -1.527822148663360e-03, + 1.00e+02, 9.112115468727220e-01, 6.929365375457962e-01, 1.389596781839941e-04, -1.400022216471988e-03, + 1.25e+02, 9.144863787253888e-01, 6.607560539923331e-01, 1.309932741066744e-04, -1.287219342138526e-03, + 1.50e+02, 9.175658812302724e-01, 6.314975094496025e-01, 1.231801001953414e-04, -1.170341781709223e-03, + }); + } + + std::vector norne_pvto_1_2_incl_der() + { + return makeTable(5, { + 7.00e+01, 8.887150957146157e-01, 8.336914593945738e-01, -2.015977284331128e-03, 8.889317463209720e-03, + 9.50e+01, 8.924826189009969e-01, 7.940236822962605e-01, 1.507009274552473e-04, -1.586711083932530e-03, + 1.20e+02, 8.960252320705352e-01, 7.580585719716880e-01, 1.417045267815320e-04, -1.438604412982900e-03, + 1.45e+02, 8.993533649306149e-01, 7.247005358022682e-01, 1.331253144031885e-04, -1.334321446776792e-03, + 1.70e+02, 9.024944947835819e-01, 6.942265344489091e-01, 1.256451941186798e-04, -1.218960054134364e-03, + }); + } + + std::vector norne_pvto_1_3_incl_der() + { + return makeTable(5, { + 9.00e+01, 8.736829229935872e-01, 9.063100860929328e-01, -1.922272726474237e-03, 9.286269398767148e-03, + 1.15e+02, 8.775085776463464e-01, 8.653930746019195e-01, 1.530261861103677e-04, -1.636680459640534e-03, + 1.40e+02, 8.811038468993955e-01, 8.281051192663491e-01, 1.438107701219638e-04, -1.491518213422815e-03, + 1.65e+02, 8.844861135680170e-01, 7.932610884018090e-01, 1.352906667448606e-04, -1.393761234581605e-03, + 1.90e+02, 8.876816418559648e-01, 7.613050101680658e-01, 1.278211315179112e-04, -1.278243129349725e-03, + }); + } + + std::vector norne_sgfn_incl_der() + { + return makeTable(5, { + 0, 0, 0, 0, 0, + 5.000000000000000e-02, 1.655000000000000e-03, 0, 3.310000000000000e-02, 0, + 1.000000000000000e-01, 6.913000000000000e-03, 0, 1.051600000000000e-01, 0, + 1.500000000000000e-01, 1.621300000000000e-02, 0, 1.860000000000001e-01, 0, + 2.000000000000000e-01, 2.999000000000000e-02, 0, 2.755399999999998e-01, 0, + 2.500000000000000e-01, 4.865500000000000e-02, 0, 3.733000000000000e-01, 0, + 3.000000000000000e-01, 7.257300000000000e-02, 0, 4.783600000000001e-01, 0, + 3.500000000000000e-01, 1.020460000000000e-01, 0, 5.894600000000001e-01, 0, + 4.000000000000000e-01, 1.372870000000000e-01, 0, 7.048199999999992e-01, 0, + 4.500000000000000e-01, 1.784020000000000e-01, 0, 8.223000000000005e-01, 0, + 5.000000000000000e-01, 2.253680000000000e-01, 0, 9.393200000000004e-01, 0, + 5.500000000000000e-01, 2.780300000000000e-01, 0, 1.053239999999999e+00, 0, + 6.000000000000000e-01, 3.360930000000000e-01, 0, 1.161260000000001e+00, 0, + 6.500000000000000e-01, 3.991350000000000e-01, 0, 1.260840000000000e+00, 0, + 7.000000000000000e-01, 4.666310000000000e-01, 0, 1.349920000000002e+00, 0, + 7.500000000000000e-01, 5.380000000000000e-01, 0, 1.427379999999999e+00, 0, + 8.000000000000000e-01, 6.126650000000000e-01, 0, 1.493299999999998e+00, 0, + 8.500000000000000e-01, 6.901690000000000e-01, 0, 1.550080000000002e+00, 0, + 9.000000000000000e-01, 7.703950000000001e-01, 0, 1.604519999999999e+00, 0, + 9.500000000000000e-01, 8.542180000000000e-01, 0, 1.676460000000002e+00, 0, + 9.999000000000000e-01, 9.499000000000000e-01, 0, 1.917474949899796e+00, 0, + 1.000000000000000e+00, 9.500000000000000e-01, 0, 1.000000000000000e+00, 0, + }); + } +} // Anonymous + +// --------------------------------------------------------------------- +// Saturation Functions + +BOOST_AUTO_TEST_SUITE (Tabulated_Functions) + +BOOST_AUTO_TEST_CASE (SGFN) +{ + const auto inputData = norne_sgfn_incl_der(); + const auto tableRows = inputData.size() / 5; + + const auto numTables = std::size_t{1}; + const auto numPrimary = std::size_t{1}; + const auto numRows = std::size_t{30}; + const auto numCols = std::size_t{5}; + + auto sgfn = ::Opm::LinearisedOutputTable { + numTables, numPrimary, numRows, numCols + }; + + // Sg + { + const auto tableID = std::size_t{0}; + const auto primID = std::size_t{0}; + const auto colID = std::size_t{0}; + + std::copy(inputData.begin() + 0*tableRows, + inputData.begin() + 1*tableRows, + sgfn.column(tableID, primID, colID)); + } + + // Krg + { + const auto tableID = std::size_t{0}; + const auto primID = std::size_t{0}; + const auto colID = std::size_t{1}; + + std::copy(inputData.begin() + 1*tableRows, + inputData.begin() + 2*tableRows, + sgfn.column(tableID, primID, colID)); + } + + // Pcgo + { + const auto tableID = std::size_t{0}; + const auto primID = std::size_t{0}; + const auto colID = std::size_t{2}; + + std::copy(inputData.begin() + 2*tableRows, + inputData.begin() + 3*tableRows, + sgfn.column(tableID, primID, colID)); + } + + // d[Krg]/dSg + { + const auto tableID = std::size_t{0}; + const auto primID = std::size_t{0}; + const auto colID = std::size_t{3}; + + std::copy(inputData.begin() + 3*tableRows, + inputData.begin() + 4*tableRows, + sgfn.column(tableID, primID, colID)); + } + + // d[Pcgo]/dSg + { + const auto tableID = std::size_t{0}; + const auto primID = std::size_t{0}; + const auto colID = std::size_t{4}; + + std::copy(inputData.begin() + 4*tableRows, + inputData.begin() + 5*tableRows, + sgfn.column(tableID, primID, colID)); + } + + const auto expect = makeTable(5, + { + 0, 0, 0, 0, 0, + 5.000e-02, 1.65500e-03, 0, 3.310000000000000e-02, 0, + 1.000e-01, 6.91300e-03, 0, 1.051600000000000e-01, 0, + 1.500e-01, 1.62130e-02, 0, 1.860000000000001e-01, 0, + 2.000e-01, 2.99900e-02, 0, 2.755399999999998e-01, 0, + 2.500e-01, 4.86550e-02, 0, 3.733000000000000e-01, 0, + 3.000e-01, 7.25730e-02, 0, 4.783600000000001e-01, 0, + 3.500e-01, 1.02046e-01, 0, 5.894600000000001e-01, 0, + 4.000e-01, 1.37287e-01, 0, 7.048199999999992e-01, 0, + 4.500e-01, 1.78402e-01, 0, 8.223000000000005e-01, 0, + 5.000e-01, 2.25368e-01, 0, 9.393200000000004e-01, 0, + 5.500e-01, 2.78030e-01, 0, 1.053239999999999e+00, 0, + 6.000e-01, 3.36093e-01, 0, 1.161260000000001e+00, 0, + 6.500e-01, 3.99135e-01, 0, 1.260840000000000e+00, 0, + 7.000e-01, 4.66631e-01, 0, 1.349920000000002e+00, 0, + 7.500e-01, 5.38000e-01, 0, 1.427379999999999e+00, 0, + 8.000e-01, 6.12665e-01, 0, 1.493299999999998e+00, 0, + 8.500e-01, 6.90169e-01, 0, 1.550080000000002e+00, 0, + 9.000e-01, 7.70395e-01, 0, 1.604519999999999e+00, 0, + 9.500e-01, 8.54218e-01, 0, 1.676460000000002e+00, 0, + 9.999e-01, 9.49900e-01, 0, 1.917474949899796e+00, 0, + 1.000e+00, 9.50000e-01, 0, 1.000000000000000e+00, 0, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + 1.000e+20, 1.00000e+20, 1.e+20, 1.000000000000000e+20, 1.e+20, + }); + + check_is_close(sgfn.getData(), expect); +} + +// --------------------------------------------------------------------- +// PVT + +BOOST_AUTO_TEST_CASE (PVTO) +{ + const auto inputData = std::vector< std::vector > + { + norne_pvto_1_1_incl_der(), + norne_pvto_1_2_incl_der(), + norne_pvto_1_3_incl_der(), + }; + + const auto numTables = std::size_t{1}; + const auto numPrimary = std::size_t{5}; + const auto numRows = std::size_t{8}; + const auto numCols = std::size_t{5}; + + auto pvto = ::Opm::LinearisedOutputTable { + numTables, numPrimary, numRows, numCols + }; + + { + auto primID = std::size_t{0}; + for (const auto& subTab : inputData) { + const auto tableRows = subTab.size() / numCols; + + // Po + { + const auto tableID = std::size_t{0}; + const auto colID = std::size_t{0}; + + std::copy(subTab.begin() + 0*tableRows, + subTab.begin() + 1*tableRows, + pvto.column(tableID, primID, colID)); + } + + // 1/Bo + { + const auto tableID = std::size_t{0}; + const auto colID = std::size_t{1}; + + std::copy(subTab.begin() + 1*tableRows, + subTab.begin() + 2*tableRows, + pvto.column(tableID, primID, colID)); + } + + // 1/(Bo*mu_o) + { + const auto tableID = std::size_t{0}; + const auto colID = std::size_t{2}; + + std::copy(subTab.begin() + 2*tableRows, + subTab.begin() + 3*tableRows, + pvto.column(tableID, primID, colID)); + } + + // d[1/Bo]/dPo + { + const auto tableID = std::size_t{0}; + const auto colID = std::size_t{3}; + + std::copy(subTab.begin() + 3*tableRows, + subTab.begin() + 4*tableRows, + pvto.column(tableID, primID, colID)); + } + + // d[1/(Bo*mu_o)]/dPo + { + const auto tableID = std::size_t{0}; + const auto colID = std::size_t{4}; + + std::copy(subTab.begin() + 4*tableRows, + subTab.begin() + 5*tableRows, + pvto.column(tableID, primID, colID)); + } + + primID += 1; + } + } + + const auto expect = makeTable(5, { + 5.000000000000000e+01, 9.040365230755323e-01, 7.661326466741799e-01, 2.000000000000000e+20, 2.000000000000000e+20, + 7.500000000000000e+01, 9.077375549181221e-01, 7.279370929575959e-01, 1.480412737035941e-04, -1.527822148663360e-03, + 1.000000000000000e+02, 9.112115468727220e-01, 6.929365375457962e-01, 1.389596781839941e-04, -1.400022216471988e-03, + 1.250000000000000e+02, 9.144863787253888e-01, 6.607560539923331e-01, 1.309932741066744e-04, -1.287219342138526e-03, + 1.500000000000000e+02, 9.175658812302724e-01, 6.314975094496025e-01, 1.231801001953414e-04, -1.170341781709223e-03, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 7.000000000000000e+01, 8.887150957146157e-01, 8.336914593945738e-01, -2.015977284331128e-03, 8.889317463209720e-03, + 9.500000000000000e+01, 8.924826189009969e-01, 7.940236822962605e-01, 1.507009274552473e-04, -1.586711083932530e-03, + 1.200000000000000e+02, 8.960252320705352e-01, 7.580585719716880e-01, 1.417045267815320e-04, -1.438604412982900e-03, + 1.450000000000000e+02, 8.993533649306149e-01, 7.247005358022682e-01, 1.331253144031885e-04, -1.334321446776792e-03, + 1.700000000000000e+02, 9.024944947835819e-01, 6.942265344489091e-01, 1.256451941186798e-04, -1.218960054134364e-03, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 9.000000000000000e+01, 8.736829229935872e-01, 9.063100860929328e-01, -1.922272726474237e-03, 9.286269398767148e-03, + 1.150000000000000e+02, 8.775085776463464e-01, 8.653930746019195e-01, 1.530261861103677e-04, -1.636680459640534e-03, + 1.400000000000000e+02, 8.811038468993955e-01, 8.281051192663491e-01, 1.438107701219638e-04, -1.491518213422815e-03, + 1.650000000000000e+02, 8.844861135680170e-01, 7.932610884018090e-01, 1.352906667448606e-04, -1.393761234581605e-03, + 1.900000000000000e+02, 8.876816418559648e-01, 7.613050101680658e-01, 1.278211315179112e-04, -1.278243129349725e-03, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + }); + + check_is_close(pvto.getData(), expect); +} + +BOOST_AUTO_TEST_SUITE_END () + +// --------------------------------------------------------------------- +// Derivatives of tabulated, piecewise linear functions + +BOOST_AUTO_TEST_SUITE (Calculated_Slopes) + +BOOST_AUTO_TEST_CASE (No_Derivatives) +{ + auto descr = ::Opm::DifferentiateOutputTable::Descriptor{}; + + descr.tableID = 0; + descr.primID = 0; + descr.numActRows = 1; + + auto linTable = ::Opm::LinearisedOutputTable { + 1, 1, 3, 3 // Single table, one prim. key, 3 declared rows, 3 cols. + }; + + { + auto x = 0.0; + auto y = x; + + *linTable.column(descr.tableID, descr.primID, 0) = x; + *linTable.column(descr.tableID, descr.primID, 1) = y; + } + + // Argument dependent symbol lookup. + calcSlopes(1, descr, linTable); // One dependent column. + + // Too few active rows (< 2). Leave derivatives alone + const auto expect = makeTable(3, { + 0, 0, 1.e+20, + 1.e+20, 1.e+20, 1.e+20, + 1.e+20, 1.e+20, 1.e+20, + }); + + check_is_close(linTable.getData(), expect); +} + +BOOST_AUTO_TEST_CASE (Constant_Function) +{ + auto descr = ::Opm::DifferentiateOutputTable::Descriptor{}; + + descr.tableID = 0; + descr.primID = 0; + descr.numActRows = 11; + + auto linTable = ::Opm::LinearisedOutputTable { + 1, 1, 15, 3 // Single table, one prim. key, 15 declared rows, 3 cols. + }; + + { + auto x = std::vector { + 0.0, 0.1, 0.2, 0.3, 0.4, + 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 }; + + auto y = std::vector(x.size(), 1.25); + + std::copy(x.begin(), x.end(), + linTable.column(descr.tableID, descr.primID, 0)); + + std::copy(y.begin(), y.end(), + linTable.column(descr.tableID, descr.primID, 1)); + } + + // Argument dependent symbol lookup. + calcSlopes(1, descr, linTable); // One dependent column. + + // Compute slopes for all intervals, store in left end point. + // Non-active rows left at defaulted values. + const auto expect = makeTable(3, { + 0, 1.25e+00, 0, + 1.0e-01, 1.25e+00, 0, + 2.0e-01, 1.25e+00, 0, + 3.0e-01, 1.25e+00, 0, + 4.0e-01, 1.25e+00, 0, + 5.0e-01, 1.25e+00, 0, + 6.0e-01, 1.25e+00, 0, + 7.0e-01, 1.25e+00, 0, + 8.0e-01, 1.25e+00, 0, + 9.0e-01, 1.25e+00, 0, + 1.0e+00, 1.25e+00, 1.0e+20, + 1.0e+20, 1.00e+20, 1.0e+20, + 1.0e+20, 1.00e+20, 1.0e+20, + 1.0e+20, 1.00e+20, 1.0e+20, + 1.0e+20, 1.00e+20, 1.0e+20, + }); + + check_is_close(linTable.getData(), expect); +} + +BOOST_AUTO_TEST_CASE (Linear_Function) +{ + auto descr = ::Opm::DifferentiateOutputTable::Descriptor{}; + + descr.tableID = 0; + descr.primID = 0; + descr.numActRows = 11; + + auto linTable = ::Opm::LinearisedOutputTable { + 1, 1, 11, 3 // Single table, one prim. key, 11 declared rows, 3 cols. + }; + + { + auto x = std::vector { + 0.0, 0.1, 0.2, 0.3, 0.4, + 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 }; + + auto y = x; + + std::copy(x.begin(), x.end(), + linTable.column(descr.tableID, descr.primID, 0)); + + std::copy(y.begin(), y.end(), + linTable.column(descr.tableID, descr.primID, 1)); + } + + // Argument dependent symbol lookup. + calcSlopes(1, descr, linTable); // One dependent column. + + // Compute slopes for all intervals, store in left end point. + const auto expect = makeTable(3, { + 0, 0, 1.0, + 1.0e-01, 1.0e-01, 1.0, + 2.0e-01, 2.0e-01, 1.0, + 3.0e-01, 3.0e-01, 1.0, + 4.0e-01, 4.0e-01, 1.0, + 5.0e-01, 5.0e-01, 1.0, + 6.0e-01, 6.0e-01, 1.0, + 7.0e-01, 7.0e-01, 1.0, + 8.0e-01, 8.0e-01, 1.0, + 9.0e-01, 9.0e-01, 1.0, + 1.0e+00, 1.0e+00, 1.0e+20, + }); + + check_is_close(linTable.getData(), expect); +} + +BOOST_AUTO_TEST_CASE (Nonlinear_Functions) +{ + auto descr = ::Opm::DifferentiateOutputTable::Descriptor{}; + + descr.tableID = 0; + descr.primID = 0; + descr.numActRows = 11; + + auto linTable = ::Opm::LinearisedOutputTable { + 1, 1, 15, 7 // Single table, one prim. key, 15 declared rows, 7 cols. + }; + + { + const auto x = std::vector { + 0.0, 0.1, 0.2, 0.3, 0.4, + 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 }; + + // sin(2*pi * x) + const auto s = std::vector { + 0, + 5.877852522924731e-01, + 9.510565162951535e-01, + 9.510565162951536e-01, + 5.877852522924732e-01, + 1.224646799147353e-16, + -5.877852522924730e-01, + -9.510565162951535e-01, + -9.510565162951536e-01, + -5.877852522924734e-01, + -2.449293598294706e-16, + }; + + // cos(4*pi * x)^2 + const auto c = std::vector { + 1.000000000000000e+00, + 9.549150281252630e-02, + 6.545084971874736e-01, + 6.545084971874737e-01, + 9.549150281252616e-02, + 1.000000000000000e+00, + 9.549150281252648e-02, + 6.545084971874734e-01, + 6.545084971874742e-01, + 9.549150281252602e-02, + 1.000000000000000e+00, + }; + + // exp(-x) / (1 + x) + const auto f = std::vector { + 1.000000000000000e+00, + 8.225794709417813e-01, + 6.822756275649848e-01, + 5.698601697551676e-01, + 4.788000328825995e-01, + 4.043537731417556e-01, + 3.430072725587666e-01, + 2.921090022302409e-01, + 2.496272022873453e-01, + 2.139840314424206e-01, + 1.839397205857212e-01, + }; + + std::copy(x.begin(), x.end(), + linTable.column(descr.tableID, descr.primID, 0)); + + std::copy(s.begin(), s.end(), + linTable.column(descr.tableID, descr.primID, 1)); + + std::copy(c.begin(), c.end(), + linTable.column(descr.tableID, descr.primID, 2)); + + std::copy(f.begin(), f.end(), + linTable.column(descr.tableID, descr.primID, 3)); + } + + // Argument dependent symbol lookup. + calcSlopes(3, descr, linTable); // Three dependent columns. + + // Compute slopes for all intervals, store in left end point. + const auto expect = makeTable(7, { + 0, 0, 1.000000000000000e+00, 1.000000000000000e+00, 5.877852522924731e+00, -9.045084971874736e+00, -1.774205290582187e+00, + 1.0e-01, 5.877852522924731e-01, 9.549150281252630e-02, 8.225794709417813e-01, 3.632712640026804e+00, 5.590169943749473e+00, -1.403038433767965e+00, + 2.0e-01, 9.510565162951535e-01, 6.545084971874736e-01, 6.822756275649848e-01, 1.110223024625157e-15, 1.110223024625157e-15, -1.124154578098172e+00, + 3.0e-01, 9.510565162951536e-01, 6.545084971874737e-01, 5.698601697551676e-01, -3.632712640026803e+00, -5.590169943749474e+00, -9.106013687256805e-01, + 4.0e-01, 5.877852522924732e-01, 9.549150281252616e-02, 4.788000328825995e-01, -5.877852522924733e+00, 9.045084971874740e+00, -7.444625974084391e-01, + 5.0e-01, 1.224646799147353e-16, 1.000000000000000e+00, 4.043537731417556e-01, -5.877852522924733e+00, -9.045084971874736e+00, -6.134650058298908e-01, + 6.0e-01, -5.877852522924730e-01, 9.549150281252648e-02, 3.430072725587666e-01, -3.632712640026806e+00, 5.590169943749470e+00, -5.089827032852569e-01, + 7.0e-01, -9.510565162951535e-01, 6.545084971874734e-01, 2.921090022302409e-01, -1.110223024625156e-15, 7.771561172376089e-15, -4.248179994289554e-01, + 8.0e-01, -9.510565162951536e-01, 6.545084971874742e-01, 2.496272022873453e-01, 3.632712640026804e+00, -5.590169943749483e+00, -3.564317084492472e-01, + 9.0e-01, -5.877852522924734e-01, 9.549150281252602e-02, 2.139840314424206e-01, 5.877852522924733e+00, 9.045084971874742e+00, -3.004431085669943e-01, + 1.0e+00, -2.449293598294706e-16, 1.000000000000000e+00, 1.839397205857212e-01, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + }); + + check_is_close(linTable.getData(), expect); +} + +BOOST_AUTO_TEST_SUITE_END () From 38d280485d4415f22bf8b826fd7889885cda0576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Wed, 15 Nov 2017 16:55:56 +0100 Subject: [PATCH 4/7] Linearised Output Table: Store Derivatives at Right-Hand End Point This is more in keeping with the intended application--at least for saturation function output to the INIT result set. While here, also remove an unused data table (SWOF from SPE1). --- opm/output/eclipse/LinearisedOutputTable.cpp | 3 + tests/test_LinearisedOutputTable.cpp | 58 +++++++------------- 2 files changed, 22 insertions(+), 39 deletions(-) diff --git a/opm/output/eclipse/LinearisedOutputTable.cpp b/opm/output/eclipse/LinearisedOutputTable.cpp index 0b9e924..81a1e63 100644 --- a/opm/output/eclipse/LinearisedOutputTable.cpp +++ b/opm/output/eclipse/LinearisedOutputTable.cpp @@ -70,6 +70,9 @@ Opm::DifferentiateOutputTable::calcSlopes(const std::size_t nDep, dy.push_back(table.column(desc.tableID, desc.primID, j + 1 + 1*nDep)); y1[j] = *y.back(); ++y.back(); + + // Store derivatives at right interval end-point. + ++dy.back(); } using std::swap; diff --git a/tests/test_LinearisedOutputTable.cpp b/tests/test_LinearisedOutputTable.cpp index 06df163..f2104f1 100644 --- a/tests/test_LinearisedOutputTable.cpp +++ b/tests/test_LinearisedOutputTable.cpp @@ -70,26 +70,6 @@ namespace { return result; } - std::vector spe1_swof() - { - return makeTable(4, { - 0.12, 0, 1, 0, // 0 - 0.18, 4.64876033057851E-008, 1, 0, // 1 - 0.24, 0.000000186, 0.997, 0, // 2 - 0.3 , 4.18388429752066E-007, 0.98, 0, // 3 - 0.36, 7.43801652892562E-007, 0.7, 0, // 4 - 0.42, 1.16219008264463E-006, 0.35, 0, // 5 - 0.48, 1.67355371900826E-006, 0.2, 0, // 6 - 0.54, 2.27789256198347E-006, 0.09, 0, // 7 - 0.6 , 2.97520661157025E-006, 0.021, 0, // 8 - 0.66, 3.7654958677686E-006, 0.01, 0, // 9 - 0.72, 4.64876033057851E-006, 0.001, 0, // 10 - 0.78, 0.000005625, 0.0001, 0, // 11 - 0.84, 6.69421487603306E-006, 0, 0, // 12 - 0.91, 8.05914256198347E-006, 0, 0, // 13 - 1 , 0.00001, 0, 0, }); // 14 - } - std::vector norne_pvto_1_1_incl_der() { return makeTable(5, { @@ -162,10 +142,10 @@ BOOST_AUTO_TEST_CASE (SGFN) const auto inputData = norne_sgfn_incl_der(); const auto tableRows = inputData.size() / 5; - const auto numTables = std::size_t{1}; - const auto numPrimary = std::size_t{1}; - const auto numRows = std::size_t{30}; - const auto numCols = std::size_t{5}; + const auto numTables = std::size_t{ 1}; + const auto numPrimary = std::size_t{ 1}; + const auto numRows = std::size_t{30}; + const auto numCols = std::size_t{ 5}; auto sgfn = ::Opm::LinearisedOutputTable { numTables, numPrimary, numRows, numCols @@ -461,7 +441,7 @@ BOOST_AUTO_TEST_CASE (Constant_Function) // Compute slopes for all intervals, store in left end point. // Non-active rows left at defaulted values. const auto expect = makeTable(3, { - 0, 1.25e+00, 0, + 0, 1.25e+00, 1.0e+20, 1.0e-01, 1.25e+00, 0, 2.0e-01, 1.25e+00, 0, 3.0e-01, 1.25e+00, 0, @@ -471,7 +451,7 @@ BOOST_AUTO_TEST_CASE (Constant_Function) 7.0e-01, 1.25e+00, 0, 8.0e-01, 1.25e+00, 0, 9.0e-01, 1.25e+00, 0, - 1.0e+00, 1.25e+00, 1.0e+20, + 1.0e+00, 1.25e+00, 0, 1.0e+20, 1.00e+20, 1.0e+20, 1.0e+20, 1.00e+20, 1.0e+20, 1.0e+20, 1.00e+20, 1.0e+20, @@ -512,7 +492,7 @@ BOOST_AUTO_TEST_CASE (Linear_Function) // Compute slopes for all intervals, store in left end point. const auto expect = makeTable(3, { - 0, 0, 1.0, + 0, 0, 1.0e+20, 1.0e-01, 1.0e-01, 1.0, 2.0e-01, 2.0e-01, 1.0, 3.0e-01, 3.0e-01, 1.0, @@ -522,7 +502,7 @@ BOOST_AUTO_TEST_CASE (Linear_Function) 7.0e-01, 7.0e-01, 1.0, 8.0e-01, 8.0e-01, 1.0, 9.0e-01, 9.0e-01, 1.0, - 1.0e+00, 1.0e+00, 1.0e+20, + 1.0e+00, 1.0e+00, 1.0, }); check_is_close(linTable.getData(), expect); @@ -608,17 +588,17 @@ BOOST_AUTO_TEST_CASE (Nonlinear_Functions) // Compute slopes for all intervals, store in left end point. const auto expect = makeTable(7, { - 0, 0, 1.000000000000000e+00, 1.000000000000000e+00, 5.877852522924731e+00, -9.045084971874736e+00, -1.774205290582187e+00, - 1.0e-01, 5.877852522924731e-01, 9.549150281252630e-02, 8.225794709417813e-01, 3.632712640026804e+00, 5.590169943749473e+00, -1.403038433767965e+00, - 2.0e-01, 9.510565162951535e-01, 6.545084971874736e-01, 6.822756275649848e-01, 1.110223024625157e-15, 1.110223024625157e-15, -1.124154578098172e+00, - 3.0e-01, 9.510565162951536e-01, 6.545084971874737e-01, 5.698601697551676e-01, -3.632712640026803e+00, -5.590169943749474e+00, -9.106013687256805e-01, - 4.0e-01, 5.877852522924732e-01, 9.549150281252616e-02, 4.788000328825995e-01, -5.877852522924733e+00, 9.045084971874740e+00, -7.444625974084391e-01, - 5.0e-01, 1.224646799147353e-16, 1.000000000000000e+00, 4.043537731417556e-01, -5.877852522924733e+00, -9.045084971874736e+00, -6.134650058298908e-01, - 6.0e-01, -5.877852522924730e-01, 9.549150281252648e-02, 3.430072725587666e-01, -3.632712640026806e+00, 5.590169943749470e+00, -5.089827032852569e-01, - 7.0e-01, -9.510565162951535e-01, 6.545084971874734e-01, 2.921090022302409e-01, -1.110223024625156e-15, 7.771561172376089e-15, -4.248179994289554e-01, - 8.0e-01, -9.510565162951536e-01, 6.545084971874742e-01, 2.496272022873453e-01, 3.632712640026804e+00, -5.590169943749483e+00, -3.564317084492472e-01, - 9.0e-01, -5.877852522924734e-01, 9.549150281252602e-02, 2.139840314424206e-01, 5.877852522924733e+00, 9.045084971874742e+00, -3.004431085669943e-01, - 1.0e+00, -2.449293598294706e-16, 1.000000000000000e+00, 1.839397205857212e-01, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 0, 0, 1.000000000000000e+00, 1.000000000000000e+00, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0e-01, 5.877852522924731e-01, 9.549150281252630e-02, 8.225794709417813e-01, 5.877852522924731e+00, -9.045084971874736e+00, -1.774205290582187e+00, + 2.0e-01, 9.510565162951535e-01, 6.545084971874736e-01, 6.822756275649848e-01, 3.632712640026804e+00, 5.590169943749473e+00, -1.403038433767965e+00, + 3.0e-01, 9.510565162951536e-01, 6.545084971874737e-01, 5.698601697551676e-01, 1.110223024625157e-15, 1.110223024625157e-15, -1.124154578098172e+00, + 4.0e-01, 5.877852522924732e-01, 9.549150281252616e-02, 4.788000328825995e-01, -3.632712640026803e+00, -5.590169943749474e+00, -9.106013687256805e-01, + 5.0e-01, 1.224646799147353e-16, 1.000000000000000e+00, 4.043537731417556e-01, -5.877852522924733e+00, 9.045084971874740e+00, -7.444625974084391e-01, + 6.0e-01, -5.877852522924730e-01, 9.549150281252648e-02, 3.430072725587666e-01, -5.877852522924733e+00, -9.045084971874736e+00, -6.134650058298908e-01, + 7.0e-01, -9.510565162951535e-01, 6.545084971874734e-01, 2.921090022302409e-01, -3.632712640026806e+00, 5.590169943749470e+00, -5.089827032852569e-01, + 8.0e-01, -9.510565162951536e-01, 6.545084971874742e-01, 2.496272022873453e-01, -1.110223024625156e-15, 7.771561172376089e-15, -4.248179994289554e-01, + 9.0e-01, -5.877852522924734e-01, 9.549150281252602e-02, 2.139840314424206e-01, 3.632712640026804e+00, -5.590169943749483e+00, -3.564317084492472e-01, + 1.0e+00, -2.449293598294706e-16, 1.000000000000000e+00, 1.839397205857212e-01, 5.877852522924733e+00, 9.045084971874742e+00, -3.004431085669943e-01, 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, From 07aad01bb8a9caef8e786152949d5ec0634cc704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Thu, 16 Nov 2017 16:34:05 +0100 Subject: [PATCH 5/7] INIT File: Add Support for Writing Saturation Function Tables This commit extends the INIT file Table writing to also output the saturation function tables in normalised form. We support generating the INIT file's SGFN, SOFN, and SWFN tables--including the derivative information--for both two and three phases from both families of saturation function keywords (S{G,W}OF and S{G,W}FN + SOF{2,3}). We do not yet support generating the appropriate tables from input keyword SLGOF. We leverage the LinearisedOutputTable to abstract away some of the details of indexing into the linear 'tab' array and create a helper function to loop across saturation function regions whence each table generator need only be concerned about the specific data pertaining to that region's saturation function (i.e., the values of independent and dependent variates and number of active rows). We allocate the output tables according to information in the TABDIMS keyword, notably the number of saturation nodes (item 3 of TABDIMS). Generating the three-phase SOFN table, which has the same columns as the input table SOF3, in the case of family One (SGOF and SWOF) is slightly involved. In particular we need to join the SGOF and SWOF tables on common oil saturation values and derive/insert missing KroX data through piecewise linear interpolation in the appropriate input table. We defer the details of merging on common (and uniqe) oil saturation values to the standard library routine 'set_union()' which outputs repeated saturation values exactly once rather than for each occurrence. That way we only need to wrap the input tables in a simple class to facilitate look-up of oil saturation values and the mechanics of piecewise linear interpolation of the relative permeability column for oil. Due to this merging process, the number of rows in SOFN is twice the number of saturation nodes in this case. Since this support depends on being able to determine which phases are active in a particular run, what table sizes to use for the output and which keywords are being used to represent the saturation function tables we introduce a single new public member function void Tables::addSatFunc(const EclipseState& es) This function determines the run's active phases and dispatches to the new helper functions void Tables::addSatFunc_FamilyOne() void Tables::addSatFunc_FamilyTwo() according to which keyword family exists in the input deck. These functions in turn call additional helper functions to handle each phase table separately. For instance addSatFunc_FamilyOne() uses the helper function SatFunc::Oil::ThreePhase::fromSGOFandSWOF() to generate a three-phase SOFN table based on the information in the SGOF and SWOF tables. Information about slopes/derivatives for the piecewise interpolants of the dependent variates is computed through the helper function DifferentiateOutputTable::calcSlopes() whence the first entry of each derivative column is undefined (i.e., assigned the sentinel value 1e+20). This should arguably be zero instead. Further testing and comparison with INIT result sets generated by ECL will inform the decision here. We add unit tests for all combinations of number of active phases (two or three) and which saturation function keyword family is present in the simulation case. The unit tests use the tables from SPE 9 for keyword family One and the tables from SPE 1 for keyword family Two. Comparison data is extracted directly from the ECL INIT file in the case of the SPE 9 tables and derived from independent calculation for the SPE 1 tables. --- opm/output/eclipse/Tables.cpp | 1135 ++++++++++++++++++++++++- opm/output/eclipse/Tables.hpp | 43 +- tests/test_Tables.cpp | 1460 ++++++++++++++++++++++++++++++++- 3 files changed, 2629 insertions(+), 9 deletions(-) diff --git a/opm/output/eclipse/Tables.cpp b/opm/output/eclipse/Tables.cpp index 75c0da7..96da0c0 100644 --- a/opm/output/eclipse/Tables.cpp +++ b/opm/output/eclipse/Tables.cpp @@ -17,20 +17,995 @@ along with OPM. If not, see . */ +#include + #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include +#include #include #include -#include #include +/// Functions to facilitate generating TAB vector entries for tabulated +/// saturation functions. +namespace { namespace SatFunc { + namespace detail { + /// Create linearised, padded TAB vector entries for a collection of + /// tabulated saturation functions corresponding to a single input + /// keyword. + /// + /// \tparam BuildDependent Callable entity that extracts the + /// independent and primary dependent variates of a single + /// saturation function table into a linearised output table. + /// Must implement a function call operator of the form + /// \code + /// std::size_t + /// operator()(const std::size_t tableID, + /// const std::size_t primID, + /// LinearisedOutputTable& table); + /// \endcode + /// that will assign the independent variate of the sub-table + /// primID within the table identified as tableID to column zero + /// of 'table' and all dependent variates to columns one &c of + /// 'table'. The function call operator must return the number + /// of active (used) rows within the sub-table through its return + /// value. + /// + /// \param[in] numTab Number of tables in this table collection. + /// + /// \param[in] numRows Number of rows to allocate for each padded + /// output table. + /// + /// \param[in] numDep Number of dependent variates (columns) in each + /// table of this collection of input tables. Total number of + /// columns in the result vector will be 1 + 2*numDep to account + /// for the independent variate, the dependent variates and the + /// derivatives of the dependent variates with respect to the + /// independent variate. + /// + /// \param[in] buildDeps Function object that implements the + /// protocol outlined for \code BuildDependent::operator()() + /// \endcode. Typically a lambda expression. + /// + /// \return Linearised, padded TAB vector entries for a collection + /// of tabulated saturation functions corresponding to a single + /// input keyword. Derivatives included as additional columns. + template + std::vector + createSatfuncTable(const std::size_t numTab, + const std::size_t numRows, + const std::size_t numDep, + BuildDependent&& buildDeps) + { + const auto numPrim = std::size_t{1}; + const auto numCols = 1 + 2*numDep; + + auto descr = ::Opm::DifferentiateOutputTable::Descriptor{}; + descr.primID = 0 * numPrim; + + auto linTable = ::Opm::LinearisedOutputTable { + numTab, numPrim, numRows, numCols + }; + + for (descr.tableID = 0*numTab; + descr.tableID < 1*numTab; ++descr.tableID) + { + descr.numActRows = + buildDeps(descr.tableID, descr.primID, linTable); + + // Derivatives. Use values already stored in linTable to + // take advantage of any unit conversion already applied. + // We don't have to do anything special for the units here. + // + // Note: argument 'descr' implies argument-dependent lookup + // whence we unambiguously invoke function calcSlopes() + // from namespace ::Opm::DifferentiateOutputTable. + calcSlopes(numDep, descr, linTable); + } + + return linTable.getDataDestructively(); + } + } // detail + + /// Functions to create linearised, padded, and normalised SGFN output + /// tables from various input saturation function keywords. + namespace Gas { + /// Create linearised and padded 'TAB' vector entries of normalised + /// SGFN tables for all saturation function regions from Family Two + /// table data (SGFN keyword). + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be equal to the number of + /// declared saturation nodes in the simulation run's TABDIMS + /// keyword (Item 3). + /// + /// \param[in] units Active unit system. Needed to convert SI + /// convention capillary pressure values (Pascal) to declared + /// conventions of the run specification. + /// + /// \param[in] sgfn Collection of SGFN tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for output + /// SGFN tables. A unit-converted copy of the input table \p + /// sgfn with added derivatives. + std::vector + fromSGFN(const std::size_t numRows, + const Opm::UnitSystem& units, + const Opm::TableContainer& sgfn) + { + using SGFN = ::Opm::SgfnTable; + + const auto numTab = sgfn.size(); + const auto numDep = std::size_t{2}; // Krg, Pcgo + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&units, &sgfn](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = sgfn.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // Sg + { + const auto& Sg = t.getSgColumn(); + + numActRows = Sg.size(); + std::copy(std::begin(Sg), std::end(Sg), + linTable.column(tableID, primID, 0)); + } + + // Krg(Sg) + { + const auto& kr = t.getKrgColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 1)); + } + + // Pcgo(Sg) + { + const auto uPress = ::Opm::UnitSystem::measure::pressure; + + const auto& pc = t.getPcogColumn(); + std::transform(std::begin(pc), std::end(pc), + linTable.column(tableID, primID, 2), + [&units, uPress](const double Pc) -> double + { + return units.from_si(uPress, Pc); + }); + } + + // Inform createSatfuncTable() of number of active rows in + // this table. Needed to compute slopes of piecewise linear + // interpolants. + return numActRows; + }); + } + + /// Create linearised and padded 'TAB' vector entries of normalised + /// SGFN tables for all saturation function regions from Family One + /// table data (SGOF keyword). + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be equal to the number of + /// declared saturation nodes in the simulation run's TABDIMS + /// keyword (Item 3). + /// + /// \param[in] units Active unit system. Needed to convert SI + /// convention capillary pressure values (Pascal) to declared + /// conventions of the run specification. + /// + /// \param[in] swof Collection of SGOF tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for output + /// SGFN tables. Corresponds to unit-converted copies of columns + /// 1, 2, and 4--with added derivatives--of the input SGOF tables. + std::vector + fromSGOF(const std::size_t numRows, + const Opm::UnitSystem& units, + const Opm::TableContainer& sgof) + { + using SGOF = ::Opm::SgofTable; + + const auto numTab = sgof.size(); + const auto numDep = std::size_t{2}; // Krg, Pcgo + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&units, &sgof](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = sgof.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // Sg + { + const auto& Sg = t.getSgColumn(); + + numActRows = Sg.size(); + std::copy(std::begin(Sg), std::end(Sg), + linTable.column(tableID, primID, 0)); + } + + // Krg(Sg) + { + const auto& kr = t.getKrgColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 1)); + } + + // Pcgo(Sg) + { + const auto uPress = ::Opm::UnitSystem::measure::pressure; + + const auto& pc = t.getPcogColumn(); + std::transform(std::begin(pc), std::end(pc), + linTable.column(tableID, primID, 2), + [&units, uPress](const double Pc) -> double + { + return units.from_si(uPress, Pc); + }); + } + + // Inform createSatfuncTable() of number of active rows in + // this table. Needed to compute slopes of piecewise linear + // interpolants. + return numActRows; + }); + } + } // Gas + + /// Functions to create linearised, padded, and normalised SOFN output + /// tables from various input saturation function keywords, depending on + /// number of active phases. + namespace Oil { + /// Form normalised SOFN output tables for two-phase runs. + namespace TwoPhase { + /// Create linearised and padded 'TAB' vector entries of + /// normalised two-phase SOFN tables for all saturation function + /// regions from Family Two table data (SOF2 keyword). + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be equal to the + /// number of declared saturation nodes in the simulation + /// run's TABDIMS keyword (Item 3). + /// + /// \param[in] sof2 Collection of SOF2 tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for + /// three-phase SOFN tables. Essentially just a padded copy + /// of the input SOF2 table--with added derivatives. + std::vector + fromSOF2(const std::size_t numRows, + const Opm::TableContainer& sof2) + { + using SOF2 = ::Opm::Sof2Table; + + const auto numTab = sof2.size(); + const auto numDep = std::size_t{1}; // Kro + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&sof2](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = sof2.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // So + { + const auto& So = t.getSoColumn(); + + numActRows = So.size(); + std::copy(std::begin(So), std::end(So), + linTable.column(tableID, primID, 0)); + } + + // Kro(So) + { + const auto& kr = t.getKroColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 1)); + } + + // Inform createSatfuncTable() of number of active rows + // in this table. Needed to compute slopes of piecewise + // linear interpolants. + return numActRows; + }); + } + + /// Create linearised and padded 'TAB' vector entries of + /// normalised two-phase SOFN tables for all saturation function + /// regions from Family One table data (SGOF keyword--G/O System). + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be equal to the + /// number of declared saturation nodes in the simulation + /// run's TABDIMS keyword (Item 3). + /// + /// \param[in] sgof Collection of SGOF tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for + /// two-phase SOFN tables. Corresponds to translated (1-Sg), + /// reverse saturation column (column 1) and reverse column + /// of relative permeability for oil (column 3) from the + /// input SGOF table--with added derivatives. + std::vector + fromSGOF(const std::size_t numRows, + const Opm::TableContainer& sgof) + { + using SGOF = ::Opm::SgofTable; + + const auto numTab = sgof.size(); + const auto numDep = std::size_t{1}; // Kro + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&sgof](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = sgof.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // So + { + const auto& Sg = t.getSgColumn(); + numActRows = Sg.size(); + + auto So = std::vector{}; + So.reserve(numActRows); + + // Two-phase system => So = 1-Sg + std::transform(std::begin(Sg), std::end(Sg), + std::back_inserter(So), + [](const double sg) + { + return 1.0 - sg; + }); + + std::copy(So.rbegin(), So.rend(), + linTable.column(tableID, primID, 0)); + } + + // Kro(So) + { + const auto& kr = t.getKrogColumn(); + + const auto krog = std::vector { + std::begin(kr), std::end(kr) + }; + + std::copy(krog.rbegin(), krog.rend(), + linTable.column(tableID, primID, 1)); + } + + // Inform createSatfuncTable() of number of active rows + // in this table. Needed to compute slopes of piecewise + // linear interpolants. + return numActRows; + }); + } + + /// Create linearised and padded 'TAB' vector entries for + /// normalised two-phase SOFN tables for all saturation function + /// regions from Family One table data (SWOF keyword--O/W System). + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be equal to the + /// number of declared saturation nodes in the simulation + /// run's TABDIMS keyword (Item 3). + /// + /// \param[in] swof Collection of SWOF tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for + /// two-phase SOFN tables. Corresponds to translated (1-Sw), + /// reverse saturation column (column 1) and reverse column + /// of relative permeability for oil (column 3) from the + /// input SWOF table--with added derivatives. + std::vector + fromSWOF(const std::size_t numRows, + const Opm::TableContainer& swof) + { + using SWOF = ::Opm::SwofTable; + + const auto numTab = swof.size(); + const auto numDep = std::size_t{1}; // Kro + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&swof](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = swof.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // So + { + const auto& Sw = t.getSwColumn(); + numActRows = Sw.size(); + + auto So = std::vector{}; + So.reserve(numActRows); + + // Two-phase system => So = 1-Sw + std::transform(std::begin(Sw), std::end(Sw), + std::back_inserter(So), + [](const double sw) + { + return 1.0 - sw; + }); + + std::copy(So.rbegin(), So.rend(), + linTable.column(tableID, primID, 0)); + } + + // Kro(So) + { + const auto& kr = t.getKrowColumn(); + + const auto krow = std::vector { + std::begin(kr), std::end(kr) + }; + + std::copy(krow.rbegin(), krow.rend(), + linTable.column(tableID, primID, 1)); + } + + // Inform createSatfuncTable() of number of active rows + // in this table. Needed to compute slopes of piecewise + // linear interpolants. + return numActRows; + }); + } + } // TwoPhase + + /// Form normalised SOFN output tables for three-phase runs. + namespace ThreePhase { + /// Facility to provide oil saturation and relative permeability + /// look-up based on data in a Family One table. + class DerivedKroFunction + { + public: + /// Constructor + /// + /// \param[in] s Phase saturation values. Increasing Sg in + /// the case of SGOF or increasing Sw in the case of SWOF. + /// + /// \param[in] kro Relative permeability for oil. Should be + /// the decreasing KrOG column in the case of SGOF or the + /// decreasing KrOW column in the case of SWOF. + /// + /// \param[in] So_off Oil saturation offset through which to + /// convert input phase saturation values to saturation + /// values for oil. Should be (1 - Sw_conn) in the case + /// of SGOF and 1.0 for the case of SWOF. + DerivedKroFunction(std::vector s, + std::vector kro, + const double So_off) + : s_ (std::move(s)) + , kro_ (std::move(kro)) + , So_off_(So_off) + {} + + /// Get oil saturation at particular node. + /// + /// \param[in] i Saturation node identifier. + /// + /// \return Oil saturation at node \p i. + double So(const std::size_t i) const + { + return this->So_off_ - this->s_[i]; + } + + /// Get relative permeability for oil at particular node. + /// + /// \param[in] i Saturation node identifier. + /// + /// \return Relative permeability for oil at node \p i. + double Kro(const std::size_t i) const + { + return this->kro_[i]; + } + + /// Get relative permeability for oil at particular oil + /// saturation. + /// + /// Uses piecewise linear interpolation in the input KrO + /// table. + /// + /// \param[in] So Oil saturation. + /// + /// \return Relative permeability for oil at So. + double Kro(const double So) const + { + const auto s = this->So_off_ - So; + + auto b = std::begin(this->s_); + auto e = std::end (this->s_); + auto p = std::lower_bound(b, e, s); + + if (p == b) { return this->kro_.front(); } + if (p == e) { return this->kro_.back (); } + + const auto i = p - b; // *Right-hand* end-point. + + const auto sl = this->s_ [i - 1]; + const auto yl = this->kro_[i - 1]; + + const auto sr = this->s_ [i - 0]; + const auto yr = this->kro_[i - 0]; + + const auto t = (s - sl) / (sr - sl); + + return t*yr + (1.0 - t)*yl; + } + + /// Retrieve number of active saturation nodes in this + /// table. + std::vector::size_type size() const + { + return this->s_.size(); + } + + private: + /// Input phase saturation. Sg or Sw. + std::vector s_; + + /// Input relative permeabilty for oil. KrOG or KrOW. + std::vector kro_; + + /// Oil saturation offset through which to convert between + /// input phase saturation and oil saturation. + double So_off_; + }; + + /// Pair of saturation node index and saturation function table. + struct TableElement { + /// Which numeric table to use for look-up. + std::size_t function; + + /// Saturation node ID within 'function'. + std::size_t index; + }; + + // S{G,W}OF tables have KrOX data in terms of increasing phase + // saturation for Gas and Water, respectively, so we need to + // traverse those tables in the opposite direction in order to + // generate the KrOX values in terms of increasing phase + // saturation for Oil. + std::vector + makeReverseRange(const std::size_t function, + const std::size_t n) + { + auto ret = std::vector{}; + ret.reserve(n); + + for (auto i = n; i > 0; --i) { + ret.push_back( TableElement { + function, i - 1 + }); + } + + return ret; + } + + // Join derived KrO functions on common saturation values for + // oil. Heavy lifting by std::set_union() to avoid outputting + // common oil saturation values more than once. Relies on input + // tables having sorted phase saturation values (required by ECL + // format). + std::vector + mergeTables(const std::vector& t) + { + auto ret = std::vector{}; + + const auto t0 = makeReverseRange(0, t[0].size()); + const auto t1 = makeReverseRange(1, t[1].size()); + + ret.reserve(t0.size() + t1.size()); + + std::set_union(std::begin(t0), std::end(t0), + std::begin(t1), std::end(t1), + std::back_inserter(ret), + [&t](const TableElement& e1, const TableElement& e2) + { + return t[e1.function].So(e1.index) + < t[e2.function].So(e2.index); + }); + + return ret; + } + + // Create collection of individual columns of single SOF3 table + // through joining input SGOF and SWOF tables on increasing oil + // saturation and appropriate KrOX columns. + std::array, 3> + makeSOF3Table(const Opm::SgofTable& sgof, + const Opm::SwofTable& swof) + { + auto ret = std::array, 3>{}; + + auto tbl = std::vector{}; + tbl.reserve(2); + + // Note: Order between Krow(So) and Krog(So) matters + // here. This order must match the expected column + // order in SOF3--i.e. [ So, Krow, Krog ]. + + // 1) Krow(So) + { + // So = 1.0 - Sw + const auto& Sw = swof.getSwColumn(); + const auto& Krow = swof.getKrowColumn(); + const auto& So_off = 1.0; + + tbl.emplace_back(Sw .vectorCopy(), + Krow.vectorCopy(), So_off); + } + + // 2) Krog(So) + { + // So = (1.0 - Sw_conn) - Sg + const auto& Sg = sgof.getSgColumn(); + const auto& Krog = sgof.getKrogColumn(); + const auto So_off = + 1.0 - swof.getSwColumn()[0]; + + tbl.emplace_back(Sg .vectorCopy(), + Krog.vectorCopy(), So_off); + } + + const auto mrg = mergeTables(tbl); + + for (auto& col : ret) { col.reserve(mrg.size()); } + + for (const auto& row : mrg) { + const auto self = row.function; + const auto other = 1 - row.function; + + // 1) Assign So + ret[0].push_back(tbl[self].So(row.index)); + + // 2) Assign Kro for "self" column (the one that got + // picked for this row). + ret[1 + self].push_back(tbl[self].Kro(row.index)); + + // 3) Assign Kro for "other" column (the one that + // did not get picked for this row). + ret[1 + other].push_back(tbl[other].Kro(ret[0].back())); + } + + return ret; + } + + /// Create linearised and padded 'TAB' vector entries of + /// normalised three-phase SOFN tables for all saturation + /// function regions from Family One table data. + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be twice the number + /// of declared saturation nodes in the simulation run's + /// TABDIMS keyword (Item 3). + /// + /// \param[in] sgof Collection of SGOF tables for all saturation + /// regions. + /// + /// \param[in] swof Collection of SWOF tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for + /// three-phase SOFN tables. Corresponds to column 1 from + /// both of the input SGOF and SWOF tables, as well as column + /// 3 from the input SWOF table and column 3 from the input + /// SGOF table--expanded so as to have values for all oil + /// saturation nodes. Derivatives added in columns 4 and 5. + std::vector + fromSGOFandSWOF(const std::size_t numRows, + const Opm::TableContainer& sgof, + const Opm::TableContainer& swof) + { + using SGOF = ::Opm::SgofTable; + using SWOF = ::Opm::SwofTable; + + const auto numTab = sgof.size(); + const auto numDep = std::size_t{2}; // Krow, Krog + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&sgof, &swof](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto sof3 = + makeSOF3Table(sgof.getTable(tableID), + swof.getTable(tableID)); + + auto numActRows = std::size_t{0}; + + // So + { + const auto& So = sof3[0]; + + numActRows = So.size(); + std::copy(std::begin(So), std::end(So), + linTable.column(tableID, primID, 0)); + } + + // Krow(So) + { + const auto& krow = sof3[1]; + std::copy(std::begin(krow), std::end(krow), + linTable.column(tableID, primID, 1)); + } + + // Krog(So) + { + const auto& krog = sof3[2]; + std::copy(std::begin(krog), std::end(krog), + linTable.column(tableID, primID, 2)); + } + + // Inform createSatfuncTable() of number of active rows + // in this table. Needed to compute slopes of piecewise + // linear interpolants. + return numActRows; + }); + } + + /// Create linearised and padded 'TAB' vector entries of + /// normalised three-phase SOFN tables for all saturation + /// function regions from Family Two table data (SOF3 keyword). + /// + /// \param[in] numRows Number of rows to allocate in the output + /// vector for each table. Expected to be equal to the + /// number of declared saturation nodes in the simulation + /// run's TABDIMS keyword (Item 3). + /// + /// \param[in] sof3 Collection of SOF3 tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for output + /// three-phase SOFN tables. Essentially a padded copy of + /// the input SOF3 tables, \p sof3, with added derivatives. + std::vector + fromSOF3(const std::size_t numRows, + const Opm::TableContainer& sof3) + { + using SOF3 = ::Opm::Sof3Table; + + const auto numTab = sof3.size(); + const auto numDep = std::size_t{2}; // Krow, Krog + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&sof3](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = sof3.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // So + { + const auto& So = t.getSoColumn(); + + numActRows = So.size(); + std::copy(std::begin(So), std::end(So), + linTable.column(tableID, primID, 0)); + } + + // Krow(So) + { + const auto& kr = t.getKrowColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 1)); + } + + // Krog(So) + { + const auto& kr = t.getKrogColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 2)); + } + + // Inform createSatfuncTable() of number of active rows + // in this table. Needed to compute slopes of piecewise + // linear interpolants. + return numActRows; + }); + } + } // ThreePhase + } // Oil + + /// Functions to create linearised, padded, and normalised SWFN output + /// tables from various input saturation function keywords. + namespace Water { + /// Create linearised and padded 'TAB' vector entries of normalised + /// SWFN tables for all saturation function regions from Family Two + /// table data (SWFN keyword). + /// + /// \param[in] numRows Number of rows to allocate for each table in + /// the output vector. Expected to be equal to the number of + /// declared saturation nodes in the simulation run's TABDIMS + /// keyword (Item 3). + /// + /// \param[in] units Active unit system. Needed to convert SI + /// convention capillary pressure values (Pascal) to declared + /// conventions of the run specification. + /// + /// \param[in] swfn Collection of SWFN tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for output + /// SWFN tables. A unit-converted copy of the input table \p + /// swfn with added derivatives. + std::vector + fromSWFN(const std::size_t numRows, + const Opm::UnitSystem& units, + const Opm::TableContainer& swfn) + { + using SWFN = ::Opm::SwfnTable; + + const auto numTab = swfn.size(); + const auto numDep = std::size_t{2}; // Krw, Pcow + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&swfn, &units](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = swfn.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // Sw + { + const auto& Sw = t.getSwColumn(); + + numActRows = Sw.size(); + std::copy(std::begin(Sw), std::end(Sw), + linTable.column(tableID, primID, 0)); + } + + // Krw(Sw) + { + const auto& kr = t.getKrwColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 1)); + } + + // Pcow(Sw) + { + const auto uPress = ::Opm::UnitSystem::measure::pressure; + + const auto& pc = t.getPcowColumn(); + std::transform(std::begin(pc), std::end(pc), + linTable.column(tableID, primID, 2), + [&units, uPress](const double Pc) -> double + { + return units.from_si(uPress, Pc); + }); + } + + // Inform createSatfuncTable() of number of active rows in + // this table. Needed to compute slopes of piecewise linear + // interpolants. + return numActRows; + }); + } + + /// Create linearised and padded 'TAB' vector entries of normalised + /// SWFN tables for all saturation function regions from Family One + /// table data (SWOF keyword). + /// + /// \param[in] numRows Number of rows to allocate for each table in + /// the output vector. Expected to be equal to the number of + /// declared saturation nodes in the simulation run's TABDIMS + /// keyword (Item 3). + /// + /// \param[in] units Active unit system. Needed to convert SI + /// convention capillary pressure values (Pascal) to declared + /// conventions of the run specification. + /// + /// \param[in] swof Collection of SWOF tables for all saturation + /// regions. + /// + /// \return Linearised and padded 'TAB' vector values for output + /// SWFN tables. Corresponds to unit-converted copies of columns + /// 1, 2, and 4--with added derivatives--of the input SWOF tables. + std::vector + fromSWOF(const std::size_t numRows, + const Opm::UnitSystem& units, + const Opm::TableContainer& swof) + { + using SWOF = ::Opm::SwofTable; + + const auto numTab = swof.size(); + const auto numDep = std::size_t{2}; // Krw, Pcow + + return detail::createSatfuncTable(numTab, numRows, numDep, + [&swof, &units](const std::size_t tableID, + const std::size_t primID, + Opm::LinearisedOutputTable& linTable) + -> std::size_t + { + const auto& t = swof.getTable(tableID); + + auto numActRows = std::size_t{0}; + + // Sw + { + const auto& Sw = t.getSwColumn(); + + numActRows = Sw.size(); + std::copy(std::begin(Sw), std::end(Sw), + linTable.column(tableID, primID, 0)); + } + + // Krw(Sw) + { + const auto& kr = t.getKrwColumn(); + std::copy(std::begin(kr), std::end(kr), + linTable.column(tableID, primID, 1)); + } + + // Pcow(Sw) + { + const auto uPress = ::Opm::UnitSystem::measure::pressure; + + const auto& pc = t.getPcowColumn(); + std::transform(std::begin(pc), std::end(pc), + linTable.column(tableID, primID, 2), + [&units, uPress](const double Pc) -> double + { + return units.from_si(uPress, Pc); + }); + } + + // Inform createSatfuncTable() of number of active rows in + // this table. Needed to compute slopes of piecewise linear + // interpolants. + return numActRows; + }); + } + } // Water +}} // Anonymous::SatFunc + namespace Opm { Tables::Tables(const UnitSystem& units) @@ -227,6 +1202,37 @@ namespace Opm { } } + void Tables::addSatFunc(const EclipseState& es) + { + const auto& tabMgr = es.getTableManager(); + const auto& phases = es.runspec().phases(); + const auto gas = phases.active(Phase::GAS); + const auto oil = phases.active(Phase::OIL); + const auto wat = phases.active(Phase::WATER); + const auto threeP = gas && oil && wat; + + const auto famI = // SGOF and/or SWOF + (gas && tabMgr.hasTables("SGOF")) || + (wat && tabMgr.hasTables("SWOF")); + + const auto famII = // SGFN, SOF{2,3}, SWFN + (gas && tabMgr.hasTables("SGFN")) || + (oil && ((threeP && tabMgr.hasTables("SOF3")) || + tabMgr.hasTables("SOF2"))) || + (wat && tabMgr.hasTables("SWFN")); + + if ((famI + famII) != 1) { + // Both Fam I && Fam II or neither of them. Can't have that. + return; // Logging here? + } + else if (famI) { + this->addSatFunc_FamilyOne(es, gas, oil, wat); + } + else { + // Family II + this->addSatFunc_FamilyTwo(es, gas, oil, wat); + } + } const std::vector& Tables::tabdims() const { @@ -238,6 +1244,131 @@ namespace Opm { return this->data_; } + void Tables::addSatFunc_FamilyOne(const EclipseState& es, + const bool gas, + const bool oil, + const bool wat) + { + const auto& tabMgr = es.getTableManager(); + const auto& tabd = es.runspec().tabdims(); + const auto nssfun = tabd.getNumSatNodes(); + + if (gas) { + const auto& tables = tabMgr.getSgofTables(); + + const auto sgfn = + SatFunc::Gas::fromSGOF(nssfun, this->units_, tables); + + this->addData(TABDIMS_IBSGFN_OFFSET_ITEM, sgfn); + this->tabdims_[TABDIMS_NSSGFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSGFN_ITEM] = tables.size(); + } + + if (oil) { + if (gas && !wat) { // 2p G/O System + const auto& tables = tabMgr.getSgofTables(); + + const auto sofn = + SatFunc::Oil::TwoPhase::fromSGOF(nssfun, tables); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + } + else if (wat && !gas) { // 2p O/W System + const auto& tables = tabMgr.getSwofTables(); + + const auto sofn = + SatFunc::Oil::TwoPhase::fromSWOF(nssfun, tables); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + } + else { // 3p G/O/W System + const auto& sgof = tabMgr.getSgofTables(); + const auto& swof = tabMgr.getSwofTables(); + + // Allocate 2*nssfun rows to account for table merging. + + const auto numRows = 2 * nssfun; + + const auto sofn = SatFunc::Oil::ThreePhase:: + fromSGOFandSWOF(numRows, sgof, swof); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + this->tabdims_[TABDIMS_NSSOFN_ITEM] = numRows; + this->tabdims_[TABDIMS_NTSOFN_ITEM] = sgof.size(); + } + } + + if (wat) { + const auto& tables = tabMgr.getSwofTables(); + + const auto swfn = + SatFunc::Water::fromSWOF(nssfun, this->units_, tables); + + this->addData(TABDIMS_IBSWFN_OFFSET_ITEM, swfn); + this->tabdims_[TABDIMS_NSSWFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSWFN_ITEM] = tables.size(); + } + } + + void Tables::addSatFunc_FamilyTwo(const EclipseState& es, + const bool gas, + const bool oil, + const bool wat) + { + const auto& tabMgr = es.getTableManager(); + const auto& tabd = es.runspec().tabdims(); + const auto nssfun = tabd.getNumSatNodes(); + + if (gas) { + const auto& tables = tabMgr.getSgfnTables(); + + const auto sgfn = + SatFunc::Gas::fromSGFN(nssfun, this->units_, tables); + + this->addData(TABDIMS_IBSGFN_OFFSET_ITEM, sgfn); + this->tabdims_[TABDIMS_NSSGFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSGFN_ITEM] = tables.size(); + } + + if (oil) { + if (gas + wat == 1) { // 2p G/O or O/W System + const auto& tables = tabMgr.getSof2Tables(); + + const auto sofn = + SatFunc::Oil::TwoPhase::fromSOF2(nssfun, tables); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + } + else { // 3p G/O/W System + const auto& tables = tabMgr.getSof3Tables(); + + const auto sofn = + SatFunc::Oil::ThreePhase::fromSOF3(nssfun, tables); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + } + } + + if (wat) { + const auto& tables = tabMgr.getSwfnTables(); + + const auto swfn = + SatFunc::Water::fromSWFN(nssfun, this->units_, tables); + + this->addData(TABDIMS_IBSWFN_OFFSET_ITEM, swfn); + this->tabdims_[TABDIMS_NSSWFN_ITEM] = nssfun; + this->tabdims_[TABDIMS_NTSWFN_ITEM] = tables.size(); + } + } + void fwrite(const Tables& tables, ERT::FortIO& fortio) { diff --git a/opm/output/eclipse/Tables.hpp b/opm/output/eclipse/Tables.hpp index c65b2b2..af14a66 100644 --- a/opm/output/eclipse/Tables.hpp +++ b/opm/output/eclipse/Tables.hpp @@ -29,9 +29,9 @@ #include #include - namespace Opm { class UnitSystem; + class EclipseState; class Tables { public: @@ -42,6 +42,13 @@ namespace Opm { void addPVTW(const PvtwTable& pvtwTable); void addDensity(const DensityTable& density); + /// Add normalised saturation 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"). + void addSatFunc(const EclipseState& es); + /// Acquire read-only reference to internal TABDIMS vector. const std::vector& tabdims() const; @@ -55,6 +62,40 @@ namespace Opm { void addData(const std::size_t offset_index, const std::vector& new_data); + + /// Add saturation function tables corresponding to family I (SGOF, + /// SWOF) 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. + /// + /// \param[in] gas Whether or not gas is active the current run. + /// + /// \param[in] oil Whether or not oil is active the current run. + /// + /// \param[in] wat Whether or not water is active the current run. + void addSatFunc_FamilyOne(const EclipseState& es, + const bool gas, + const bool oil, + const bool wat); + + /// Add saturation function tables corresponding to family II (SGFN, + /// SOF{2,3}, SWFN) 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. + /// + /// \param[in] gas Whether or not gas is active the current run. + /// + /// \param[in] oil Whether or not oil is active the current run. + /// + /// \param[in] wat Whether or not water is active the current run. + void addSatFunc_FamilyTwo(const EclipseState& es, + const bool gas, + const bool oil, + const bool wat); }; /// Emit normalised tabular information (TABDIMS and TAB vectors) to diff --git a/tests/test_Tables.cpp b/tests/test_Tables.cpp index 10361fc..a64aa35 100644 --- a/tests/test_Tables.cpp +++ b/tests/test_Tables.cpp @@ -23,12 +23,19 @@ #define BOOST_TEST_DYN_LINK #endif -#define BOOST_TEST_MODULE Wells +#define BOOST_TEST_MODULE Tabular_INIT_Output #include + +#include + #include -#include +#include +#include #include +#include +#include +#include #include #include @@ -36,10 +43,6 @@ #include #include -#include -#include -#include - #include #include #include @@ -65,8 +68,1121 @@ struct setup { }; +namespace { + template + void check_is_close(const Collection1& c1, const Collection2& c2) + { + BOOST_REQUIRE_EQUAL(c1.size(), c2.size()); + + if (! c1.empty()) { + auto i1 = c1.begin(), e1 = c1.end(); + auto i2 = c2.begin(); + + for (; i1 != e1; ++i1, ++i2) { + BOOST_CHECK_CLOSE(*i1, *i2, 1.0e-10); + } + } + } + + std::vector + makeTable(const std::size_t ncol, + std::initializer_list data) + { + auto result = std::vector(data.size(), 0.0); + const auto nrows = data.size() / ncol; + + auto di = std::begin(data); + for (auto i = 0*nrows; i < nrows; ++i) { + for (auto j = 0*ncol; j < ncol; ++j, ++di) { + result[i + j*nrows] = *di; + } + } + + return result; + } + + namespace SPE1 { // Family II (SGFN, SOF{2,3}, SWFN) + namespace TwoPhase { + namespace GasOil { + Opm::EclipseState satfuncTables() + { + const auto* input = R"( +RUNSPEC +OIL +GAS + +METRIC + +DIMENS + 1 1 1 / + +TABDIMS +/ + +-- ======================================= +GRID + +DXV + 1 / + +DYV + 1 / + +DZV + 0.1 / + +DEPTHZ + 4*2000.0 / + +PERMX + 100.0 / + +COPY + 'PERMX' 'PERMY' / + 'PERMX' 'PERMZ' / +/ + +MULTIPLY + 'PERMZ' 0.1 / +/ + +PORO + 0.3 / + +-- ======================================= +PROPS + +SGFN +-- SPE 1 Table + 0 0 0 + 0.001 0 0 + 0.02 0 0 + 0.05 0.005 0 + 0.12 0.025 0 + 0.2 0.075 0 + 0.25 0.125 0 + 0.3 0.190 0 + 0.4 0.410 0 + 0.45 0.60 0 + 0.5 0.72 0 + 0.6 0.87 0 + 0.7 0.94 0 + 0.85 0.98 0 + 0.88 0.984 0 / + +SOF2 +-- SPE 1 Table + 0 0 + 0.03 0 + 0.18 0 + 0.28 0.0001 + 0.38 0.001 + 0.43 0.01 + 0.48 0.021 + 0.58 0.09 + 0.63 0.2 + 0.68 0.35 + 0.76 0.7 + 0.83 0.98 + 0.86 0.997 + 0.879 1 + 0.88 1 / + +DENSITY + 853.0 1014.0 0.75 / + +END +)"; + + const auto deck = Opm::Deck{ + Opm::Parser{}.parseString(input, Opm::ParseContext{}) + }; + + return {deck, Opm::ParseContext{}}; + } + + std::vector expect_SGFN() + { + return makeTable(5, { + 0, 0, 0, 1.000000000000000e+20, 1.0e+20, + 1.00e-03, 0, 0, 0, 0, + 2.00e-02, 0, 0, 0, 0, + 5.00e-02, 5.000000000000000e-03, 0, 1.666666666666667e-01, 0, + 1.20e-01, 2.500000000000000e-02, 0, 2.857142857142858e-01, 0, + 2.00e-01, 7.500000000000000e-02, 0, 6.249999999999998e-01, 0, + 2.50e-01, 1.250000000000000e-01, 0, 1.000000000000000e+00, 0, + 3.00e-01, 1.900000000000000e-01, 0, 1.300000000000000e+00, 0, + 4.00e-01, 4.100000000000000e-01, 0, 2.199999999999999e+00, 0, + 4.50e-01, 6.000000000000000e-01, 0, 3.800000000000001e+00, 0, + 5.00e-01, 7.200000000000000e-01, 0, 2.400000000000000e+00, 0, + 6.00e-01, 8.700000000000000e-01, 0, 1.500000000000001e+00, 0, + 7.00e-01, 9.399999999999999e-01, 0, 6.999999999999996e-01, 0, + 8.50e-01, 9.800000000000000e-01, 0, 2.666666666666669e-01, 0, + 8.80e-01, 9.840000000000000e-01, 0, 1.333333333333333e-01, 0, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + }); + } + + std::vector expect_SOFN() + { + return makeTable(3, { + 0, 0, 1.000000000000000e+20, + 3.00e-02, 0, 0, + 1.80e-01, 0, 0, + 2.80e-01, 1.00e-04, 9.999999999999998e-04, + 3.80e-01, 1.00e-03, 9.000000000000001e-03, + 4.30e-01, 1.00e-02, 1.800000000000000e-01, + 4.80e-01, 2.10e-02, 2.200000000000001e-01, + 5.80e-01, 9.00e-02, 6.900000000000001e-01, + 6.30e-01, 2.00e-01, 2.199999999999998e+00, + 6.80e-01, 3.50e-01, 2.999999999999997e+00, + 7.60e-01, 7.00e-01, 4.375000000000002e+00, + 8.30e-01, 9.80e-01, 4.000000000000004e+00, + 8.60e-01, 9.97e-01, 5.666666666666667e-01, + 8.79e-01, 1.00e+00, 1.578947368421053e-01, + 8.80e-01, 1.00e+00, 0, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + }); + } + } // GasOil + + namespace OilWater { + Opm::EclipseState satfuncTables() + { + const auto* input = R"( +RUNSPEC +WATER +OIL + +METRIC + +DIMENS + 1 1 1 / + +TABDIMS +/ + +-- ======================================= +GRID + +DXV + 1 / + +DYV + 1 / + +DZV + 0.1 / + +DEPTHZ + 4*2000.0 / + +PERMX + 100.0 / + +COPY + 'PERMX' 'PERMY' / + 'PERMX' 'PERMZ' / +/ + +MULTIPLY + 'PERMZ' 0.1 / +/ + +PORO + 0.3 / + +-- ======================================= +PROPS + +SWFN +-- SPE 1 Table + 0.12 0 0 + 0.18 4.64876033057851E-008 0 + 0.24 0.000000186 0 + 0.3 4.18388429752066E-007 0 + 0.36 7.43801652892562E-007 0 + 0.42 1.16219008264463E-006 0 + 0.48 1.67355371900826E-006 0 + 0.54 2.27789256198347E-006 0 + 0.6 2.97520661157025E-006 0 + 0.66 3.7654958677686E-006 0 + 0.72 4.64876033057851E-006 0 + 0.78 0.000005625 0 + 0.84 6.69421487603306E-006 0 + 0.91 8.05914256198347E-006 0 + 1 0.00001 0 / + +SOF2 +-- SPE 1 Table + 0 0 + 0.03 0 + 0.18 0 + 0.28 0.0001 + 0.38 0.001 + 0.43 0.01 + 0.48 0.021 + 0.58 0.09 + 0.63 0.2 + 0.68 0.35 + 0.76 0.7 + 0.83 0.98 + 0.86 0.997 + 0.879 1 + 0.88 1 + / + +DENSITY + 853.0 1014.0 0.75 / + +END +)"; + + const auto deck = Opm::Deck{ + Opm::Parser{}.parseString(input, Opm::ParseContext{}) + }; + + return {deck, Opm::ParseContext{}}; + } + + std::vector expect_SOFN() + { + return makeTable(3, { + 0, 0, 1.000000000000000e+20, + 3.00e-02, 0, 0, + 1.80e-01, 0, 0, + 2.80e-01, 1.00e-04, 9.999999999999998e-04, + 3.80e-01, 1.00e-03, 9.000000000000001e-03, + 4.30e-01, 1.00e-02, 1.800000000000000e-01, + 4.80e-01, 2.10e-02, 2.200000000000001e-01, + 5.80e-01, 9.00e-02, 6.900000000000001e-01, + 6.30e-01, 2.00e-01, 2.199999999999998e+00, + 6.80e-01, 3.50e-01, 2.999999999999997e+00, + 7.60e-01, 7.00e-01, 4.375000000000002e+00, + 8.30e-01, 9.80e-01, 4.000000000000004e+00, + 8.60e-01, 9.97e-01, 5.666666666666667e-01, + 8.79e-01, 1.00e+00, 1.578947368421053e-01, + 8.80e-01, 1.00e+00, 0, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.000000000000000e+20, + }); + } + + std::vector expect_SWFN() + { + return makeTable(5, { + 1.20e-01, 0, 0, 1.000000000000000e+20, 1.0e+20, + 1.80e-01, 4.648760330578510e-08, 0, 7.747933884297517e-07, 0, + 2.40e-01, 1.860000000000000e-07, 0, 2.325206611570248e-06, 0, + 3.00e-01, 4.183884297520660e-07, 0, 3.873140495867767e-06, 0, + 3.60e-01, 7.438016528925620e-07, 0, 5.423553719008267e-06, 0, + 4.20e-01, 1.162190082644630e-06, 0, 6.973140495867802e-06, 0, + 4.80e-01, 1.673553719008260e-06, 0, 8.522727272727165e-06, 0, + 5.40e-01, 2.277892561983470e-06, 0, 1.007231404958682e-05, 0, + 6.00e-01, 2.975206611570250e-06, 0, 1.162190082644635e-05, 0, + 6.60e-01, 3.765495867768600e-06, 0, 1.317148760330582e-05, 0, + 7.20e-01, 4.648760330578510e-06, 0, 1.472107438016518e-05, 0, + 7.80e-01, 5.625000000000000e-06, 0, 1.627066115702482e-05, 0, + 8.40e-01, 6.694214876033060e-06, 0, 1.782024793388435e-05, 0, + 9.10e-01, 8.059142561983471e-06, 0, 1.949896694214870e-05, 0, + 1.00e+00, 1.000000000000000e-05, 0, 2.156508264462812e-05, 0, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + }); + } + } // OilWater + } // TwoPhase + + namespace ThreePhase { + Opm::EclipseState satfuncTables() + { + const auto* input = R"( +RUNSPEC +WATER +OIL +GAS + +METRIC + +DIMENS + 1 1 1 / + +TABDIMS +/ + +-- ======================================= +GRID + +DXV + 1 / + +DYV + 1 / + +DZV + 0.1 / + +DEPTHZ + 4*2000.0 / + +PERMX + 100.0 / + +COPY + 'PERMX' 'PERMY' / + 'PERMX' 'PERMZ' / +/ + +MULTIPLY + 'PERMZ' 0.1 / +/ + +PORO + 0.3 / + +-- ======================================= +PROPS + +SWFN +-- SPE 1 Table + 0.12 0 0 + 0.18 4.64876033057851E-008 0 + 0.24 0.000000186 0 + 0.3 4.18388429752066E-007 0 + 0.36 7.43801652892562E-007 0 + 0.42 1.16219008264463E-006 0 + 0.48 1.67355371900826E-006 0 + 0.54 2.27789256198347E-006 0 + 0.6 2.97520661157025E-006 0 + 0.66 3.7654958677686E-006 0 + 0.72 4.64876033057851E-006 0 + 0.78 0.000005625 0 + 0.84 6.69421487603306E-006 0 + 0.91 8.05914256198347E-006 0 + 1 0.00001 0 / + +SGFN +-- SPE 1 Table + 0 0 0 + 0.001 0 0 + 0.02 0 0 + 0.05 0.005 0 + 0.12 0.025 0 + 0.2 0.075 0 + 0.25 0.125 0 + 0.3 0.190 0 + 0.4 0.410 0 + 0.45 0.60 0 + 0.5 0.72 0 + 0.6 0.87 0 + 0.7 0.94 0 + 0.85 0.98 0 + 0.88 0.984 0 / + +SOF3 +-- SPE 1 Table + 0 0 0 + 0.03 0 0 + 0.18 0 0 + 0.28 0.0001 0.0001 + 0.38 0.001 0.001 + 0.43 0.01 0.01 + 0.48 0.021 0.021 + 0.58 0.09 0.09 + 0.63 0.2 0.2 + 0.68 0.35 0.35 + 0.76 0.7 0.7 + 0.83 0.98 0.98 + 0.86 0.997 0.997 + 0.879 1 1 + 0.88 1 1 / + +DENSITY + 853.0 1014.0 0.75 / + +END +)"; + + const auto deck = Opm::Deck{ + Opm::Parser{}.parseString(input, Opm::ParseContext{}) + }; + + return {deck, Opm::ParseContext{}}; + } + + std::vector expect_SGFN() + { + return makeTable(5, { + 0, 0, 0, 1.000000000000000e+20, 1.0e+20, + 1.00e-03, 0, 0, 0, 0, + 2.00e-02, 0, 0, 0, 0, + 5.00e-02, 5.000000000000000e-03, 0, 1.666666666666667e-01, 0, + 1.20e-01, 2.500000000000000e-02, 0, 2.857142857142858e-01, 0, + 2.00e-01, 7.500000000000000e-02, 0, 6.249999999999998e-01, 0, + 2.50e-01, 1.250000000000000e-01, 0, 1.000000000000000e+00, 0, + 3.00e-01, 1.900000000000000e-01, 0, 1.300000000000000e+00, 0, + 4.00e-01, 4.100000000000000e-01, 0, 2.199999999999999e+00, 0, + 4.50e-01, 6.000000000000000e-01, 0, 3.800000000000001e+00, 0, + 5.00e-01, 7.200000000000000e-01, 0, 2.400000000000000e+00, 0, + 6.00e-01, 8.700000000000000e-01, 0, 1.500000000000001e+00, 0, + 7.00e-01, 9.399999999999999e-01, 0, 6.999999999999996e-01, 0, + 8.50e-01, 9.800000000000000e-01, 0, 2.666666666666669e-01, 0, + 8.80e-01, 9.840000000000000e-01, 0, 1.333333333333333e-01, 0, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + }); + } + + std::vector expect_SOFN() + { + return makeTable(5, { + 0, 0, 0, 1.000000000000000e+20, 1.000000000000000e+20, + 3.00e-02, 0, 0, 0, 0, + 1.80e-01, 0, 0, 0, 0, + 2.80e-01, 1.00e-04, 1.00e-04, 9.999999999999998e-04, 9.999999999999998e-04, + 3.80e-01, 1.00e-03, 1.00e-03, 9.000000000000001e-03, 9.000000000000001e-03, + 4.30e-01, 1.00e-02, 1.00e-02, 1.800000000000000e-01, 1.800000000000000e-01, + 4.80e-01, 2.10e-02, 2.10e-02, 2.200000000000001e-01, 2.200000000000001e-01, + 5.80e-01, 9.00e-02, 9.00e-02, 6.900000000000001e-01, 6.900000000000001e-01, + 6.30e-01, 2.00e-01, 2.00e-01, 2.199999999999998e+00, 2.199999999999998e+00, + 6.80e-01, 3.50e-01, 3.50e-01, 2.999999999999997e+00, 2.999999999999997e+00, + 7.60e-01, 7.00e-01, 7.00e-01, 4.375000000000002e+00, 4.375000000000002e+00, + 8.30e-01, 9.80e-01, 9.80e-01, 4.000000000000004e+00, 4.000000000000004e+00, + 8.60e-01, 9.97e-01, 9.97e-01, 5.666666666666667e-01, 5.666666666666667e-01, + 8.79e-01, 1.00e+00, 1.00e+00, 1.578947368421053e-01, 1.578947368421053e-01, + 8.80e-01, 1.00e+00, 1.00e+00, 0, 0, + 1.00e+20, 1.00e+20, 1.00e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.00e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.00e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.00e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.00e+20, 1.00e+20, 1.00e+20, 1.000000000000000e+20, 1.000000000000000e+20, + }); + } + + std::vector expect_SWFN() + { + return makeTable(5, { + 1.20e-01, 0, 0, 1.000000000000000e+20, 1.0e+20, + 1.80e-01, 4.648760330578510e-08, 0, 7.747933884297517e-07, 0, + 2.40e-01, 1.860000000000000e-07, 0, 2.325206611570248e-06, 0, + 3.00e-01, 4.183884297520660e-07, 0, 3.873140495867767e-06, 0, + 3.60e-01, 7.438016528925620e-07, 0, 5.423553719008267e-06, 0, + 4.20e-01, 1.162190082644630e-06, 0, 6.973140495867802e-06, 0, + 4.80e-01, 1.673553719008260e-06, 0, 8.522727272727165e-06, 0, + 5.40e-01, 2.277892561983470e-06, 0, 1.007231404958682e-05, 0, + 6.00e-01, 2.975206611570250e-06, 0, 1.162190082644635e-05, 0, + 6.60e-01, 3.765495867768600e-06, 0, 1.317148760330582e-05, 0, + 7.20e-01, 4.648760330578510e-06, 0, 1.472107438016518e-05, 0, + 7.80e-01, 5.625000000000000e-06, 0, 1.627066115702482e-05, 0, + 8.40e-01, 6.694214876033060e-06, 0, 1.782024793388435e-05, 0, + 9.10e-01, 8.059142561983471e-06, 0, 1.949896694214870e-05, 0, + 1.00e+00, 1.000000000000000e-05, 0, 2.156508264462812e-05, 0, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + 1.00e+20, 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, 1.0e+20, + }); + } + } // ThreePhase + } // SPE1 + + namespace SPE9 { // Family One (SGOF and SWOF) + namespace TwoPhase { + namespace GasOil { + Opm::EclipseState satfuncTables() + { + const auto* input = R"( +RUNSPEC +OIL +GAS + +METRIC + +DIMENS + 1 1 1 / + +TABDIMS + 1 1 30 20 1 20 / + +-- ======================================= +GRID + +DXV + 1 / + +DYV + 1 / + +DZV + 0.1 / + +DEPTHZ + 4*2000.0 / + +PERMX + 100.0 / + +COPY + 'PERMX' 'PERMY' / + 'PERMX' 'PERMZ' / +/ + +MULTIPLY + 'PERMZ' 0.1 / +/ + +PORO + 0.3 / + +-- ======================================= +PROPS + +SGOF +-- SPE 9 Table + 0 0 1.000000000000000e+00 0 + 4.000000000000000e-02 0 6.000000000000000e-01 1.378951458633672e-02 + 1.000000000000000e-01 2.200000000000000e-02 3.300000000000000e-01 3.447378646584180e-02 + 2.000000000000000e-01 1.000000000000000e-01 1.000000000000000e-01 6.894757293168360e-02 + 3.000000000000000e-01 2.400000000000000e-01 2.000000000000000e-02 1.034213593975254e-01 + 4.000000000000000e-01 3.400000000000000e-01 0 1.378951458633672e-01 + 5.000000000000000e-01 4.200000000000000e-01 0 1.723689323292090e-01 + 6.000000000000000e-01 5.000000000000000e-01 0 2.068427187950508e-01 + 7.000000000000000e-01 8.125000000000000e-01 0 2.413165052608926e-01 + 8.489100000000001e-01 9.635000000000000e-01 0 2.633797285990314e-01 / + +DENSITY + 853.0 1014.0 0.75 / + +END +)"; + + const auto deck = Opm::Deck{ + Opm::Parser{}.parseString(input, Opm::ParseContext{}) + }; + + return {deck, Opm::ParseContext{}}; + } + + std::vector expect_SGFN() + { + // Columns 1, 2, 4 (+ derivatives) of SGOF + return makeTable(5, { + 0, 0, 0, 1.000000000000000e+20, 1.000000000000000e+20, + 4.0000e-02, 0, 1.378951458633672e-02, 0, 3.447378646584180e-01, + 1.0000e-01, 2.200e-02, 3.447378646584180e-02, 3.666666666666666e-01, 3.447378646584180e-01, + 2.0000e-01, 1.000e-01, 6.894757293168360e-02, 7.800000000000001e-01, 3.447378646584180e-01, + 3.0000e-01, 2.400e-01, 1.034213593975254e-01, 1.400000000000000e+00, 3.447378646584180e-01, + 4.0000e-01, 3.400e-01, 1.378951458633672e-01, 1.000000000000000e+00, 3.447378646584179e-01, + 5.0000e-01, 4.200e-01, 1.723689323292090e-01, 7.999999999999998e-01, 3.447378646584180e-01, + 6.0000e-01, 5.000e-01, 2.068427187950508e-01, 8.000000000000004e-01, 3.447378646584180e-01, + 7.0000e-01, 8.125e-01, 2.413165052608926e-01, 3.125000000000001e+00, 3.447378646584180e-01, + 8.4891e-01, 9.635e-01, 2.633797285990314e-01, 1.014035323349674e+00, 1.481648199458648e-01, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + }); + } + + std::vector expect_SOFN() + { + // Columns 1 and 3 from SGOF (using So = 1 - Sg in 2p + // system) + derivatives + return makeTable(3, { + 1.510899999999999e-01, 0, 1.000000000000000e+20, + 3.000000000000000e-01, 0, 0, + 4.000000000000000e-01, 0, 0, + 5.000000000000000e-01, 0, 0, + 6.000000000000000e-01, 0, 0, + 7.000000000000000e-01, 2.0e-02, 2.000000000000000e-01, + 8.000000000000000e-01, 1.0e-01, 7.999999999999993e-01, + 9.000000000000000e-01, 3.3e-01, 2.300000000000001e+00, + 9.600000000000000e-01, 6.0e-01, 4.500000000000004e+00, + 1.000000000000000e+00, 1.0e+00, 9.999999999999991e+00, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.0e+20, 1.000000000000000e+20, + }); + } + } // GasOil + + namespace OilWater { + Opm::EclipseState satfuncTables() + { + const auto* input = R"( +RUNSPEC +WATER +OIL + +METRIC + +DIMENS + 1 1 1 / + +TABDIMS + 1 1 30 20 1 20 / + +-- ======================================= +GRID + +DXV + 1 / + +DYV + 1 / + +DZV + 0.1 / + +DEPTHZ + 4*2000.0 / + +PERMX + 100.0 / + +COPY + 'PERMX' 'PERMY' / + 'PERMX' 'PERMZ' / +/ + +MULTIPLY + 'PERMZ' 0.1 / +/ + +PORO + 0.3 / + +-- ======================================= +PROPS + +SWOF +-- SPE 9 Table + 1.510900000000000e-01 0 1.000000000000000e+00 2.757902917267344e+01 + 1.512300000000000e-01 0 9.999700000000000e-01 2.476527872133143e+01 + 1.517400000000000e-01 0 9.999300000000000e-01 1.778295801053983e+01 + 1.524600000000000e-01 0 9.999100000000000e-01 1.284562231290197e+01 + 1.564700000000000e-01 0 9.995100000000000e-01 5.450995115978905e+00 + 1.658500000000000e-01 0 9.962900000000000e-01 2.758592392996661e+00 + 1.783500000000000e-01 0 9.915900000000000e-01 1.925705711981923e+00 + 2.033500000000000e-01 1.000000000000000e-05 9.788300000000000e-01 1.406530487806345e+00 + 2.533500000000000e-01 3.000000000000000e-05 9.437300000000000e-01 1.072134759087680e+00 + 3.500000000000000e-01 2.800000000000000e-04 8.302300000000000e-01 8.035839625187723e-01 + 3.520000000000000e-01 2.292000000000000e-03 8.042770000000000e-01 6.012228359642811e-01 + 3.540000000000000e-01 4.304000000000000e-03 7.783260000000000e-01 4.100312162247224e-01 + 3.560000000000000e-01 6.316000000000000e-03 7.523740000000000e-01 2.286990994143945e-01 + 3.580000000000000e-01 8.328000000000000e-03 7.264220000000000e-01 8.032392246541140e-02 + 3.600000000000000e-01 1.034000000000000e-02 7.004700000000000e-01 3.192272626736951e-02 + 3.643950000000000e-01 1.554800000000000e-02 6.422580000000000e-01 -3.440483889291011e-02 + 3.687900000000000e-01 2.075600000000000e-02 5.840460000000000e-01 -7.853128556918762e-02 + 3.700000000000000e-01 2.219000000000000e-02 5.680200000000000e-01 -8.232340208043021e-02 + 3.800000000000000e-01 3.589000000000000e-02 4.349800000000000e-01 -1.066618953253145e-01 + 4.000000000000000e-01 6.952999999999999e-02 1.714300000000000e-01 -1.105919069824205e-01 + 4.334500000000000e-01 8.790000000000001e-02 1.253100000000000e-01 -1.179003497131789e-01 + 4.613900000000000e-01 1.049100000000000e-01 9.497999999999999e-02 -1.227266798183968e-01 + 4.893200000000000e-01 1.232900000000000e-01 7.053000000000000e-02 -1.282424856529315e-01 + 5.172500000000000e-01 1.430300000000000e-01 5.113000000000000e-02 -1.330688157581493e-01 + 5.731200000000000e-01 1.865900000000000e-01 2.464000000000000e-02 -1.427214759685850e-01 + 6.010600000000000e-01 2.103800000000000e-01 1.619000000000000e-02 -1.468583303444861e-01 + 6.569300000000000e-01 2.619000000000000e-01 5.940000000000000e-03 -1.558215148256049e-01 + 7.128000000000000e-01 3.186500000000000e-01 1.590000000000000e-03 -1.640952235774069e-01 + 8.111100000000000e-01 4.309200000000000e-01 2.000000000000000e-05 -1.792636896223773e-01 + 8.814900000000000e-01 4.900000000000000e-01 0 -1.896058255621299e-01 / + +DENSITY + 853.0 1014.0 0.75 / + +END +)"; + + const auto deck = Opm::Deck{ + Opm::Parser{}.parseString(input, Opm::ParseContext{}) + }; + + return {deck, Opm::ParseContext{}}; + } + + std::vector expect_SOFN() + { + return makeTable(3, { + 1.185100000000000e-01, 0, 1.000000000000000e+20, + 1.888900000000000e-01, 2.000000000000000e-05, 2.841716396703610e-04, + 2.872000000000000e-01, 1.590000000000000e-03, 1.596989116061438e-02, + 3.430700000000000e-01, 5.940000000000000e-03, 7.785931626991233e-02, + 3.989400000000000e-01, 1.619000000000000e-02, 1.834616073026670e-01, + 4.268800000000000e-01, 2.464000000000000e-02, 3.024337866857543e-01, + 4.827500000000000e-01, 5.113000000000000e-02, 4.741363880436731e-01, + 5.106800000000000e-01, 7.053000000000000e-02, 6.945936269244535e-01, + 5.386100000000000e-01, 9.497999999999999e-02, 8.754027926960254e-01, + 5.665500000000000e-01, 1.253100000000000e-01, 1.085540443808162e+00, + 6.000000000000000e-01, 1.714300000000000e-01, 1.378774289985053e+00, + 6.200000000000000e-01, 4.349800000000000e-01, 1.317749999999999e+01, + 6.300000000000000e-01, 5.680200000000000e-01, 1.330399999999999e+01, + 6.312100000000000e-01, 5.840460000000000e-01, 1.324462809917306e+01, + 6.356050000000000e-01, 6.422580000000000e-01, 1.324505119453948e+01, + 6.400000000000000e-01, 7.004700000000000e-01, 1.324505119453914e+01, + 6.420000000000000e-01, 7.264220000000000e-01, 1.297599999999998e+01, + 6.440000000000000e-01, 7.523740000000000e-01, 1.297599999999998e+01, + 6.460000000000000e-01, 7.783260000000000e-01, 1.297599999999998e+01, + 6.480000000000000e-01, 8.042770000000000e-01, 1.297550000000002e+01, + 6.500000000000000e-01, 8.302300000000000e-01, 1.297649999999999e+01, + 7.466500000000000e-01, 9.437300000000000e-01, 1.174340403517847e+00, + 7.966500000000000e-01, 9.788300000000000e-01, 7.020000000000013e-01, + 8.216500000000000e-01, 9.915900000000000e-01, 5.103999999999993e-01, + 8.341499999999999e-01, 9.962900000000000e-01, 3.760000000000043e-01, + 8.435300000000000e-01, 9.995100000000000e-01, 3.432835820895503e-01, + 8.475400000000000e-01, 9.999100000000000e-01, 9.975062344138656e-02, + 8.482600000000000e-01, 9.999300000000000e-01, 2.777777777780348e-02, + 8.487700000000000e-01, 9.999700000000000e-01, 7.843137254909643e-02, + 8.489100000000001e-01, 1.000000000000000e+00, 2.142857142854877e-01, + }); + } + + std::vector expect_SWFN() + { + // Columns 1, 2, 4 (+ derivatives) of SWOF + return makeTable(5, { + 1.51090e-01, 0, 2.757902917267344e+01, 1.000000000000000e+20, 1.000000000000000e+20, + 1.51230e-01, 0, 2.476527872133143e+01, 0, -2.009821750958577e+04, + 1.51740e-01, 0, 1.778295801053983e+01, 0, -1.369082492312075e+04, + 1.52460e-01, 0, 1.284562231290197e+01, 0, -6.857410691163744e+03, + 1.56470e-01, 0, 5.450995115978905e+00, 0, -1.844046682524494e+03, + 1.65850e-01, 0, 2.758592392996661e+00, 0, -2.870365376313702e+02, + 1.78350e-01, 0, 1.925705711981923e+00, 0, -6.663093448117903e+01, + 2.03350e-01, 1.000000000000000e-05, 1.406530487806345e+00, 4.000000000000000e-04, -2.076700896702310e+01, + 2.53350e-01, 3.000000000000000e-05, 1.072134759087680e+00, 4.000000000000000e-04, -6.687914574373308e+00, + 3.50000e-01, 2.800000000000000e-04, 8.035839625187723e-01, 2.586652871184700e-03, -2.778590756015570e+00, + 3.52000e-01, 2.292000000000000e-03, 6.012228359642811e-01, 1.006000000000000e+00, -1.011805632772457e+02, + 3.54000e-01, 4.304000000000000e-03, 4.100312162247224e-01, 1.006000000000000e+00, -9.559580986977932e+01, + 3.56000e-01, 6.316000000000000e-03, 2.286990994143945e-01, 1.006000000000000e+00, -9.066605840516394e+01, + 3.58000e-01, 8.328000000000000e-03, 8.032392246541140e-02, 1.006000000000000e+00, -7.418758847449155e+01, + 3.60000e-01, 1.034000000000000e-02, 3.192272626736951e-02, 1.006000000000000e+00, -2.420059809902094e+01, + 3.64395e-01, 1.554800000000000e-02, -3.440483889291011e-02, 1.184982935153600e+00, -1.509159616843634e+01, + 3.68790e-01, 2.075600000000000e-02, -7.853128556918762e-02, 1.184982935153600e+00, -1.004014713908486e+01, + 3.70000e-01, 2.219000000000000e-02, -8.232340208043021e-02, 1.185123966942200e+00, -3.133980587803838e+00, + 3.80000e-01, 3.589000000000000e-02, -1.066618953253145e-01, 1.370000000000000e+00, -2.433849324488431e+00, + 4.00000e-01, 6.952999999999999e-02, -1.105919069824205e-01, 1.682000000000000e+00, -1.965005828552983e-01, + 4.33450e-01, 8.790000000000001e-02, -1.179003497131789e-01, 5.491778774290000e-01, -2.184885719210279e-01, + 4.61390e-01, 1.049100000000000e-01, -1.227266798183968e-01, 6.088045812455301e-01, -1.727390875167428e-01, + 4.89320e-01, 1.232900000000000e-01, -1.282424856529315e-01, 6.580737558181200e-01, -1.974867824752831e-01, + 5.17250e-01, 1.430300000000000e-01, -1.330688157581493e-01, 7.067669172932300e-01, -1.728009346658736e-01, + 5.73120e-01, 1.865900000000000e-01, -1.427214759685850e-01, 7.796670843028500e-01, -1.727700055563935e-01, + 6.01060e-01, 2.103800000000000e-01, -1.468583303444861e-01, 8.514674302075900e-01, -1.480620750143510e-01, + 6.56930e-01, 2.619000000000000e-01, -1.558215148256049e-01, 9.221406837300899e-01, -1.604292908737955e-01, + 7.12800e-01, 3.186500000000000e-01, -1.640952235774069e-01, 1.015750850187900e+00, -1.480885761911974e-01, + 8.11110e-01, 4.309200000000000e-01, -1.792636896223773e-01, 1.141999796561900e+00, -1.542921986061490e-01, + 8.81490e-01, 4.900000000000000e-01, -1.896058255621299e-01, 8.394430235862500e-01, -1.469470863846619e-01, + }); + } + } // OilWater + } // TwoPhase + + namespace ThreePhase { + Opm::EclipseState satfuncTables() + { + const auto* input = R"( +RUNSPEC +WATER +OIL +GAS + +METRIC + +DIMENS + 1 1 1 / + +TABDIMS + 1 1 30 20 1 20 / + +-- ======================================= +GRID +DXV + 1 / +DYV + 1 / + +DZV + 0.1 / + +DEPTHZ + 4*2000.0 / + +PERMX + 100.0 / + +COPY + 'PERMX' 'PERMY' / + 'PERMX' 'PERMZ' / +/ + +MULTIPLY + 'PERMZ' 0.1 / +/ + +PORO + 0.3 / + +-- ======================================= +PROPS + +SWOF +-- SPE 9 Table + 1.510900000000000e-01 0 1.000000000000000e+00 2.757902917267344e+01 + 1.512300000000000e-01 0 9.999700000000000e-01 2.476527872133143e+01 + 1.517400000000000e-01 0 9.999300000000000e-01 1.778295801053983e+01 + 1.524600000000000e-01 0 9.999100000000000e-01 1.284562231290197e+01 + 1.564700000000000e-01 0 9.995100000000000e-01 5.450995115978905e+00 + 1.658500000000000e-01 0 9.962900000000000e-01 2.758592392996661e+00 + 1.783500000000000e-01 0 9.915900000000000e-01 1.925705711981923e+00 + 2.033500000000000e-01 1.000000000000000e-05 9.788300000000000e-01 1.406530487806345e+00 + 2.533500000000000e-01 3.000000000000000e-05 9.437300000000000e-01 1.072134759087680e+00 + 3.500000000000000e-01 2.800000000000000e-04 8.302300000000000e-01 8.035839625187723e-01 + 3.520000000000000e-01 2.292000000000000e-03 8.042770000000000e-01 6.012228359642811e-01 + 3.540000000000000e-01 4.304000000000000e-03 7.783260000000000e-01 4.100312162247224e-01 + 3.560000000000000e-01 6.316000000000000e-03 7.523740000000000e-01 2.286990994143945e-01 + 3.580000000000000e-01 8.328000000000000e-03 7.264220000000000e-01 8.032392246541140e-02 + 3.600000000000000e-01 1.034000000000000e-02 7.004700000000000e-01 3.192272626736951e-02 + 3.643950000000000e-01 1.554800000000000e-02 6.422580000000000e-01 -3.440483889291011e-02 + 3.687900000000000e-01 2.075600000000000e-02 5.840460000000000e-01 -7.853128556918762e-02 + 3.700000000000000e-01 2.219000000000000e-02 5.680200000000000e-01 -8.232340208043021e-02 + 3.800000000000000e-01 3.589000000000000e-02 4.349800000000000e-01 -1.066618953253145e-01 + 4.000000000000000e-01 6.952999999999999e-02 1.714300000000000e-01 -1.105919069824205e-01 + 4.334500000000000e-01 8.790000000000001e-02 1.253100000000000e-01 -1.179003497131789e-01 + 4.613900000000000e-01 1.049100000000000e-01 9.497999999999999e-02 -1.227266798183968e-01 + 4.893200000000000e-01 1.232900000000000e-01 7.053000000000000e-02 -1.282424856529315e-01 + 5.172500000000000e-01 1.430300000000000e-01 5.113000000000000e-02 -1.330688157581493e-01 + 5.731200000000000e-01 1.865900000000000e-01 2.464000000000000e-02 -1.427214759685850e-01 + 6.010600000000000e-01 2.103800000000000e-01 1.619000000000000e-02 -1.468583303444861e-01 + 6.569300000000000e-01 2.619000000000000e-01 5.940000000000000e-03 -1.558215148256049e-01 + 7.128000000000000e-01 3.186500000000000e-01 1.590000000000000e-03 -1.640952235774069e-01 + 8.111100000000000e-01 4.309200000000000e-01 2.000000000000000e-05 -1.792636896223773e-01 + 8.814900000000000e-01 4.900000000000000e-01 0 -1.896058255621299e-01 / + +SGOF +-- SPE 9 Table + 0 0 1.000000000000000e+00 0 + 4.000000000000000e-02 0 6.000000000000000e-01 1.378951458633672e-02 + 1.000000000000000e-01 2.200000000000000e-02 3.300000000000000e-01 3.447378646584180e-02 + 2.000000000000000e-01 1.000000000000000e-01 1.000000000000000e-01 6.894757293168360e-02 + 3.000000000000000e-01 2.400000000000000e-01 2.000000000000000e-02 1.034213593975254e-01 + 4.000000000000000e-01 3.400000000000000e-01 0 1.378951458633672e-01 + 5.000000000000000e-01 4.200000000000000e-01 0 1.723689323292090e-01 + 6.000000000000000e-01 5.000000000000000e-01 0 2.068427187950508e-01 + 7.000000000000000e-01 8.125000000000000e-01 0 2.413165052608926e-01 + 8.489100000000001e-01 9.635000000000000e-01 0 2.633797285990314e-01 / + +DENSITY + 853.0 1014.0 0.75 / + +END +)"; + + const auto deck = Opm::Deck{ + Opm::Parser{}.parseString(input, Opm::ParseContext{}) + }; + + return {deck, Opm::ParseContext{}}; + } + + std::vector expect_SGFN() + { + // Columns 1, 2, 4 (+ derivatives) of SGOF + return makeTable(5, { + 0, 0, 0, 1.000000000000000e+20, 1.000000000000000e+20, + 4.0000e-02, 0, 1.378951458633672e-02, 0, 3.447378646584180e-01, + 1.0000e-01, 2.200e-02, 3.447378646584180e-02, 3.666666666666666e-01, 3.447378646584180e-01, + 2.0000e-01, 1.000e-01, 6.894757293168360e-02, 7.800000000000001e-01, 3.447378646584180e-01, + 3.0000e-01, 2.400e-01, 1.034213593975254e-01, 1.400000000000000e+00, 3.447378646584180e-01, + 4.0000e-01, 3.400e-01, 1.378951458633672e-01, 1.000000000000000e+00, 3.447378646584179e-01, + 5.0000e-01, 4.200e-01, 1.723689323292090e-01, 7.999999999999998e-01, 3.447378646584180e-01, + 6.0000e-01, 5.000e-01, 2.068427187950508e-01, 8.000000000000004e-01, 3.447378646584180e-01, + 7.0000e-01, 8.125e-01, 2.413165052608926e-01, 3.125000000000001e+00, 3.447378646584180e-01, + 8.4891e-01, 9.635e-01, 2.633797285990314e-01, 1.014035323349674e+00, 1.481648199458648e-01, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.0000e+20, 1.000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + }); + } + + std::vector expect_SOFN() + { + // Column 1 from SGOF merged with column 1 from SWOF, Column 3 from + // SWOF (+ piecewise linear interp), Column 3 from SGOF (+piecewise + // linear interp) + derivatives of those. + return makeTable(5, { + 0, 0, 0, 1.000000000000000e+20, 1.000000000000000e+20, + 1.185100000000000e-01, 0, 0, 0, 0, + 1.489100000000001e-01, 8.638817845978999e-06, 0, 2.841716396703609e-04, 0, + 1.888900000000000e-01, 2.000000000000000e-05, 0, 2.841716396703610e-04, 0, + 2.489100000000001e-01, 9.785128674600764e-04, 0, 1.596989116061438e-02, 0, + 2.872000000000000e-01, 1.590000000000000e-03, 0, 1.596989116061438e-02, 0, + 3.430700000000000e-01, 5.940000000000000e-03, 0, 7.785931626991233e-02, 0, + 3.489100000000001e-01, 7.011415786647587e-03, 0, 1.834616073026669e-01, 0, + 3.989400000000000e-01, 1.619000000000000e-02, 0, 1.834616073026670e-01, 0, + 4.268800000000000e-01, 2.464000000000000e-02, 0, 3.024337866857543e-01, 0, + 4.489100000000000e-01, 3.508522462860211e-02, 0, 4.741363880436730e-01, 0, + 4.827500000000000e-01, 5.113000000000000e-02, 6.767999999999998e-03, 4.741363880436731e-01, 2.000000000000000e-01, + 5.106800000000000e-01, 7.053000000000000e-02, 1.235400000000000e-02, 6.945936269244535e-01, 2.000000000000000e-01, + 5.386100000000000e-01, 9.497999999999999e-02, 1.794000000000000e-02, 8.754027926960254e-01, 2.000000000000001e-01, + 5.489100000000000e-01, 1.061610665712240e-01, 2.000000000000000e-02, 1.085540443808162e+00, 2.000000000000001e-01, + 5.665500000000000e-01, 1.253100000000000e-01, 3.411199999999998e-02, 1.085540443808162e+00, 7.999999999999990e-01, + 6.000000000000000e-01, 1.714300000000000e-01, 6.087199999999994e-02, 1.378774289985053e+00, 7.999999999999994e-01, + 6.200000000000000e-01, 4.349800000000000e-01, 7.687199999999994e-02, 1.317749999999999e+01, 7.999999999999993e-01, + 6.300000000000000e-01, 5.680200000000000e-01, 8.487199999999995e-02, 1.330399999999999e+01, 8.000000000000000e-01, + 6.312100000000000e-01, 5.840460000000000e-01, 8.583999999999999e-02, 1.324462809917306e+01, 8.000000000000023e-01, + 6.356050000000000e-01, 6.422580000000000e-01, 8.935599999999992e-02, 1.324505119453948e+01, 7.999999999999987e-01, + 6.400000000000000e-01, 7.004700000000000e-01, 9.287199999999994e-02, 1.324505119453914e+01, 7.999999999999975e-01, + 6.420000000000000e-01, 7.264220000000000e-01, 9.447199999999994e-02, 1.297599999999998e+01, 8.000000000000014e-01, + 6.440000000000000e-01, 7.523740000000000e-01, 9.607199999999995e-02, 1.297599999999998e+01, 8.000000000000014e-01, + 6.460000000000000e-01, 7.783260000000000e-01, 9.767199999999995e-02, 1.297599999999998e+01, 8.000000000000014e-01, + 6.480000000000000e-01, 8.042770000000000e-01, 9.927199999999994e-02, 1.297550000000002e+01, 7.999999999999945e-01, + 6.489100000000001e-01, 8.160856150000010e-01, 1.000000000000000e-01, 1.297649999999996e+01, 8.000000000000000e-01, + 6.500000000000000e-01, 8.302300000000000e-01, 1.025069999999998e-01, 1.297650000000002e+01, 2.300000000000002e+00, + 7.466500000000000e-01, 9.437300000000000e-01, 3.248019999999999e-01, 1.174340403517847e+00, 2.300000000000000e+00, + 7.489100000000001e-01, 9.453165200000000e-01, 3.300000000000000e-01, 7.020000000000034e-01, 2.300000000000000e+00, + 7.966500000000000e-01, 9.788300000000000e-01, 5.448299999999997e-01, 7.020000000000013e-01, 4.500000000000004e+00, + 8.089100000000000e-01, 9.850875040000000e-01, 6.000000000000000e-01, 5.104000000000000e-01, 4.500000000000004e+00, + 8.216500000000000e-01, 9.915900000000000e-01, 7.273999999999996e-01, 5.103999999999986e-01, 9.999999999999991e+00, + 8.341499999999999e-01, 9.962900000000000e-01, 8.523999999999990e-01, 3.760000000000043e-01, 9.999999999999991e+00, + 8.435300000000000e-01, 9.995100000000000e-01, 9.461999999999995e-01, 3.432835820895503e-01, 9.999999999999988e+00, + 8.475400000000000e-01, 9.999100000000000e-01, 9.862999999999991e-01, 9.975062344138656e-02, 1.000000000000000e+01, + 8.482600000000000e-01, 9.999300000000000e-01, 9.934999999999996e-01, 2.777777777780348e-02, 1.000000000000000e+01, + 8.487700000000000e-01, 9.999700000000000e-01, 9.985999999999997e-01, 7.843137254909643e-02, 1.000000000000000e+01, + 8.489100000000001e-01, 1.000000000000000e+00, 1.000000000000000e+00, 2.142857142854877e-01, 1.000000000000000e+01, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, + }); + } + + std::vector expect_SWFN() + { + // Columns 1, 2, 4 (+ derivatives) of SWOF + return makeTable(5, { + 1.51090e-01, 0, 2.757902917267344e+01, 1.000000000000000e+20, 1.000000000000000e+20, + 1.51230e-01, 0, 2.476527872133143e+01, 0, -2.009821750958577e+04, + 1.51740e-01, 0, 1.778295801053983e+01, 0, -1.369082492312075e+04, + 1.52460e-01, 0, 1.284562231290197e+01, 0, -6.857410691163744e+03, + 1.56470e-01, 0, 5.450995115978905e+00, 0, -1.844046682524494e+03, + 1.65850e-01, 0, 2.758592392996661e+00, 0, -2.870365376313702e+02, + 1.78350e-01, 0, 1.925705711981923e+00, 0, -6.663093448117903e+01, + 2.03350e-01, 1.000000000000000e-05, 1.406530487806345e+00, 4.000000000000000e-04, -2.076700896702310e+01, + 2.53350e-01, 3.000000000000000e-05, 1.072134759087680e+00, 4.000000000000000e-04, -6.687914574373308e+00, + 3.50000e-01, 2.800000000000000e-04, 8.035839625187723e-01, 2.586652871184700e-03, -2.778590756015570e+00, + 3.52000e-01, 2.292000000000000e-03, 6.012228359642811e-01, 1.006000000000000e+00, -1.011805632772457e+02, + 3.54000e-01, 4.304000000000000e-03, 4.100312162247224e-01, 1.006000000000000e+00, -9.559580986977932e+01, + 3.56000e-01, 6.316000000000000e-03, 2.286990994143945e-01, 1.006000000000000e+00, -9.066605840516394e+01, + 3.58000e-01, 8.328000000000000e-03, 8.032392246541140e-02, 1.006000000000000e+00, -7.418758847449155e+01, + 3.60000e-01, 1.034000000000000e-02, 3.192272626736951e-02, 1.006000000000000e+00, -2.420059809902094e+01, + 3.64395e-01, 1.554800000000000e-02, -3.440483889291011e-02, 1.184982935153600e+00, -1.509159616843634e+01, + 3.68790e-01, 2.075600000000000e-02, -7.853128556918762e-02, 1.184982935153600e+00, -1.004014713908486e+01, + 3.70000e-01, 2.219000000000000e-02, -8.232340208043021e-02, 1.185123966942200e+00, -3.133980587803838e+00, + 3.80000e-01, 3.589000000000000e-02, -1.066618953253145e-01, 1.370000000000000e+00, -2.433849324488431e+00, + 4.00000e-01, 6.952999999999999e-02, -1.105919069824205e-01, 1.682000000000000e+00, -1.965005828552983e-01, + 4.33450e-01, 8.790000000000001e-02, -1.179003497131789e-01, 5.491778774290000e-01, -2.184885719210279e-01, + 4.61390e-01, 1.049100000000000e-01, -1.227266798183968e-01, 6.088045812455301e-01, -1.727390875167428e-01, + 4.89320e-01, 1.232900000000000e-01, -1.282424856529315e-01, 6.580737558181200e-01, -1.974867824752831e-01, + 5.17250e-01, 1.430300000000000e-01, -1.330688157581493e-01, 7.067669172932300e-01, -1.728009346658736e-01, + 5.73120e-01, 1.865900000000000e-01, -1.427214759685850e-01, 7.796670843028500e-01, -1.727700055563935e-01, + 6.01060e-01, 2.103800000000000e-01, -1.468583303444861e-01, 8.514674302075900e-01, -1.480620750143510e-01, + 6.56930e-01, 2.619000000000000e-01, -1.558215148256049e-01, 9.221406837300899e-01, -1.604292908737955e-01, + 7.12800e-01, 3.186500000000000e-01, -1.640952235774069e-01, 1.015750850187900e+00, -1.480885761911974e-01, + 8.11110e-01, 4.309200000000000e-01, -1.792636896223773e-01, 1.141999796561900e+00, -1.542921986061490e-01, + 8.81490e-01, 4.900000000000000e-01, -1.896058255621299e-01, 8.394430235862500e-01, -1.469470863846619e-01, + }); + } + } // ThreePhase + } // SPE9 +} + +BOOST_AUTO_TEST_SUITE (FileWrite_PVT) BOOST_AUTO_TEST_CASE(Test_PVTX) { setup cfg( "table_deck.DATA"); @@ -161,3 +1277,335 @@ BOOST_AUTO_TEST_CASE(Test_PVTX) { ecl_file_close( f ); } } + +BOOST_AUTO_TEST_SUITE_END () + +// ##################################################################### + +BOOST_AUTO_TEST_SUITE (Two_Phase) + +BOOST_AUTO_TEST_CASE (Oil_Water_Family_One) +{ + const auto es = SPE9::TwoPhase::OilWater::satfuncTables(); + + auto tables = Opm::Tables{ es.getUnits() }; + tables.addSatFunc(es); + + const auto& tabdims = tables.tabdims(); + const auto& tab = tables.tab(); + + // SOFN + { + const auto ibsofn = tabdims[ TABDIMS_IBSOFN_OFFSET_ITEM ] - 1; + const auto nssofn = tabdims[ TABDIMS_NSSOFN_ITEM ]; + const auto ntsofn = tabdims[ TABDIMS_NTSOFN_ITEM ]; + const auto ncol = 3; + + const auto sofn = std::vector { + &tab[ ibsofn ] + 0, + &tab[ ibsofn ] + ntsofn*nssofn*ncol + }; + + BOOST_CHECK_EQUAL(nssofn, 30); + BOOST_CHECK_EQUAL(ntsofn, 1); + + check_is_close(sofn, SPE9::TwoPhase::OilWater::expect_SOFN()); + } + + // SWFN + { + const auto ibswfn = tabdims[ TABDIMS_IBSWFN_OFFSET_ITEM ] - 1; + const auto nsswfn = tabdims[ TABDIMS_NSSWFN_ITEM ]; + const auto ntswfn = tabdims[ TABDIMS_NTSWFN_ITEM ]; + const auto ncol = 5; + + const auto swfn = std::vector { + &tab[ ibswfn ] + 0, + &tab[ ibswfn ] + ntswfn*nsswfn*ncol + }; + + BOOST_CHECK_EQUAL(nsswfn, 30); + BOOST_CHECK_EQUAL(ntswfn, 1); + + check_is_close(swfn, SPE9::TwoPhase::OilWater::expect_SWFN()); + } +} + +BOOST_AUTO_TEST_CASE (Oil_Water_Family_Two) +{ + const auto es = SPE1::TwoPhase::OilWater::satfuncTables(); + + auto tables = Opm::Tables{ es.getUnits() }; + tables.addSatFunc(es); + + const auto& tabdims = tables.tabdims(); + const auto& tab = tables.tab(); + + // SOFN + { + const auto ibsofn = tabdims[ TABDIMS_IBSOFN_OFFSET_ITEM ] - 1; + const auto nssofn = tabdims[ TABDIMS_NSSOFN_ITEM ]; + const auto ntsofn = tabdims[ TABDIMS_NTSOFN_ITEM ]; + const auto ncol = 3; + + const auto sofn = std::vector { + &tab[ ibsofn ] + 0, + &tab[ ibsofn ] + ntsofn*nssofn*ncol + }; + + BOOST_CHECK_EQUAL(nssofn, 20); + BOOST_CHECK_EQUAL(ntsofn, 1); + + check_is_close(sofn, SPE1::TwoPhase::OilWater::expect_SOFN()); + } + + // SWFN + { + const auto ibswfn = tabdims[ TABDIMS_IBSWFN_OFFSET_ITEM ] - 1; + const auto nsswfn = tabdims[ TABDIMS_NSSWFN_ITEM ]; + const auto ntswfn = tabdims[ TABDIMS_NTSWFN_ITEM ]; + const auto ncol = 5; + + const auto swfn = std::vector { + &tab[ ibswfn ] + 0, + &tab[ ibswfn ] + ntswfn*nsswfn*ncol + }; + + BOOST_CHECK_EQUAL(nsswfn, 20); + BOOST_CHECK_EQUAL(ntswfn, 1); + + check_is_close(swfn, SPE1::TwoPhase::OilWater::expect_SWFN()); + } +} + +BOOST_AUTO_TEST_CASE (Gas_Oil_Familiy_One) +{ + const auto es = SPE9::TwoPhase::GasOil::satfuncTables(); + + auto tables = Opm::Tables{ es.getUnits() }; + tables.addSatFunc(es); + + const auto& tabdims = tables.tabdims(); + const auto& tab = tables.tab(); + + // SGFN + { + const auto ibsgfn = tabdims[ TABDIMS_IBSGFN_OFFSET_ITEM ] - 1; + const auto nssgfn = tabdims[ TABDIMS_NSSGFN_ITEM ]; + const auto ntsgfn = tabdims[ TABDIMS_NTSGFN_ITEM ]; + const auto ncol = 5; + + const auto sgfn = std::vector { + &tab[ ibsgfn ] + 0, + &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol + }; + + BOOST_CHECK_EQUAL(nssgfn, 30); + BOOST_CHECK_EQUAL(ntsgfn, 1); + + check_is_close(sgfn, SPE9::TwoPhase::GasOil::expect_SGFN()); + } + + // SOFN + { + const auto ibsofn = tabdims[ TABDIMS_IBSOFN_OFFSET_ITEM ] - 1; + const auto nssofn = tabdims[ TABDIMS_NSSOFN_ITEM ]; + const auto ntsofn = tabdims[ TABDIMS_NTSOFN_ITEM ]; + const auto ncol = 3; + + const auto sofn = std::vector { + &tab[ ibsofn ] + 0, + &tab[ ibsofn ] + ntsofn*nssofn*ncol + }; + + BOOST_CHECK_EQUAL(nssofn, 30); + BOOST_CHECK_EQUAL(ntsofn, 1); + + check_is_close(sofn, SPE9::TwoPhase::GasOil::expect_SOFN()); + } +} + +BOOST_AUTO_TEST_CASE (Gas_Oil_Familiy_Two) +{ + const auto es = SPE1::TwoPhase::GasOil::satfuncTables(); + + auto tables = Opm::Tables{ es.getUnits() }; + tables.addSatFunc(es); + + const auto& tabdims = tables.tabdims(); + const auto& tab = tables.tab(); + + // SGFN + { + const auto ibsgfn = tabdims[ TABDIMS_IBSGFN_OFFSET_ITEM ] - 1; + const auto nssgfn = tabdims[ TABDIMS_NSSGFN_ITEM ]; + const auto ntsgfn = tabdims[ TABDIMS_NTSGFN_ITEM ]; + const auto ncol = 5; + + const auto sgfn = std::vector { + &tab[ ibsgfn ] + 0, + &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol + }; + + BOOST_CHECK_EQUAL(nssgfn, 20); + BOOST_CHECK_EQUAL(ntsgfn, 1); + + check_is_close(sgfn, SPE1::TwoPhase::GasOil::expect_SGFN()); + } + + // SOFN + { + const auto ibsofn = tabdims[ TABDIMS_IBSOFN_OFFSET_ITEM ] - 1; + const auto nssofn = tabdims[ TABDIMS_NSSOFN_ITEM ]; + const auto ntsofn = tabdims[ TABDIMS_NTSOFN_ITEM ]; + const auto ncol = 3; + + const auto sofn = std::vector { + &tab[ ibsofn ] + 0, + &tab[ ibsofn ] + ntsofn*nssofn*ncol + }; + + BOOST_CHECK_EQUAL(nssofn, 20); + BOOST_CHECK_EQUAL(ntsofn, 1); + + check_is_close(sofn, SPE1::TwoPhase::GasOil::expect_SOFN()); + } +} + +BOOST_AUTO_TEST_SUITE_END () + +// ##################################################################### + +BOOST_AUTO_TEST_SUITE (Three_Phase) + +BOOST_AUTO_TEST_CASE (Serialize_Family_One) +{ + const auto es = SPE9::ThreePhase::satfuncTables(); + + auto tables = Opm::Tables{ es.getUnits() }; + tables.addSatFunc(es); + + const auto& tabdims = tables.tabdims(); + const auto& tab = tables.tab(); + + // SGFN + { + const auto ibsgfn = tabdims[ TABDIMS_IBSGFN_OFFSET_ITEM ] - 1; + const auto nssgfn = tabdims[ TABDIMS_NSSGFN_ITEM ]; + const auto ntsgfn = tabdims[ TABDIMS_NTSGFN_ITEM ]; + const auto ncol = 5; + + const auto sgfn = std::vector { + &tab[ ibsgfn ] + 0, + &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol + }; + + BOOST_CHECK_EQUAL(nssgfn, 30); + BOOST_CHECK_EQUAL(ntsgfn, 1); + + check_is_close(sgfn, SPE9::ThreePhase::expect_SGFN()); + } + + // SOFN + { + const auto ibsofn = tabdims[ TABDIMS_IBSOFN_OFFSET_ITEM ] - 1; + const auto nssofn = tabdims[ TABDIMS_NSSOFN_ITEM ]; + const auto ntsofn = tabdims[ TABDIMS_NTSOFN_ITEM ]; + const auto ncol = 5; + + const auto sofn = std::vector { + &tab[ ibsofn ] + 0, + &tab[ ibsofn ] + ntsofn*nssofn*ncol + }; + + BOOST_CHECK_EQUAL(nssofn, 2 * 30); + BOOST_CHECK_EQUAL(ntsofn, 1); + + check_is_close(sofn, SPE9::ThreePhase::expect_SOFN()); + } + + // SWFN + { + const auto ibswfn = tabdims[ TABDIMS_IBSWFN_OFFSET_ITEM ] - 1; + const auto nsswfn = tabdims[ TABDIMS_NSSWFN_ITEM ]; + const auto ntswfn = tabdims[ TABDIMS_NTSWFN_ITEM ]; + const auto ncol = 5; + + const auto swfn = std::vector { + &tab[ ibswfn ] + 0, + &tab[ ibswfn ] + ntswfn*nsswfn*ncol + }; + + BOOST_CHECK_EQUAL(nsswfn, 30); + BOOST_CHECK_EQUAL(ntswfn, 1); + + check_is_close(swfn, SPE9::ThreePhase::expect_SWFN()); + } +} + +BOOST_AUTO_TEST_CASE (Serialize_Family_Two) +{ + const auto es = SPE1::ThreePhase::satfuncTables(); + + auto tables = Opm::Tables{ es.getUnits() }; + tables.addSatFunc(es); + + const auto& tabdims = tables.tabdims(); + const auto& tab = tables.tab(); + + // SGFN + { + const auto ibsgfn = tabdims[ TABDIMS_IBSGFN_OFFSET_ITEM ] - 1; + const auto nssgfn = tabdims[ TABDIMS_NSSGFN_ITEM ]; + const auto ntsgfn = tabdims[ TABDIMS_NTSGFN_ITEM ]; + const auto ncol = 5; + + const auto sgfn = std::vector { + &tab[ ibsgfn ] + 0, + &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol + }; + + BOOST_CHECK_EQUAL(nssgfn, 20); + BOOST_CHECK_EQUAL(ntsgfn, 1); + + check_is_close(sgfn, SPE1::ThreePhase::expect_SGFN()); + } + + // SOFN + { + const auto ibsofn = tabdims[ TABDIMS_IBSOFN_OFFSET_ITEM ] - 1; + const auto nssofn = tabdims[ TABDIMS_NSSOFN_ITEM ]; + const auto ntsofn = tabdims[ TABDIMS_NTSOFN_ITEM ]; + const auto ncol = 5; + + const auto sofn = std::vector { + &tab[ ibsofn ] + 0, + &tab[ ibsofn ] + ntsofn*nssofn*ncol + }; + + BOOST_CHECK_EQUAL(nssofn, 20); + BOOST_CHECK_EQUAL(ntsofn, 1); + + check_is_close(sofn, SPE1::ThreePhase::expect_SOFN()); + } + + // SWFN + { + const auto ibswfn = tabdims[ TABDIMS_IBSWFN_OFFSET_ITEM ] - 1; + const auto nsswfn = tabdims[ TABDIMS_NSSWFN_ITEM ]; + const auto ntswfn = tabdims[ TABDIMS_NTSWFN_ITEM ]; + const auto ncol = 5; + + const auto swfn = std::vector { + &tab[ ibswfn ] + 0, + &tab[ ibswfn ] + ntswfn*nsswfn*ncol + }; + + BOOST_CHECK_EQUAL(nsswfn, 20); + BOOST_CHECK_EQUAL(ntswfn, 1); + + check_is_close(swfn, SPE1::ThreePhase::expect_SWFN()); + } +} + +BOOST_AUTO_TEST_SUITE_END () From baf536ab1d3cdce746dc150271b0ec42d9a99e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Thu, 16 Nov 2017 18:36:39 +0100 Subject: [PATCH 6/7] Init File: Hook Saturation Function Writing Up to System --- opm/output/eclipse/EclipseIO.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/opm/output/eclipse/EclipseIO.cpp b/opm/output/eclipse/EclipseIO.cpp index a6e8579..a445647 100644 --- a/opm/output/eclipse/EclipseIO.cpp +++ b/opm/output/eclipse/EclipseIO.cpp @@ -313,6 +313,7 @@ void EclipseIO::Impl::writeINITFile( const data::Solution& simProps, std::mapes.getTableManager().getPvtgTables() ); tables.addPVTW( this->es.getTableManager().getPvtwTable() ); tables.addDensity( this->es.getTableManager().getDensityTable( ) ); + tables.addSatFunc(this->es); fwrite(tables, fortio); } From ea30ed22b79607458c83888f4441dce4bfd133a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 27 Nov 2017 10:25:48 +0100 Subject: [PATCH 7/7] Table Output: Switch Naming Convention for Data Members Mostly to remove trailing underscores. The internal 'tabdims' vector in Opm::Tables has been renamed to 'm_tabdims' to avoid conflicting with the member function named 'tabdims'. --- opm/output/eclipse/LinearisedOutputTable.cpp | 28 ++--- opm/output/eclipse/LinearisedOutputTable.hpp | 10 +- opm/output/eclipse/Tables.cpp | 102 +++++++++---------- opm/output/eclipse/Tables.hpp | 17 ++-- 4 files changed, 81 insertions(+), 76 deletions(-) diff --git a/opm/output/eclipse/LinearisedOutputTable.cpp b/opm/output/eclipse/LinearisedOutputTable.cpp index 81a1e63..5f5c4e9 100644 --- a/opm/output/eclipse/LinearisedOutputTable.cpp +++ b/opm/output/eclipse/LinearisedOutputTable.cpp @@ -6,14 +6,14 @@ #include Opm::LinearisedOutputTable:: -LinearisedOutputTable(const std::size_t numTables, - const std::size_t numPrimary, - const std::size_t numRows, - const std::size_t numCols) - : data_ (numTables * numPrimary * numRows * numCols, 1.0e20) - , numTables_ (numTables) - , numPrimary_(numPrimary) - , numRows_ (numRows) +LinearisedOutputTable(const std::size_t numTables0, + const std::size_t numPrimary0, + const std::size_t numRows0, + const std::size_t numCols0) + : data (numTables0 * numPrimary0 * numRows0 * numCols0, 1.0e20) + , numTables (numTables0) + , numPrimary(numPrimary0) + , numRows (numRows0) {} std::vector::iterator @@ -21,27 +21,27 @@ Opm::LinearisedOutputTable::column(const std::size_t tableID, const std::size_t primID, const std::size_t colID) { - // Table format: numRows_ * numPrimary_ * numTables_ values for first + // Table format: numRows * numPrimary * numTables values for first // column (ID == 0), followed by same number of entries for second // column &c. const auto offset = - 0 + this->numRows_*(primID + this->numPrimary_*(tableID + this->numTables_*colID)); + 0 + this->numRows*(primID + this->numPrimary*(tableID + this->numTables*colID)); - assert (offset + this->numRows_ <= this->data_.size()); + assert (offset + this->numRows <= this->data.size()); - return this->data_.begin() + offset; + return this->data.begin() + offset; } const std::vector& Opm::LinearisedOutputTable::getData() const { - return this->data_; + return this->data; } std::vector Opm::LinearisedOutputTable::getDataDestructively() { - return std::move(this->data_); + return std::move(this->data); } // --------------------------------------------------------------------- diff --git a/opm/output/eclipse/LinearisedOutputTable.hpp b/opm/output/eclipse/LinearisedOutputTable.hpp index 1cda47c..3373837 100644 --- a/opm/output/eclipse/LinearisedOutputTable.hpp +++ b/opm/output/eclipse/LinearisedOutputTable.hpp @@ -92,16 +92,16 @@ namespace Opm { private: /// Internal buffer for tabular data. - std::vector data_; + std::vector data; - /// Number of tables managed by \c data_. - std::size_t numTables_; + /// Number of tables managed by \c data. + std::size_t numTables; /// Number of primary look-up keys/sub-tables in \c data_. - std::size_t numPrimary_; + std::size_t numPrimary; /// Number of rows per sub-table in \c data_. - std::size_t numRows_; + std::size_t numRows; }; /// Apply piecewise linear differentiation (i.e., compute slopes) on a diff --git a/opm/output/eclipse/Tables.cpp b/opm/output/eclipse/Tables.cpp index 96da0c0..e827445 100644 --- a/opm/output/eclipse/Tables.cpp +++ b/opm/output/eclipse/Tables.cpp @@ -1008,24 +1008,24 @@ namespace { namespace SatFunc { namespace Opm { - Tables::Tables(const UnitSystem& units) - : units_ (units) - , tabdims_(TABDIMS_SIZE, 0) + Tables::Tables(const UnitSystem& units0) + : units (units0) + , m_tabdims(TABDIMS_SIZE, 0) { // Initialize subset of base pointers and dimensions to 1 to honour // requirements of TABDIMS protocol. The magic constant 59 is // derived from the file-formats documentation. - std::fill_n(std::begin(this->tabdims_), 59, 1); + std::fill_n(std::begin(this->m_tabdims), 59, 1); } void Tables::addData(const std::size_t offset_index, const std::vector& new_data) { - this->tabdims_[ offset_index ] = this->data_.size() + 1; + this->m_tabdims[ offset_index ] = this->data.size() + 1; - this->data_.insert(this->data_.end(), new_data.begin(), new_data.end()); + this->data.insert(this->data.end(), new_data.begin(), new_data.end()); - this->tabdims_[ TABDIMS_TAB_SIZE_ITEM ] = this->data_.size(); + this->m_tabdims[ TABDIMS_TAB_SIZE_ITEM ] = this->data.size(); } @@ -1060,9 +1060,9 @@ namespace Opm { { const double default_value = 2e20; PvtxDims dims = tableDims( pvtoTables ); - this->tabdims_[ TABDIMS_NTPVTO_ITEM ] = dims.num_tables; - this->tabdims_[ TABDIMS_NRPVTO_ITEM ] = dims.outer_size; - this->tabdims_[ TABDIMS_NPPVTO_ITEM ] = dims.inner_size; + this->m_tabdims[ TABDIMS_NTPVTO_ITEM ] = dims.num_tables; + this->m_tabdims[ TABDIMS_NRPVTO_ITEM ] = dims.outer_size; + this->m_tabdims[ TABDIMS_NPPVTO_ITEM ] = dims.inner_size; { std::vector pvtoData( dims.data_size , default_value ); @@ -1082,9 +1082,9 @@ namespace Opm { for (size_t row = 0; row < p.size(); row++) { size_t data_index = row + composition_stride * composition_index + table_stride * table_index; - pvtoData[ data_index ] = this->units_.from_si( UnitSystem::measure::pressure, p[row]); + pvtoData[ data_index ] = this->units.from_si( UnitSystem::measure::pressure, p[row]); pvtoData[ data_index + column_stride ] = 1.0 / bo[row]; - pvtoData[ data_index + 2*column_stride] = this->units_.from_si( UnitSystem::measure::viscosity , mu[row]) / bo[row]; + pvtoData[ data_index + 2*column_stride] = this->units.from_si( UnitSystem::measure::viscosity , mu[row]) / bo[row]; } composition_index++; } @@ -1111,9 +1111,9 @@ namespace Opm { void Tables::addPVTG( const std::vector& pvtgTables) { const double default_value = -2e20; PvtxDims dims = tableDims( pvtgTables ); - this->tabdims_[ TABDIMS_NTPVTG_ITEM ] = dims.num_tables; - this->tabdims_[ TABDIMS_NRPVTG_ITEM ] = dims.outer_size; - this->tabdims_[ TABDIMS_NPPVTG_ITEM ] = dims.inner_size; + this->m_tabdims[ TABDIMS_NTPVTG_ITEM ] = dims.num_tables; + this->m_tabdims[ TABDIMS_NRPVTG_ITEM ] = dims.outer_size; + this->m_tabdims[ TABDIMS_NPPVTG_ITEM ] = dims.inner_size; { std::vector pvtgData( dims.data_size , default_value ); @@ -1133,9 +1133,9 @@ namespace Opm { for (size_t row = 0; row < col0.size(); row++) { size_t data_index = row + composition_stride * composition_index + table_stride * table_index; - pvtgData[ data_index ] = this->units_.from_si( UnitSystem::measure::gas_oil_ratio, col0[row]); - pvtgData[ data_index + column_stride ] = this->units_.from_si( UnitSystem::measure::gas_oil_ratio, col1[row]); - pvtgData[ data_index + 2*column_stride] = this->units_.from_si( UnitSystem::measure::viscosity , col2[row]); + pvtgData[ data_index ] = this->units.from_si( UnitSystem::measure::gas_oil_ratio, col0[row]); + pvtgData[ data_index + column_stride ] = this->units.from_si( UnitSystem::measure::gas_oil_ratio, col1[row]); + pvtgData[ data_index + 2*column_stride] = this->units.from_si( UnitSystem::measure::viscosity , col2[row]); } composition_index++; @@ -1146,7 +1146,7 @@ namespace Opm { const auto& p = sat_table.getColumn("PG"); for (size_t index = 0; index < p.size(); index++) p_values[index + table_index * dims.outer_size ] = - this->units_.from_si( UnitSystem::measure::pressure , p[index]); + this->units.from_si( UnitSystem::measure::pressure , p[index]); } table_index++; @@ -1164,13 +1164,13 @@ namespace Opm { const size_t num_columns = pvtwTable[0].size; std::vector pvtwData( pvtwTable.size() * num_columns , default_value); - this->tabdims_[ TABDIMS_NTPVTW_ITEM ] = pvtwTable.size(); + this->m_tabdims[ TABDIMS_NTPVTW_ITEM ] = pvtwTable.size(); for (size_t table_num = 0; table_num < pvtwTable.size(); table_num++) { const auto& record = pvtwTable[table_num]; - pvtwData[ table_num * num_columns ] = this->units_.from_si( UnitSystem::measure::pressure , record.reference_pressure); + pvtwData[ table_num * num_columns ] = this->units.from_si( UnitSystem::measure::pressure , record.reference_pressure); pvtwData[ table_num * num_columns + 1] = 1.0 / record.volume_factor; - pvtwData[ table_num * num_columns + 2] = this->units_.to_si( UnitSystem::measure::pressure, record.compressibility); - pvtwData[ table_num * num_columns + 3] = record.volume_factor / this->units_.from_si( UnitSystem::measure::viscosity , record.viscosity); + pvtwData[ table_num * num_columns + 2] = this->units.to_si( UnitSystem::measure::pressure, record.compressibility); + pvtwData[ table_num * num_columns + 3] = record.volume_factor / this->units.from_si( UnitSystem::measure::viscosity , record.viscosity); // The last column should contain information about @@ -1191,12 +1191,12 @@ namespace Opm { const size_t num_columns = density[0].size; std::vector densityData( density.size() * num_columns , default_value); - this->tabdims_[ TABDIMS_NTDENS_ITEM ] = density.size(); + this->m_tabdims[ TABDIMS_NTDENS_ITEM ] = density.size(); for (size_t table_num = 0; table_num < density.size(); table_num++) { const auto& record = density[table_num]; - densityData[ table_num * num_columns ] = this->units_.from_si( UnitSystem::measure::density , record.oil); - densityData[ table_num * num_columns + 1] = this->units_.from_si( UnitSystem::measure::density , record.water); - densityData[ table_num * num_columns + 2] = this->units_.from_si( UnitSystem::measure::density , record.gas); + densityData[ table_num * num_columns ] = this->units.from_si( UnitSystem::measure::density , record.oil); + densityData[ table_num * num_columns + 1] = this->units.from_si( UnitSystem::measure::density , record.water); + densityData[ table_num * num_columns + 2] = this->units.from_si( UnitSystem::measure::density , record.gas); } this->addData( TABDIMS_IBDENS_OFFSET_ITEM , densityData ); } @@ -1236,12 +1236,12 @@ namespace Opm { const std::vector& Tables::tabdims() const { - return this->tabdims_; + return this->m_tabdims; } const std::vector& Tables::tab() const { - return this->data_; + return this->data; } void Tables::addSatFunc_FamilyOne(const EclipseState& es, @@ -1257,11 +1257,11 @@ namespace Opm { const auto& tables = tabMgr.getSgofTables(); const auto sgfn = - SatFunc::Gas::fromSGOF(nssfun, this->units_, tables); + SatFunc::Gas::fromSGOF(nssfun, this->units, tables); this->addData(TABDIMS_IBSGFN_OFFSET_ITEM, sgfn); - this->tabdims_[TABDIMS_NSSGFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSGFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSGFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSGFN_ITEM] = tables.size(); } if (oil) { @@ -1272,8 +1272,8 @@ namespace Opm { SatFunc::Oil::TwoPhase::fromSGOF(nssfun, tables); this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); - this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSOFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSOFN_ITEM] = tables.size(); } else if (wat && !gas) { // 2p O/W System const auto& tables = tabMgr.getSwofTables(); @@ -1282,8 +1282,8 @@ namespace Opm { SatFunc::Oil::TwoPhase::fromSWOF(nssfun, tables); this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); - this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSOFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSOFN_ITEM] = tables.size(); } else { // 3p G/O/W System const auto& sgof = tabMgr.getSgofTables(); @@ -1297,8 +1297,8 @@ namespace Opm { fromSGOFandSWOF(numRows, sgof, swof); this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); - this->tabdims_[TABDIMS_NSSOFN_ITEM] = numRows; - this->tabdims_[TABDIMS_NTSOFN_ITEM] = sgof.size(); + this->m_tabdims[TABDIMS_NSSOFN_ITEM] = numRows; + this->m_tabdims[TABDIMS_NTSOFN_ITEM] = sgof.size(); } } @@ -1306,11 +1306,11 @@ namespace Opm { const auto& tables = tabMgr.getSwofTables(); const auto swfn = - SatFunc::Water::fromSWOF(nssfun, this->units_, tables); + SatFunc::Water::fromSWOF(nssfun, this->units, tables); this->addData(TABDIMS_IBSWFN_OFFSET_ITEM, swfn); - this->tabdims_[TABDIMS_NSSWFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSWFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSWFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSWFN_ITEM] = tables.size(); } } @@ -1327,11 +1327,11 @@ namespace Opm { const auto& tables = tabMgr.getSgfnTables(); const auto sgfn = - SatFunc::Gas::fromSGFN(nssfun, this->units_, tables); + SatFunc::Gas::fromSGFN(nssfun, this->units, tables); this->addData(TABDIMS_IBSGFN_OFFSET_ITEM, sgfn); - this->tabdims_[TABDIMS_NSSGFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSGFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSGFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSGFN_ITEM] = tables.size(); } if (oil) { @@ -1342,8 +1342,8 @@ namespace Opm { SatFunc::Oil::TwoPhase::fromSOF2(nssfun, tables); this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); - this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSOFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSOFN_ITEM] = tables.size(); } else { // 3p G/O/W System const auto& tables = tabMgr.getSof3Tables(); @@ -1352,8 +1352,8 @@ namespace Opm { SatFunc::Oil::ThreePhase::fromSOF3(nssfun, tables); this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); - this->tabdims_[TABDIMS_NSSOFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSOFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSOFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSOFN_ITEM] = tables.size(); } } @@ -1361,11 +1361,11 @@ namespace Opm { const auto& tables = tabMgr.getSwfnTables(); const auto swfn = - SatFunc::Water::fromSWFN(nssfun, this->units_, tables); + SatFunc::Water::fromSWFN(nssfun, this->units, tables); this->addData(TABDIMS_IBSWFN_OFFSET_ITEM, swfn); - this->tabdims_[TABDIMS_NSSWFN_ITEM] = nssfun; - this->tabdims_[TABDIMS_NTSWFN_ITEM] = tables.size(); + this->m_tabdims[TABDIMS_NSSWFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSWFN_ITEM] = tables.size(); } } diff --git a/opm/output/eclipse/Tables.hpp b/opm/output/eclipse/Tables.hpp index af14a66..18052af 100644 --- a/opm/output/eclipse/Tables.hpp +++ b/opm/output/eclipse/Tables.hpp @@ -56,9 +56,14 @@ namespace Opm { const std::vector& tab() const; private: - const UnitSystem& units_; - std::vector tabdims_; - std::vector data_; + /// Convention for units of measure of the result set. + const UnitSystem& units; + + /// Offset and size information for the tabular data. + std::vector m_tabdims; + + /// Linearised tabular data of PVT and saturation functions. + std::vector data; void addData(const std::size_t offset_index, const std::vector& new_data); @@ -101,13 +106,13 @@ namespace Opm { /// Emit normalised tabular information (TABDIMS and TAB vectors) to /// ECL-like result set file (typically INIT file). /// - /// \param[in,out] fortio ECL-like result set file. Typically - /// corresponds to a preopened stream attached to the INIT file. - /// /// \param[in] tables Collection of normalised tables. Its \code /// tabdims() \endcode and \code tab() \endcode vectors will be /// emitted to \p fortio as ECL keywords "TABDIMS" and "TAB", /// respectively. + /// + /// \param[in,out] fortio ECL-like result set file. Typically + /// corresponds to a preopened stream attached to the INIT file. void fwrite(const Tables& tables, ERT::FortIO& fortio); }