diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake
index 4c30092ab..4cb71f66f 100644
--- a/CMakeLists_files.cmake
+++ b/CMakeLists_files.cmake
@@ -104,6 +104,7 @@ list (APPEND MAIN_SOURCE_FILES
opm/simulators/wells/VFPProdProperties.cpp
opm/simulators/wells/VFPInjProperties.cpp
opm/simulators/wells/WellBhpThpCalculator.cpp
+ opm/simulators/wells/WellConstraints.cpp
opm/simulators/wells/WellConvergence.cpp
opm/simulators/wells/WellGroupConstraints.cpp
opm/simulators/wells/WellGroupControls.cpp
@@ -388,6 +389,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/wells/VFPProperties.hpp
opm/simulators/wells/WellBhpThpCalculator.hpp
opm/simulators/wells/WellConnectionAuxiliaryModule.hpp
+ opm/simulators/wells/WellConstraints.hpp
opm/simulators/wells/WellConvergence.hpp
opm/simulators/wells/WellGroupConstraints.hpp
opm/simulators/wells/WellGroupControls.hpp
diff --git a/opm/simulators/wells/WellConstraints.cpp b/opm/simulators/wells/WellConstraints.cpp
new file mode 100644
index 000000000..3df31f0b9
--- /dev/null
+++ b/opm/simulators/wells/WellConstraints.cpp
@@ -0,0 +1,159 @@
+/*
+ Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
+ Copyright 2017 Statoil ASA.
+ Copyright 2018 IRIS
+
+ 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
+
+namespace Opm
+{
+
+Well::ProducerCMode WellConstraints::
+activeProductionConstraint(const SingleWellState& ws,
+ const SummaryState& summaryState,
+ const RateConvFunc& calcReservoirVoidageRates,
+ bool& thp_limit_violated_but_not_switched,
+ DeferredLogger& deferred_logger) const
+{
+ const PhaseUsage& pu = well_.phaseUsage();
+ const auto controls = well_.wellEcl().productionControls(summaryState);
+ const auto currentControl = ws.production_cmode;
+
+ if (controls.hasControl(Well::ProducerCMode::BHP) && currentControl != Well::ProducerCMode::BHP) {
+ const double bhp_limit = controls.bhp_limit;
+ double current_bhp = ws.bhp;
+ if (bhp_limit > current_bhp)
+ return Well::ProducerCMode::BHP;
+ }
+
+ if (controls.hasControl(Well::ProducerCMode::ORAT) && currentControl != Well::ProducerCMode::ORAT) {
+ double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]];
+ if (controls.oil_rate < current_rate)
+ return Well::ProducerCMode::ORAT;
+ }
+
+ if (controls.hasControl(Well::ProducerCMode::WRAT) && currentControl != Well::ProducerCMode::WRAT) {
+ double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
+ if (controls.water_rate < current_rate)
+ return Well::ProducerCMode::WRAT;
+ }
+
+ if (controls.hasControl(Well::ProducerCMode::GRAT) && currentControl != Well::ProducerCMode::GRAT) {
+ double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Vapour]];
+ if (controls.gas_rate < current_rate)
+ return Well::ProducerCMode::GRAT;
+ }
+
+ if (controls.hasControl(Well::ProducerCMode::LRAT) && currentControl != Well::ProducerCMode::LRAT) {
+ double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]];
+ current_rate -= ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
+
+ bool skip = false;
+ if (controls.liquid_rate == controls.oil_rate) {
+ const double current_water_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
+ if (std::abs(current_water_rate) < 1e-12) {
+ skip = true;
+ deferred_logger.debug("LRAT_ORAT_WELL", "Well " + well_.name() + " The LRAT target is equal the ORAT target and the water rate is zero, skip checking LRAT");
+ }
+ }
+ if (!skip && controls.liquid_rate < current_rate)
+ return Well::ProducerCMode::LRAT;
+ }
+
+ if (controls.hasControl(Well::ProducerCMode::RESV) && currentControl != Well::ProducerCMode::RESV) {
+ double current_rate = 0.0;
+ if (pu.phase_used[BlackoilPhases::Aqua])
+ current_rate -= ws.reservoir_rates[pu.phase_pos[BlackoilPhases::Aqua]];
+
+ if (pu.phase_used[BlackoilPhases::Liquid])
+ current_rate -= ws.reservoir_rates[pu.phase_pos[BlackoilPhases::Liquid]];
+
+ if (pu.phase_used[BlackoilPhases::Vapour])
+ current_rate -= ws.reservoir_rates[pu.phase_pos[BlackoilPhases::Vapour]];
+
+ if (controls.prediction_mode && controls.resv_rate < current_rate)
+ return Well::ProducerCMode::RESV;
+
+ if (!controls.prediction_mode) {
+ const int fipreg = 0; // not considering the region for now
+ const int np = well_.numPhases();
+
+ std::vector surface_rates(np, 0.0);
+ if (pu.phase_used[BlackoilPhases::Aqua])
+ surface_rates[pu.phase_pos[BlackoilPhases::Aqua]] = controls.water_rate;
+ if (pu.phase_used[BlackoilPhases::Liquid])
+ surface_rates[pu.phase_pos[BlackoilPhases::Liquid]] = controls.oil_rate;
+ if (pu.phase_used[BlackoilPhases::Vapour])
+ surface_rates[pu.phase_pos[BlackoilPhases::Vapour]] = controls.gas_rate;
+
+ std::vector voidage_rates(np, 0.0);
+ calcReservoirVoidageRates(fipreg, well_.pvtRegionIdx(), surface_rates, voidage_rates);
+
+ double resv_rate = 0.0;
+ for (int p = 0; p < np; ++p)
+ resv_rate += voidage_rates[p];
+
+ if (resv_rate < current_rate)
+ return Well::ProducerCMode::RESV;
+ }
+ }
+
+ if (controls.hasControl(Well::ProducerCMode::THP) && currentControl != Well::ProducerCMode::THP) {
+ const auto& thp = well_.getTHPConstraint(summaryState);
+ double current_thp = ws.thp;
+ if (thp > current_thp && !ws.trivial_target) {
+ // If WVFPEXP item 4 is set to YES1 or YES2
+ // switching to THP is prevented if the well will
+ // produce at a higher rate with THP control
+ const auto& wvfpexp = well_.wellEcl().getWVFPEXP();
+ bool rate_less_than_potential = true;
+ if (wvfpexp.prevent()) {
+ for (int p = 0; p < well_.numPhases(); ++p) {
+ // Currently we use the well potentials here computed before the iterations.
+ // We may need to recompute the well potentials to get a more
+ // accurate check here.
+ rate_less_than_potential = rate_less_than_potential && (-ws.surface_rates[p]) <= ws.well_potentials[p];
+ }
+ }
+ if (!wvfpexp.prevent() || !rate_less_than_potential) {
+ thp_limit_violated_but_not_switched = false;
+ return Well::ProducerCMode::THP;
+ } else {
+ thp_limit_violated_but_not_switched = true;
+ deferred_logger.info("NOT_SWITCHING_TO_THP",
+ "The THP limit is violated for producer " +
+ well_.name() +
+ ". But the rate will increase if switched to THP. " +
+ "The well is therefore kept at " + Well::ProducerCMode2String(currentControl));
+ }
+ }
+ }
+
+ return currentControl;
+}
+
+} // namespace Opm
diff --git a/opm/simulators/wells/WellConstraints.hpp b/opm/simulators/wells/WellConstraints.hpp
new file mode 100644
index 000000000..ab6f3afad
--- /dev/null
+++ b/opm/simulators/wells/WellConstraints.hpp
@@ -0,0 +1,65 @@
+/*
+ Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
+ Copyright 2017 Statoil ASA.
+ Copyright 2017 IRIS
+ Copyright 2019 Norce
+
+ 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_WELL_CONSTRAINTS_HEADER_INCLUDED
+#define OPM_WELL_CONSTRAINTS_HEADER_INCLUDED
+
+#include
+
+#include
+#include
+#include
+
+namespace Opm
+{
+
+class DeferredLogger;
+using RegionId = int;
+class Rates;
+class SingleWellState;
+class WellInterfaceGeneric;
+
+//! \brief Class for computing well group constraints.
+class WellConstraints {
+public:
+ //! \brief Constructor sets reference to well.
+ WellConstraints(const WellInterfaceGeneric& well) : well_(well) {}
+
+ using RateConvFunc = std::function&,
+ std::vector&)>;
+
+ Well::ProducerCMode
+ activeProductionConstraint(const SingleWellState& ws,
+ const SummaryState& summaryState,
+ const RateConvFunc& calcReservoirVoidageRates,
+ bool& thp_limit_violated_but_not_switched,
+ DeferredLogger& deferred_logger) const;
+
+private:
+ const WellInterfaceGeneric& well_; //!< Reference to well interface
+};
+
+}
+
+#endif // OPM_WELL_CONSTRAINTS_HEADER_INCLUDED
diff --git a/opm/simulators/wells/WellInterfaceFluidSystem.cpp b/opm/simulators/wells/WellInterfaceFluidSystem.cpp
index ed927046f..b0ae52205 100644
--- a/opm/simulators/wells/WellInterfaceFluidSystem.cpp
+++ b/opm/simulators/wells/WellInterfaceFluidSystem.cpp
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -81,132 +82,6 @@ calculateReservoirRates(SingleWellState& ws) const
ws.reservoir_rates = voidage_rates;
}
-
-template
-Well::ProducerCMode
-WellInterfaceFluidSystem::
-activeProductionConstraint(const SingleWellState& ws,
- const SummaryState& summaryState,
- DeferredLogger& deferred_logger) const
-{
- const PhaseUsage& pu = this->phaseUsage();
- const auto controls = this->well_ecl_.productionControls(summaryState);
- const auto currentControl = ws.production_cmode;
-
- if (controls.hasControl(Well::ProducerCMode::BHP) && currentControl != Well::ProducerCMode::BHP) {
- const double bhp_limit = controls.bhp_limit;
- double current_bhp = ws.bhp;
- if (bhp_limit > current_bhp)
- return Well::ProducerCMode::BHP;
- }
-
- if (controls.hasControl(Well::ProducerCMode::ORAT) && currentControl != Well::ProducerCMode::ORAT) {
- double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]];
- if (controls.oil_rate < current_rate)
- return Well::ProducerCMode::ORAT;
- }
-
- if (controls.hasControl(Well::ProducerCMode::WRAT) && currentControl != Well::ProducerCMode::WRAT) {
- double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
- if (controls.water_rate < current_rate)
- return Well::ProducerCMode::WRAT;
- }
-
- if (controls.hasControl(Well::ProducerCMode::GRAT) && currentControl != Well::ProducerCMode::GRAT) {
- double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Vapour]];
- if (controls.gas_rate < current_rate)
- return Well::ProducerCMode::GRAT;
- }
-
- if (controls.hasControl(Well::ProducerCMode::LRAT) && currentControl != Well::ProducerCMode::LRAT) {
- double current_rate = -ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]];
- current_rate -= ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
-
- bool skip = false;
- if (controls.liquid_rate == controls.oil_rate) {
- const double current_water_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
- if (std::abs(current_water_rate) < 1e-12) {
- skip = true;
- deferred_logger.debug("LRAT_ORAT_WELL", "Well " + this->name() + " The LRAT target is equal the ORAT target and the water rate is zero, skip checking LRAT");
- }
- }
- if (!skip && controls.liquid_rate < current_rate)
- return Well::ProducerCMode::LRAT;
- }
-
- if (controls.hasControl(Well::ProducerCMode::RESV) && currentControl != Well::ProducerCMode::RESV) {
- double current_rate = 0.0;
- if (pu.phase_used[BlackoilPhases::Aqua])
- current_rate -= ws.reservoir_rates[pu.phase_pos[BlackoilPhases::Aqua]];
-
- if (pu.phase_used[BlackoilPhases::Liquid])
- current_rate -= ws.reservoir_rates[pu.phase_pos[BlackoilPhases::Liquid]];
-
- if (pu.phase_used[BlackoilPhases::Vapour])
- current_rate -= ws.reservoir_rates[pu.phase_pos[BlackoilPhases::Vapour]];
-
- if (controls.prediction_mode && controls.resv_rate < current_rate)
- return Well::ProducerCMode::RESV;
-
- if (!controls.prediction_mode) {
- const int fipreg = 0; // not considering the region for now
- const int np = number_of_phases_;
-
- std::vector surface_rates(np, 0.0);
- if (pu.phase_used[BlackoilPhases::Aqua])
- surface_rates[pu.phase_pos[BlackoilPhases::Aqua]] = controls.water_rate;
- if (pu.phase_used[BlackoilPhases::Liquid])
- surface_rates[pu.phase_pos[BlackoilPhases::Liquid]] = controls.oil_rate;
- if (pu.phase_used[BlackoilPhases::Vapour])
- surface_rates[pu.phase_pos[BlackoilPhases::Vapour]] = controls.gas_rate;
-
- std::vector voidage_rates(np, 0.0);
- rateConverter_.calcReservoirVoidageRates(fipreg, pvtRegionIdx_, surface_rates, voidage_rates);
-
- double resv_rate = 0.0;
- for (int p = 0; p < np; ++p)
- resv_rate += voidage_rates[p];
-
- if (resv_rate < current_rate)
- return Well::ProducerCMode::RESV;
- }
- }
-
- if (controls.hasControl(Well::ProducerCMode::THP) && currentControl != Well::ProducerCMode::THP) {
- const auto& thp = getTHPConstraint(summaryState);
- double current_thp = ws.thp;
- if (thp > current_thp && !ws.trivial_target) {
- // If WVFPEXP item 4 is set to YES1 or YES2
- // switching to THP is prevented if the well will
- // produce at a higher rate with THP control
- const auto& wvfpexp = this->well_ecl_.getWVFPEXP();
- bool rate_less_than_potential = true;
- if (wvfpexp.prevent()) {
- for (int p = 0; p < number_of_phases_; ++p) {
- // Currently we use the well potentials here computed before the iterations.
- // We may need to recompute the well potentials to get a more
- // accurate check here.
- rate_less_than_potential = rate_less_than_potential && (-ws.surface_rates[p]) <= ws.well_potentials[p];
- }
- }
- if(!wvfpexp.prevent() || !rate_less_than_potential) {
- this->operability_status_.thp_limit_violated_but_not_switched = false;
- return Well::ProducerCMode::THP;
- } else {
- this->operability_status_.thp_limit_violated_but_not_switched = true;
- deferred_logger.info("NOT_SWITCHING_TO_THP",
- "The THP limit is violated for producer " +
- this->name() +
- ". But the rate will increase if switched to THP. " +
- "The well is therefore kept at " + Well::ProducerCMode2String(currentControl));
- }
- }
- }
-
- return currentControl;
-}
-
-
template
Well::InjectorCMode
WellInterfaceFluidSystem::
@@ -308,8 +183,20 @@ checkIndividualConstraints(SingleWellState& ws,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
+ auto rRates = [this](const int fipreg,
+ const int pvtRegion,
+ const std::vector& surface_rates,
+ std::vector& voidage_rates)
+ {
+ return rateConverter_.calcReservoirVoidageRates(fipreg, pvtRegion,
+ surface_rates, voidage_rates);
+ };
+
if (this->well_ecl_.isProducer()) {
- auto new_cmode = this->activeProductionConstraint(ws, summaryState, deferred_logger);
+ auto new_cmode = WellConstraints(*this).activeProductionConstraint(ws, summaryState,
+ rRates,
+ this->operability_status_.thp_limit_violated_but_not_switched,
+ deferred_logger);
if (new_cmode != ws.production_cmode) {
ws.production_cmode = new_cmode;
return true;
diff --git a/opm/simulators/wells/WellInterfaceFluidSystem.hpp b/opm/simulators/wells/WellInterfaceFluidSystem.hpp
index 18f2ec8eb..b1427e227 100644
--- a/opm/simulators/wells/WellInterfaceFluidSystem.hpp
+++ b/opm/simulators/wells/WellInterfaceFluidSystem.hpp
@@ -85,10 +85,6 @@ protected:
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
- Well::ProducerCMode activeProductionConstraint(const SingleWellState& ws,
- const SummaryState& summaryState,
- DeferredLogger& deferred_logger) const;
-
bool checkGroupConstraints(WellState& well_state,
const GroupState& group_state,
const Schedule& schedule,