diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 6baf5602e..d3b7842f3 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -108,6 +108,7 @@ if(ENABLE_ECL_INPUT) src/opm/parser/eclipse/EclipseState/Tables/JFunc.cpp src/opm/parser/eclipse/EclipseState/Tables/PvtxTable.cpp src/opm/parser/eclipse/EclipseState/Tables/SimpleTable.cpp + src/opm/parser/eclipse/EclipseState/Tables/PolyInjTables.cpp src/opm/parser/eclipse/EclipseState/Tables/TableColumn.cpp src/opm/parser/eclipse/EclipseState/Tables/TableContainer.cpp src/opm/parser/eclipse/EclipseState/Tables/TableIndex.cpp @@ -380,6 +381,7 @@ if(ENABLE_ECL_INPUT) opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp opm/parser/eclipse/EclipseState/EndpointScaling.hpp opm/parser/eclipse/EclipseState/Tables/SimpleTable.hpp + opm/parser/eclipse/EclipseState/Tables/PolyInjTable.hpp opm/parser/eclipse/EclipseState/Tables/PdvdTable.hpp opm/parser/eclipse/EclipseState/Tables/TlpmixpaTable.hpp opm/parser/eclipse/EclipseState/Tables/PvdgTable.hpp @@ -389,8 +391,11 @@ if(ENABLE_ECL_INPUT) opm/parser/eclipse/EclipseState/Tables/Eqldims.hpp opm/parser/eclipse/EclipseState/Tables/SpecrockTable.hpp opm/parser/eclipse/EclipseState/Tables/PlydhflfTable.hpp + opm/parser/eclipse/EclipseState/Tables/PlymwinjTable.hpp opm/parser/eclipse/EclipseState/Tables/PlyshlogTable.hpp opm/parser/eclipse/EclipseState/Tables/RsvdTable.hpp + opm/parser/eclipse/EclipseState/Tables/SkprwatTable.hpp + opm/parser/eclipse/EclipseState/Tables/SkprpolyTable.hpp opm/parser/eclipse/EclipseState/Tables/SpecheatTable.hpp opm/parser/eclipse/EclipseState/Tables/SgcwmisTable.hpp opm/parser/eclipse/EclipseState/Tables/Sof2Table.hpp diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index ce043cadd..5330bdf4f 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -177,6 +177,8 @@ namespace Opm void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); + void handleWPMITAB( const DeckKeyword& keyword, const size_t currentStep, const ParseContext& parseContext); + void handleWSKPTAB( const DeckKeyword& keyword, const size_t currentStep, const ParseContext& parseContext); void handleWINJTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWCONINJH( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWELOPEN( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext ); diff --git a/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp b/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp index 6b8bc23d2..9f36aff3f 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp @@ -26,6 +26,9 @@ namespace Opm { struct WellPolymerProperties { double m_polymerConcentration; double m_saltConcentration; + int m_plymwinjtable; + int m_skprwattable; + int m_skprpolytable; bool operator==(const WellPolymerProperties& other) const; bool operator!=(const WellPolymerProperties& other) const; diff --git a/opm/parser/eclipse/EclipseState/Tables/PlymwinjTable.hpp b/opm/parser/eclipse/EclipseState/Tables/PlymwinjTable.hpp new file mode 100644 index 000000000..47b7d897d --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Tables/PlymwinjTable.hpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2018 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 OPM_PARSER_PLYMWINJ_TABLE_HPP +#define OPM_PARSER_PLYMWINJ_TABLE_HPP + +#include +namespace Opm { + + class DeckKeyword; + + class PlymwinjTable : public PolyInjTable { + public: + + explicit PlymwinjTable(const DeckKeyword& table); + + const std::vector>& getMoleWeights() const; + }; + +} + +#endif //OPM_PARSER_PLYMWINJ_TABLE_HPP diff --git a/opm/parser/eclipse/EclipseState/Tables/PolyInjTable.hpp b/opm/parser/eclipse/EclipseState/Tables/PolyInjTable.hpp new file mode 100644 index 000000000..87fd2bd4c --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Tables/PolyInjTable.hpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2018 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 OPM_PARSER_POLY_INJ_TABLE_HPP +#define OPM_PARSER_POLY_INJ_TABLE_HPP + + +/* This class is introduced for the following keywords related to polymer injectivity study. + * PLYMWINJ, SKPRWAT, SKPRPOLY . + * These keywords share very similar structure with small difference. + * + * KEYWORD + * 1 / --table number + * 0 20 30 / -- water throughputs + * 0 0.1 0.2 0.3 / -- water velocities + * -- the rest is the table data, + * -- each row corresponds to one value in throughputs + * -- each column corresponds to one value in water velocities + * 20 19 18 17 / + * 20 18 17 16 / + * 20 17 16 15 / + */ + +#include + +namespace Opm { + + class PolyInjTable { + public: + + int getTableNumber() const; + + const std::vector& getThroughputs() const; + const std::vector& getVelocities() const; + const std::vector>& getTableData() const; + + protected: + std::vector m_throughputs; + std::vector m_velocities; + + // TODO: maybe not needed, since this is also stored in the std::map + int m_table_number; + + // each vector corresponds to the values corresponds to one value related to one x sampling point + // as a result, the number of the vector should be equal to be the size of m_x_points, + // the size of each vector should be equal to the size of m_y_points + std::vector > m_data; + }; +} + +#endif // OPM_PARSER_POLY_INJ_TABLE_HPP diff --git a/opm/parser/eclipse/EclipseState/Tables/SkprpolyTable.hpp b/opm/parser/eclipse/EclipseState/Tables/SkprpolyTable.hpp new file mode 100644 index 000000000..a86597c5f --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Tables/SkprpolyTable.hpp @@ -0,0 +1,44 @@ +/* + Copyright (C) 2018 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 OPM_PARSER_SKPRPOLY_TABLE_HPP +#define OPM_PARSER_SKPRPOLY_TABLE_HPP + +#include +namespace Opm { + + class DeckKeyword; + + class SkprpolyTable : public PolyInjTable { + public: + + explicit SkprpolyTable(const DeckKeyword& table); + + double referenceConcentration() const; + + const std::vector>& getSkinPressures() const; + + private: + double m_ref_polymer_concentration; + + }; + +} + +#endif //OPM_PARSER_SKPRPOLY_TABLE_HPP diff --git a/opm/parser/eclipse/EclipseState/Tables/SkprwatTable.hpp b/opm/parser/eclipse/EclipseState/Tables/SkprwatTable.hpp new file mode 100644 index 000000000..530068fb2 --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Tables/SkprwatTable.hpp @@ -0,0 +1,39 @@ +/* + Copyright (C) 2018 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 OPM_PARSER_SKPRWAT_TABLE_HPP +#define OPM_PARSER_SKPRWAT_TABLE_HPP + +#include +namespace Opm { + + class DeckKeyword; + + class SkprwatTable : public PolyInjTable { + public: + + explicit SkprwatTable(const DeckKeyword& table); + + const std::vector>& getSkinPressures() const; + + }; + +} + +#endif //OPM_PARSER_SKPRWAT_TABLE_HPP diff --git a/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp b/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp index 27d5e0cea..544e28224 100644 --- a/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp +++ b/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp @@ -45,6 +45,9 @@ #include #include #include +#include +#include +#include namespace Opm { @@ -121,6 +124,9 @@ namespace Opm { const RockTable& getRockTable() const; const ViscrefTable& getViscrefTable() const; const WatdentTable& getWatdentTable() const; + const std::map& getPlymwinjTables() const; + const std::map& getSkprwatTables() const; + const std::map& getSkprpolyTables() const; /// deck has keyword "IMPTVD" --- Imbition end-point versus depth tables bool useImptvd() const; @@ -151,6 +157,10 @@ namespace Opm { void initPlyrockTables(const Deck& deck); void initPlyshlogTables(const Deck& deck); + void initPlymwinjTables(const Deck& deck); + void initSkprwatTables(const Deck& deck); + void initSkprpolyTables(const Deck& deck); + @@ -287,6 +297,9 @@ namespace Opm { RockTable m_rockTable; ViscrefTable m_viscrefTable; WatdentTable m_watdentTable; + std::map m_plymwinjTables; + std::map m_skprwatTables; + std::map m_skprpolyTables; Tabdims m_tabdims; std::shared_ptr m_regdims; diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index facbcc3cb..7a408e8e8 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -198,6 +198,12 @@ namespace Opm { else if (keyword.name() == "WTEMP") handleWTEMP(keyword, currentStep, parseContext); + else if (keyword.name() == "WPMITAB") + handleWPMITAB(keyword, currentStep, parseContext); + + else if (keyword.name() == "WSKPTAB") + handleWSKPTAB(keyword, currentStep, parseContext); + else if (keyword.name() == "WINJTEMP") handleWINJTEMP(keyword, currentStep, parseContext); @@ -762,6 +768,52 @@ namespace Opm { } + void Schedule::handleWPMITAB( const DeckKeyword& keyword, const size_t currentStep, const ParseContext& parseContext) { + + for (const auto& record : keyword) { + + const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); + const auto wells = getWells(wellNamePattern); + + if (wells.empty()) { + invalidNamePattern(wellNamePattern, parseContext, keyword); + } + + for (auto* well : wells) { + if (well->isProducer(currentStep) ) { + throw std::logic_error("WPMITAB keyword can not be applied to production well " + well->name() ); + } + WellPolymerProperties properties(well->getPolymerProperties(currentStep)); + properties.m_plymwinjtable = record.getItem("TABLE_NUMBER").get(0); + well->setPolymerProperties(currentStep, properties); + } + } + } + + + void Schedule::handleWSKPTAB( const DeckKeyword& keyword, const size_t currentStep, const ParseContext& parseContext) { + + + for (const auto& record : keyword) { + const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); + const auto wells = getWells(wellNamePattern); + + if (wells.empty()) { + invalidNamePattern(wellNamePattern, parseContext, keyword); + } + + for (auto* well : wells) { + if (well->isProducer(currentStep) ) { + throw std::logic_error("WSKPTAB can not be applied to production well " + well->name() ); + } + WellPolymerProperties properties(well->getPolymerProperties(currentStep)); + properties.m_skprwattable = record.getItem("TABLE_NUMBER_WATER").get(0); + properties.m_skprpolytable = record.getItem("TABLE_NUMBER_POLYMER").get(0); + well->setPolymerProperties(currentStep, properties); + } + } + } + void Schedule::handleWECON( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext) { for( const auto& record : keyword ) { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp index ec99654b1..e3e9f67a0 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp @@ -26,11 +26,17 @@ namespace Opm { WellPolymerProperties::WellPolymerProperties() { m_polymerConcentration = 0.0; m_saltConcentration = 0.0; + m_plymwinjtable = -1; // unusable table number + m_skprwattable = -1; + m_skprpolytable = -1; } bool WellPolymerProperties::operator==(const WellPolymerProperties& other) const { if ((m_polymerConcentration == other.m_polymerConcentration) && - (m_saltConcentration == other.m_saltConcentration)) + (m_saltConcentration == other.m_saltConcentration) && + (m_plymwinjtable == other.m_plymwinjtable) && + (m_skprwattable == other.m_skprwattable) && + (m_skprpolytable == other.m_skprpolytable) ) return true; else return false; diff --git a/src/opm/parser/eclipse/EclipseState/Tables/PolyInjTables.cpp b/src/opm/parser/eclipse/EclipseState/Tables/PolyInjTables.cpp new file mode 100644 index 000000000..7b9ea1d43 --- /dev/null +++ b/src/opm/parser/eclipse/EclipseState/Tables/PolyInjTables.cpp @@ -0,0 +1,212 @@ +/* + Copyright 2018 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 . +*/ + + +/* This is the implementation for the following three keywords related to + * polymer injectivity study : + * PLYMWINJ, SKPRWAT, SKPRPOLY + */ + +#include + +#include +#include + +#include +#include +#include +#include + + +namespace Opm{ + + // PolyInjTable + + int PolyInjTable::getTableNumber() const + { + return m_table_number; + } + + const std::vector& PolyInjTable::getThroughputs() const + { + return m_throughputs; + } + + const std::vector& PolyInjTable::getVelocities() const + { + return m_velocities; + } + + const std::vector>& PolyInjTable::getTableData() const + { + return m_data; + } + + + + // PlymwinjTable + + PlymwinjTable::PlymwinjTable(const Opm::DeckKeyword& table) + { + using namespace ParserKeywords; + + const DeckRecord& record0 = table.getRecord(0); + + m_table_number = record0.getItem().get< int >(0); + if (m_table_number <= 0) { + const std::string msg = "PLYMWINJ table has non-positive table number " + std::to_string(m_table_number); + throw std::invalid_argument(msg); + } + + m_throughputs = table.getRecord(1).getItem().getSIDoubleData(); + const size_t num_cols = m_throughputs.size(); + + if (table.size() != num_cols + 3) { + const std::string msg = "PLYMWINJ table " + std::to_string(m_table_number) + + " does not have enough records!"; + throw std::invalid_argument(msg); + } + + m_velocities = table.getRecord(2).getItem().getSIDoubleData(); + const size_t num_rows = m_velocities.size(); + + for (size_t i = 3; i < table.size(); ++i) { + const DeckRecord& record_i = table.getRecord(i); + const std::vector& data_i = record_i.getItem().getSIDoubleData(); + if (data_i.size() != num_rows) { + const std::string msg = "PLYMWINJ table " + std::to_string(m_table_number) + + " record " + std::to_string(i) + + " does not have correct number of data "; + throw std::invalid_argument(msg); + } + m_data.push_back(data_i); + } + } + + const std::vector>& + PlymwinjTable::getMoleWeights() const + { + return getTableData(); + } + + + // SkprwatTable + + SkprwatTable::SkprwatTable(const Opm::DeckKeyword &table) + { + using namespace ParserKeywords; + + const DeckRecord& record0 = table.getRecord(0); + + m_table_number = record0.getItem().get< int >(0); + if (m_table_number <= 0) { + const std::string msg = "SKPRWAT table has non-positive table number " + std::to_string(m_table_number); + throw std::invalid_argument(msg); + } + + m_throughputs = table.getRecord(1).getItem().getSIDoubleData(); + const size_t num_cols = m_throughputs.size(); + + if (table.size() != num_cols + 3) { + const std::string msg = "SKPRWAT table " + std::to_string(m_table_number) + + " does not have enough records!"; + throw std::invalid_argument(msg); + } + + m_velocities = table.getRecord(2).getItem().getSIDoubleData(); + const size_t num_rows = m_velocities.size(); + + for (size_t i = 3; i < table.size(); ++i) { + const DeckRecord& record_i = table.getRecord(i); + const std::vector& data_i = record_i.getItem().getSIDoubleData(); + if (data_i.size() != num_rows) { + const std::string msg = "SKPRWAT table " + std::to_string(m_table_number) + + " record " + std::to_string(i) + + " does not have correct number of data "; + throw std::invalid_argument(msg); + } + m_data.push_back(data_i); + } + } + + const std::vector>& + SkprwatTable::getSkinPressures() const + { + return getTableData(); + } + + + // SkprpolyTable + + SkprpolyTable::SkprpolyTable(const Opm::DeckKeyword &table) + { + using namespace ParserKeywords; + + const DeckRecord& record0 = table.getRecord(0); + + m_table_number = record0.getItem().get< int >(0); + if (m_table_number <= 0) { + const std::string msg = "SKPRPOLY table has non-positive table number " + std::to_string(m_table_number); + throw std::invalid_argument(msg); + } + + m_ref_polymer_concentration = record0.getItem().get< double >(0); + if (m_ref_polymer_concentration <= 0.) { + const std::string msg = "Non-positive reference polymer concentration is specified for SKPRPOLY table " + + std::to_string(m_table_number); + throw std::invalid_argument(msg); + } + + m_throughputs = table.getRecord(1).getItem().getSIDoubleData(); + const size_t num_cols = m_throughputs.size(); + + if (table.size() != num_cols + 3) { + const std::string msg = "SKPRPOLY table " + std::to_string(m_table_number) + + " does not have enough records!"; + throw std::invalid_argument(msg); + } + + m_velocities = table.getRecord(2).getItem().getSIDoubleData(); + const size_t num_rows = m_velocities.size(); + + for (size_t i = 3; i < table.size(); ++i) { + const DeckRecord& record_i = table.getRecord(i); + const std::vector& data_i = record_i.getItem().getSIDoubleData(); + if (data_i.size() != num_rows) { + const std::string msg = "SKPRPOLY table " + std::to_string(m_table_number) + + " record " + std::to_string(i) + + " does not have correct number of data "; + throw std::invalid_argument(msg); + } + m_data.push_back(data_i); + } + } + + double SkprpolyTable::referenceConcentration() const + { + return m_ref_polymer_concentration; + } + + const std::vector>& + SkprpolyTable::getSkinPressures() const + { + return getTableData(); + } + +} diff --git a/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp b/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp index ae801d978..5d0132684 100644 --- a/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp +++ b/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include // Phase::PhaseEnum #include @@ -342,6 +343,9 @@ namespace Opm { initRTempTables(deck); initRocktabTables(deck); initPlyshlogTables(deck); + initPlymwinjTables(deck); + initSkprpolyTables(deck); + initSkprwatTables(deck); } @@ -417,6 +421,83 @@ namespace Opm { } } + void TableManager::initPlymwinjTables(const Deck& deck) { + if (!deck.hasKeyword("PLYMWINJ")) { + return; + } + + const size_t num_tables = deck.count("PLYMWINJ"); + const auto& keywords = deck.getKeywordList(); + for (size_t i = 0; i < num_tables; ++i) { + const DeckKeyword &keyword = *keywords[i]; + + // not const for std::move + PlymwinjTable table(keyword); + + // we need to check the value of the table_number against the allowed ones + const int table_number = table.getTableNumber(); + // we should check if the table_number is valid + if (m_plymwinjTables.find(table_number) == m_plymwinjTables.end()) { + m_plymwinjTables.insert(std::make_pair(table_number, std::move(table))); + } else { + throw std::invalid_argument("Duplicated table number " + + std::to_string(table_number) + + " for keyword PLYMWINJ found"); + } + } + } + + void TableManager::initSkprwatTables(const Opm::Deck &deck) { + if (!deck.hasKeyword("SKPRWAT")) { + return; + } + + const size_t num_tables = deck.count("SKPRWAT"); + const auto& keywords = deck.getKeywordList(); + for (size_t i = 0; i < num_tables; ++i) { + const DeckKeyword &keyword = *keywords[i]; + + // not const for std::move + SkprwatTable table(keyword); + + // we need to check the value of the table_number against the allowed ones + const int table_number = table.getTableNumber(); + // we should check if the table_number is valid + if (m_skprwatTables.find(table_number) == m_skprwatTables.end()) { + m_skprwatTables.insert(std::make_pair(table_number, std::move(table))); + } else { + throw std::invalid_argument("Duplicated table number " + + std::to_string(table_number) + + " for keyword SKPRWAT found"); + } + } + } + + void TableManager::initSkprpolyTables(const Opm::Deck &deck) { + if (!deck.hasKeyword("SKPRPOLY")) { + return; + } + + const size_t num_tables = deck.count("SKPRPOLY"); + const auto& keywords = deck.getKeywordList(); + for (size_t i = 0; i < num_tables; ++i) { + const DeckKeyword &keyword = *keywords[i]; + + // not const for std::move + SkprpolyTable table(keyword); + + // we need to check the value of the table_number against the allowed ones + const int table_number = table.getTableNumber(); + // we should check if the table_number is valid + if (m_skprpolyTables.find(table_number) == m_skprpolyTables.end()) { + m_skprpolyTables.insert(std::make_pair(table_number, std::move(table))); + } else { + throw std::invalid_argument("Duplicated table number " + + std::to_string(table_number) + + " for keyword SKPRPOLY found"); + } + } + } void TableManager::initPlyrockTables(const Deck& deck) { size_t numTables = m_tabdims.getNumSatTables(); @@ -724,6 +805,19 @@ namespace Opm { return *jfunc; } + + const std::map& TableManager::getPlymwinjTables() const { + return m_plymwinjTables; + } + + const std::map& TableManager::getSkprwatTables() const { + return m_skprwatTables; + } + + const std::map& TableManager::getSkprpolyTables() const { + return m_skprpolyTables; + } + bool TableManager::useImptvd() const { return hasImptvd; } diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/P/PINTDIMS b/src/opm/parser/eclipse/share/keywords/900_OPM/P/PINTDIMS index 64f39297d..0b96e19c4 100644 --- a/src/opm/parser/eclipse/share/keywords/900_OPM/P/PINTDIMS +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/P/PINTDIMS @@ -1,6 +1,5 @@ {"name" : "PINTDIMS", "sections" : ["RUNSPEC"], "size" : 1, "items" : [ {"name" : "NTSKWAT" , "value_type" : "INT" , "default" : 1}, {"name" : "NTSKPOLY" , "value_type" : "INT" , "default" : 1}, - {"name" : "NTPMWINJ" , "value_type" : "INT" , "default" : 1}, - {"name" : "NPLYVMH" , "value_type" : "INT" , "default" : 1} + {"name" : "NTPMWINJ" , "value_type" : "INT" , "default" : 1} ]} diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYMWINJ b/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYMWINJ new file mode 100644 index 000000000..d67fdc139 --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYMWINJ @@ -0,0 +1,7 @@ +{"name" : "PLYMWINJ" , "sections" : ["PROPS"], "size" : "UNKNOWN", + "records" : [ +[{"name" : "TABLE_NUMBER" , "value_type" : "INT"}], +[{"name" : "THROUGHPUT", "value_type" : "DOUBLE", "dimension" : "Length", "size_type" : "ALL"}], +[{"name" : "VELOCITY", "value_type" : "DOUBLE", "dimension" : "Length/Time", "size_type" : "ALL"}], +[{"name" : "MOLECULARWEIGHT", "value_type" : "DOUBLE", "dimension" : "1", "size_type" : "ALL"}] +]} diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYVMH b/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYVMH index 6de34e720..1c500ea77 100644 --- a/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYVMH +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/P/PLYVMH @@ -1,4 +1,4 @@ -{"name" : "PLYVMH" , "sections" : ["PROPS"], "size" : {"keyword" : "PINTDIMS" , "item" : "NPLYVMH"} , "items" : +{"name" : "PLYVMH" , "sections" : ["PROPS"], "size" : {"keyword" : "REGDIMS" , "item" : "NPLMIX"} , "items" : [ {"name" : "K_MH", "value_type" : "DOUBLE", "dimension" : "1" }, {"name" : "A_MH", "value_type" : "DOUBLE", "dimension" : "1" }, diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/S/SKPRPOLY b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SKPRPOLY new file mode 100644 index 000000000..a1630541a --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SKPRPOLY @@ -0,0 +1,8 @@ +{"name" : "SKPRPOLY" , "sections" : ["PROPS"], "size" : "UNKNOWN", + "records" : [ +[{"name" : "TABLE_NUMBER" , "value_type" : "INT"}, +{"name" : "POLYMERCONCENTRATION" , "value_type" : "DOUBLE", "dimension" : "PolymerDensity"}], +[{"name" : "THROUGHPUT", "value_type" : "DOUBLE", "dimension" : "Length", "size_type" : "ALL"}], +[{"name" : "VELOCITY", "value_type" : "DOUBLE", "dimension" : "Length/Time", "size_type" : "ALL"}], +[{"name" : "SKINPRESSURE", "value_type" : "DOUBLE", "dimension" : "Pressure", "size_type" : "ALL"}] +]} diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/S/SKPRWAT b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SKPRWAT new file mode 100644 index 000000000..41e484940 --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SKPRWAT @@ -0,0 +1,7 @@ +{"name" : "SKPRWAT" , "sections" : ["PROPS"], "size" : "UNKNOWN", + "records" : [ +[{"name" : "TABLE_NUMBER" , "value_type" : "INT"}], +[{"name" : "THROUGHPUT", "value_type" : "DOUBLE", "dimension" : "Length", "size_type" : "ALL"}], +[{"name" : "VELOCITY", "value_type" : "DOUBLE", "dimension" : "Length/Time", "size_type" : "ALL"}], +[{"name" : "SKINPRESSURE", "value_type" : "DOUBLE", "dimension" : "Pressure", "size_type" : "ALL"}] +]} diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/W/WPMITAB b/src/opm/parser/eclipse/share/keywords/900_OPM/W/WPMITAB new file mode 100644 index 000000000..29867eb6c --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/W/WPMITAB @@ -0,0 +1,8 @@ +{ + "name" : "WPMITAB", + "sections" : ["SCHEDULE" ], + "items" : + [{"name" : "WELL" , "value_type" : "STRING"}, + {"name" : "TABLE_NUMBER" , "value_type" : "INT"} + ] +} diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/W/WSKPTAB b/src/opm/parser/eclipse/share/keywords/900_OPM/W/WSKPTAB new file mode 100644 index 000000000..9dcaa09d9 --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/W/WSKPTAB @@ -0,0 +1,9 @@ +{ + "name" : "WSKPTAB", + "sections" : ["SCHEDULE" ], + "items" : + [{"name" : "WELL" , "value_type" : "STRING"}, + {"name" : "TABLE_NUMBER_WATER" , "value_type" : "INT"}, + {"name" : "TABLE_NUMBER_POLYMER" , "value_type" : "INT"} + ] +} diff --git a/src/opm/parser/eclipse/share/keywords/keyword_list.cmake b/src/opm/parser/eclipse/share/keywords/keyword_list.cmake index 5c870b1aa..939d55063 100644 --- a/src/opm/parser/eclipse/share/keywords/keyword_list.cmake +++ b/src/opm/parser/eclipse/share/keywords/keyword_list.cmake @@ -455,6 +455,11 @@ set( keywords 900_OPM/P/PINTDIMS 900_OPM/P/PLYVMH 900_OPM/P/POLYMW + 900_OPM/P/PLYMWINJ 900_OPM/R/RHO + 900_OPM/S/SKPRPOLY + 900_OPM/S/SKPRWAT 900_OPM/S/SPOLYMW - 900_OPM/T/TLPMIXPA) + 900_OPM/T/TLPMIXPA + 900_OPM/W/WPMITAB + 900_OPM/W/WSKPTAB) diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index a5500af61..9e920827b 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -2739,6 +2739,72 @@ VFPINJ \n \ } } +// tests for the polymer injectivity case +BOOST_AUTO_TEST_CASE(POLYINJ_TEST) { + const char *deckData = + "START\n" + " 8 MAR 2018/\n" + "PROPS\n \n" + "SCHEDULE\n" + "WELSPECS\n" + "'INJE01' 'I' 1 1 1* 'WATER' /\n" + "/\n" + "TSTEP\n" + " 1/\n" + "WPOLYMER\n" + " 'INJE01' 1.0 0.0 /\n" + "/\n" + "WPMITAB\n" + " 'INJE01' 2 /\n" + "/\n" + "WSKPTAB\n" + " 'INJE01' 1 1 /\n" + "/\n" + "TSTEP\n" + " 2*1/\n" + "WPMITAB\n" + " 'INJE01' 3 /\n" + "/\n" + "WSKPTAB\n" + " 'INJE01' 2 2 /\n" + "/\n" + "TSTEP\n" + " 1 /\n"; + + Opm::Parser parser; + auto deck = parser.parseString(deckData, Opm::ParseContext()); + EclipseGrid grid1(10,10,10); + TableManager table ( deck ); + Eclipse3DProperties eclipseProperties ( deck , table, grid1); + Runspec runspec (deck); + Schedule schedule(deck, grid1 , eclipseProperties, runspec , ParseContext() ); + + const Opm::Well* well_inj01 = schedule.getWell("INJE01"); + + // start + { + const auto wpolymer = well_inj01->getPolymerProperties(0); + BOOST_CHECK_EQUAL(wpolymer.m_plymwinjtable, -1); + BOOST_CHECK_EQUAL(wpolymer.m_skprwattable, -1); + BOOST_CHECK_EQUAL(wpolymer.m_skprpolytable, -1); + } + + // report step 1 + { + const auto wpolymer = well_inj01->getPolymerProperties(1); + BOOST_CHECK_EQUAL(wpolymer.m_plymwinjtable, 2); + BOOST_CHECK_EQUAL(wpolymer.m_skprwattable, 1); + BOOST_CHECK_EQUAL(wpolymer.m_skprpolytable, 1); + } + + // report step 3 + { + const auto wpolymer = well_inj01->getPolymerProperties(3); + BOOST_CHECK_EQUAL(wpolymer.m_plymwinjtable, 3); + BOOST_CHECK_EQUAL(wpolymer.m_skprwattable, 2); + BOOST_CHECK_EQUAL(wpolymer.m_skprpolytable, 2); + } +} BOOST_AUTO_TEST_CASE(WTEST_CONFIG) { diff --git a/tests/parser/TableManagerTests.cpp b/tests/parser/TableManagerTests.cpp index fd4856291..e23fdec07 100644 --- a/tests/parser/TableManagerTests.cpp +++ b/tests/parser/TableManagerTests.cpp @@ -1190,6 +1190,246 @@ VFPINJ \n\ } +BOOST_AUTO_TEST_CASE( TestPLYMWINJ ) { + const char *inputstring = + "PLYMWINJ \n" + " 2 / -- table number \n" + " 0.0 200.0 800.0 / -- throughput values \n" + " 0.0 1.0 2.0 3.0 / -- velocity values \n" + " -- the rest will be the polymer molecular weight \n" + " -- each row corresponds to one sample points in the throughput direction \n" + " 20. 19. 18. 16. /\n" + " 20. 16. 14. 12. /\n" + " 20. 12. 8. 4. /\n" + "PLYMWINJ \n" + " 3 / -- table number \n" + " 0.0 100.0 / -- throughput values \n" + " 0.0 1.0 2.0 / -- velocity values \n" + " -- the rest will be the polymer molecular weight \n" + " -- each row corresponds to one sample points in the throughput direction \n" + " 20. 19. 18. /\n" + " 20. 16. 14. /\n"; + + Opm::Parser parser; + const Opm::Deck deck = parser.parseString(inputstring, Opm::ParseContext()); + const Opm::TableManager tables( deck ); + const auto& plymwinjtables = tables.getPlymwinjTables(); + + BOOST_CHECK_EQUAL( plymwinjtables.size(), 2 ); + + BOOST_CHECK( plymwinjtables.find(1) == plymwinjtables.end() ); + + { + const auto searchtable2 = plymwinjtables.find(2); + BOOST_CHECK( searchtable2 != plymwinjtables.end() ); + const auto& table2 = searchtable2->second; + BOOST_CHECK_EQUAL( searchtable2->first, table2.getTableNumber() ); + BOOST_CHECK_EQUAL( table2.getTableNumber(), 2 ); + + const std::vector& throughputs = table2.getThroughputs(); + BOOST_CHECK_EQUAL( throughputs.size(), 3 ); + BOOST_CHECK_EQUAL( throughputs[1], 200.0 ); + const std::vector& velocities = table2.getVelocities(); + BOOST_CHECK_EQUAL( velocities.size(), 4 ); + constexpr double dayinseconds = 86400.; + BOOST_CHECK_EQUAL( velocities[2], 2.0 / dayinseconds ); + const std::vector>& mwdata = table2.getMoleWeights(); + + BOOST_CHECK_EQUAL( mwdata.size(), throughputs.size() ); + for (const auto& data : mwdata) { + BOOST_CHECK_EQUAL( data.size(), velocities.size() ); + } + BOOST_CHECK_EQUAL(mwdata[2][3], 4.0); + BOOST_CHECK_EQUAL(mwdata[1][1], 16.0); + } + + { + const auto searchtable3 = plymwinjtables.find(3); + BOOST_CHECK( searchtable3 != plymwinjtables.end() ); + const auto& table3 = searchtable3->second; + BOOST_CHECK_EQUAL( searchtable3->first, table3.getTableNumber() ); + BOOST_CHECK_EQUAL( table3.getTableNumber(), 3 ); + + const std::vector& throughputs = table3.getThroughputs(); + BOOST_CHECK_EQUAL( throughputs.size(), 2 ); + BOOST_CHECK_EQUAL( throughputs[1], 100.0 ); + const std::vector& velocities = table3.getVelocities(); + BOOST_CHECK_EQUAL( velocities.size(), 3 ); + constexpr double dayinseconds = 86400.; + BOOST_CHECK_EQUAL( velocities[2], 2.0 / dayinseconds ); + const std::vector>& mwdata = table3.getMoleWeights(); + + BOOST_CHECK_EQUAL( mwdata.size(), throughputs.size() ); + for (const auto& data : mwdata) { + BOOST_CHECK_EQUAL( data.size(), velocities.size() ); + } + BOOST_CHECK_EQUAL(mwdata[1][2], 14.0); + BOOST_CHECK_EQUAL(mwdata[0][0], 20.0); + } +} + +BOOST_AUTO_TEST_CASE( TestSKPRWAT ) { + const char *inputstring = + "SKPRWAT \n" + " 1 / -- table number \n" + " 0.0 200.0 800.0 / -- throughput values \n" + " 0.0 1.0 2.0 3.0 / -- velocity values \n" + " -- the rest will be the skin pressure \n" + " -- each row corresponds to one sample points in the throughput direction \n" + " 20. 19. 18. 16. /\n" + " 20. 16. 14. 12. /\n" + " 20. 12. 8. 4. /\n" + "SKPRWAT \n" + " 2 / -- table number \n" + " 0.0 100.0 / -- throughput values \n" + " 0.0 1.0 2.0 / -- velocity values \n" + " -- the rest will be the skin pressure \n" + " -- each row corresponds to one sample points in the throughput direction \n" + " 20. 19. 18. /\n" + " 20. 16. 14. /\n"; + + Opm::Parser parser; + const Opm::Deck deck = parser.parseString(inputstring, Opm::ParseContext()); + const Opm::TableManager tables( deck ); + const auto& skprwattables = tables.getSkprwatTables(); + + BOOST_CHECK_EQUAL( skprwattables.size(), 2 ); + + BOOST_CHECK( skprwattables.find(3) == skprwattables.end() ); + + { + const auto searchtable1 = skprwattables.find(1); + BOOST_CHECK( searchtable1 != skprwattables.end() ); + const auto& table1 = searchtable1->second; + BOOST_CHECK_EQUAL( searchtable1->first, table1.getTableNumber() ); + BOOST_CHECK_EQUAL( table1.getTableNumber(), 1 ); + + const std::vector& throughputs = table1.getThroughputs(); + BOOST_CHECK_EQUAL( throughputs.size(), 3 ); + BOOST_CHECK_EQUAL( throughputs[1], 200.0 ); + const std::vector& velocities = table1.getVelocities(); + BOOST_CHECK_EQUAL( velocities.size(), 4 ); + constexpr double dayinseconds = 86400.; + BOOST_CHECK_EQUAL( velocities[2], 2.0 / dayinseconds ); + const std::vector>& skindata = table1.getSkinPressures(); + + BOOST_CHECK_EQUAL( skindata.size(), throughputs.size() ); + for (const auto& data : skindata) { + BOOST_CHECK_EQUAL( data.size(), velocities.size() ); + } + constexpr double barsa = 1.0e5; + BOOST_CHECK_EQUAL(skindata[2][3], 4.0 * barsa); + BOOST_CHECK_EQUAL(skindata[1][1], 16.0 * barsa); + } + + { + const auto searchtable2 = skprwattables.find(2); + BOOST_CHECK( searchtable2 != skprwattables.end() ); + const auto& table2 = searchtable2->second; + BOOST_CHECK_EQUAL( searchtable2->first, table2.getTableNumber() ); + BOOST_CHECK_EQUAL( table2.getTableNumber(), 2 ); + + const std::vector& throughputs = table2.getThroughputs(); + BOOST_CHECK_EQUAL( throughputs.size(), 2 ); + BOOST_CHECK_EQUAL( throughputs[1], 100.0 ); + const std::vector& velocities = table2.getVelocities(); + BOOST_CHECK_EQUAL( velocities.size(), 3 ); + constexpr double dayinseconds = 86400.; + BOOST_CHECK_EQUAL( velocities[2], 2.0 / dayinseconds ); + const std::vector>& skindata = table2.getSkinPressures(); + + BOOST_CHECK_EQUAL( skindata.size(), throughputs.size() ); + for (const auto& data : skindata) { + BOOST_CHECK_EQUAL( data.size(), velocities.size() ); + } + constexpr double barsa = 1.0e5; + BOOST_CHECK_EQUAL(skindata[1][2], 14.0 * barsa); + BOOST_CHECK_EQUAL(skindata[0][0], 20.0 * barsa); + } +} + +BOOST_AUTO_TEST_CASE( TestSKPRPOLY ) { + const char *inputstring = + "SKPRPOLY \n" + " 1 2.0 / -- table number & reference concentration \n" + " 0.0 200.0 800.0 / -- throughput values \n" + " 0.0 1.0 2.0 3.0 / -- velocity values \n" + " -- the rest will be the skin pressure \n" + " -- each row corresponds to one sample points in the throughput direction \n" + " 20. 19. 18. 16. /\n" + " 20. 16. 14. 12. /\n" + " 20. 12. 8. 4. /\n" + "SKPRPOLY \n" + " 2 3.0 / -- table number & reference concentration \n" + " 0.0 100.0 / -- throughput values \n" + " 0.0 1.0 2.0 / -- velocity values \n" + " -- the rest will be the skin pressure \n" + " -- each row corresponds to one sample points in the throughput direction \n" + " 20. 19. 18. /\n" + " 20. 16. 14. /\n"; + + Opm::Parser parser; + const Opm::Deck deck = parser.parseString(inputstring, Opm::ParseContext()); + const Opm::TableManager tables( deck ); + const auto& skprpolytables = tables.getSkprpolyTables(); + + BOOST_CHECK_EQUAL( skprpolytables.size(), 2 ); + + BOOST_CHECK( skprpolytables.find(4) == skprpolytables.end() ); + + { + const auto searchtable1 = skprpolytables.find(1); + BOOST_CHECK( searchtable1 != skprpolytables.end() ); + const auto& table1 = searchtable1->second; + BOOST_CHECK_EQUAL( searchtable1->first, table1.getTableNumber() ); + BOOST_CHECK_EQUAL( table1.getTableNumber(), 1 ); + + BOOST_CHECK_EQUAL( table1.referenceConcentration(), 2.0 ); + const std::vector& throughputs = table1.getThroughputs(); + BOOST_CHECK_EQUAL( throughputs.size(), 3 ); + BOOST_CHECK_EQUAL( throughputs[1], 200.0 ); + const std::vector& velocities = table1.getVelocities(); + BOOST_CHECK_EQUAL( velocities.size(), 4 ); + constexpr double dayinseconds = 86400.; + BOOST_CHECK_EQUAL( velocities[2], 2.0 / dayinseconds ); + const std::vector>& skindata = table1.getSkinPressures(); + + BOOST_CHECK_EQUAL( skindata.size(), throughputs.size() ); + for (const auto& data : skindata) { + BOOST_CHECK_EQUAL( data.size(), velocities.size() ); + } + constexpr double barsa = 1.0e5; + BOOST_CHECK_EQUAL(skindata[2][3], 4.0 * barsa); + BOOST_CHECK_EQUAL(skindata[1][1], 16.0 * barsa); + } + + { + const auto searchtable2 = skprpolytables.find(2); + BOOST_CHECK( searchtable2 != skprpolytables.end() ); + const auto& table2 = searchtable2->second; + BOOST_CHECK_EQUAL( searchtable2->first, table2.getTableNumber() ); + BOOST_CHECK_EQUAL( table2.getTableNumber(), 2 ); + + BOOST_CHECK_EQUAL( table2.referenceConcentration(), 3.0 ); + const std::vector& throughputs = table2.getThroughputs(); + BOOST_CHECK_EQUAL( throughputs.size(), 2 ); + BOOST_CHECK_EQUAL( throughputs[1], 100.0 ); + const std::vector& velocities = table2.getVelocities(); + BOOST_CHECK_EQUAL( velocities.size(), 3 ); + constexpr double dayinseconds = 86400.; + BOOST_CHECK_EQUAL( velocities[2], 2.0 / dayinseconds ); + const std::vector>& skindata = table2.getSkinPressures(); + + BOOST_CHECK_EQUAL( skindata.size(), throughputs.size() ); + for (const auto& data : skindata) { + BOOST_CHECK_EQUAL( data.size(), velocities.size() ); + } + constexpr double barsa = 1.0e5; + BOOST_CHECK_EQUAL(skindata[1][2], 14.0 * barsa); + BOOST_CHECK_EQUAL(skindata[0][0], 20.0 * barsa); + } +} + BOOST_AUTO_TEST_CASE( TestPLYROCK ) { const char *data = "TABDIMS\n"