Merge pull request #2018 from bska/preferred-is-injected
Use Injected Phase as Preferred Phase for Injectors
This commit is contained in:
commit
452c222f71
@ -433,6 +433,28 @@ public:
|
||||
double getBHPLimit() const;
|
||||
};
|
||||
|
||||
struct WellProductivityIndex {
|
||||
double pi_value;
|
||||
Phase preferred_phase;
|
||||
|
||||
bool operator==(const WellProductivityIndex& rhs) const
|
||||
{
|
||||
return (this->pi_value == rhs.pi_value)
|
||||
&& (this->preferred_phase == rhs.preferred_phase);
|
||||
}
|
||||
|
||||
bool operator!=(const WellProductivityIndex& rhs) const
|
||||
{
|
||||
return ! (*this == rhs);
|
||||
}
|
||||
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer(this->pi_value);
|
||||
serializer(this->preferred_phase);
|
||||
}
|
||||
};
|
||||
|
||||
Well() = default;
|
||||
Well(const std::string& wname,
|
||||
@ -497,6 +519,7 @@ public:
|
||||
const WellPolymerProperties& getPolymerProperties() const;
|
||||
const WellBrineProperties& getBrineProperties() const;
|
||||
const WellTracerProperties& getTracerProperties() const;
|
||||
const WellProductivityIndex& getWellProductivityIndex() const;
|
||||
/* The rate of a given phase under the following assumptions:
|
||||
* * Returns zero if production is requested for an injector (and vice
|
||||
* versa)
|
||||
@ -547,7 +570,7 @@ public:
|
||||
bool updateEconLimits(std::shared_ptr<WellEconProductionLimits> econ_limits);
|
||||
bool updateProduction(std::shared_ptr<WellProductionProperties> production);
|
||||
bool updateInjection(std::shared_ptr<WellInjectionProperties> injection);
|
||||
bool updateWellProductivityIndex(const double prodIndex);
|
||||
bool updateWellProductivityIndex(const WellProductivityIndex& prodIndex);
|
||||
bool updateWSEGSICD(const std::vector<std::pair<int, SICD> >& sicd_pairs);
|
||||
bool updateWSEGVALV(const std::vector<std::pair<int, Valve> >& valve_pairs);
|
||||
|
||||
@ -557,6 +580,8 @@ public:
|
||||
bool handleCOMPLUMP(const DeckRecord& record);
|
||||
bool handleWPIMULT(const DeckRecord& record);
|
||||
|
||||
void forceUpdateConnections(std::shared_ptr<WellConnections> connections_arg);
|
||||
|
||||
void filterConnections(const ActiveGridCells& grid);
|
||||
ProductionControls productionControls(const SummaryState& st) const;
|
||||
InjectionControls injectionControls(const SummaryState& st) const;
|
||||
@ -601,7 +626,7 @@ public:
|
||||
serializer(has_produced);
|
||||
serializer(has_injected);
|
||||
serializer(prediction_mode);
|
||||
serializer(productivity_index);
|
||||
serializer.optional(productivity_index);
|
||||
serializer(econ_limits);
|
||||
serializer(foam_properties);
|
||||
serializer(polymer_properties);
|
||||
@ -639,7 +664,7 @@ private:
|
||||
bool has_produced = false;
|
||||
bool has_injected = false;
|
||||
bool prediction_mode = true;
|
||||
std::optional<double> productivity_index{ std::nullopt };
|
||||
std::optional<WellProductivityIndex> productivity_index{ std::nullopt };
|
||||
|
||||
std::shared_ptr<WellEconProductionLimits> econ_limits;
|
||||
std::shared_ptr<WellFoamProperties> foam_properties;
|
||||
|
@ -21,10 +21,12 @@
|
||||
#include <fnmatch.h>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
@ -1112,11 +1114,23 @@ namespace {
|
||||
const auto rawProdIndex = record.getItem<PI>().get<double>(0);
|
||||
for (const auto& well_name : well_names) {
|
||||
// All wells in a single record *hopefully* have the same preferred phase...
|
||||
const auto& well = this->getWell(well_name, handlerContext.currentStep);
|
||||
const auto unitPI = (well.getPreferredPhase() == Phase::GAS) ? gasPI : liqPI;
|
||||
const auto& well = this->getWell(well_name, handlerContext.currentStep);
|
||||
const auto preferred = well.getPreferredPhase();
|
||||
const auto unitPI = (preferred == Phase::GAS) ? gasPI : liqPI;
|
||||
|
||||
auto well2 = std::make_shared<Well>(well);
|
||||
if (well2->updateWellProductivityIndex(usys.to_si(unitPI, rawProdIndex)))
|
||||
const auto wellPI = Well::WellProductivityIndex {
|
||||
usys.to_si(unitPI, rawProdIndex),
|
||||
preferred
|
||||
};
|
||||
|
||||
// Note: Need to ensure we have an independent copy of
|
||||
// well's connections because
|
||||
// Well::updateWellProductivityIndex() implicitly mutates
|
||||
// internal state in the WellConnections class.
|
||||
auto well2 = std::make_shared<Well>(well);
|
||||
auto connections = std::make_shared<WellConnections>(well2->getConnections());
|
||||
well2->forceUpdateConnections(std::move(connections));
|
||||
if (well2->updateWellProductivityIndex(wellPI))
|
||||
this->updateWell(std::move(well2), handlerContext.currentStep);
|
||||
|
||||
this->addWellGroupEvent(well_name, ScheduleEvents::WELL_PRODUCTIVITY_INDEX, handlerContext.currentStep);
|
||||
|
@ -201,7 +201,7 @@ int WellType::ecl_phase() const {
|
||||
|
||||
|
||||
Phase WellType::preferred_phase() const {
|
||||
return this->m_welspecs_phase;
|
||||
return this->injector() ? this->injection_phase : this->m_welspecs_phase;
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <fnmatch.h>
|
||||
#include <cmath>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
@ -375,7 +377,7 @@ Well Well::serializeObject()
|
||||
result.efficiency_factor = 8.0;
|
||||
result.solvent_fraction = 9.0;
|
||||
result.prediction_mode = false;
|
||||
result.productivity_index = 10.0;
|
||||
result.productivity_index = WellProductivityIndex { 10.0, Phase::GAS };
|
||||
result.econ_limits = std::make_shared<Opm::WellEconProductionLimits>(Opm::WellEconProductionLimits::serializeObject());
|
||||
result.foam_properties = std::make_shared<WellFoamProperties>(WellFoamProperties::serializeObject());
|
||||
result.polymer_properties = std::make_shared<WellPolymerProperties>(WellPolymerProperties::serializeObject());
|
||||
@ -477,19 +479,21 @@ void Well::switchToInjector() {
|
||||
}
|
||||
|
||||
bool Well::updateInjection(std::shared_ptr<WellInjectionProperties> injection_arg) {
|
||||
this->wtype.update(injection_arg->injectorType);
|
||||
if (this->wtype.producer())
|
||||
auto update = this->wtype.update(injection_arg->injectorType);
|
||||
if (this->wtype.producer()) {
|
||||
this->switchToInjector();
|
||||
update = true;
|
||||
}
|
||||
|
||||
if (*this->injection != *injection_arg) {
|
||||
this->injection = injection_arg;
|
||||
return true;
|
||||
update = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return update;
|
||||
}
|
||||
|
||||
bool Well::updateWellProductivityIndex(const double prodIndex) {
|
||||
bool Well::updateWellProductivityIndex(const WellProductivityIndex& prodIndex) {
|
||||
const auto update = this->productivity_index != prodIndex;
|
||||
if (update)
|
||||
this->productivity_index = prodIndex;
|
||||
@ -831,11 +835,11 @@ void Well::applyWellProdIndexScaling(const double currentEffectivePI) {
|
||||
// WELPI not activated. Nothing to do.
|
||||
return;
|
||||
|
||||
if (this->productivity_index == currentEffectivePI)
|
||||
if (this->productivity_index->pi_value == currentEffectivePI)
|
||||
// No change in scaling.
|
||||
return;
|
||||
|
||||
this->connections->applyWellPIScaling(*this->productivity_index / currentEffectivePI);
|
||||
this->connections->applyWellPIScaling(this->productivity_index->pi_value / currentEffectivePI);
|
||||
}
|
||||
|
||||
const WellConnections& Well::getConnections() const {
|
||||
@ -858,6 +862,16 @@ const WellTracerProperties& Well::getTracerProperties() const {
|
||||
return *this->tracer_properties;
|
||||
}
|
||||
|
||||
const Well::WellProductivityIndex& Well::getWellProductivityIndex() const
|
||||
{
|
||||
if (this->productivity_index)
|
||||
return *this->productivity_index;
|
||||
else
|
||||
throw std::logic_error {
|
||||
"WELPI not activated in well " + this->name()
|
||||
};
|
||||
}
|
||||
|
||||
const WellEconProductionLimits& Well::getEconLimits() const {
|
||||
return *this->econ_limits;
|
||||
}
|
||||
@ -1054,6 +1068,11 @@ bool Well::updateWSEGVALV(const std::vector<std::pair<int, Valve> >& valve_pairs
|
||||
return false;
|
||||
}
|
||||
|
||||
void Well::forceUpdateConnections(std::shared_ptr<WellConnections> connections_arg) {
|
||||
connections_arg->order();
|
||||
this->connections = std::move(connections_arg);
|
||||
}
|
||||
|
||||
void Well::filterConnections(const ActiveGridCells& grid) {
|
||||
this->connections->filter(grid);
|
||||
}
|
||||
|
@ -3760,6 +3760,14 @@ TSTEP
|
||||
10
|
||||
/
|
||||
|
||||
COMPDAT
|
||||
'P' 0 0 2 2 OPEN 1 50 /
|
||||
/
|
||||
|
||||
TSTEP
|
||||
10
|
||||
/
|
||||
|
||||
END
|
||||
)");
|
||||
|
||||
@ -3788,11 +3796,29 @@ END
|
||||
}
|
||||
}
|
||||
|
||||
// Apply WELPI after new COMPDAT.
|
||||
{
|
||||
const auto expectCF = (200.0 / 100.0) * 100.0*cp_rm3_per_db();
|
||||
auto wellP = sched.getWell("P", 2);
|
||||
|
||||
wellP.applyWellProdIndexScaling(100.0*liquid_PI_unit());
|
||||
const auto& connP = wellP.getConnections();
|
||||
BOOST_CHECK_CLOSE(connP[0].CF(), expectCF , 1.0e-10);
|
||||
BOOST_CHECK_CLOSE(connP[1].CF(), 50*cp_rm3_per_db(), 1.0e-10);
|
||||
BOOST_CHECK_CLOSE(connP[2].CF(), expectCF , 1.0e-10);
|
||||
}
|
||||
|
||||
BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 0),
|
||||
"Well P must have WELL_CONNECTIONS_UPDATED event at report step 0");
|
||||
|
||||
BOOST_CHECK_MESSAGE(!sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 1),
|
||||
"Well P must NOT have WELL_CONNECTIONS_UPDATED event at report step 0");
|
||||
"Well P must NOT have WELL_CONNECTIONS_UPDATED event at report step 1");
|
||||
|
||||
BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 2),
|
||||
"Well P must have WELL_CONNECTIONS_UPDATED event at report step 2");
|
||||
|
||||
BOOST_CHECK_MESSAGE(!sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 3),
|
||||
"Well P must NOT have WELL_CONNECTIONS_UPDATED event at report step 3");
|
||||
|
||||
BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_PRODUCTIVITY_INDEX, 1),
|
||||
"Must have WELL_PRODUCTIVITY_INDEX event at report step 1");
|
||||
|
@ -908,7 +908,7 @@ BOOST_AUTO_TEST_CASE(WellTypeTest) {
|
||||
wtp.update( InjectorType::GAS );
|
||||
BOOST_CHECK_EQUAL(wtp.ecl_wtype(), 4);
|
||||
BOOST_CHECK_EQUAL(wtp.ecl_phase(), 2);
|
||||
BOOST_CHECK(wtp.preferred_phase() == Phase::WATER);
|
||||
BOOST_CHECK(wtp.preferred_phase() == Phase::GAS);
|
||||
BOOST_CHECK(wtp.injector_type() == InjectorType::GAS);
|
||||
}
|
||||
|
||||
@ -1197,6 +1197,8 @@ COMPDAT
|
||||
END
|
||||
)");
|
||||
|
||||
using WellPI = Well::WellProductivityIndex;
|
||||
|
||||
const auto es = EclipseState{ deck };
|
||||
const auto sched = Schedule{ deck, es };
|
||||
|
||||
@ -1221,8 +1223,10 @@ END
|
||||
// /
|
||||
//
|
||||
// (ignoring units of measure)
|
||||
BOOST_CHECK_MESSAGE( wellP.updateWellProductivityIndex(2.0), "First call to updateWellProductivityIndex() must be a state change");
|
||||
BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(2.0), "Second call to updateWellProductivityIndex() must NOT be a state change");
|
||||
BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPI{ 2.0, Phase::GAS }),
|
||||
"First call to updateWellProductivityIndex() must be a state change");
|
||||
BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPI{ 2.0, Phase::GAS }),
|
||||
"Second call to updateWellProductivityIndex() must NOT be a state change");
|
||||
|
||||
// Want PI=2, but actual/effective PI=1 => scale CF by 2.0/1.0.
|
||||
wellP.applyWellProdIndexScaling(1.0);
|
||||
@ -1237,7 +1241,7 @@ END
|
||||
}
|
||||
|
||||
// New WELPI record does not reset the scaling factors
|
||||
wellP.updateWellProductivityIndex(3.0);
|
||||
wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::GAS });
|
||||
for (const auto& conn : wellP.getConnections()) {
|
||||
BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10);
|
||||
}
|
||||
@ -1247,4 +1251,9 @@ END
|
||||
for (const auto& conn : wellP.getConnections()) {
|
||||
BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10);
|
||||
}
|
||||
|
||||
BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }),
|
||||
"Fourth call to updateWellProductivityIndex() must be a state change");
|
||||
BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }),
|
||||
"Fifth call to updateWellProductivityIndex() must NOT be a state change");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user