From 16dbcc67664d1058c4731fa0b304fb4b8ca4a48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Wed, 23 Oct 2024 10:40:43 +0200 Subject: [PATCH] Add support for DUMPCUPL Adds support for the DUMPCUPL keyword used in reservoir coupling. --- CMakeLists_files.cmake | 2 + .../eclipse/Schedule/ResCoup/CouplingFile.cpp | 64 +++++++++++++++++++ .../eclipse/Schedule/ResCoup/CouplingFile.hpp | 28 ++++++++ .../ResCoup/ReservoirCouplingInfo.cpp | 3 +- .../ResCoup/ReservoirCouplingInfo.hpp | 16 +++++ .../ReservoirCouplingKeywordHandlers.cpp | 2 + tests/parser/ReservoirCouplingTests.cpp | 59 ++++++++++++++++- 7 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp create mode 100644 opm/input/eclipse/Schedule/ResCoup/CouplingFile.hpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index dc1d856971a..14b36c63c41 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -285,6 +285,7 @@ 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/UDQ/UDQKeywordHandlers.cpp opm/input/eclipse/Schedule/UDQ/UDQActive.cpp opm/input/eclipse/Schedule/UDQ/UDQAssign.cpp @@ -1309,6 +1310,7 @@ 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/VFPInjTable.hpp opm/input/eclipse/Schedule/VFPProdTable.hpp opm/input/eclipse/Schedule/Well/Connection.hpp diff --git a/opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp b/opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp new file mode 100644 index 00000000000..e291147633c --- /dev/null +++ b/opm/input/eclipse/Schedule/ResCoup/CouplingFile.cpp @@ -0,0 +1,64 @@ +/* + 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 { + +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(); + 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("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); + schedule_state.rescoup.update( std::move( rescoup )); +} + +} // namespace Opm + diff --git a/opm/input/eclipse/Schedule/ResCoup/CouplingFile.hpp b/opm/input/eclipse/Schedule/ResCoup/CouplingFile.hpp new file mode 100644 index 00000000000..8cbbe6376f1 --- /dev/null +++ b/opm/input/eclipse/Schedule/ResCoup/CouplingFile.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 RESERVOIR_COUPLING_FILE_HPP +#define RESERVOIR_COUPLING_FILE_HPP +namespace Opm { + +class HandlerContext; + +extern void handleDUMPCUPL(HandlerContext& handlerContext); + +} // namespace Opm +#endif // RESERVOIR_COUPLING_FILE_HPP diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp index 8462e81abca..eae69161cf5 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp @@ -29,7 +29,8 @@ bool CouplingInfo::operator==(const CouplingInfo& rhs) const { 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_master_min_time_step == rhs.m_master_min_time_step && + this->m_coupling_file_flag == rhs.m_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 d1f0884ba95..55acc681cf2 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp @@ -32,10 +32,24 @@ namespace Opm::ReservoirCoupling { class CouplingInfo { public: + enum class CouplingFileFlag { + NONE, + FORMATTED, + UNFORMATTED + }; + CouplingInfo() = default; // 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; } @@ -116,6 +130,7 @@ class CouplingInfo { serializer(m_grup_slavs); serializer(m_master_mode); serializer(m_master_min_time_step); + serializer(m_coupling_file_flag); } // Non-inline methods (defined in CouplingInfo.cpp) @@ -130,6 +145,7 @@ 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}; }; } // namespace Opm::ReservoirCoupling diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp index 3d2301566cd..cc0df2a00c6 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp @@ -24,6 +24,7 @@ #include "Slaves.hpp" #include "MasterGroup.hpp" #include "MasterMinimumTimeStep.hpp" +#include "CouplingFile.hpp" #include @@ -37,6 +38,7 @@ getReservoirCouplingHandlers() { "GRUPMAST", &handleGRUPMAST}, { "GRUPSLAV", &handleGRUPSLAV}, { "RCMASTS", &handleRCMASTS}, + { "DUMPCUPL", &handleDUMPCUPL}, }; } diff --git a/tests/parser/ReservoirCouplingTests.cpp b/tests/parser/ReservoirCouplingTests.cpp index 11f3878b795..31f9d1142ce 100644 --- a/tests/parser/ReservoirCouplingTests.cpp +++ b/tests/parser/ReservoirCouplingTests.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,11 @@ GRUPMAST return prefix + end_of_deck_string; } +std::string getCouplingFileDeckString(const std::string &end_of_deck_string) +{ + return getMinimumMasterTimeStepDeckString(end_of_deck_string); +} + void removeStringLogger() { OpmLog::removeBackend("MYLOGGER"); } @@ -490,13 +496,13 @@ TUNING / RCMASTS - 0.01 / + 0.0001 / )"; std::string deck_string = getMinimumMasterTimeStepDeckString(end_of_deck_string); const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); const auto& rescoup = schedule[0].rescoup(); - BOOST_CHECK(rescoup.masterMinTimeStep() == 0.01); - + // NOTE: Metric unit system is used by default, to time is in days + BOOST_CHECK(rescoup.masterMinTimeStep() == (0.0001 * Opm::unit::day)); } BOOST_AUTO_TEST_CASE(NEGATIVE_VALUE_PROVIDED) { @@ -520,3 +526,50 @@ RCMASTS } BOOST_AUTO_TEST_SUITE_END() + +// ------------------------------------------------ +// Testing DUMPCUPL keyword (sorted alphabetically) +// ------------------------------------------------ + +BOOST_AUTO_TEST_SUITE(DumpCouplingFile) + +BOOST_AUTO_TEST_CASE(FORMATTED_FILE) { + std::string end_of_deck_string = R"( +DUMPCUPL + 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.couplingFileFlag() == + Opm::ReservoirCoupling::CouplingInfo::CouplingFileFlag::FORMATTED); + +} + +BOOST_AUTO_TEST_CASE(BAD_VALUE) { + std::string end_of_deck_string = R"( +DUMPCUPL + S / +)"; + std::string deck_string = getCouplingFileDeckString(end_of_deck_string); + assertRaisesInputErrorException( + deck_string, + /*slave_mode=*/false, + /*exception_string=*/"Problem with keyword DUMPCUPL\nIn line 28\nInvalid DUMPCUPL value: S" + ); +} + +BOOST_AUTO_TEST_CASE(DEFAULT_NOT_ALLOWED) { + std::string end_of_deck_string = R"( +DUMPCUPL + * / +)"; + std::string deck_string = getCouplingFileDeckString(end_of_deck_string); + assertRaisesInputErrorException( + deck_string, + /*slave_mode=*/false, + /*exception_string=*/"Problem with keyword DUMPCUPL\nIn line 28\nDUMPCUPL keyword cannot be defaulted." + ); +} + +BOOST_AUTO_TEST_SUITE_END()