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/EclipseIO.cpp b/opm/output/eclipse/EclipseIO.cpp index f176899..a445647 100644 --- a/opm/output/eclipse/EclipseIO.cpp +++ b/opm/output/eclipse/EclipseIO.cpp @@ -313,7 +313,8 @@ 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 ); + tables.addSatFunc(this->es); + fwrite(tables, fortio); } // Write all integer field properties from the input deck. diff --git a/opm/output/eclipse/LinearisedOutputTable.cpp b/opm/output/eclipse/LinearisedOutputTable.cpp new file mode 100644 index 0000000..5f5c4e9 --- /dev/null +++ b/opm/output/eclipse/LinearisedOutputTable.cpp @@ -0,0 +1,104 @@ +#include + +#include +#include +#include +#include + +Opm::LinearisedOutputTable:: +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 +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(); + + // Store derivatives at right interval end-point. + ++dy.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..3373837 --- /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/opm/output/eclipse/Tables.cpp b/opm/output/eclipse/Tables.cpp index d4ea284..e827445 100644 --- a/opm/output/eclipse/Tables.cpp +++ b/opm/output/eclipse/Tables.cpp @@ -17,27 +17,1015 @@ 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 + +/// 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_ ) : - units( units_ ), - tabdims( "TABDIMS" , TABDIMS_SIZE ) + 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->m_tabdims), 59, 1); } + void Tables::addData(const std::size_t offset_index, + const std::vector& new_data) + { + this->m_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(); - 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(); } @@ -72,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 ); @@ -94,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 ] = 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 +1103,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->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 ); @@ -147,10 +1133,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 +1145,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 +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 ] = 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 +1180,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 +1191,195 @@ 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 ] = 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::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")); - void Tables::fwrite( ERT::FortIO& fortio ) const + 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 { - tabdims.fwrite( fortio ); - { - ERT::EclKW tab( "TAB" , this->data ); - tab.fwrite( fortio ); + return this->m_tabdims; + } + + const std::vector& Tables::tab() const + { + 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->m_tabdims[TABDIMS_NSSGFN_ITEM] = nssfun; + this->m_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->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(); + + const auto sofn = + SatFunc::Oil::TwoPhase::fromSWOF(nssfun, tables); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + 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(); + 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->m_tabdims[TABDIMS_NSSOFN_ITEM] = numRows; + this->m_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->m_tabdims[TABDIMS_NSSWFN_ITEM] = nssfun; + this->m_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->m_tabdims[TABDIMS_NSSGFN_ITEM] = nssfun; + this->m_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->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(); + + const auto sofn = + SatFunc::Oil::ThreePhase::fromSOF3(nssfun, tables); + + this->addData(TABDIMS_IBSOFN_OFFSET_ITEM, sofn); + this->m_tabdims[TABDIMS_NSSOFN_ITEM] = nssfun; + this->m_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->m_tabdims[TABDIMS_NSSWFN_ITEM] = nssfun; + this->m_tabdims[TABDIMS_NTSWFN_ITEM] = tables.size(); + } + } + + void fwrite(const Tables& tables, + ERT::FortIO& 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..18052af 100644 --- a/opm/output/eclipse/Tables.hpp +++ b/opm/output/eclipse/Tables.hpp @@ -29,26 +29,92 @@ #include #include - namespace Opm { class UnitSystem; + class EclipseState; 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); + + /// 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; + + /// 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); + /// Convention for units of measure of the result set. + const UnitSystem& units; - const UnitSystem& units; - ERT::EclKW tabdims; + /// 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); + + /// 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 + /// ECL-like result set file (typically 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); } diff --git a/tests/test_LinearisedOutputTable.cpp b/tests/test_LinearisedOutputTable.cpp new file mode 100644 index 0000000..f2104f1 --- /dev/null +++ b/tests/test_LinearisedOutputTable.cpp @@ -0,0 +1,611 @@ +/* + 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 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, 1.0e+20, + 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, 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, + 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.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, + 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.0, + }); + + 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, 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, + 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 () diff --git a/tests/test_Tables.cpp b/tests/test_Tables.cpp index cd6bad0..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"); @@ -78,7 +1194,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); } @@ -90,8 +1206,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 +1229,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 +1248,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 +1266,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 ); @@ -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 ()