From b1b23a57de9fbcc2c058ccec94a326b4f22c1deb Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Tue, 22 Feb 2022 15:25:10 +0100 Subject: [PATCH] Add option for explicit vfp lookup for problmatic wells --- .../wells/BlackoilWellModel_impl.hpp | 2 +- opm/simulators/wells/VFPHelpers.cpp | 9 +++++- opm/simulators/wells/VFPHelpers.hpp | 5 +++- opm/simulators/wells/VFPProdProperties.cpp | 18 ++++++++--- opm/simulators/wells/VFPProdProperties.hpp | 10 +++++-- opm/simulators/wells/VFPProperties.hpp | 30 ++++++++++++++++++- opm/simulators/wells/WellGroupHelpers.cpp | 5 +++- opm/simulators/wells/WellInterfaceEval.cpp | 5 +++- opm/simulators/wells/WellInterfaceGeneric.cpp | 5 ++++ opm/simulators/wells/WellInterfaceGeneric.hpp | 3 ++ opm/simulators/wells/WellInterface_impl.hpp | 6 ++++ 11 files changed, 86 insertions(+), 12 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 40e30a7f8..981e2dedf 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -227,7 +227,7 @@ namespace Opm { { const auto& sched_state = this->schedule()[timeStepIdx]; // update VFP properties - vfp_properties_.reset(new VFPProperties( sched_state.vfpinj(), sched_state.vfpprod()) ); + vfp_properties_.reset(new VFPProperties( sched_state.vfpinj(), sched_state.vfpprod(), this->prevWellState())); this->initializeWellProdIndCalculators(); if (sched_state.events().hasEvent(ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX)) { this->runWellPIScaling(timeStepIdx, local_deferredLogger); diff --git a/opm/simulators/wells/VFPHelpers.cpp b/opm/simulators/wells/VFPHelpers.cpp index a9a6d5fa8..c6fec4056 100644 --- a/opm/simulators/wells/VFPHelpers.cpp +++ b/opm/simulators/wells/VFPHelpers.cpp @@ -345,12 +345,19 @@ VFPEvaluation bhp(const VFPProdTable& table, const double liquid, const double vapour, const double thp, - const double alq) + const double alq, + const double explicit_wfr, + const double explicit_gfr, + const bool vfpexplicit) { //Find interpolation variables double flo = detail::getFlo(table, aqua, liquid, vapour); double wfr = detail::getWFR(table, aqua, liquid, vapour); double gfr = detail::getGFR(table, aqua, liquid, vapour); + if (vfpexplicit) { + wfr = explicit_wfr; + gfr = explicit_gfr; + } //First, find the values to interpolate between //Recall that flo is negative in Opm, so switch sign. diff --git a/opm/simulators/wells/VFPHelpers.hpp b/opm/simulators/wells/VFPHelpers.hpp index b0d8e013e..f23a20585 100644 --- a/opm/simulators/wells/VFPHelpers.hpp +++ b/opm/simulators/wells/VFPHelpers.hpp @@ -136,7 +136,10 @@ VFPEvaluation bhp(const VFPProdTable& table, const double liquid, const double vapour, const double thp, - const double alq); + const double alq, + const double explicit_wfr, + const double explicit_gfr, + const bool vfpexplicit); VFPEvaluation bhp(const VFPInjTable& table, const double aqua, diff --git a/opm/simulators/wells/VFPProdProperties.cpp b/opm/simulators/wells/VFPProdProperties.cpp index 41f86530b..972b20c47 100644 --- a/opm/simulators/wells/VFPProdProperties.cpp +++ b/opm/simulators/wells/VFPProdProperties.cpp @@ -87,10 +87,13 @@ double VFPProdProperties::bhp(int table_id, const double& liquid, const double& vapour, const double& thp_arg, - const double& alq) const { + const double& alq, + const double& explicit_wfr, + const double& explicit_gfr, + const bool expvfp) const { const VFPProdTable& table = detail::getTable(m_tables, table_id); - detail::VFPEvaluation retval = detail::bhp(table, aqua, liquid, vapour, thp_arg, alq); + detail::VFPEvaluation retval = detail::bhp(table, aqua, liquid, vapour, thp_arg, alq, explicit_wfr,explicit_gfr, expvfp); return retval.value; } @@ -145,7 +148,10 @@ EvalWell VFPProdProperties::bhp(const int table_id, const EvalWell& liquid, const EvalWell& vapour, const double& thp, - const double& alq) const + const double& alq, + const double& explicit_wfr, + const double& explicit_gfr, + const bool expvfp) const { //Get the table const VFPProdTable& table = detail::getTable(m_tables, table_id); @@ -155,6 +161,10 @@ EvalWell VFPProdProperties::bhp(const int table_id, EvalWell flo = detail::getFlo(table, aqua, liquid, vapour); EvalWell wfr = detail::getWFR(table, aqua, liquid, vapour); EvalWell gfr = detail::getGFR(table, aqua, liquid, vapour); + if(expvfp) { + wfr = explicit_wfr; + gfr = explicit_gfr; + } //First, find the values to interpolate between //Value of FLO is negative in OPM for producers, but positive in VFP table @@ -175,7 +185,7 @@ EvalWell VFPProdProperties::bhp(const int table_id, #define INSTANCE(...) \ template __VA_ARGS__ VFPProdProperties::bhp<__VA_ARGS__>(const int, \ const __VA_ARGS__&, const __VA_ARGS__&, const __VA_ARGS__&, \ - const double&, const double&) const; + const double&, const double&, const double&, const double&, const bool) const; INSTANCE(DenseAd::Evaluation) INSTANCE(DenseAd::Evaluation) diff --git a/opm/simulators/wells/VFPProdProperties.hpp b/opm/simulators/wells/VFPProdProperties.hpp index f2bd9eaa6..05e5a9cd1 100644 --- a/opm/simulators/wells/VFPProdProperties.hpp +++ b/opm/simulators/wells/VFPProdProperties.hpp @@ -65,7 +65,10 @@ public: const EvalWell& liquid, const EvalWell& vapour, const double& thp, - const double& alq) const; + const double& alq, + const double& wfr, + const double& gfr, + const bool expvfp) const; /** * Linear interpolation of bhp as a function of the input parameters @@ -84,7 +87,10 @@ public: const double& liquid, const double& vapour, const double& thp, - const double& alq) const; + const double& alq, + const double& explicit_wfr, + const double& explicit_gfr, + const bool expvfp) const; /** * Linear interpolation of thp as a function of the input parameters diff --git a/opm/simulators/wells/VFPProperties.hpp b/opm/simulators/wells/VFPProperties.hpp index 9c4b31edd..ddfb71464 100644 --- a/opm/simulators/wells/VFPProperties.hpp +++ b/opm/simulators/wells/VFPProperties.hpp @@ -22,6 +22,8 @@ #include #include +#include +#include #include @@ -47,7 +49,9 @@ public: */ VFPProperties(const std::vector>& inj_tables, - const std::vector>& prod_tables) + const std::vector>& prod_tables, + const WellState& well_state) + :well_state_(well_state) { for (const auto& vfpinj : inj_tables) this->m_inj.addTable( vfpinj ); @@ -70,9 +74,33 @@ public: return &m_prod; } + double getExplicitWFR(const int table_id, const size_t well_index) const { + const auto& rates = well_state_.well(well_index).surface_rates; + assert(rates.size() == 3); + const auto& pu = well_state_.phaseUsage(); + const auto& aqua = rates[pu.phase_pos[BlackoilPhases::Aqua]]; + const auto& liquid = rates[pu.phase_pos[BlackoilPhases::Liquid]]; + const auto& vapour = rates[pu.phase_pos[BlackoilPhases::Vapour]]; + const VFPProdTable& table = this->m_prod.getTable(table_id); + return detail::getWFR(table, aqua, liquid, vapour); + } + + double getExplicitGFR(const int table_id, const size_t well_index) const { + const auto& rates = well_state_.well(well_index).surface_rates; + assert(rates.size() == 3); + const auto& pu = well_state_.phaseUsage(); + const auto& aqua = rates[pu.phase_pos[BlackoilPhases::Aqua]]; + const auto& liquid = rates[pu.phase_pos[BlackoilPhases::Liquid]]; + const auto& vapour = rates[pu.phase_pos[BlackoilPhases::Vapour]]; + const VFPProdTable& table = this->m_prod.getTable(table_id); + return detail::getGFR(table, aqua, liquid, vapour); + } + private: VFPInjProperties m_inj; VFPProdProperties m_prod; + const WellState& well_state_; + }; diff --git a/opm/simulators/wells/WellGroupHelpers.cpp b/opm/simulators/wells/WellGroupHelpers.cpp index eec227c76..15efbf37d 100644 --- a/opm/simulators/wells/WellGroupHelpers.cpp +++ b/opm/simulators/wells/WellGroupHelpers.cpp @@ -766,7 +766,10 @@ namespace WellGroupHelpers rates[BlackoilPhases::Liquid], rates[BlackoilPhases::Vapour], up_press, - alq); + alq, + 0.0, //explicit_wfr + 0.0, //explicit_gfr + false); //expvfp we dont support explicit lookup #define EXTRA_DEBUG_NETWORK 0 #if EXTRA_DEBUG_NETWORK std::ostringstream oss; diff --git a/opm/simulators/wells/WellInterfaceEval.cpp b/opm/simulators/wells/WellInterfaceEval.cpp index 81db282b5..8dd56b234 100644 --- a/opm/simulators/wells/WellInterfaceEval.cpp +++ b/opm/simulators/wells/WellInterfaceEval.cpp @@ -493,7 +493,10 @@ calculateBhpFromThp(const WellState& well_state, const auto& controls = well.productionControls(summaryState); const double vfp_ref_depth = baseif_.vfpProperties()->getProd()->getTable(controls.vfp_table_number).getDatumDepth(); const double dp = wellhelpers::computeHydrostaticCorrection(baseif_.refDepth(), vfp_ref_depth, rho, baseif_.gravity()); - return baseif_.vfpProperties()->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, baseif_.getTHPConstraint(summaryState), baseif_.getALQ(well_state)) - dp; + const auto& wfr = baseif_.vfpProperties()->getExplicitWFR(controls.vfp_table_number, baseif_.indexOfWell()); + const auto& gfr = baseif_.vfpProperties()->getExplicitGFR(controls.vfp_table_number, baseif_.indexOfWell()); + const bool vfpexp = baseif_.vfpExplicit(); + return baseif_.vfpProperties()->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, baseif_.getTHPConstraint(summaryState), baseif_.getALQ(well_state), wfr, gfr, vfpexp) - dp; } else { OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER for well " + baseif_.name(), deferred_logger); diff --git a/opm/simulators/wells/WellInterfaceGeneric.cpp b/opm/simulators/wells/WellInterfaceGeneric.cpp index ed9dc5c35..015604bb5 100644 --- a/opm/simulators/wells/WellInterfaceGeneric.cpp +++ b/opm/simulators/wells/WellInterfaceGeneric.cpp @@ -414,6 +414,11 @@ bool WellInterfaceGeneric::isOperableAndSolvable() const return operability_status_.isOperableAndSolvable(); } +bool WellInterfaceGeneric::vfpExplicit() const +{ + return operability_status_.vfpexplicit; +} + double WellInterfaceGeneric::getALQ(const WellState& well_state) const { return well_state.getALQ(name()); diff --git a/opm/simulators/wells/WellInterfaceGeneric.hpp b/opm/simulators/wells/WellInterfaceGeneric.hpp index 4aefa1299..c778c7d62 100644 --- a/opm/simulators/wells/WellInterfaceGeneric.hpp +++ b/opm/simulators/wells/WellInterfaceGeneric.hpp @@ -88,6 +88,7 @@ public: // whether the well is operable bool isOperableAndSolvable() const; + bool vfpExplicit () const; void initCompletions(); void closeCompletions(const WellTestState& wellTestState); @@ -265,6 +266,8 @@ protected: bool has_negative_potentials = false; //thp limit violated but not switched mutable bool thp_limit_violated_but_not_switched = false; + + bool vfpexplicit = false; }; OperabilityStatus operability_status_; diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index 7f322a62f..3ab0ad35e 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -613,6 +613,12 @@ namespace Opm } updateWellOperability(ebos_simulator, well_state, deferred_logger); + if (!this->operability_status_.isOperableAndSolvable()) { + this->operability_status_.vfpexplicit = true; + deferred_logger.debug("EXPLICIT_LOOKUP_VFP", + "well not operable, trying with explicit vfp lookup: " + this->name()); + updateWellOperability(ebos_simulator, well_state, deferred_logger); + } } template