diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index bd5defda8..4d34bcb99 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -94,6 +94,7 @@ if(ENABLE_ECL_INPUT) src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.cpp + src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp src/opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.cpp src/opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.cpp src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp @@ -459,6 +460,7 @@ if(ENABLE_ECL_INPUT) opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.hpp + opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp opm/parser/eclipse/EclipseState/SimulationConfig/ThresholdPressure.hpp opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp diff --git a/opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp b/opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp new file mode 100644 index 000000000..ce63e82c3 --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Schedule/WellTestState.hpp @@ -0,0 +1,82 @@ +/* + 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 . +*/ +#ifndef WELLTEST_STATE_H +#define WELLTEST_STATE_H + +#include +#include +#include + +#include + +namespace Opm { + +class WellTestState { +public: + /* + This class implements a small mutable state object which keeps track of + which wells have been automatically closed by the simulator, and by + checking with the WTEST configuration object the class can return a list + (well_name,reason) pairs for wells which should be checked as candiates + for opening. + */ + + + + struct ClosedWell { + std::string name; + WellTestConfig::Reason reason; + double last_test; + int num_attempt; + }; + + /* + The simulator has decided to close a particular well; we then add it here + as a closed well with a particualar reason. + */ + void addClosedWell(const std::string& well_name, WellTestConfig::Reason reason, double sim_time); + + /* + The update will consult the WellTestConfig object and return a list of + wells which should be checked for possible reopening; observe that the + update method will update the internal state of the object by counting up + the openiing attempts, and also set the time for the last attempt to open. + */ + std::vector> update(const WellTestConfig& config, double sim_time); + + /* + If the simulator decides that a constraint is no longer met the drop() + method should be called to indicate that this reason for keeping the well + closed is no longer active. + */ + void drop(const std::string& well_name, WellTestConfig::Reason reason); + + + bool has(const std::string well_name, WellTestConfig::Reason reason) const; + void openWell(const std::string& well_name); + size_t size() const; +private: + std::vector wells; +}; + + +} + +#endif + diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp new file mode 100644 index 000000000..2bf0f55cb --- /dev/null +++ b/src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp @@ -0,0 +1,86 @@ +/* + 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 . +*/ +#include +#include + +#include +#include + +namespace Opm { + + void WellTestState::addClosedWell(const std::string& well_name, WellTestConfig::Reason reason, double sim_time) { + if (this->has(well_name, reason)) + return; + + this->wells.push_back({well_name, reason, sim_time, 0}); + } + + + void WellTestState::openWell(const std::string& well_name) { + wells.erase(std::remove_if(wells.begin(), + wells.end(), + [&well_name](const ClosedWell& well) { return (well.name == well_name); }), + wells.end()); + } + + + void WellTestState::drop(const std::string& well_name, WellTestConfig::Reason reason) { + wells.erase(std::remove_if(wells.begin(), + wells.end(), + [&well_name, reason](const ClosedWell& well) { return (well.name == well_name && well.reason == reason); }), + wells.end()); + } + + + bool WellTestState::has(const std::string well_name, WellTestConfig::Reason reason) const { + const auto well_iter = std::find_if(wells.begin(), + wells.end(), + [&well_name, &reason](const ClosedWell& well) + { + return (reason == well.reason && well.name == well_name); + }); + return (well_iter != wells.end()); + } + + size_t WellTestState::size() const { + return this->wells.size(); + } + + + std::vector> WellTestState::update(const WellTestConfig& config, double sim_time) { + std::vector> output; + for (auto& closed_well : this->wells) { + if (config.has(closed_well.name, closed_well.reason)) { + const auto& well_config = config.get(closed_well.name, closed_well.reason); + double elapsed = sim_time - closed_well.last_test; + + if (elapsed >= well_config.test_interval) + if (well_config.num_test == 0 || (closed_well.num_attempt < well_config.num_test)) { + closed_well.last_test = sim_time; + closed_well.num_attempt += 1; + output.push_back(std::make_pair(closed_well.name, closed_well.reason)); + } + + } + } + return output; + } +} + + diff --git a/tests/parser/WTEST.cpp b/tests/parser/WTEST.cpp index 27e2e4fab..563d360e5 100644 --- a/tests/parser/WTEST.cpp +++ b/tests/parser/WTEST.cpp @@ -24,6 +24,7 @@ #define BOOST_TEST_MODULE WTEST #include +#include #include #include #include @@ -61,10 +62,60 @@ BOOST_AUTO_TEST_CASE(CreateWellTestConfig) { BOOST_CHECK(!wc.has("NAMEX", WellTestConfig::Reason::ECONOMIC)); BOOST_CHECK(!wc.has("NAME")); - BOOST_CHECK_THROW(wc.get("NAMEX", WellTestConfig::Reason::ECONOMIC), std::invalid_argument); BOOST_CHECK_THROW(wc.get("NO_NAME", WellTestConfig::Reason::ECONOMIC), std::invalid_argument); const auto& wt = wc.get("NAMEX", WellTestConfig::Reason::PHYSICAL); BOOST_CHECK_EQUAL(wt.name, "NAMEX"); } + +BOOST_AUTO_TEST_CASE(WTEST_STATE2) { + WellTestConfig wc; + WellTestState st; + wc.add_well("WELL_NAME", WellTestConfig::Reason::PHYSICAL, 0, 0, 0); + st.addClosedWell("WELL_NAME", WellTestConfig::Reason::PHYSICAL, 100); + BOOST_CHECK_EQUAL(st.size(), 1); + + auto shut_wells = st.update(wc, 5000); + BOOST_CHECK_EQUAL( shut_wells.size(), 1); +} + +BOOST_AUTO_TEST_CASE(WTEST_STATE) { + WellTestConfig wc; + WellTestState st; + st.addClosedWell("WELL_NAME", WellTestConfig::Reason::ECONOMIC, 100); + BOOST_CHECK_EQUAL(st.size(), 1); + + st.addClosedWell("WELL_NAME", WellTestConfig::Reason::ECONOMIC, 100); + BOOST_CHECK_EQUAL(st.size(), 1); + + st.addClosedWell("WELL_NAME", WellTestConfig::Reason::PHYSICAL, 100); + BOOST_CHECK_EQUAL(st.size(), 2); + + st.addClosedWell("WELLX", WellTestConfig::Reason::PHYSICAL, 100); + BOOST_CHECK_EQUAL(st.size(), 3); + + auto shut_wells = st.update(wc, 5000); + BOOST_CHECK_EQUAL( shut_wells.size(), 0); + + wc.add_well("WELL_NAME", WellTestConfig::Reason::PHYSICAL, 1000, 2, 0); + // Not sufficient time has passed. + BOOST_CHECK_EQUAL( st.update(wc, 200).size(), 0); + + // We should test it: + BOOST_CHECK_EQUAL( st.update(wc, 1200).size(), 1); + + // Not sufficient time has passed. + BOOST_CHECK_EQUAL( st.update(wc, 1700).size(), 0); + + // We should test it: + BOOST_CHECK_EQUAL( st.update(wc, 2400).size(), 1); + + // Too many attempts: + BOOST_CHECK_EQUAL( st.update(wc, 24000).size(), 0); + + st.drop("WELL_NAME", WellTestConfig::Reason::ECONOMIC); + + st.openWell("WELL_NAME"); + BOOST_CHECK_EQUAL(st.size(), 1); +}