diff --git a/opm/output/eclipse/Tables.hpp b/opm/output/eclipse/Tables.hpp new file mode 100644 index 000000000..0720543c5 --- /dev/null +++ b/opm/output/eclipse/Tables.hpp @@ -0,0 +1,51 @@ +/* + Copyright 2016 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 OUTPUT_TABLES_HPP +#define OUTPUT_TABLES_HPP + +#include + +#include +#include + +#include + + +namespace Opm { + class UnitSystem; + + class Tables { + public: + Tables( const UnitSystem& units_); + void fwrite( ERT::FortIO& fortio ) const; + void addPVTO( const std::vector& pvtoTables); + + + private: + void addData( size_t offset_index , const std::vector& new_data); + + const UnitSystem& units; + ERT::EclKW tabdims; + std::vector data; + }; +} + + +#endif diff --git a/src/opm/output/eclipse/EclipseWriter.cpp b/src/opm/output/eclipse/EclipseWriter.cpp index 61de030f8..6238c04d8 100644 --- a/src/opm/output/eclipse/EclipseWriter.cpp +++ b/src/opm/output/eclipse/EclipseWriter.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -507,6 +508,12 @@ void EclipseWriter::Impl::writeINITFile( const data::Solution& simProps, const N } } + // Write tables + { + Tables tables( this->es.getUnits() ); + tables.addPVTO( this->es.getTableManager().getPvtoTables() ); + tables.fwrite( fortio ); + } // Write all integer field properties from the input deck. { diff --git a/src/opm/output/eclipse/Tables.cpp b/src/opm/output/eclipse/Tables.cpp new file mode 100644 index 000000000..c0390db85 --- /dev/null +++ b/src/opm/output/eclipse/Tables.cpp @@ -0,0 +1,133 @@ +/* + Copyright 2016 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 . + */ + +#include +#include +#include + +#include + +#include + +namespace Opm { + + Tables::Tables( const UnitSystem& units_ ) : + units( units_ ), + tabdims( "TABDIMS" , TABDIMS_SIZE ) + { + } + + + 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()); + } + + + namespace { + struct PvtxDims { + size_t num_tables; + size_t outer_size; + size_t inner_size; + size_t num_columns = 3; + size_t data_size; + }; + + template + PvtxDims tableDims( const std::vector& pvtxTables) { + PvtxDims dims; + + dims.num_tables = pvtxTables.size(); + dims.inner_size = 0; + dims.outer_size = 0; + for (const auto& table : pvtxTables) { + dims.outer_size = std::max( dims.outer_size, table.size()); + for (const auto& underSatTable : table) + dims.inner_size = std::max(dims.inner_size, underSatTable.numRows() ); + } + dims.data_size = dims.num_tables * dims.outer_size * dims.inner_size * dims.num_columns; + + return dims; + } + } + + void Tables::addPVTO( const std::vector& pvtoTables) + { + 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; + + { + std::vector pvtoData( dims.data_size , default_value ); + std::vector rs_values( dims.num_tables * dims.outer_size , default_value ); + size_t composition_stride = dims.inner_size; + size_t table_stride = dims.outer_size * composition_stride; + size_t column_stride = table_stride * pvtoTables.size(); + + size_t table_index = 0; + for (const auto& table : pvtoTables) { + size_t composition_index = 0; + for (const auto& underSatTable : table) { + const auto& p = underSatTable.getColumn("P"); + const auto& bo = underSatTable.getColumn("BO"); + const auto& mu = underSatTable.getColumn("MU"); + + 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 + column_stride ] = 1.0 / bo[row]; + pvtoData[ data_index + 2*column_stride] = units.from_si( UnitSystem::measure::viscosity , mu[row]) / bo[row]; + } + composition_index++; + } + + /* + The RS values which apply for one inner table each + are added as a separate data vector to the TABS + array. + */ + { + const auto& sat_table = table.getSaturatedTable(); + const auto& rs = sat_table.getColumn("RS"); + for (size_t index = 0; index < rs.size(); index++) + rs_values[index + table_index * dims.outer_size ] = rs[index]; + } + table_index++; + } + + addData( TABDIMS_IBPVTO_OFFSET_ITEM , pvtoData ); + addData( TABDIMS_JBPVTO_OFFSET_ITEM , rs_values ); + } + } + + + + void Tables::fwrite( ERT::FortIO& fortio ) const + { + tabdims.fwrite( fortio ); + { + ERT::EclKW tab( "TAB" , this->data ); + tab.fwrite( fortio ); + } + } + +} diff --git a/tests/table_deck.DATA b/tests/table_deck.DATA new file mode 100644 index 000000000..d234b3035 --- /dev/null +++ b/tests/table_deck.DATA @@ -0,0 +1,72 @@ +RUNSPEC + +TITLE + SIMPLE TEST + +DIMENS + 10 10 10 / + +OIL + +WATER + +GAS + +DISGAS + +VAPOIL + +METRIC + +EQLDIMS + 1 100 2 1 1 / + +TABDIMS + 1 1 33 60 16 60 / + + +GRID + +DX +1000*1 / + +DY +1000*1 / + +DZ +1000*1 / + +TOPS +100*1 / + + + +PROPS =============================================================== +PVTO + +-- RSO PRESSURE B-OIL VISCOSITY +-- (BAR) (CP) + + 20.59 50.00 1.10615 1.180 + 75.00 1.10164 1.247 + 100.00 1.09744 1.315 + 125.00 1.09351 1.384 + 150.00 1.08984 1.453 / + + 28.19 70.00 1.12522 1.066 + 95.00 1.12047 1.124 + 120.00 1.11604 1.182 + 170.00 1.10804 1.300 / +/ + + + +PVTG +-- + 20.00 0.00002448 0.061895 0.01299 + 0.00001224 0.061810 0.01300 + 0.00000000 0.061725 0.01300 / + 40.00 0.00000628 0.030252 0.01383 + 0.00000314 0.030249 0.01383 + 0.00000000 0.030245 0.01383 / +/ diff --git a/tests/test_Tables.cpp b/tests/test_Tables.cpp new file mode 100644 index 000000000..2fb5e7d0a --- /dev/null +++ b/tests/test_Tables.cpp @@ -0,0 +1,111 @@ +/* + Copyright 2016 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 . + */ + +#include "config.h" + +#if HAVE_DYNAMIC_BOOST_TEST +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_MODULE Wells +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace Opm; + + +struct setup { + Deck deck; + EclipseState es; + ERT::TestArea ta; + + setup( const std::string& name, const std::string& path , const ParseContext& parseContext = ParseContext( )) : + deck( Parser().parseFile( path, parseContext ) ), + es( deck, ParseContext() ), + ta( ERT::TestArea("test_tables") ) + { + } + +}; + + + + +BOOST_AUTO_TEST_CASE(Test_PVTO) { + setup cfg( "PVTO" , "table_deck.DATA"); + Tables tables( cfg.es.getUnits() ); + + tables.addPVTO( cfg.es.getTableManager().getPvtoTables() ); + { + ERT::FortIO f("TEST.INIT" , std::fstream::out); + tables.fwrite( f ); + } + + + { + ecl_file_type * f = ecl_file_open("TEST.INIT" , 0 ); + + BOOST_CHECK( ecl_file_has_kw( f , "TABDIMS" )); + BOOST_CHECK( ecl_file_has_kw( f , "TAB" )); + { + const ecl_kw_type * tabdims = ecl_file_iget_named_kw( f , "TABDIMS" , 0 ); + const ecl_kw_type * tab = ecl_file_iget_named_kw( f , "TAB" , 0 ); + int offset = ecl_kw_iget_int( tabdims , TABDIMS_IBPVTO_OFFSET_ITEM ); + int rs_offset = ecl_kw_iget_int( tabdims , TABDIMS_JBPVTO_OFFSET_ITEM ); + 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 ) ); + BOOST_CHECK_EQUAL( 5, ecl_kw_iget_int( tabdims , TABDIMS_NPPVTO_ITEM ) ); + BOOST_CHECK_EQUAL( 1, ecl_kw_iget_int( tabdims , TABDIMS_NTPVTO_ITEM ) ); + + BOOST_CHECK_CLOSE(50.0 , ecl_kw_iget_double( tab , offset ), 1e-6 ); + BOOST_CHECK_CLOSE(1.0 / 1.10615 , ecl_kw_iget_double( tab , offset + column_stride), 1e-6 ); + BOOST_CHECK_CLOSE(1.18 / 1.10615 , ecl_kw_iget_double( tab , offset + 2*column_stride ), 1e-6 ); + + BOOST_CHECK_CLOSE(150.0 , ecl_kw_iget_double( tab , 4 + offset ), 1e-6 ); + BOOST_CHECK_CLOSE(1.0 / 1.08984 , ecl_kw_iget_double( tab , 4 + offset + column_stride), 1e-6 ); + BOOST_CHECK_CLOSE(1.453 / 1.08984 , ecl_kw_iget_double( tab , 4 + offset + 2*column_stride ), 1e-6 ); + + BOOST_CHECK_CLOSE(20.59 , ecl_kw_iget_double( tab , rs_offset ), 1e-6 ); + BOOST_CHECK_CLOSE(28.19 , ecl_kw_iget_double( tab , rs_offset + 1), 1e-6 ); + } + ecl_file_close( f ); + } +}