diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index bb6eed25a99..16cc5379bdb 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -284,6 +284,7 @@ if(ENABLE_ECL_INPUT) opm/input/eclipse/Schedule/ResCoup/GrupSlav.cpp 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/UDQ/UDQKeywordHandlers.cpp opm/input/eclipse/Schedule/UDQ/UDQActive.cpp opm/input/eclipse/Schedule/UDQ/UDQAssign.cpp @@ -1310,6 +1311,7 @@ if(ENABLE_ECL_INPUT) opm/input/eclipse/Schedule/ResCoup/GrupSlav.hpp 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/VFPInjTable.hpp opm/input/eclipse/Schedule/VFPProdTable.hpp opm/input/eclipse/Schedule/Well/Connection.hpp diff --git a/opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.cpp b/opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.cpp new file mode 100644 index 00000000000..7fc4084d497 --- /dev/null +++ b/opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.cpp @@ -0,0 +1,58 @@ +/* + 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 handleRCMASTS(HandlerContext& handlerContext) +{ + auto& schedule_state = handlerContext.state(); + auto rescoup = schedule_state.rescoup(); + auto tuning = schedule_state.tuning(); + const auto& keyword = handlerContext.keyword; + if (keyword.size() != 1) { + throw OpmInputError("RCMASTS keyword requires exactly one record.", keyword.location()); + } + auto record = keyword[0]; + auto deck_item = record.getItem(); + if (deck_item.defaultApplied(0)) { + // The default value is the current value TSMINZ + rescoup.masterMinTimeStep(tuning.TSMINZ); + } + else { + auto tstep = deck_item.getSIDouble(0); + if (tstep < 0.0) { + throw OpmInputError("Negative value for RCMASTS is not allowed.", keyword.location()); + } + rescoup.masterMinTimeStep(tstep); + } + schedule_state.rescoup.update( std::move( rescoup )); +} + +} // namespace Opm + diff --git a/opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.hpp b/opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.hpp new file mode 100644 index 00000000000..a963a9fbc45 --- /dev/null +++ b/opm/input/eclipse/Schedule/ResCoup/MasterMinimumTimeStep.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_MASTER_MINIMUM_TIMESTEP_HPP +#define RESERVOIR_COUPLING_MASTER_MINIMUM_TIMESTEP_HPP +namespace Opm { + +class HandlerContext; + +extern void handleRCMASTS(HandlerContext& handlerContext); + +} // namespace Opm +#endif // RESERVOIR_COUPLING_MASTER_MINIMUM_TIMESTEP_HPP diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp index d71a082db37..3e086af3538 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.cpp @@ -27,7 +27,8 @@ namespace ReservoirCoupling { 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_grup_slavs == rhs.m_grup_slavs && + this->m_master_min_time_step == rhs.m_master_min_time_step; } CouplingInfo CouplingInfo::serializationTestObject() diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp index 3c319eb59cf..eeef31188be 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp @@ -53,6 +53,7 @@ class CouplingInfo { bool hasGrupSlav(const std::string& name) const { return m_grup_slavs.find(name) != m_grup_slavs.end(); } + bool hasMasterGroup(const std::string& name) const { return m_master_groups.find(name) != m_master_groups.end(); } @@ -69,10 +70,18 @@ class CouplingInfo { const MasterGroup& masterGroup(const std::string& name) const { return m_master_groups.at(name); } + int masterGroupCount() const { return m_master_groups.size(); } + double masterMinTimeStep() const { + return m_master_min_time_step; + } + void masterMinTimeStep(double tstep) { + m_master_min_time_step = tstep; + } + const std::map& slaves() const { return this->m_slaves; } @@ -93,11 +102,14 @@ class CouplingInfo { serializer(m_slaves); serializer(m_master_groups); serializer(m_grup_slavs); + serializer(m_master_min_time_step); } + private: std::map m_slaves; std::map m_master_groups; std::map m_grup_slavs; + double m_master_min_time_step{0.0}; }; } // namespace Opm::ReservoirCoupling diff --git a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp index 4e7a0082b76..3d2301566cd 100644 --- a/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp +++ b/opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingKeywordHandlers.cpp @@ -23,22 +23,20 @@ #include "GrupSlav.hpp" #include "Slaves.hpp" #include "MasterGroup.hpp" +#include "MasterMinimumTimeStep.hpp" #include namespace Opm { -namespace { - -} // anonymous namespace - std::vector> getReservoirCouplingHandlers() { return { { "SLAVES", &handleSLAVES }, { "GRUPMAST", &handleGRUPMAST}, - { "GRUPSLAV", &handleGRUPSLAV} + { "GRUPSLAV", &handleGRUPSLAV}, + { "RCMASTS", &handleRCMASTS}, }; } diff --git a/tests/parser/ReservoirCouplingTests.cpp b/tests/parser/ReservoirCouplingTests.cpp index ddf8c710bba..294868e0463 100644 --- a/tests/parser/ReservoirCouplingTests.cpp +++ b/tests/parser/ReservoirCouplingTests.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ using namespace Opm; namespace { -Schedule make_schedule(const std::string& schedule_string, bool slave_mode) { +Schedule makeSchedule(const std::string& schedule_string, bool slave_mode) { Parser parser; auto python = std::make_shared(); Deck deck = parser.parseString(schedule_string); @@ -61,11 +62,11 @@ void addStringLogger(std::ostringstream& stream_buffer) { } void assertRaisesInputErrorException(const std::string& schedule_string, bool slave_mode, const std::string& exception_string) { - BOOST_CHECK_THROW(make_schedule(schedule_string, slave_mode), Opm::OpmInputError); + BOOST_CHECK_THROW(makeSchedule(schedule_string, slave_mode), Opm::OpmInputError); try { // Now that we know that it will throw the specific exception Opm::OpmInputError, // we can check that the exception message is correct - make_schedule(schedule_string, slave_mode); + makeSchedule(schedule_string, slave_mode); } catch (const Opm::OpmInputError& e) { BOOST_CHECK_EQUAL(std::string(e.what()), exception_string); @@ -96,51 +97,85 @@ void checkLastLineStringBuffer( } } +std::string getMinimumMasterTimeStepDeckString(const std::string &end_of_deck_string) +{ + std::string prefix = R"( +SCHEDULE + +GRUPTREE + 'PLAT-A' 'FIELD' / + + 'MOD1' 'PLAT-A' / + + 'B1_M' 'MOD1' / + 'D1_M' 'MOD1' / + 'C1_M' 'MOD1' / + + 'E1_M' 'PLAT-A' / +/ + +SLAVES + 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' 4 / + 'RES-2' 'RC-01_MOD2_PRED' 1* '../mod2' 1 / +/ + +GRUPMAST + 'D1_M' 'RES-1' 'MANI-D' 1* / + 'B1_M' 'RES-1' 'MANI-B' 1* / + 'C1_M' 'RES-1' 'MANI-C' 1* / + 'E1_M' 'RES-2' 'E1' 1* / +/ +)"; + return prefix + end_of_deck_string; +} + void removeStringLogger() { OpmLog::removeBackend("MYLOGGER"); } } // namespace -// ------------------------------- -// Testing SLAVES keyword -// ------------------------------- +// ---------------------------------------------- +// Testing SLAVES keyword (sorted alphabetically) +// ---------------------------------------------- +BOOST_AUTO_TEST_SUITE(SlaveTests) -BOOST_AUTO_TEST_CASE(SLAVES_OK) { +BOOST_AUTO_TEST_CASE(FAIL_NEGATIVE_NUMPROCS) { std::string deck_string = R"( - SCHEDULE SLAVES - 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' 4 / + 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' -4 / 'RES-2' 'RC-01_MOD2_PRED' 1* '../mod2' 1 / / )"; - const auto& schedule = make_schedule(deck_string, /*slave_mode=*/false); - const auto& rescoup = schedule[0].rescoup(); - BOOST_CHECK(rescoup.hasSlave("RES-1")); - auto slave = rescoup.slave("RES-1"); - BOOST_CHECK_EQUAL(slave.name(), "RES-1"); - BOOST_CHECK_EQUAL(slave.dataFilename(), "RC-01_MOD1_PRED"); - BOOST_CHECK_EQUAL(slave.directoryPath(), "../mod1"); - BOOST_CHECK_EQUAL(slave.numprocs(), 4); + assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/ "Problem with keyword SLAVES\nIn line 3\nNumber of processors must be positive. Got: -4."); } -BOOST_AUTO_TEST_CASE(SLAVES_FAIL_NEGATIVE_NUMPROCS) { +BOOST_AUTO_TEST_CASE(SYNTAX_OK) { std::string deck_string = R"( + SCHEDULE SLAVES - 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' -4 / + 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' 4 / 'RES-2' 'RC-01_MOD2_PRED' 1* '../mod2' 1 / / )"; - assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/ "Problem with keyword SLAVES\nIn line 3\nNumber of processors must be positive. Got: -4."); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); + const auto& rescoup = schedule[0].rescoup(); + BOOST_CHECK(rescoup.hasSlave("RES-1")); + auto slave = rescoup.slave("RES-1"); + BOOST_CHECK_EQUAL(slave.name(), "RES-1"); + BOOST_CHECK_EQUAL(slave.dataFilename(), "RC-01_MOD1_PRED"); + BOOST_CHECK_EQUAL(slave.directoryPath(), "../mod1"); + BOOST_CHECK_EQUAL(slave.numprocs(), 4); } -BOOST_AUTO_TEST_CASE(SLAVES_WARN_DUPLICATE_NAME) { + +BOOST_AUTO_TEST_CASE(WARN_DUPLICATE_NAME) { std::string deck_string = R"( SCHEDULE SLAVES @@ -151,7 +186,7 @@ SLAVES )"; std::ostringstream stream_buffer; addStringLogger(stream_buffer); - const auto& schedule = make_schedule(deck_string, /*slave_mode=*/false); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); checkLastLineStringBuffer( stream_buffer, "Slave reservoir 'RES-1' already defined. Redefining", @@ -159,32 +194,23 @@ SLAVES ); removeStringLogger(); } +BOOST_AUTO_TEST_SUITE_END() -// ------------------------------- -// Testing GRUPMAST keyword -// ------------------------------- +// ------------------------------------------------ +// Testing GRUPMAST keyword (sorted alphabetically) +// ------------------------------------------------ -BOOST_AUTO_TEST_CASE(GRUPMAST_OK) { - std::string deck_string = R"( +BOOST_AUTO_TEST_SUITE(GrupMastTests) +BOOST_AUTO_TEST_CASE(FAIL_MISSING_MASTER_GROUP) { + std::string deck_string = R"( SCHEDULE + SLAVES 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' 4 / 'RES-2' 'RC-01_MOD2_PRED' 1* '../mod2' 1 / / -GRUPTREE - 'PLAT-A' 'FIELD' / - - 'MOD1' 'PLAT-A' / - - 'B1_M' 'MOD1' / - 'D1_M' 'MOD1' / - 'C1_M' 'MOD1' / - - 'E1_M' 'PLAT-A' / -/ - GRUPMAST 'D1_M' 'RES-1' 'MANI-D' 1* / 'B1_M' 'RES-1' 'MANI-B' 1* / @@ -193,23 +219,24 @@ GRUPMAST / )"; - const auto& schedule = make_schedule(deck_string, /*slave_mode=*/false); - const auto& rescoup = schedule[0].rescoup(); - BOOST_CHECK(rescoup.hasMasterGroup("D1_M")); - auto master_group = rescoup.masterGroup("D1_M"); - BOOST_CHECK_EQUAL(master_group.name(), "D1_M"); - BOOST_CHECK_EQUAL(master_group.slaveName(), "RES-1"); - BOOST_CHECK_EQUAL(master_group.slaveGroupName(), "MANI-D"); - BOOST_CHECK_EQUAL(master_group.flowLimitFraction(), 1e+20); + assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/"Problem with keyword GRUPMAST\nIn line 9\nGroup 'D1_M': Not defined. Master groups should be defined in advance by using GRUPTREE before referenced in GRUPMAST."); } -BOOST_AUTO_TEST_CASE(GRUPMAST_FAIL_MISSING_MASTER_GROUP) { +BOOST_AUTO_TEST_CASE(FAIL_MISSING_SLAVE) { std::string deck_string = R"( + SCHEDULE -SLAVES - 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' 4 / - 'RES-2' 'RC-01_MOD2_PRED' 1* '../mod2' 1 / +GRUPTREE + 'PLAT-A' 'FIELD' / + + 'MOD1' 'PLAT-A' / + + 'B1_M' 'MOD1' / + 'D1_M' 'MOD1' / + 'C1_M' 'MOD1' / + + 'E1_M' 'PLAT-A' / / GRUPMAST @@ -220,10 +247,10 @@ GRUPMAST / )"; - assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/"Problem with keyword GRUPMAST\nIn line 9\nGroup 'D1_M': Not defined. Master groups should be defined in advance by using GRUPTREE before referenced in GRUPMAST."); + assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/"Problem with keyword GRUPMAST\nIn line 17\nSlave reservoir 'RES-1': Not defined. Slave reservoirs should be defined in advance by using SLAVES before referenced in GRUPMAST."); } -BOOST_AUTO_TEST_CASE(GRUPMAST_FAIL_SUBORDINATE_GROUPS) { +BOOST_AUTO_TEST_CASE(FAIL_SUBORDINATE_GROUPS) { std::string deck_string = R"( SCHEDULE @@ -255,7 +282,7 @@ GRUPMAST assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/"Problem with keyword GRUPMAST\nIn line 21\nGroup 'FIELD' has subgroups: A master group cannot contain any wells or subordinate groups."); } -BOOST_AUTO_TEST_CASE(GRUPMAST_FAIL_SUBORDINATE_WELLS) { +BOOST_AUTO_TEST_CASE(FAIL_SUBORDINATE_WELLS) { std::string deck_string = R"( SCHEDULE @@ -292,10 +319,14 @@ GRUPMAST assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/"Problem with keyword GRUPMAST\nIn line 26\nGroup 'D1_M' has wells: A master group cannot contain any wells or subordinate groups."); } -BOOST_AUTO_TEST_CASE(GRUPMAST_FAIL_MISSING_SLAVE) { - std::string deck_string = R"( +BOOST_AUTO_TEST_CASE(SYNTAX_OK) { + std::string deck_string = R"( SCHEDULE +SLAVES + 'RES-1' 'RC-01_MOD1_PRED' 1* '../mod1' 4 / + 'RES-2' 'RC-01_MOD2_PRED' 1* '../mod2' 1 / +/ GRUPTREE 'PLAT-A' 'FIELD' / @@ -317,13 +348,25 @@ GRUPMAST / )"; - assertRaisesInputErrorException(deck_string, /*slave_mode=*/false, /*exception_string=*/"Problem with keyword GRUPMAST\nIn line 17\nSlave reservoir 'RES-1': Not defined. Slave reservoirs should be defined in advance by using SLAVES before referenced in GRUPMAST."); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); + const auto& rescoup = schedule[0].rescoup(); + BOOST_CHECK(rescoup.hasMasterGroup("D1_M")); + auto master_group = rescoup.masterGroup("D1_M"); + BOOST_CHECK_EQUAL(master_group.name(), "D1_M"); + BOOST_CHECK_EQUAL(master_group.slaveName(), "RES-1"); + BOOST_CHECK_EQUAL(master_group.slaveGroupName(), "MANI-D"); + BOOST_CHECK_EQUAL(master_group.flowLimitFraction(), 1e+20); } -// ------------------------------- -// Testing GRUPSLAV keyword -// ------------------------------- -BOOST_AUTO_TEST_CASE(GRUPSLAV_OK) { +BOOST_AUTO_TEST_SUITE_END() + +// ------------------------------------------------ +// Testing GRUPSLAV keyword (sorted alphabetically) +// ------------------------------------------------ + +BOOST_AUTO_TEST_SUITE(GrupSlavTests) + +BOOST_AUTO_TEST_CASE(DEFAULT_APPLIED) { std::string deck_string = R"( SCHEDULE @@ -335,28 +378,21 @@ GRUPTREE / GRUPSLAV - 'MANI-D' 'D1_M' / + 'MANI-D' 1* / 'MANI-B' 'B1_M' / 'MANI-C' 'C1_M' / / )"; - const auto& schedule = make_schedule(deck_string, /*slave_mode=*/true); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/true); const auto& rescoup = schedule[0].rescoup(); BOOST_CHECK(rescoup.hasGrupSlav("MANI-D")); auto grup_slav = rescoup.grupSlav("MANI-D"); BOOST_CHECK_EQUAL(grup_slav.name(), "MANI-D"); - BOOST_CHECK_EQUAL(grup_slav.masterGroupName(), "D1_M"); - BOOST_CHECK_EQUAL(grup_slav.oilProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); - BOOST_CHECK_EQUAL(grup_slav.liquidProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); - BOOST_CHECK_EQUAL(grup_slav.gasProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); - BOOST_CHECK_EQUAL(grup_slav.fluidVolumeProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); - BOOST_CHECK_EQUAL(grup_slav.oilInjFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); - BOOST_CHECK_EQUAL(grup_slav.waterInjFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); - BOOST_CHECK_EQUAL(grup_slav.gasInjFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.masterGroupName(), "MANI-D"); } -BOOST_AUTO_TEST_CASE(GRUPSLAV_FAIL_MISSING_GROUP) { +BOOST_AUTO_TEST_CASE(FAIL_MISSING_GROUP) { std::string deck_string = R"( SCHEDULE @@ -370,7 +406,7 @@ GRUPSLAV assertRaisesInputErrorException(deck_string, /*slave_mode=*/true, /*exception_string=*/"Problem with keyword GRUPSLAV\nIn line 4\nGroup 'MANI-D': Not defined. Slave groups should be defined in advance by using GRUPTREE or WELSPECS before referenced in GRUPSLAV."); } -BOOST_AUTO_TEST_CASE(GRUPSLAV_DEFAULT_APPLIED) { +BOOST_AUTO_TEST_CASE(SYNTAX_OK) { std::string deck_string = R"( SCHEDULE @@ -382,16 +418,106 @@ GRUPTREE / GRUPSLAV - 'MANI-D' 1* / + 'MANI-D' 'D1_M' / 'MANI-B' 'B1_M' / 'MANI-C' 'C1_M' / / )"; - const auto& schedule = make_schedule(deck_string, /*slave_mode=*/true); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/true); const auto& rescoup = schedule[0].rescoup(); BOOST_CHECK(rescoup.hasGrupSlav("MANI-D")); auto grup_slav = rescoup.grupSlav("MANI-D"); BOOST_CHECK_EQUAL(grup_slav.name(), "MANI-D"); - BOOST_CHECK_EQUAL(grup_slav.masterGroupName(), "MANI-D"); + BOOST_CHECK_EQUAL(grup_slav.masterGroupName(), "D1_M"); + BOOST_CHECK_EQUAL(grup_slav.oilProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.liquidProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.gasProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.fluidVolumeProdFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.oilInjFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.waterInjFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); + BOOST_CHECK_EQUAL(grup_slav.gasInjFlag(), Opm::ReservoirCoupling::GrupSlav::FilterFlag::MAST); +} + +BOOST_AUTO_TEST_SUITE_END() + +// ------------------------------------------------ +// Testing RCMASTS keyword (sorted alphabetically) +// ------------------------------------------------ + +BOOST_AUTO_TEST_SUITE(MinimumMasterTimeStep) + +BOOST_AUTO_TEST_CASE(DEFAULT_APPLIED1) { + std::string end_of_deck_string = R"( +TUNING +-- TSINIT TSMAXZ TSMINZ + * * 0.1 / +/ +/ +)"; + 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.0); // Default value when RCMASTS is not given + +} + +BOOST_AUTO_TEST_CASE(DEFAULT_APPLIED2) { + std::string end_of_deck_string = R"( +TUNING +-- TSINIT TSMAXZ TSMINZ + * * 0.1 / +/ +/ + +RCMASTS + * / +)"; + std::string deck_string = getMinimumMasterTimeStepDeckString(end_of_deck_string); + const auto& schedule = makeSchedule(deck_string, /*slave_mode=*/false); + const auto& rescoup = schedule[0].rescoup(); + const auto& tuning = schedule[0].tuning(); + // Default value when RCMASTS is given but no value is provided + BOOST_CHECK(rescoup.masterMinTimeStep() == tuning.TSMINZ); + +} + +BOOST_AUTO_TEST_CASE(VALUE_PROVIDED) { + std::string end_of_deck_string = R"( +TUNING +-- TSINIT TSMAXZ TSMINZ + * * 0.1 / +/ +/ + +RCMASTS + 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(); + // 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) { + std::string end_of_deck_string = R"( +TUNING +-- TSINIT TSMAXZ TSMINZ + * * 0.1 / +/ +/ + +RCMASTS + -0.1 / +)"; + std::string deck_string = getMinimumMasterTimeStepDeckString(end_of_deck_string); + assertRaisesInputErrorException( + deck_string, + /*slave_mode=*/false, + /*exception_string=*/"Problem with keyword RCMASTS\nIn line 34\nNegative value for RCMASTS is not allowed." + ); + } + +BOOST_AUTO_TEST_SUITE_END()