diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index f3d685ff8..6b10c1d57 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -40,6 +40,7 @@ list (APPEND MAIN_SOURCE_FILES opm/simulators/utils/DeferredLogger.cpp opm/simulators/utils/gatherDeferredLogger.cpp opm/simulators/utils/ParallelRestart.cpp + opm/simulators/wells/GroupState.cpp opm/simulators/wells/ParallelWellInfo.cpp opm/simulators/wells/VFPProdProperties.cpp opm/simulators/wells/VFPInjProperties.cpp @@ -106,6 +107,7 @@ list (APPEND TEST_SOURCE_FILES tests/test_parallelwellinfo.cpp tests/test_glift1.cpp tests/test_keyword_validator.cpp + tests/test_GroupState.cpp ) if(MPI_FOUND) @@ -253,6 +255,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/simulators/wells/TargetCalculator.hpp opm/simulators/wells/WellConnectionAuxiliaryModule.hpp opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp + opm/simulators/wells/GroupState.hpp opm/simulators/wells/VFPProperties.hpp opm/simulators/wells/VFPHelpers.hpp opm/simulators/wells/VFPInjProperties.hpp diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index bc2d74530..80bfb17a7 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -33,7 +33,11 @@ namespace Opm { template BlackoilWellModel:: BlackoilWellModel(Simulator& ebosSimulator) - : ebosSimulator_(ebosSimulator) + : ebosSimulator_(ebosSimulator), + phase_usage_(phaseUsageFromDeck(ebosSimulator_.vanguard().eclState())), + active_well_state_(phase_usage_.num_phases), + last_valid_well_state_(phase_usage_.num_phases), + nupcol_well_state_(phase_usage_.num_phases) { terminal_output_ = false; if (ebosSimulator.gridView().comm().rank() == 0) @@ -75,13 +79,9 @@ namespace Opm { BlackoilWellModel:: init() { - const Opm::EclipseState& eclState = ebosSimulator_.vanguard().eclState(); - extractLegacyCellPvtRegionIndex_(); extractLegacyDepth_(); - phase_usage_ = phaseUsageFromDeck(eclState); - gravity_ = ebosSimulator_.problem().gravity()[2]; initial_step_ = true; diff --git a/opm/simulators/wells/GroupState.cpp b/opm/simulators/wells/GroupState.cpp new file mode 100644 index 000000000..87fc18951 --- /dev/null +++ b/opm/simulators/wells/GroupState.cpp @@ -0,0 +1,237 @@ +/* + 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 + +namespace Opm { + +GroupState::GroupState(std::size_t np) : + num_phases(np) +{} + +bool GroupState::operator==(const GroupState& other) const { + return this->m_production_rates == other.m_production_rates && + this->production_controls == other.production_controls && + this->prod_red_rates == other.prod_red_rates && + this->inj_red_rates == other.inj_red_rates && + this->inj_resv_rates == other.inj_resv_rates && + this->inj_potentials == other.inj_potentials && + this->inj_rein_rates == other.inj_rein_rates && + this->inj_vrep_rate == other.inj_vrep_rate && + this->m_grat_sales_target == other.m_grat_sales_target && + this->injection_controls == other.injection_controls; +} + +//------------------------------------------------------------------------- + +bool GroupState::has_production_rates(const std::string& gname) const { + auto group_iter = this->m_production_rates.find(gname); + return (group_iter != this->m_production_rates.end()); +} + +void GroupState::update_production_rates(const std::string& gname, const std::vector& rates) { + if (rates.size() != this->num_phases) + throw std::logic_error("Wrong number of phases"); + + this->m_production_rates[gname] = rates; +} + +const std::vector& GroupState::production_rates(const std::string& gname) const { + auto group_iter = this->m_production_rates.find(gname); + if (group_iter == this->m_production_rates.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +bool GroupState::has_production_reduction_rates(const std::string& gname) const { + auto group_iter = this->prod_red_rates.find(gname); + return (group_iter != this->prod_red_rates.end()); +} + +void GroupState::update_production_reduction_rates(const std::string& gname, const std::vector& rates) { + if (rates.size() != this->num_phases) + throw std::logic_error("Wrong number of phases"); + + this->prod_red_rates[gname] = rates; +} + +const std::vector& GroupState::production_reduction_rates(const std::string& gname) const { + auto group_iter = this->prod_red_rates.find(gname); + if (group_iter == this->prod_red_rates.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +bool GroupState::has_injection_reduction_rates(const std::string& gname) const { + auto group_iter = this->inj_red_rates.find(gname); + return (group_iter != this->inj_red_rates.end()); +} + +void GroupState::update_injection_reduction_rates(const std::string& gname, const std::vector& rates) { + if (rates.size() != this->num_phases) + throw std::logic_error("Wrong number of phases"); + + this->inj_red_rates[gname] = rates; +} + +const std::vector& GroupState::injection_reduction_rates(const std::string& gname) const { + auto group_iter = this->inj_red_rates.find(gname); + if (group_iter == this->inj_red_rates.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +bool GroupState::has_injection_reservoir_rates(const std::string& gname) const { + auto group_iter = this->inj_resv_rates.find(gname); + return (group_iter != this->inj_resv_rates.end()); +} + +void GroupState::update_injection_reservoir_rates(const std::string& gname, const std::vector& rates) { + if (rates.size() != this->num_phases) + throw std::logic_error("Wrong number of phases"); + + this->inj_resv_rates[gname] = rates; +} + +const std::vector& GroupState::injection_reservoir_rates(const std::string& gname) const { + auto group_iter = this->inj_resv_rates.find(gname); + if (group_iter == this->inj_resv_rates.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +void GroupState::update_injection_rein_rates(const std::string& gname, const std::vector& rates) { + if (rates.size() != this->num_phases) + throw std::logic_error("Wrong number of phases"); + + this->inj_rein_rates[gname] = rates; +} + +const std::vector& GroupState::injection_rein_rates(const std::string& gname) const { + auto group_iter = this->inj_rein_rates.find(gname); + if (group_iter == this->inj_rein_rates.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +void GroupState::update_injection_vrep_rate(const std::string& gname, double rate) { + this->inj_vrep_rate[gname] = rate; +} + +double GroupState::injection_vrep_rate(const std::string& gname) const { + auto group_iter = this->inj_vrep_rate.find(gname); + if (group_iter == this->inj_vrep_rate.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +void GroupState::update_grat_sales_target(const std::string& gname, double target) { + this->m_grat_sales_target[gname] = target; +} + +double GroupState::grat_sales_target(const std::string& gname) const { + auto group_iter = this->m_grat_sales_target.find(gname); + if (group_iter == this->m_grat_sales_target.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +bool GroupState::has_grat_sales_target(const std::string& gname) const { + return (this->m_grat_sales_target.count(gname) > 0); +} + +//------------------------------------------------------------------------- + +void GroupState::update_injection_potentials(const std::string& gname, const std::vector& potentials) { + if (potentials.size() != this->num_phases) + throw std::logic_error("Wrong number of phases"); + + this->inj_potentials[gname] = potentials; +} + +const std::vector& GroupState::injection_potentials(const std::string& gname) const { + auto group_iter = this->inj_potentials.find(gname); + if (group_iter == this->inj_potentials.end()) + throw std::logic_error("No such group"); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +bool GroupState::has_production_control(const std::string& gname) const { + auto group_iter = this->production_controls.find(gname); + if (group_iter == this->production_controls.end()) + return false; + + return true; +} + +void GroupState::production_control(const std::string& gname, Group::ProductionCMode cmode) { + this->production_controls[gname] = cmode; +} + +Group::ProductionCMode GroupState::production_control(const std::string& gname) const { + auto group_iter = this->production_controls.find(gname); + if (group_iter == this->production_controls.end()) + throw std::logic_error("Could not find any control for production group: " + gname); + + return group_iter->second; +} + +//------------------------------------------------------------------------- + +bool GroupState::has_injection_control(const std::string& gname, Phase phase) const { + return this->injection_controls.count(std::make_pair(phase, gname)) > 0; +} + +void GroupState::injection_control(const std::string& gname, Phase phase, Group::InjectionCMode cmode) { + this->injection_controls[ std::make_pair(phase, gname) ] = cmode; +} + +Group::InjectionCMode GroupState::injection_control(const std::string& gname, Phase phase) const { + auto key = std::make_pair(phase, gname); + auto group_iter = this->injection_controls.find( key ); + if (group_iter == this->injection_controls.end()) + throw std::logic_error("Could not find ontrol for injection group: " + gname); + + return group_iter->second; +} +} diff --git a/opm/simulators/wells/GroupState.hpp b/opm/simulators/wells/GroupState.hpp new file mode 100644 index 000000000..6b2115fbc --- /dev/null +++ b/opm/simulators/wells/GroupState.hpp @@ -0,0 +1,168 @@ +/* + 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 . +*/ + +#ifndef OPM_GROUPSTATE_HEADER_INCLUDED +#define OPM_GROUPSTATE_HEADER_INCLUDED + +#include +#include + +#include +#include + +namespace Opm { + +class GroupState { +public: + explicit GroupState(std::size_t num_phases); + bool operator==(const GroupState& other) const; + + bool has_production_rates(const std::string& gname) const; + void update_production_rates(const std::string& gname, const std::vector& rates); + const std::vector& production_rates(const std::string& gname) const; + + bool has_production_reduction_rates(const std::string& gname) const; + void update_production_reduction_rates(const std::string& gname, const std::vector& rates); + const std::vector& production_reduction_rates(const std::string& gname) const; + + bool has_injection_reduction_rates(const std::string& gname) const; + void update_injection_reduction_rates(const std::string& gname, const std::vector& rates); + const std::vector& injection_reduction_rates(const std::string& gname) const; + + bool has_injection_reservoir_rates(const std::string& gname) const; + void update_injection_reservoir_rates(const std::string& gname, const std::vector& rates); + const std::vector& injection_reservoir_rates(const std::string& gname) const; + + void update_injection_rein_rates(const std::string& gname, const std::vector& rates); + const std::vector& injection_rein_rates(const std::string& gname) const; + + void update_injection_potentials(const std::string& gname, const std::vector& potentials); + const std::vector& injection_potentials(const std::string& gname) const; + + void update_injection_vrep_rate(const std::string& gname, double rate); + double injection_vrep_rate(const std::string& gname) const; + + void update_grat_sales_target(const std::string& gname, double target); + double grat_sales_target(const std::string& gname) const; + bool has_grat_sales_target(const std::string& gname) const; + + bool has_production_control(const std::string& gname) const; + void production_control(const std::string& gname, Group::ProductionCMode cmode); + Group::ProductionCMode production_control(const std::string& gname) const; + + bool has_injection_control(const std::string& gname, Phase phase) const; + void injection_control(const std::string& gname, Phase phase, Group::InjectionCMode cmode); + Group::InjectionCMode injection_control(const std::string& gname, Phase phase) const; + + std::size_t data_size() const; + std::size_t collect(double * data) const; + std::size_t distribute(const double * data); + + + template + void communicate_rates(const Comm& comm) + { + // Note that injection_group_vrep_rates is handled separate from + // the forAllGroupData() function, since it contains single doubles, + // not vectors. + + // Create a function that calls some function + // for all the individual data items to simplify + // the further code. + auto iterateContainer = [](auto& container, auto& func) { + for (auto& x : container) { + func(x.second); + } + }; + + + auto forAllGroupData = [&](auto& func) { + iterateContainer(m_production_rates, func); + iterateContainer(prod_red_rates, func); + iterateContainer(inj_red_rates, func); + iterateContainer(inj_resv_rates, func); + iterateContainer(inj_rein_rates, func); + }; + + // Compute the size of the data. + std::size_t sz = 0; + auto computeSize = [&sz](const auto& v) { + sz += v.size(); + }; + forAllGroupData(computeSize); + sz += this->inj_vrep_rate.size(); + + // Make a vector and collect all data into it. + std::vector data(sz); + std::size_t pos = 0; + + + + // That the collect function mutates the vector v is an artifact for + // testing. + auto collect = [&data, &pos](auto& v) { + for (auto& x : v) { + data[pos++] = x; + x = -1; + } + }; + forAllGroupData(collect); + for (const auto& x : this->inj_vrep_rate) { + data[pos++] = x.second; + } + if (pos != sz) + throw std::logic_error("Internal size mismatch when collecting groupData"); + + // Communicate it with a single sum() call. + comm.sum(data.data(), data.size()); + + // Distribute the summed vector to the data items. + pos = 0; + auto distribute = [&data, &pos](auto& v) { + for (auto& x : v) { + x = data[pos++]; + } + }; + forAllGroupData(distribute); + for (auto& x : this->inj_vrep_rate) { + x.second = data[pos++]; + } + if (pos != sz) + throw std::logic_error("Internal size mismatch when distributing groupData"); + } + +private: + std::size_t num_phases; + std::map> m_production_rates; + std::map production_controls; + std::map> prod_red_rates; + std::map> inj_red_rates; + std::map> inj_resv_rates; + std::map> inj_potentials; + std::map> inj_rein_rates; + std::map inj_vrep_rate; + std::map m_grat_sales_target; + + + std::map, Group::InjectionCMode> injection_controls; +}; + +} + +#endif diff --git a/opm/simulators/wells/WellState.hpp b/opm/simulators/wells/WellState.hpp index 7a20fbd15..9551bb9b1 100644 --- a/opm/simulators/wells/WellState.hpp +++ b/opm/simulators/wells/WellState.hpp @@ -46,6 +46,13 @@ namespace Opm typedef std::array< int, 3 > mapentry_t; typedef std::map< std::string, mapentry_t > WellMapType; + + + explicit WellState(int num_phases) : + np_(num_phases) + {} + + /// Allocate and initialize if wells is non-null. /// Also tries to give useful initial values to the bhp() and /// wellRates() fields, depending on controls. The @@ -397,9 +404,8 @@ namespace Opm // Set default zero initial well rates. // May be overwritten below. - const int np = pu.num_phases; - for (int p = 0; p < np; ++p) { - wellrates_[np*w + p] = 0.0; + for (int p = 0; p < this->np_; ++p) { + wellrates_[this->np_*w + p] = 0.0; } if ( well.isInjector() ) { @@ -465,15 +471,15 @@ namespace Opm switch (inj_controls.injector_type) { case InjectorType::WATER: assert(pu.phase_used[BlackoilPhases::Aqua]); - wellrates_[np*w + pu.phase_pos[BlackoilPhases::Aqua]] = inj_surf_rate; + wellrates_[this->np_*w + pu.phase_pos[BlackoilPhases::Aqua]] = inj_surf_rate; break; case InjectorType::GAS: assert(pu.phase_used[BlackoilPhases::Vapour]); - wellrates_[np*w + pu.phase_pos[BlackoilPhases::Vapour]] = inj_surf_rate; + wellrates_[this->np_*w + pu.phase_pos[BlackoilPhases::Vapour]] = inj_surf_rate; break; case InjectorType::OIL: assert(pu.phase_used[BlackoilPhases::Liquid]); - wellrates_[np*w + pu.phase_pos[BlackoilPhases::Liquid]] = inj_surf_rate; + wellrates_[this->np_*w + pu.phase_pos[BlackoilPhases::Liquid]] = inj_surf_rate; break; case InjectorType::MULTI: // Not currently handled, keep zero init. @@ -488,15 +494,15 @@ namespace Opm switch (prod_controls.cmode) { case Well::ProducerCMode::ORAT: assert(pu.phase_used[BlackoilPhases::Liquid]); - wellrates_[np*w + pu.phase_pos[BlackoilPhases::Liquid]] = -prod_controls.oil_rate; + wellrates_[this->np_*w + pu.phase_pos[BlackoilPhases::Liquid]] = -prod_controls.oil_rate; break; case Well::ProducerCMode::WRAT: assert(pu.phase_used[BlackoilPhases::Aqua]); - wellrates_[np*w + pu.phase_pos[BlackoilPhases::Aqua]] = -prod_controls.water_rate; + wellrates_[this->np_*w + pu.phase_pos[BlackoilPhases::Aqua]] = -prod_controls.water_rate; break; case Well::ProducerCMode::GRAT: assert(pu.phase_used[BlackoilPhases::Vapour]); - wellrates_[np*w + pu.phase_pos[BlackoilPhases::Vapour]] = -prod_controls.gas_rate; + wellrates_[this->np_*w + pu.phase_pos[BlackoilPhases::Vapour]] = -prod_controls.gas_rate; break; default: // Keep zero init. diff --git a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp index e08a6bf02..53d73b9fd 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 @@ -68,6 +69,12 @@ namespace Opm using BaseType :: resetConnectionTransFactors; using BaseType :: updateStatus; + explicit WellStateFullyImplicitBlackoil(int num_phases) : + WellState(num_phases), + group_state(num_phases) + {} + + /// Allocate and initialize if wells is non-null. Also tries /// to give useful initial values to the bhp(), wellRates() /// and perfPhaseRates() fields, depending on controls @@ -105,7 +112,7 @@ namespace Opm nperf += wpd.size(); } - well_reservoir_rates_.resize(nw * np, 0.0); + well_reservoir_rates_.resize(nw * this->numPhases(), 0.0); well_dissolved_gas_rates_.resize(nw, 0.0); well_vaporized_oil_rates_.resize(nw, 0.0); @@ -129,7 +136,7 @@ namespace Opm // Ensure that we start out with zero rates by default. perfphaserates_.clear(); - perfphaserates_.resize(nperf * np, 0.0); + perfphaserates_.resize(nperf * this->numPhases(), 0.0); // these are only used to monitor the injectivity perf_water_throughput_.clear(); @@ -152,8 +159,8 @@ namespace Opm for (int perf = connpos; perf < connpos + num_perf_this_well; ++perf) { if (wells_ecl[w].getStatus() == Well::Status::OPEN) { - for (int p = 0; p < np; ++p) { - perfphaserates_[np*perf + p] = wellRates()[np*w + p] / double(global_num_perf_this_well); + for (int p = 0; p < this->numPhases(); ++p) { + perfphaserates_[this->numPhases()*perf + p] = wellRates()[this->numPhases()*w + p] / double(global_num_perf_this_well); } } perfPress()[perf] = cellPressures[well_perf_data[w][perf-connpos].cell_index]; @@ -182,9 +189,9 @@ namespace Opm perfRateSolvent_.clear(); perfRateSolvent_.resize(nperf, 0.0); - productivity_index_.resize(nw * np, 0.0); - conn_productivity_index_.resize(nperf * np, 0.0); - well_potentials_.resize(nw * np, 0.0); + productivity_index_.resize(nw * this->numPhases(), 0.0); + conn_productivity_index_.resize(nperf * this->numPhases(), 0.0); + well_potentials_.resize(nw * this->numPhases(), 0.0); perfRatePolymer_.clear(); perfRatePolymer_.resize(nperf, 0.0); @@ -407,39 +414,29 @@ namespace Opm const std::vector& currentProductionControls() const { return current_production_controls_; } bool hasProductionGroupControl(const std::string& groupName) const { - return current_production_group_controls_.count(groupName) > 0; + return this->group_state.has_production_control(groupName); } bool hasInjectionGroupControl(const Opm::Phase& phase, const std::string& groupName) const { - return current_injection_group_controls_.count(std::make_pair(phase, groupName)) > 0; + return this->group_state.has_injection_control(groupName, phase); } /// One current control per group. void setCurrentProductionGroupControl(const std::string& groupName, const Group::ProductionCMode& groupControl ) { - current_production_group_controls_[groupName] = groupControl; + this->group_state.production_control(groupName, groupControl); } - const Group::ProductionCMode& currentProductionGroupControl(const std::string& groupName) const { - auto it = current_production_group_controls_.find(groupName); - - if (it == current_production_group_controls_.end()) - OPM_THROW(std::logic_error, "Could not find any control for production group " << groupName); - - return it->second; + Group::ProductionCMode currentProductionGroupControl(const std::string& groupName) const { + return this->group_state.production_control(groupName); } /// One current control per group. void setCurrentInjectionGroupControl(const Opm::Phase& phase, const std::string& groupName, const Group::InjectionCMode& groupControl ) { - current_injection_group_controls_[std::make_pair(phase, groupName)] = groupControl; + this->group_state.injection_control(groupName, phase, groupControl); } - const Group::InjectionCMode& currentInjectionGroupControl(const Opm::Phase& phase, const std::string& groupName) const { - auto it = current_injection_group_controls_.find(std::make_pair(phase, groupName)); - - if (it == current_injection_group_controls_.end()) - OPM_THROW(std::logic_error, "Could not find any control for " << phase << " injection group " << groupName); - - return it->second; + Group::InjectionCMode currentInjectionGroupControl(const Opm::Phase& phase, const std::string& groupName) const { + return this->group_state.injection_control(groupName, phase); } void setCurrentWellRates(const std::string& wellName, const std::vector& rates ) { @@ -460,117 +457,76 @@ namespace Opm } void setCurrentProductionGroupRates(const std::string& groupName, const std::vector& rates ) { - production_group_rates[groupName] = rates; + this->group_state.update_production_rates(groupName, rates); } const std::vector& currentProductionGroupRates(const std::string& groupName) const { - auto it = production_group_rates.find(groupName); - - if (it == production_group_rates.end()) - OPM_THROW(std::logic_error, "Could not find any rates for productino group " << groupName); - - return it->second; + return this->group_state.production_rates(groupName); } bool hasProductionGroupRates(const std::string& groupName) const { - return this->production_group_rates.find(groupName) != this->production_group_rates.end(); + return this->group_state.has_production_rates(groupName); } void setCurrentProductionGroupReductionRates(const std::string& groupName, const std::vector& target ) { - production_group_reduction_rates[groupName] = target; + this->group_state.update_production_reduction_rates(groupName, target); } const std::vector& currentProductionGroupReductionRates(const std::string& groupName) const { - auto it = production_group_reduction_rates.find(groupName); - - if (it == production_group_reduction_rates.end()) - OPM_THROW(std::logic_error, "Could not find any reduction rates for production group " << groupName); - - return it->second; + return this->group_state.production_reduction_rates(groupName); } void setCurrentInjectionGroupReductionRates(const std::string& groupName, const std::vector& target ) { - injection_group_reduction_rates[groupName] = target; + this->group_state.update_injection_reduction_rates(groupName, target); } const std::vector& currentInjectionGroupReductionRates(const std::string& groupName) const { - auto it = injection_group_reduction_rates.find(groupName); - - if (it == injection_group_reduction_rates.end()) - OPM_THROW(std::logic_error, "Could not find any reduction rates for injection group " << groupName); - - return it->second; + return this->group_state.injection_reduction_rates(groupName); } void setCurrentInjectionGroupReservoirRates(const std::string& groupName, const std::vector& target ) { - injection_group_reservoir_rates[groupName] = target; + this->group_state.update_injection_reservoir_rates(groupName, target); } const std::vector& currentInjectionGroupReservoirRates(const std::string& groupName) const { - auto it = injection_group_reservoir_rates.find(groupName); - - if (it == injection_group_reservoir_rates.end()) - OPM_THROW(std::logic_error, "Could not find any reservoir rates for injection group " << groupName); - - return it->second; + return this->group_state.injection_reservoir_rates(groupName); } void setCurrentInjectionVREPRates(const std::string& groupName, const double& target ) { - injection_group_vrep_rates[groupName] = target; + this->group_state.update_injection_vrep_rate(groupName, target); } - const double& currentInjectionVREPRates(const std::string& groupName) const { - auto it = injection_group_vrep_rates.find(groupName); - - if (it == injection_group_vrep_rates.end()) - OPM_THROW(std::logic_error, "Could not find any VREP rates for group " << groupName); - - return it->second; + double currentInjectionVREPRates(const std::string& groupName) const { + return this->group_state.injection_vrep_rate(groupName); } void setCurrentInjectionREINRates(const std::string& groupName, const std::vector& target ) { - injection_group_rein_rates[groupName] = target; + this->group_state.update_injection_rein_rates(groupName, target); } const std::vector& currentInjectionREINRates(const std::string& groupName) const { - auto it = injection_group_rein_rates.find(groupName); - - if (it == injection_group_rein_rates.end()) - OPM_THROW(std::logic_error, "Could not find any REIN rates for group " << groupName); - - return it->second; + return this->group_state.injection_rein_rates(groupName); } void setCurrentGroupGratTargetFromSales(const std::string& groupName, const double& target ) { - group_grat_target_from_sales[groupName] = target; + this->group_state.update_grat_sales_target(groupName, target); } bool hasGroupGratTargetFromSales(const std::string& groupName) const { - auto it = group_grat_target_from_sales.find(groupName); - return it != group_grat_target_from_sales.end(); + return this->group_state.has_grat_sales_target(groupName); } - const double& currentGroupGratTargetFromSales(const std::string& groupName) const { - auto it = group_grat_target_from_sales.find(groupName); - - if (it == group_grat_target_from_sales.end()) - OPM_THROW(std::logic_error, "Could not find any grat target from sales for group " << groupName); - - return it->second; + double currentGroupGratTargetFromSales(const std::string& groupName) const { + return this->group_state.grat_sales_target(groupName); } void setCurrentGroupInjectionPotentials(const std::string& groupName, const std::vector& pot ) { - injection_group_potentials[groupName] = pot; + this->group_state.update_injection_potentials(groupName, pot); } const std::vector& currentGroupInjectionPotentials(const std::string& groupName) const { - auto it = injection_group_potentials.find(groupName); - - if (it == injection_group_potentials.end()) - OPM_THROW(std::logic_error, "Could not find any potentials for group " << groupName); - - return it->second; + return this->group_state.injection_potentials(groupName); } data::Wells @@ -1136,11 +1092,6 @@ namespace Opm // Create a function that calls some function // for all the individual data items to simplify // the further code. - auto iterateContainer = [](auto& container, auto& func) { - for (auto& x : container) { - func(x.second); - } - }; auto iterateRatesContainer = [](auto& container, auto& func) { for (auto& x : container) { if (x.second.first) @@ -1158,22 +1109,13 @@ namespace Opm } }; - auto forAllGroupData = [&](auto& func) { - iterateContainer(injection_group_rein_rates, func); - iterateContainer(production_group_reduction_rates, func); - iterateContainer(injection_group_reduction_rates, func); - iterateContainer(injection_group_reservoir_rates, func); - iterateContainer(production_group_rates, func); - iterateRatesContainer(well_rates, func); - }; // Compute the size of the data. std::size_t sz = 0; auto computeSize = [&sz](const auto& v) { sz += v.size(); }; - forAllGroupData(computeSize); - sz += injection_group_vrep_rates.size(); + iterateRatesContainer(this->well_rates, computeSize); sz += current_alq_.size(); // Make a vector and collect all data into it. @@ -1184,10 +1126,7 @@ namespace Opm data[pos++] = x; } }; - forAllGroupData(collect); - for (const auto& x : injection_group_vrep_rates) { - data[pos++] = x.second; - } + iterateRatesContainer(this->well_rates, collect); for (const auto& x : current_alq_) { data[pos++] = x.second; } @@ -1203,14 +1142,13 @@ namespace Opm x = data[pos++]; } }; - forAllGroupData(distribute); - for (auto& x : injection_group_vrep_rates) { - x.second = data[pos++]; - } + iterateRatesContainer(this->well_rates, distribute); for (auto& x : current_alq_) { x.second = data[pos++]; } assert(pos == sz); + + this->group_state.communicate_rates(comm); } template @@ -1378,19 +1316,10 @@ namespace Opm std::vector globalIsInjectionGrup_; std::vector globalIsProductionGrup_; std::map wellNameToGlobalIdx_; - - std::map current_production_group_controls_; - std::map, Group::InjectionCMode> current_injection_group_controls_; - std::map>> well_rates; - std::map> production_group_rates; - std::map> production_group_reduction_rates; - std::map> injection_group_reduction_rates; - std::map> injection_group_reservoir_rates; - std::map> injection_group_potentials; - std::map injection_group_vrep_rates; - std::map> injection_group_rein_rates; - std::map group_grat_target_from_sales; + + GroupState group_state; + std::map current_alq_; std::map default_alq_; std::map alq_increase_count_; diff --git a/tests/test_GroupState.cpp b/tests/test_GroupState.cpp new file mode 100644 index 000000000..3a5d6df52 --- /dev/null +++ b/tests/test_GroupState.cpp @@ -0,0 +1,69 @@ +/* + 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; + +class TestCommunicator { +public: + void sum(const double *, std::size_t) const {} +}; + + + +BOOST_AUTO_TEST_CASE(GroupStateCreate) { + std::size_t num_phases{3}; + GroupState gs(num_phases); + + BOOST_CHECK(!gs.has_production_rates("AGROUP")); + BOOST_CHECK_THROW( gs.update_production_rates("AGROUP", {0}), std::exception); + + std::vector rates{0,1,2}; + gs.update_production_rates("AGROUP", rates); + BOOST_CHECK(gs.has_production_rates("AGROUP")); + + BOOST_CHECK_THROW( gs.production_rates("NO_SUCH_GROUP"), std::exception ); + auto r2 = gs.production_rates("AGROUP"); + BOOST_CHECK( r2 == rates ); + + gs.update_injection_rein_rates("CGROUP", rates); + + + BOOST_CHECK(!gs.has_production_control("NO_SUCH_GROUP")); + BOOST_CHECK(!gs.has_production_control("AGROUP")); + + gs.production_control("AGROUP", Group::ProductionCMode::GRAT); + BOOST_CHECK(gs.has_production_control("AGROUP")); + BOOST_CHECK(gs.production_control("AGROUP") == Group::ProductionCMode::GRAT); + BOOST_CHECK_THROW(gs.production_control("BGROUP"), std::exception); + + + auto gs2 = gs; + BOOST_CHECK(gs2 == gs); + TestCommunicator comm; + gs.communicate_rates(comm); + BOOST_CHECK(gs2 == gs); +} + diff --git a/tests/test_wellstatefullyimplicitblackoil.cpp b/tests/test_wellstatefullyimplicitblackoil.cpp index 12886728f..4bff5ae44 100644 --- a/tests/test_wellstatefullyimplicitblackoil.cpp +++ b/tests/test_wellstatefullyimplicitblackoil.cpp @@ -121,7 +121,7 @@ namespace { buildWellState(const Setup& setup, const std::size_t timeStep, std::vector& pinfos) { - auto state = Opm::WellStateFullyImplicitBlackoil{}; + auto state = Opm::WellStateFullyImplicitBlackoil{setup.pu.num_phases}; const auto cpress = std::vector(setup.grid.c_grid()->number_of_cells,