Implement basic WTMULT behavior
This commit is contained in:
parent
a3d37aad1e
commit
5e3e20c552
@ -652,6 +652,7 @@ namespace Opm
|
||||
void handleWSOLVENT (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||
void handleWTEMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||
void handleWTEST (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||
void handleWTMULT (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||
void handleWTRACER (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||
};
|
||||
}
|
||||
|
@ -296,6 +296,7 @@ public:
|
||||
InjectionControls controls(const UnitSystem& unit_system, const SummaryState& st, double udq_default) const;
|
||||
bool updateUDQActive(const UDQConfig& udq_config, UDQActive& active) const;
|
||||
void update_uda(const UDQConfig& udq_config, UDQActive& udq_active, UDAControl control, const UDAValue& value);
|
||||
void handleWTMULT(Well::WELTARGCMode cmode, double factor);
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
@ -426,6 +427,7 @@ public:
|
||||
|
||||
void setBHPLimit(const double limit);
|
||||
int productionControls() const { return this->m_productionControls; }
|
||||
void handleWTMULT(Well::WELTARGCMode cmode, double factor);
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
|
@ -2009,6 +2009,82 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The WTMULT keyword can optionally use UDA values in three different ways:
|
||||
|
||||
1. The target can be UDA - instead of the standard strings "ORAT", "GRAT",
|
||||
"WRAT", ..., the keyword can be configured with a UDA which is evaluated to
|
||||
an integer and then mapped to one of the common controls.
|
||||
|
||||
2. The scaling factor itself can be a UDA.
|
||||
|
||||
3. The target we aim to scale might already be specified as a UDA.
|
||||
|
||||
The current implementation does not support UDA usage in any part of WTMULT
|
||||
codepath.
|
||||
*/
|
||||
|
||||
void Schedule::handleWTMULT(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||
for (const auto& record : handlerContext.keyword) {
|
||||
const auto& wellNamePattern = record.getItem<ParserKeywords::WTMULT::WELL>().getTrimmedString(0);
|
||||
const auto& control = record.getItem<ParserKeywords::WTMULT::CONTROL>().get<std::string>(0);
|
||||
const auto& factor = record.getItem<ParserKeywords::WTMULT::FACTOR>().get<UDAValue>(0);
|
||||
const auto& num = record.getItem<ParserKeywords::WTMULT::NUM>().get<int>(0);
|
||||
|
||||
if (factor.is<std::string>()) {
|
||||
std::string reason = fmt::format("Use of UDA value: {} is not supported as multiplier", factor.get<std::string>());
|
||||
throw OpmInputError(reason, handlerContext.keyword.location());
|
||||
}
|
||||
|
||||
if (this->snapshots.back().udq().has_keyword(control)) {
|
||||
std::string reason = fmt::format("Use of UDA value: {} is not supported for control target", control);
|
||||
throw OpmInputError(reason, handlerContext.keyword.location());
|
||||
}
|
||||
|
||||
if (num != 1) {
|
||||
std::string reason = fmt::format("Only NUM=1 is supported in WTMULT keyword");
|
||||
throw OpmInputError(reason, handlerContext.keyword.location());
|
||||
}
|
||||
|
||||
const auto cmode = Well::WELTARGCModeFromString(control);
|
||||
if (cmode == Well::WELTARGCMode::GUID)
|
||||
throw std::logic_error("Multiplying guide rate is not implemented");
|
||||
|
||||
const auto well_names = this->wellNames(wellNamePattern, handlerContext.currentStep, handlerContext.matching_wells);
|
||||
if (well_names.empty())
|
||||
invalidNamePattern(wellNamePattern, handlerContext.currentStep, parseContext, errors, handlerContext.keyword);
|
||||
|
||||
for (const auto& well_name : well_names) {
|
||||
auto well = this->snapshots.back().wells.get(well_name);
|
||||
if (well.isInjector()) {
|
||||
bool update_well = true;
|
||||
auto properties = std::make_shared<Well::WellInjectionProperties>(well.getInjectionProperties());
|
||||
properties->handleWTMULT( cmode, factor.get<double>());
|
||||
|
||||
well.updateInjection(properties);
|
||||
if (update_well) {
|
||||
this->snapshots.back().events().addEvent(ScheduleEvents::INJECTION_UPDATE);
|
||||
this->snapshots.back().wellgroup_events().addEvent(well_name, ScheduleEvents::INJECTION_UPDATE);
|
||||
this->snapshots.back().wells.update(std::move(well));
|
||||
}
|
||||
} else {
|
||||
bool update_well = true;
|
||||
auto properties = std::make_shared<Well::WellProductionProperties>(well.getProductionProperties());
|
||||
properties->handleWTMULT( cmode, factor.get<double>());
|
||||
|
||||
well.updateProduction(properties);
|
||||
if (update_well) {
|
||||
this->snapshots.back().events().addEvent(ScheduleEvents::PRODUCTION_UPDATE);
|
||||
this->snapshots.back().wellgroup_events().addEvent(well_name,
|
||||
ScheduleEvents::PRODUCTION_UPDATE);
|
||||
this->snapshots.back().wells.update(std::move(well));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Schedule::handleNormalKeyword(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||
using handler_function = void (Schedule::*)(const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||
static const std::unordered_map<std::string,handler_function> handler_functions = {
|
||||
@ -2100,6 +2176,7 @@ namespace {
|
||||
{ "WSOLVENT", &Schedule::handleWSOLVENT },
|
||||
{ "WTEMP" , &Schedule::handleWTEMP },
|
||||
{ "WTEST" , &Schedule::handleWTEST },
|
||||
{ "WTMULT" , &Schedule::handleWTMULT },
|
||||
{ "WTRACER" , &Schedule::handleWTRACER },
|
||||
};
|
||||
|
||||
|
@ -339,5 +339,39 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
void Well::WellInjectionProperties::handleWTMULT(Well::WELTARGCMode cmode, double factor) {
|
||||
if (cmode == Well::WELTARGCMode::BHP)
|
||||
this->BHPTarget *= factor;
|
||||
|
||||
else if (cmode == WELTARGCMode::ORAT) {
|
||||
if (this->injectorType == InjectorType::OIL)
|
||||
this->surfaceInjectionRate *= factor;
|
||||
else
|
||||
std::invalid_argument("Well type must be OIL to scale the oil rate");
|
||||
}
|
||||
|
||||
else if (cmode == WELTARGCMode::WRAT) {
|
||||
if (this->injectorType == InjectorType::WATER)
|
||||
this->surfaceInjectionRate *= factor;
|
||||
else
|
||||
std::invalid_argument("Well type must be WATER to scale the water rate");
|
||||
}
|
||||
|
||||
else if (cmode == WELTARGCMode::GRAT) {
|
||||
if(this->injectorType == InjectorType::GAS)
|
||||
this->surfaceInjectionRate *= factor;
|
||||
else
|
||||
std::invalid_argument("Well type must be GAS to scale the gas rate");
|
||||
}
|
||||
|
||||
else if (cmode == WELTARGCMode::THP)
|
||||
this->THPTarget *= factor;
|
||||
|
||||
else if (cmode == WELTARGCMode::RESV)
|
||||
this->reservoirInjectionRate*= factor;
|
||||
|
||||
else throw std::invalid_argument("Invalid keyword (MODE) supplied");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -270,6 +271,38 @@ void Well::WellProductionProperties::handleWCONHIST(const std::optional<VFPProdT
|
||||
}
|
||||
|
||||
|
||||
void Well::WellProductionProperties::handleWTMULT(Well::WELTARGCMode cmode, double factor) {
|
||||
switch (cmode) {
|
||||
case Well::WELTARGCMode::ORAT:
|
||||
this->OilRate *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::GRAT:
|
||||
this->GasRate *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::WRAT:
|
||||
this->WaterRate *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::LRAT:
|
||||
this->LiquidRate *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::RESV:
|
||||
this->ResVRate *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::BHP:
|
||||
this->BHPTarget *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::THP:
|
||||
this->THPTarget *= factor;
|
||||
break;
|
||||
case Well::WELTARGCMode::LIFT:
|
||||
this->ALQValue *= factor;
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Unhandled WTMULT control");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Well::WellProductionProperties::operator==(const Well::WellProductionProperties& other) const {
|
||||
return OilRate == other.OilRate
|
||||
|
@ -856,15 +856,24 @@ DATES -- 1
|
||||
/
|
||||
WELSPECS
|
||||
'OP_1' 'OP' 9 9 1* 'OIL' 1* 1* 1* 1* 1* 1* 1* /
|
||||
'I1' 'I' 5 5 2522.5 'WATER' /
|
||||
/
|
||||
COMPDAT
|
||||
'OP_1' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
'OP_1' 9 9 2 2 'OPEN' 1* 46.825 0.311 4332.346 1* 1* 'X' 22.123 /
|
||||
'OP_1' 9 9 3 9 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
'OP_1' 9 9 3 9 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
'I1' 8 8 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
'I1' 8 8 2 2 'OPEN' 1* 46.825 0.311 4332.346 1* 1* 'X' 22.123 /
|
||||
'I1' 8 8 3 9 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
||||
/
|
||||
|
||||
WCONPROD
|
||||
'OP_1' 'OPEN' 'ORAT' 0.000 0.000 0.000 5* /
|
||||
/
|
||||
|
||||
WCONINJE
|
||||
'I1' 'WATER' 'OPEN' 'RATE' 200 1* 450.0 /
|
||||
/
|
||||
DATES -- 2
|
||||
20 JAN 2010 /
|
||||
/
|
||||
@ -878,6 +887,20 @@ WELTARG
|
||||
OP_1 THP 2000 /
|
||||
OP_1 GUID 2300.14 /
|
||||
/
|
||||
|
||||
DATES
|
||||
1 FEB 2010 /
|
||||
/
|
||||
|
||||
WTMULT
|
||||
OP_1 ORAT 2 /
|
||||
OP_1 GRAT 3 /
|
||||
OP_1 WRAT 4 /
|
||||
I1 WRAT 2 /
|
||||
I1 BHP 3 /
|
||||
I1 THP 4 /
|
||||
/
|
||||
|
||||
)";
|
||||
|
||||
const auto& schedule = make_schedule(input);
|
||||
@ -910,8 +933,25 @@ WELTARG
|
||||
BOOST_CHECK (wpp_2.hasProductionControl( Opm::Well::ProducerCMode::ORAT) );
|
||||
BOOST_CHECK (wpp_2.hasProductionControl( Opm::Well::ProducerCMode::RESV) );
|
||||
|
||||
|
||||
const auto& well_3 = schedule.getWell("OP_1", 3);
|
||||
const auto wpp_3 = well_3.getProductionProperties();
|
||||
const auto prod_controls3 = wpp_3.controls(st, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(prod_controls3.oil_rate, 2 * 1300 * siFactorL);
|
||||
BOOST_CHECK_EQUAL(prod_controls3.water_rate, 4 * 1400 * siFactorL);
|
||||
BOOST_CHECK_EQUAL(prod_controls3.gas_rate, 3 * 1500.52 * siFactorG);
|
||||
|
||||
|
||||
const auto& inj_controls2 = schedule.getWell("I1", 2).getInjectionProperties().controls(unitSystem, st, 0);
|
||||
const auto& inj_controls3 = schedule.getWell("I1", 3).getInjectionProperties().controls(unitSystem, st, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(inj_controls2.surface_rate * 2, inj_controls3.surface_rate);
|
||||
BOOST_CHECK_EQUAL(inj_controls2.bhp_limit * 3, inj_controls3.bhp_limit);
|
||||
BOOST_CHECK_EQUAL(inj_controls2.thp_limit * 4, inj_controls3.thp_limit);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(createDeckWithWeltArg_UDA) {
|
||||
std::string input = R"(
|
||||
START -- 0
|
||||
|
Loading…
Reference in New Issue
Block a user