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 handleWSOLVENT (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleWTEMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleWTEMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleWTEST (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&);
|
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;
|
InjectionControls controls(const UnitSystem& unit_system, const SummaryState& st, double udq_default) const;
|
||||||
bool updateUDQActive(const UDQConfig& udq_config, UDQActive& active) 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 update_uda(const UDQConfig& udq_config, UDQActive& udq_active, UDAControl control, const UDAValue& value);
|
||||||
|
void handleWTMULT(Well::WELTARGCMode cmode, double factor);
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
@ -426,6 +427,7 @@ public:
|
|||||||
|
|
||||||
void setBHPLimit(const double limit);
|
void setBHPLimit(const double limit);
|
||||||
int productionControls() const { return this->m_productionControls; }
|
int productionControls() const { return this->m_productionControls; }
|
||||||
|
void handleWTMULT(Well::WELTARGCMode cmode, double factor);
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& 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) {
|
bool Schedule::handleNormalKeyword(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
using handler_function = void (Schedule::*)(const HandlerContext&, const ParseContext&, ErrorGuard&);
|
using handler_function = void (Schedule::*)(const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
static const std::unordered_map<std::string,handler_function> handler_functions = {
|
static const std::unordered_map<std::string,handler_function> handler_functions = {
|
||||||
@ -2100,6 +2176,7 @@ namespace {
|
|||||||
{ "WSOLVENT", &Schedule::handleWSOLVENT },
|
{ "WSOLVENT", &Schedule::handleWSOLVENT },
|
||||||
{ "WTEMP" , &Schedule::handleWTEMP },
|
{ "WTEMP" , &Schedule::handleWTEMP },
|
||||||
{ "WTEST" , &Schedule::handleWTEST },
|
{ "WTEST" , &Schedule::handleWTEST },
|
||||||
|
{ "WTMULT" , &Schedule::handleWTMULT },
|
||||||
{ "WTRACER" , &Schedule::handleWTRACER },
|
{ "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/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#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 {
|
bool Well::WellProductionProperties::operator==(const Well::WellProductionProperties& other) const {
|
||||||
return OilRate == other.OilRate
|
return OilRate == other.OilRate
|
||||||
|
@ -856,15 +856,24 @@ DATES -- 1
|
|||||||
/
|
/
|
||||||
WELSPECS
|
WELSPECS
|
||||||
'OP_1' 'OP' 9 9 1* 'OIL' 1* 1* 1* 1* 1* 1* 1* /
|
'OP_1' 'OP' 9 9 1* 'OIL' 1* 1* 1* 1* 1* 1* 1* /
|
||||||
|
'I1' 'I' 5 5 2522.5 'WATER' /
|
||||||
/
|
/
|
||||||
COMPDAT
|
COMPDAT
|
||||||
'OP_1' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 /
|
'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 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
|
WCONPROD
|
||||||
'OP_1' 'OPEN' 'ORAT' 0.000 0.000 0.000 5* /
|
'OP_1' 'OPEN' 'ORAT' 0.000 0.000 0.000 5* /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
WCONINJE
|
||||||
|
'I1' 'WATER' 'OPEN' 'RATE' 200 1* 450.0 /
|
||||||
|
/
|
||||||
DATES -- 2
|
DATES -- 2
|
||||||
20 JAN 2010 /
|
20 JAN 2010 /
|
||||||
/
|
/
|
||||||
@ -878,6 +887,20 @@ WELTARG
|
|||||||
OP_1 THP 2000 /
|
OP_1 THP 2000 /
|
||||||
OP_1 GUID 2300.14 /
|
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);
|
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::ORAT) );
|
||||||
BOOST_CHECK (wpp_2.hasProductionControl( Opm::Well::ProducerCMode::RESV) );
|
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) {
|
BOOST_AUTO_TEST_CASE(createDeckWithWeltArg_UDA) {
|
||||||
std::string input = R"(
|
std::string input = R"(
|
||||||
START -- 0
|
START -- 0
|
||||||
|
Loading…
Reference in New Issue
Block a user