diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 8d52a9465..ca96635a0 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -42,6 +42,7 @@ list (APPEND MAIN_SOURCE_FILES opm/simulators/utils/ParallelRestart.cpp opm/simulators/wells/GroupState.cpp opm/simulators/wells/WGState.cpp + opm/simulators/wells/ALQState.cpp opm/simulators/wells/ParallelWellInfo.cpp opm/simulators/wells/VFPProdProperties.cpp opm/simulators/wells/VFPInjProperties.cpp @@ -109,6 +110,7 @@ list (APPEND TEST_SOURCE_FILES tests/test_glift1.cpp tests/test_keyword_validator.cpp tests/test_GroupState.cpp + tests/test_ALQState.cpp ) if(MPI_FOUND) @@ -257,6 +259,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/simulators/wells/WellConnectionAuxiliaryModule.hpp opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp opm/simulators/wells/GroupState.hpp + opm/simulators/wells/ALQState.hpp opm/simulators/wells/WGState.hpp opm/simulators/wells/VFPProperties.hpp opm/simulators/wells/VFPHelpers.hpp diff --git a/opm/simulators/wells/ALQState.cpp b/opm/simulators/wells/ALQState.cpp new file mode 100644 index 000000000..2172b762e --- /dev/null +++ b/opm/simulators/wells/ALQState.cpp @@ -0,0 +1,122 @@ +/* + Copyright 2021 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 + +namespace Opm { + +double ALQState::get(const std::string& wname) const { + auto iter = this->current_alq_.find(wname); + if (iter != this->current_alq_.end()) + return iter->second; + + auto default_iter = this->default_alq_.find(wname); + if (default_iter != this->default_alq_.end()) + return default_iter->second; + + throw std::logic_error("No ALQ value registered for well: " + wname); +} + +void ALQState::update_default(const std::string& wname, double value) { + auto default_iter = this->default_alq_.find(wname); + if (default_iter == this->default_alq_.end() || default_iter->second != value) { + this->default_alq_.insert_or_assign(wname, value); + this->current_alq_.insert_or_assign(wname, value); + } +} + +void ALQState::set(const std::string& wname, double value) { + this->current_alq_[wname] = value; +} + +namespace { + +int get_counter(const std::map& count_map, const std::string& wname) { + auto count_iter = count_map.find(wname); + if (count_iter == count_map.end()) + return 0; + return count_iter->second; +} + +} + +bool ALQState::oscillation(const std::string& wname) const { + auto inc_count = get_counter(this->alq_increase_count_, wname); + if (inc_count == 0) + return false; + + auto dec_count = get_counter(this->alq_decrease_count_, wname); + return dec_count >= 1; +} + + +void ALQState::update_count(const std::string& wname, bool increase) { + if (increase) + this->alq_increase_count_[wname] += 1; + else + this->alq_decrease_count_[wname] += 1; + +} + + +void ALQState::reset_count() { + this->alq_decrease_count_.clear(); + this->alq_increase_count_.clear(); +} + + +int ALQState::get_increment_count(const std::string& wname) const { + return get_counter(this->alq_increase_count_, wname); +} + +int ALQState::get_decrement_count(const std::string& wname) const { + return get_counter(this->alq_decrease_count_, wname); +} + +std::size_t ALQState::pack_size() const { + return this->current_alq_.size(); +} + +std::size_t ALQState::pack_data(double * data) const { + std::size_t index = 0; + for (const auto& [_, value] : this->current_alq_) { + (void)_; + data[index++] = value; + } + return index; +} + +std::size_t ALQState::unpack_data(const double * data) { + std::size_t index = 0; + for (auto& [_, value] : this->current_alq_) { + (void)_; + value = data[index++]; + } + return index; +} + + + +} + + + diff --git a/opm/simulators/wells/ALQState.hpp b/opm/simulators/wells/ALQState.hpp new file mode 100644 index 000000000..d9ba27dcf --- /dev/null +++ b/opm/simulators/wells/ALQState.hpp @@ -0,0 +1,59 @@ +/* + Copyright 2021 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_ALQ_STATE_HEADER_INCLUDED +#define OPM_ALQ_STATE_HEADER_INCLUDED + +#include +#include +#include + + +namespace Opm { + +class ALQState { +public: + + std::size_t pack_size() const; + std::size_t unpack_data(const double * data); + std::size_t pack_data(double * data) const; + + double get(const std::string& wname) const; + void update_default(const std::string& wname, double value); + void set(const std::string& wname, double value); + bool oscillation(const std::string& wname) const; + void update_count(const std::string& wname, bool increase); + void reset_count(); + int get_increment_count(const std::string& wname) const; + int get_decrement_count(const std::string& wname) const; + +private: + std::map current_alq_; + std::map default_alq_; + std::map alq_increase_count_; + std::map alq_decrease_count_; +}; + + +} + +#endif + + + diff --git a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp index d507e2916..ce0fad467 100644 --- a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp +++ b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp @@ -22,6 +22,7 @@ #define OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED #include +#include #include #include @@ -1022,7 +1023,7 @@ namespace Opm sz += v.size(); }; iterateRatesContainer(this->well_rates, computeSize); - sz += current_alq_.size(); + sz += this->alq_state.pack_size(); // Make a vector and collect all data into it. std::vector data(sz); @@ -1033,9 +1034,7 @@ namespace Opm } }; iterateRatesContainer(this->well_rates, collect); - for (const auto& x : current_alq_) { - data[pos++] = x.second; - } + pos += this->alq_state.pack_data(&data[pos]); assert(pos == sz); // Communicate it with a single sum() call. @@ -1049,9 +1048,7 @@ namespace Opm } }; iterateRatesContainer(this->well_rates, distribute); - for (auto& x : current_alq_) { - x.second = data[pos++]; - } + pos += this->alq_state.unpack_data(&data[pos]); assert(pos == sz); } @@ -1106,65 +1103,28 @@ namespace Opm double getALQ( const std::string& name) const { - if (this->current_alq_.count(name) == 0) { - return this->default_alq_.at(name); - } - return this->current_alq_.at(name); + return this->alq_state.get(name); } void setALQ( const std::string& name, double value) { - this->current_alq_[name] = value; + this->alq_state.set(name, value); } bool gliftCheckAlqOscillation(const std::string &name) const { - if ((this->alq_increase_count_.count(name) == 1) && - (this->alq_decrease_count_.count(name) == 1)) - { - if ((this->alq_increase_count_.at(name) >= 1) && - (this->alq_decrease_count_.at(name) >= 1)) - { - return true; - } - } - return false; + return this->alq_state.oscillation(name); } int gliftGetAlqDecreaseCount(const std::string &name) { - if (this->alq_decrease_count_.count(name) == 0) { - return 0; - } - else { - return this->alq_decrease_count_[name]; - } + return this->alq_state.get_decrement_count(name); } int gliftGetAlqIncreaseCount(const std::string &name) { - if (this->alq_increase_count_.count(name) == 0) { - return 0; - } - else { - return this->alq_increase_count_[name]; - } + return this->alq_state.get_increment_count(name); } void gliftUpdateAlqIncreaseCount(const std::string &name, bool increase) { - if (increase) { - if (this->alq_increase_count_.count(name) == 0) { - this->alq_increase_count_[name] = 1; - } - else { - this->alq_increase_count_[name]++; - } - } - else { - if (this->alq_decrease_count_.count(name) == 0) { - this->alq_decrease_count_[name] = 1; - } - else { - this->alq_decrease_count_[name]++; - } - } + this->alq_state.update_count(name, increase); } bool gliftOptimizationEnabled() const { @@ -1172,8 +1132,7 @@ namespace Opm } void gliftTimeStepInit() { - this->alq_increase_count_.clear(); - this->alq_decrease_count_.clear(); + this->alq_state.reset_count(); disableGliftOptimization(); } @@ -1223,10 +1182,7 @@ namespace Opm std::map wellNameToGlobalIdx_; std::map>> well_rates; - std::map current_alq_; - std::map default_alq_; - std::map alq_increase_count_; - std::map alq_decrease_count_; + ALQState alq_state; bool do_glift_optimization_; std::vector perfRateSolvent_; @@ -1377,19 +1333,9 @@ namespace Opm for (int i = 0; idefault_alq_.count(name) != 0) { - if (this->default_alq_[name] == alq) { - // If the previous value was the same, we leave current_alq_ - // as it is. - continue; - } - } - this->default_alq_[name] = alq; - // Reset current ALQ if a new value was given in WCONPROD - this->current_alq_[name] = alq; + this->alq_state.update_default(well.name(), alq); } } } diff --git a/tests/test_ALQState.cpp b/tests/test_ALQState.cpp new file mode 100644 index 000000000..48bc59968 --- /dev/null +++ b/tests/test_ALQState.cpp @@ -0,0 +1,81 @@ +/* + Copyright 2021 Equinor. + + 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 + + +#define BOOST_TEST_MODULE GroupStateTest +#include + +using namespace Opm; + + + +BOOST_AUTO_TEST_CASE(ALQStateCreate) { + ALQState alq_state; + + + alq_state.update_default("W1", 100); + alq_state.update_default("W2", 200); + alq_state.set("W1", 1); + + BOOST_CHECK_THROW( alq_state.get("W3"), std::exception); + BOOST_CHECK_EQUAL( alq_state.get("W2"), 200); + BOOST_CHECK_EQUAL( alq_state.get("W1"), 1); + + alq_state.update_default("W1", 100); + BOOST_CHECK_EQUAL( alq_state.get("W1"), 1); + + alq_state.update_default("W1", 0); + BOOST_CHECK_EQUAL( alq_state.get("W1"), 0); + + BOOST_CHECK(!alq_state.oscillation("WX")); + + alq_state.update_count("WX", true); + BOOST_CHECK(!alq_state.oscillation("WX")); + + alq_state.update_count("WX", false); + BOOST_CHECK(alq_state.oscillation("WX")); + + alq_state.reset_count(); + BOOST_CHECK_EQUAL(alq_state.get_increment_count("NO_SUCH_WELL"), 0); + BOOST_CHECK_EQUAL(alq_state.get_increment_count("WX"), 0); + alq_state.update_count("WX", true); + BOOST_CHECK_EQUAL(alq_state.get_increment_count("WX"), 1); + + BOOST_CHECK_EQUAL(alq_state.get_decrement_count("WX"), 0); + alq_state.update_count("WX", false); + BOOST_CHECK_EQUAL(alq_state.get_decrement_count("WX"), 1); + + alq_state.set("W1", 1); + alq_state.set("W2", 2); + BOOST_CHECK_EQUAL(alq_state.pack_size(), 2); + std::vector data(2); + + BOOST_CHECK_EQUAL( alq_state.get("W1"), 1); + BOOST_CHECK_EQUAL( alq_state.get("W2"), 2); + BOOST_CHECK_EQUAL(alq_state.pack_data(data.data()), 2); + alq_state.set("W1", 99); + alq_state.set("W2", 101); + + BOOST_CHECK_EQUAL(alq_state.unpack_data(data.data()), 2); + BOOST_CHECK_EQUAL( alq_state.get("W1"), 1); + BOOST_CHECK_EQUAL( alq_state.get("W2"), 2); +}