From c09263fc60fbd9710223477d0527bac153e030d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Thu, 24 Oct 2024 18:06:52 +0200 Subject: [PATCH] Add support for USECUPL keyword --- CMakeLists_files.cmake | 6 +- .../Schedule/ResCoup/ReadCouplingFile.cpp | 62 +++++++++++++++++++ .../Schedule/ResCoup/ReadCouplingFile.hpp | 28 +++++++++ .../ResCoup/ReservoirCouplingInfo.cpp | 19 +++++- .../ResCoup/ReservoirCouplingInfo.hpp | 45 +++++++++++--- .../ReservoirCouplingKeywordHandlers.cpp | 4 +- ...CouplingFile.cpp => WriteCouplingFile.cpp} | 21 ++----- ...CouplingFile.hpp => WriteCouplingFile.hpp} | 0 .../share/keywords/000_Eclipse100/U/USECUPL | 1 + tests/parser/ReservoirCouplingTests.cpp | 34 +++++++++- 10 files changed, 189 insertions(+), 31 deletions(-) create mode 100644 opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.cpp create mode 100644 opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.hpp rename opm/input/eclipse/Schedule/ResCoup/{CouplingFile.cpp => WriteCouplingFile.cpp} (73%) rename opm/input/eclipse/Schedule/ResCoup/{CouplingFile.hpp => WriteCouplingFile.hpp} (100%) diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 14b36c63c41..64351f7fd2b 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -285,7 +285,8 @@ if(ENABLE_ECL_INPUT) opm/input/eclipse/Schedule/ResCoup/MasterGroup.cpp opm/input/eclipse/Schedule/ResCoup/Slaves.cpp opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.cpp - opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp + opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.cpp + opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.cpp opm/input/eclipse/Schedule/UDQ/UDQKeywordHandlers.cpp opm/input/eclipse/Schedule/UDQ/UDQActive.cpp opm/input/eclipse/Schedule/UDQ/UDQAssign.cpp @@ -1310,7 +1311,8 @@ if(ENABLE_ECL_INPUT) opm/input/eclipse/Schedule/ResCoup/MasterGroup.hpp opm/input/eclipse/Schedule/ResCoup/Slaves.hpp opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.hpp - opm/input/eclipse/Schedule/ResCoup/CouplingFile.hpp + opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.hpp + opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.hpp opm/input/eclipse/Schedule/VFPInjTable.hpp opm/input/eclipse/Schedule/VFPProdTable.hpp opm/input/eclipse/Schedule/Well/Connection.hpp diff --git a/opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.cpp b/opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.cpp new file mode 100644 index 00000000000..45681cac053 --- /dev/null +++ b/opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.cpp @@ -0,0 +1,62 @@ +/* + Copyright 2024 Equinor 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 +#include +#include "../HandlerContext.hpp" + + +namespace Opm { + +void handleUSECUPL(HandlerContext& handlerContext) +{ + auto& schedule_state = handlerContext.state(); + auto rescoup = schedule_state.rescoup(); + const auto& keyword = handlerContext.keyword; + // Opm::Parser::parseFile() (see readDeck.cpp in opm-simulators) will throw an exception if there + // is more than one record for this keyword, so we can assume that there is exactly one record here. + auto record = keyword[0]; + { + auto deck_item = record.getItem(); + if (deck_item.defaultApplied(0)) { + throw OpmInputError("Root name of coupling file (item 1) cannot be defaulted.", keyword.location()); + } + auto root_name = deck_item.getTrimmedString(0); + rescoup.readCouplingFileName(root_name); + } + { + auto deck_item = record.getItem(); + if (deck_item.defaultApplied(0)) { + throw OpmInputError("Format of coupling file (item 2) cannot be defaulted.", keyword.location()); + } + auto flag_str = deck_item.getTrimmedString(0); + auto coupling_file_flag = ReservoirCoupling::CouplingInfo::couplingFileFlagFromString( + flag_str, keyword); + rescoup.readCouplingFileFlag(coupling_file_flag); + } + schedule_state.rescoup.update( std::move( rescoup )); +} + +} // namespace Opm + diff --git a/opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.hpp b/opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.hpp new file mode 100644 index 00000000000..bee4aad14df --- /dev/null +++ b/opm/input/eclipse/Schedule/ResCoup/ReadCouplingFile.hpp @@ -0,0 +1,28 @@ +/* + Copyright 2024 Equinor 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_READ_RESERVOIR_COUPLING_FILE_HPP +#define OPM_READ_RESERVOIR_COUPLING_FILE_HPP +namespace Opm { + +class HandlerContext; + +extern void handleUSECUPL(HandlerContext& handlerContext); + +} // namespace Opm +#endif // OPM_READ_RESERVOIR_COUPLING_FILE_HPP diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp index eae69161cf5..1bc2903d426 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp @@ -19,18 +19,35 @@ #include #include +#include #include namespace Opm { namespace ReservoirCoupling { +CouplingInfo::CouplingFileFlag CouplingInfo::couplingFileFlagFromString( + const std::string& flag_str, const DeckKeyword& keyword +) +{ + //DEBUG + if (flag_str == "F") { + return CouplingInfo::CouplingFileFlag::FORMATTED; + } else if (flag_str == "U") { + return CouplingInfo::CouplingFileFlag::UNFORMATTED; + } else { + throw Opm::OpmInputError("Invalid DUMPCUPL value: " + flag_str, keyword.location()); + } +} + bool CouplingInfo::operator==(const CouplingInfo& rhs) const { return this->m_slaves == rhs.m_slaves && this->m_master_groups == rhs.m_master_groups && this->m_grup_slavs == rhs.m_grup_slavs && this->m_master_mode == rhs.m_master_mode && this->m_master_min_time_step == rhs.m_master_min_time_step && - this->m_coupling_file_flag == rhs.m_coupling_file_flag; + this->m_write_coupling_file_flag == rhs.m_write_coupling_file_flag && + this->m_read_coupling_file_name == rhs.m_read_coupling_file_name && + this->m_read_coupling_file_flag == rhs.m_read_coupling_file_flag; } CouplingInfo CouplingInfo::serializationTestObject() diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp index 275167bd58c..a43b79be565 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp @@ -19,6 +19,7 @@ #ifndef OPM_RESERVOIR_COUPLING_INFO_HPP #define OPM_RESERVOIR_COUPLING_INFO_HPP +#include #include #include #include @@ -42,14 +43,6 @@ class CouplingInfo { // Inline methods (alphabetically) - void couplingFileFlag(CouplingFileFlag flag) { - m_coupling_file_flag = flag; - } - - CouplingFileFlag couplingFileFlag() const { - return m_coupling_file_flag; - } - const std::map& grupSlavs() const { return this->m_grup_slavs; } @@ -106,6 +99,22 @@ class CouplingInfo { m_master_min_time_step = tstep; } + void readCouplingFileFlag(CouplingFileFlag flag) { + m_read_coupling_file_flag = flag; + } + + CouplingFileFlag readCouplingFileFlag() const { + return m_read_coupling_file_flag; + } + + void readCouplingFileName(const std::string& name) { + m_read_coupling_file_name = name; + } + + const std::string& readCouplingFileName() const { + return m_read_coupling_file_name; + } + const Slave& slave(const std::string& name) const { return m_slaves.at(name); } @@ -130,11 +139,25 @@ class CouplingInfo { serializer(m_grup_slavs); serializer(m_master_mode); serializer(m_master_min_time_step); - serializer(m_coupling_file_flag); + serializer(m_write_coupling_file_flag); + serializer(m_read_coupling_file_flag); + serializer(m_read_coupling_file_name); + } + + void writeCouplingFileFlag(CouplingFileFlag flag) { + m_write_coupling_file_flag = flag; } + CouplingFileFlag writeCouplingFileFlag() const { + return m_write_coupling_file_flag; + } + + // Non-inline methods (defined in CouplingInfo.cpp) + static CouplingFileFlag couplingFileFlagFromString( + const std::string& flag_str, const DeckKeyword& keyword); + bool operator==(const CouplingInfo& other) const; static CouplingInfo serializationTestObject(); @@ -145,7 +168,9 @@ class CouplingInfo { bool m_master_mode{false}; // Default value: No limit, however a positive value can be set by using keyword RCMASTS double m_master_min_time_step{0.0}; - CouplingFileFlag m_coupling_file_flag{CouplingFileFlag::NONE}; + CouplingFileFlag m_write_coupling_file_flag{CouplingFileFlag::NONE}; + CouplingFileFlag m_read_coupling_file_flag{CouplingFileFlag::NONE}; + std::string m_read_coupling_file_name{}; }; } // namespace Opm::ReservoirCoupling diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp index cc0df2a00c6..1374044d61b 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp @@ -24,7 +24,8 @@ #include "Slaves.hpp" #include "MasterGroup.hpp" #include "MasterMinimumTimeStep.hpp" -#include "CouplingFile.hpp" +#include "WriteCouplingFile.hpp" +#include "ReadCouplingFile.hpp" #include @@ -39,6 +40,7 @@ getReservoirCouplingHandlers() { "GRUPSLAV", &handleGRUPSLAV}, { "RCMASTS", &handleRCMASTS}, { "DUMPCUPL", &handleDUMPCUPL}, + { "USECUPL", &handleUSECUPL}, }; } diff --git a/opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp b/opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.cpp similarity index 73% rename from opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp rename to opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.cpp index e291147633c..caa5fc6dd2d 100644 --- a/opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.cpp @@ -18,7 +18,7 @@ */ -#include +#include #include #include #include @@ -29,19 +29,6 @@ namespace Opm { -ReservoirCoupling::CouplingInfo::CouplingFileFlag couplingFileFlagFromString( - const std::string& flag_str, const DeckKeyword& keyword -) -{ - if (flag_str == "F") { - return ReservoirCoupling::CouplingInfo::CouplingFileFlag::FORMATTED; - } else if (flag_str == "U") { - return ReservoirCoupling::CouplingInfo::CouplingFileFlag::UNFORMATTED; - } else { - throw OpmInputError("Invalid DUMPCUPL value: " + flag_str, keyword.location()); - } -} - void handleDUMPCUPL(HandlerContext& handlerContext) { auto& schedule_state = handlerContext.state(); @@ -55,8 +42,10 @@ void handleDUMPCUPL(HandlerContext& handlerContext) throw OpmInputError("DUMPCUPL keyword cannot be defaulted.", keyword.location()); } auto flag_str = deck_item.getTrimmedString(0); - auto coupling_file_flag = couplingFileFlagFromString(flag_str, keyword); - rescoup.couplingFileFlag(coupling_file_flag); + //DEBUG + auto coupling_file_flag = ReservoirCoupling::CouplingInfo::couplingFileFlagFromString( + flag_str, keyword); + rescoup.writeCouplingFileFlag(coupling_file_flag); schedule_state.rescoup.update( std::move( rescoup )); } diff --git a/opm/input/eclipse/Schedule/ResCoup/CouplingFile.hpp b/opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.hpp similarity index 100% rename from opm/input/eclipse/Schedule/ResCoup/CouplingFile.hpp rename to opm/input/eclipse/Schedule/ResCoup/WriteCouplingFile.hpp diff --git a/opm/input/eclipse/share/keywords/000_Eclipse100/U/USECUPL b/opm/input/eclipse/share/keywords/000_Eclipse100/U/USECUPL index 0b018f59dbc..dff973129bb 100644 --- a/opm/input/eclipse/share/keywords/000_Eclipse100/U/USECUPL +++ b/opm/input/eclipse/share/keywords/000_Eclipse100/U/USECUPL @@ -3,6 +3,7 @@ "sections": [ "SCHEDULE" ], + "size": 1, "items": [ { "name": "BASE", diff --git a/tests/parser/ReservoirCouplingTests.cpp b/tests/parser/ReservoirCouplingTests.cpp index 31f9d1142ce..96f94449e19 100644 --- a/tests/parser/ReservoirCouplingTests.cpp +++ b/tests/parser/ReservoirCouplingTests.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -541,7 +542,7 @@ DUMPCUPL std::string deck_string = getCouplingFileDeckString(end_of_deck_string); const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); const auto& rescoup = schedule[0].rescoup(); - BOOST_CHECK(rescoup.couplingFileFlag() == + BOOST_CHECK(rescoup.writeCouplingFileFlag() == Opm::ReservoirCoupling::CouplingInfo::CouplingFileFlag::FORMATTED); } @@ -573,3 +574,34 @@ DUMPCUPL } BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(UseCouplingFile) + +BOOST_AUTO_TEST_CASE(FORMATTED_FILE) { + std::string end_of_deck_string = R"( +USECUPL + 'BASE' 'F' / +)"; + std::string deck_string = getCouplingFileDeckString(end_of_deck_string); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); + const auto& rescoup = schedule[0].rescoup(); + BOOST_CHECK(rescoup.readCouplingFileFlag() == + Opm::ReservoirCoupling::CouplingInfo::CouplingFileFlag::FORMATTED); + BOOST_CHECK(rescoup.readCouplingFileName() == "BASE"); + +} + +BOOST_AUTO_TEST_CASE(DEFAULT_NOT_ALLOWED1) { + std::string end_of_deck_string = R"( +USECUPL + * 'U' / +)"; + std::string deck_string = getCouplingFileDeckString(end_of_deck_string); + assertRaisesInputErrorException( + deck_string, + /*slave_mode=*/false, + /*exception_string=*/"Problem with keyword USECUPL\nIn line 28\nRoot name of coupling file (item 1) cannot be defaulted." + ); +} + +BOOST_AUTO_TEST_SUITE_END()