Merge pull request #711 from joakim-hove/prod-properties-refactor

Refactor WellProductionProperties construction
This commit is contained in:
Joakim Hove 2019-04-09 18:27:04 +02:00 committed by GitHub
commit ebedc9b0b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 161 deletions

View File

@ -194,7 +194,6 @@ namespace Opm
DynamicState<std::shared_ptr<UDQInput>> udq_config;
RFTConfig rft_config;
WellProducer::ControlModeEnum m_controlModeWHISTCTL;
Actions m_actions;
std::vector< Well* > getWells(const std::string& wellNamePattern, const std::vector<std::string>& matching_wells = {});
@ -248,7 +247,7 @@ namespace Opm
void handleDRVDTR( const DeckKeyword& keyword, size_t currentStep);
void handleVAPPARS( const DeckKeyword& keyword, size_t currentStep);
void handleWECON( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleWHISTCTL(const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword);
void handleWHISTCTL(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleMESSAGES(const DeckKeyword& keyword, size_t currentStep);
void handleVFPPROD(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);
void handleVFPINJ(const DeckKeyword& vfpprodKeyword, const UnitSystem& unit_system, size_t currentStep);

View File

@ -48,19 +48,12 @@ namespace Opm {
int VFPTableNumber = 0;
double ALQValue = 0.0;
bool predictionMode = false;
WellProducer::ControlModeEnum controlMode = WellProducer::CMODE_UNDEFINED;
WellProducer::ControlModeEnum whistctl_cmode = WellProducer::CMODE_UNDEFINED;
bool operator==(const WellProductionProperties& other) const;
bool operator!=(const WellProductionProperties& other) const;
WellProductionProperties();
WellProductionProperties (const DeckRecord& record,
bool prediction_mode,
const WellProductionProperties& prev_properties,
WellProducer::ControlModeEnum controlModeWHISTCTL,
bool switching_from_injector,
bool addGrupProductionControl);
bool hasProductionControl(WellProducer::ControlModeEnum controlModeArg) const {
return (m_productionControls & controlModeArg) != 0;
@ -78,21 +71,18 @@ namespace Opm {
// this is used to check whether the specified control mode is an effective history matching production mode
static bool effectiveHistoryProductionControl(const WellProducer::ControlModeEnum cmode);
void handleWCONPROD( const DeckRecord& record);
void handleWCONHIST( const DeckRecord& record);
void resetDefaultBHPLimit();
private:
int m_productionControls = 0;
void init_rates( const DeckRecord& record );
void init_history(const WellProductionProperties& prevProperties,
const DeckRecord& record,
const WellProducer::ControlModeEnum controlModeWHISTCL,
const bool switching_from_injector);
void init_history(const DeckRecord& record);
void init_prediction( const DeckRecord& record, bool addGroupProductionControl );
WellProductionProperties(const DeckRecord& record);
void resetDefaultBHPLimit();
void setBHPLimit(const double limit);
double getBHPLimit() const;

View File

@ -89,7 +89,6 @@ namespace Opm {
udq_config(this->m_timeMap, std::make_shared<UDQInput>(deck)),
rft_config(this->m_timeMap)
{
m_controlModeWHISTCTL = WellProducer::CMODE_UNDEFINED;
addGroup( "FIELD", 0 );
/*
@ -230,7 +229,7 @@ namespace Opm {
handleWELSPECS( section, keywordIdx, currentStep );
else if (keyword.name() == "WHISTCTL")
handleWHISTCTL(parseContext, errors, keyword);
handleWHISTCTL(keyword, currentStep, parseContext, errors);
else if (keyword.name() == "WCONHIST")
handleWCONHIST(keyword, currentStep, parseContext, errors);
@ -426,27 +425,36 @@ namespace Opm {
return true;
}
void Schedule::handleWHISTCTL(const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword) {
for( const auto& record : keyword ) {
const std::string& cmodeString = record.getItem("CMODE").getTrimmedString(0);
const WellProducer::ControlModeEnum controlMode = WellProducer::ControlModeFromString( cmodeString );
if (controlMode != WellProducer::NONE) {
if (!WellProductionProperties::effectiveHistoryProductionControl(controlMode) ) {
std::string msg = "The WHISTCTL keyword specifies an un-supported control mode " + cmodeString
+ ", which makes WHISTCTL keyword not affect the simulation at all";
OpmLog::warning(msg);
}
void Schedule::handleWHISTCTL(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors) {
const auto& record = keyword.getRecord(0);
const std::string& cmodeString = record.getItem("CMODE").getTrimmedString(0);
const WellProducer::ControlModeEnum controlMode = WellProducer::ControlModeFromString( cmodeString );
if (controlMode != WellProducer::NONE) {
if (!WellProductionProperties::effectiveHistoryProductionControl(controlMode) ) {
std::string msg = "The WHISTCTL keyword specifies an un-supported control mode " + cmodeString
+ ", which makes WHISTCTL keyword not affect the simulation at all";
OpmLog::warning(msg);
}
}
m_controlModeWHISTCTL = controlMode;
const std::string bhp_terminate = record.getItem("BPH_TERMINATE").getTrimmedString(0);
if (bhp_terminate == "YES") {
std::string msg = "The WHISTCTL keyword does not handle 'YES'. i.e. to terminate the run";
OpmLog::error(msg);
parseContext.handleError( ParseContext::UNSUPPORTED_TERMINATE_IF_BHP , msg, errors );
const std::string bhp_terminate = record.getItem("BPH_TERMINATE").getTrimmedString(0);
if (bhp_terminate == "YES") {
std::string msg = "The WHISTCTL keyword does not handle 'YES'. i.e. to terminate the run";
OpmLog::error(msg);
parseContext.handleError( ParseContext::UNSUPPORTED_TERMINATE_IF_BHP , msg, errors );
}
for (auto& well_pair : this->m_wells) {
auto& well = well_pair.second;
const WellProductionProperties& properties(well.getProductionProperties(currentStep));
if (properties.whistctl_cmode != controlMode) {
WellProductionProperties new_properties( properties );
new_properties.whistctl_cmode = controlMode;
well.setProductionProperties(currentStep, new_properties);
}
}
}
@ -659,23 +667,42 @@ namespace Opm {
for( const auto& well_name : well_names) {
auto& well = this->m_wells.at(well_name);
bool addGrupProductionControl = well.isAvailableForGroupControl(currentStep);
bool switching_from_injector = !well.isProducer(currentStep);
const WellProductionProperties& prev_properties = well.getProductionProperties(currentStep);
WellProductionProperties properties(record, isPredictionMode, prev_properties, m_controlModeWHISTCTL, switching_from_injector, addGrupProductionControl);
updateWellStatus( well , currentStep , status );
if (well.setProductionProperties(currentStep, properties)) {
m_events.addEvent( ScheduleEvents::PRODUCTION_UPDATE , currentStep);
this->addWellEvent( well.name(), ScheduleEvents::PRODUCTION_UPDATE, currentStep);
}
if ( !well.getAllowCrossFlow() && !isPredictionMode && (properties.OilRate + properties.WaterRate + properties.GasRate) == 0 ) {
if (isPredictionMode) {
bool addGrupProductionControl = well.isAvailableForGroupControl(currentStep);
WellProductionProperties properties;
std::string msg =
if (addGrupProductionControl)
properties.addProductionControl(WellProducer::GRUP);
properties.handleWCONPROD(record);
if (well.setProductionProperties(currentStep, properties)) {
m_events.addEvent( ScheduleEvents::PRODUCTION_UPDATE , currentStep);
this->addWellEvent( well.name(), ScheduleEvents::PRODUCTION_UPDATE, currentStep);
}
} else {
bool switching_from_injector = !well.isProducer(currentStep);
WellProductionProperties properties(well.getProductionProperties(currentStep));
properties.handleWCONHIST(record);
if (switching_from_injector)
properties.resetDefaultBHPLimit();
if (well.setProductionProperties(currentStep, properties)) {
m_events.addEvent( ScheduleEvents::PRODUCTION_UPDATE , currentStep);
this->addWellEvent( well.name(), ScheduleEvents::PRODUCTION_UPDATE, currentStep);
}
if ( !well.getAllowCrossFlow() && !isPredictionMode && (properties.OilRate + properties.WaterRate + properties.GasRate) == 0 ) {
std::string msg =
"Well " + well.name() + " is a history matched well with zero rate where crossflow is banned. " +
"This well will be closed at " + std::to_string ( m_timeMap.getTimePassedUntil(currentStep) / (60*60*24) ) + " days";
OpmLog::note(msg);
updateWellStatus( well, currentStep, WellCommon::StatusEnum::SHUT );
OpmLog::note(msg);
updateWellStatus( well, currentStep, WellCommon::StatusEnum::SHUT );
}
}
}
}

View File

@ -36,16 +36,13 @@ namespace Opm {
void WellProductionProperties::init_rates( const DeckRecord& record ) {
this->OilRate = ( record.getItem( "ORAT" ).getSIDouble( 0 ) );
this->WaterRate = ( record.getItem( "WRAT" ).getSIDouble( 0 ) );
this->GasRate = ( record.getItem( "GRAT" ).getSIDouble( 0 ) );
this->OilRate = record.getItem("ORAT").getSIDouble(0);
this->WaterRate = record.getItem("WRAT").getSIDouble(0);
this->GasRate = record.getItem("GRAT").getSIDouble(0);
}
void WellProductionProperties::init_history(const WellProductionProperties& prev_properties,
const DeckRecord& record,
const WellProducer::ControlModeEnum controlModeWHISTCL,
const bool switching_from_injector)
void WellProductionProperties::init_history(const DeckRecord& record)
{
this->predictionMode = false;
// update LiquidRate
@ -63,14 +60,14 @@ namespace Opm {
}
namespace wp = WellProducer;
auto cmode = wp::ControlModeFromString( cmodeItem.getTrimmedString( 0 ) );
auto cmode = wp::CMODE_UNDEFINED;
// when there is an effective control mode specified by WHISTCL, we always use this control mode
if (effectiveHistoryProductionControl(controlModeWHISTCL) ) {
cmode = controlModeWHISTCL;
}
if (effectiveHistoryProductionControl(this->whistctl_cmode) )
cmode = this->whistctl_cmode;
else
cmode = wp::ControlModeFromString( cmodeItem.getTrimmedString( 0 ) );
if (effectiveHistoryProductionControl(cmode) ) {
if (effectiveHistoryProductionControl(cmode)) {
this->addProductionControl( cmode );
this->controlMode = cmode;
} else {
@ -84,44 +81,30 @@ namespace Opm {
if ( !this->hasProductionControl( wp::BHP ) )
this->addProductionControl( wp::BHP );
if (cmode == wp::BHP) {
if (cmode == wp::BHP)
this->setBHPLimit(this->BHPH);
} else {
// when the well is switching to history matching producer from prediction mode
// or switching from injector to producer
// or switching from BHP control to RATE control (under history matching mode)
// we use the defaulted BHP limit, otherwise, we use the previous BHP limit
if ( prev_properties.predictionMode || switching_from_injector
|| prev_properties.controlMode == wp::BHP ) {
this->resetDefaultBHPLimit();
} else {
this->setBHPLimit(prev_properties.getBHPLimit());
}
}
this->VFPTableNumber = record.getItem("VFPTable").get< int >(0);
const auto vfp_table = record.getItem("VFPTable").get< int >(0);
if (vfp_table != 0)
this->VFPTableNumber = vfp_table;
if (this->VFPTableNumber == 0)
this->VFPTableNumber = prev_properties.VFPTableNumber;
this->ALQValue = record.getItem("Lift").get< double >(0); //NOTE: Unit of ALQ is never touched
if (this->ALQValue == 0.)
this->ALQValue = prev_properties.ALQValue;
auto alq_value = record.getItem("Lift").get< double >(0); //NOTE: Unit of ALQ is never touched
if (alq_value != 0.)
this->ALQValue = alq_value;
}
void WellProductionProperties::init_prediction( const DeckRecord& record, bool addGroupProductionControl)
void WellProductionProperties::handleWCONPROD( const DeckRecord& record )
{
this->predictionMode = true;
this->LiquidRate = record.getItem("LRAT" ).getSIDouble(0);
this->ResVRate = record.getItem("RESV" ).getSIDouble(0);
this->BHPLimit = record.getItem("BHP" ).getSIDouble(0);
this->THPLimit = record.getItem("THP" ).getSIDouble(0);
this->ALQValue = record.getItem("ALQ" ).get< double >(0); //NOTE: Unit of ALQ is never touched
this->VFPTableNumber = record.getItem("VFP_TABLE").get< int >(0);
this->LiquidRate = record.getItem("LRAT").getSIDouble(0);
this->ResVRate = record.getItem("RESV").getSIDouble(0);
namespace wp = WellProducer;
using mode = std::pair< const std::string, wp::ControlModeEnum >;
@ -130,6 +113,8 @@ namespace Opm {
{ "LRAT", wp::LRAT }, { "RESV", wp::RESV }, { "THP", wp::THP }
};
this->init_rates(record);
for( const auto& cmode : modes ) {
if( !record.getItem( cmode.first ).defaultApplied( 0 ) ) {
@ -143,12 +128,6 @@ namespace Opm {
// There is always a BHP constraint, when not specified, will use the default value
this->addProductionControl( wp::BHP );
if (addGroupProductionControl) {
this->addProductionControl(WellProducer::GRUP);
}
{
const auto& cmodeItem = record.getItem("CMODE");
if (cmodeItem.hasValue(0)) {
@ -157,26 +136,37 @@ namespace Opm {
if (this->hasProductionControl( cmode ))
this->controlMode = cmode;
else
throw std::invalid_argument("Setting CMODE to unspecified control");
throw std::invalid_argument("Trying to set CMODE to: " + cmodeItem.getTrimmedString(0) + " - no value has been specified for this control");
}
}
}
WellProductionProperties::WellProductionProperties(const DeckRecord& record,
bool prediction_mode,
const WellProductionProperties& prev_properties,
WellProducer::ControlModeEnum controlModeWHISTCTL,
bool switching_from_injector,
bool addGrupProductionControl)
/*
This is now purely "history" constructor - i.e. the record should
originate from the WCONHIST keyword. Predictions are handled with the
default constructor and the handleWCONPROD() method.
*/
void WellProductionProperties::handleWCONHIST(const DeckRecord& record)
{
this->init_rates(record);
if (prediction_mode)
this->init_prediction(record, addGrupProductionControl);
else
this->init_history(prev_properties, record, controlModeWHISTCTL, switching_from_injector);
this->LiquidRate = 0;
this->ResVRate = 0;
// when the well is switching to history matching producer from prediction mode
// or switching from injector to producer
// or switching from BHP control to RATE control (under history matching mode)
// we use the defaulted BHP limit, otherwise, we use the previous BHP limit
if (this->predictionMode)
this->resetDefaultBHPLimit();
if (this->controlMode == WellProducer::BHP)
this->resetDefaultBHPLimit();
this->init_history(record);
}
bool WellProductionProperties::operator==(const WellProductionProperties& other) const {
return OilRate == other.OilRate
&& WaterRate == other.WaterRate
@ -190,6 +180,7 @@ namespace Opm {
&& VFPTableNumber == other.VFPTableNumber
&& controlMode == other.controlMode
&& m_productionControls == other.m_productionControls
&& whistctl_cmode == other.whistctl_cmode
&& this->predictionMode == other.predictionMode;
}

View File

@ -745,33 +745,15 @@ namespace {
return input;
}
std::string whistctl() {
const std::string input =
"WHISTCTL\n"
"ORAT /\n"
"WCONHIST\n"
"-- 1 2 3 4-6 7 8 9 10\n"
" 'P' 'OPEN' 'RESV' 3* 3 10. 1* 500/\n/\n";
return input;
}
Opm::WellProductionProperties properties(const std::string& input) {
Opm::Parser parser;
auto deck = parser.parseString(input);
const auto& record = deck.getKeyword("WCONHIST").getRecord(0);
Opm::WellProductionProperties prev_p;
prev_p.BHPLimit = 100.;
prev_p.VFPTableNumber = 12;
prev_p.ALQValue = 18.;
Opm::WellProducer::ControlModeEnum whistctl_cmode = Opm::WellProducer::NONE;
if (deck.hasKeyword("WHISTCTL") ) {
const auto& whistctl_record = deck.getKeyword("WHISTCTL").getRecord(0);
const std::string& cmode_string = whistctl_record.getItem("CMODE").getTrimmedString(0);
whistctl_cmode = Opm::WellProducer::ControlModeFromString(cmode_string);
}
Opm::WellProductionProperties hist(record, false, prev_p, whistctl_cmode, false, false);
Opm::WellProductionProperties hist;
hist.handleWCONHIST(record);
return hist;
}
@ -823,9 +805,8 @@ namespace {
auto deck = parser.parseString(input);
const auto& kwd = deck.getKeyword("WCONPROD");
const auto& record = kwd.getRecord(0);
Opm::WellProducer::ControlModeEnum whistctl_cmode = Opm::WellProducer::NONE;
Opm::WellProductionProperties prev_properties;
Opm::WellProductionProperties pred( record, true, prev_properties, whistctl_cmode, false, false );
Opm::WellProductionProperties pred;
pred.handleWCONPROD(record);
return pred;
}
@ -847,8 +828,6 @@ BOOST_AUTO_TEST_CASE(WCH_All_Specified_BHP_Defaulted)
BOOST_CHECK_EQUAL(p.controlMode , Opm::WellProducer::ORAT);
BOOST_CHECK(p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 12);
BOOST_CHECK_EQUAL(p.ALQValue, 18.);
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
@ -865,8 +844,6 @@ BOOST_AUTO_TEST_CASE(WCH_ORAT_Defaulted_BHP_Defaulted)
BOOST_CHECK_EQUAL(p.controlMode , Opm::WellProducer::WRAT);
BOOST_CHECK(p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 12);
BOOST_CHECK_EQUAL(p.ALQValue, 18.);
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
@ -883,8 +860,6 @@ BOOST_AUTO_TEST_CASE(WCH_OWRAT_Defaulted_BHP_Defaulted)
BOOST_CHECK_EQUAL(p.controlMode , Opm::WellProducer::GRAT);
BOOST_CHECK(p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 12);
BOOST_CHECK_EQUAL(p.ALQValue, 18.);
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
@ -901,8 +876,6 @@ BOOST_AUTO_TEST_CASE(WCH_Rates_Defaulted_BHP_Defaulted)
BOOST_CHECK_EQUAL(p.controlMode , Opm::WellProducer::LRAT);
BOOST_CHECK(p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 12);
BOOST_CHECK_EQUAL(p.ALQValue, 18.);
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
@ -920,8 +893,6 @@ BOOST_AUTO_TEST_CASE(WCH_Rates_Defaulted_BHP_Specified)
BOOST_CHECK_EQUAL(p.controlMode , Opm::WellProducer::RESV);
BOOST_CHECK_EQUAL(true, p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 12);
BOOST_CHECK_EQUAL(p.ALQValue, 18.);
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
@ -944,27 +915,6 @@ BOOST_AUTO_TEST_CASE(WCH_Rates_NON_Defaulted_VFP)
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
BOOST_AUTO_TEST_CASE(WCH_Whistctl)
{
const Opm::WellProductionProperties& p =
WCONHIST::properties(WCONHIST::whistctl());
// the original RESV contorl in WCONHIST should be overwritten by
// ORAT specified with WHISCTL now.
BOOST_CHECK( p.hasProductionControl(Opm::WellProducer::ORAT));
BOOST_CHECK( !p.hasProductionControl(Opm::WellProducer::WRAT));
BOOST_CHECK( !p.hasProductionControl(Opm::WellProducer::GRAT));
BOOST_CHECK( !p.hasProductionControl(Opm::WellProducer::LRAT));
BOOST_CHECK( !p.hasProductionControl(Opm::WellProducer::RESV));
BOOST_CHECK_EQUAL(p.controlMode , Opm::WellProducer::ORAT);
BOOST_CHECK_EQUAL(true, p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 3);
BOOST_CHECK_EQUAL(p.ALQValue, 10.);
BOOST_CHECK_EQUAL(p.BHPLimit, 101325.);
}
BOOST_AUTO_TEST_CASE(WCH_BHP_Specified)
{
const Opm::WellProductionProperties& p =
@ -980,15 +930,12 @@ BOOST_AUTO_TEST_CASE(WCH_BHP_Specified)
BOOST_CHECK_EQUAL(true, p.hasProductionControl(Opm::WellProducer::BHP));
BOOST_CHECK_EQUAL(p.VFPTableNumber, 12);
BOOST_CHECK_EQUAL(p.ALQValue, 18.);
BOOST_CHECK_EQUAL(p.BHPLimit, 5.e7); // 500 barsa
}
BOOST_AUTO_TEST_CASE(WCONPROD_ORAT_CMode)
{
const Opm::WellProductionProperties& p =
WCONPROD::properties(WCONPROD::orat_CMODE_other_defaulted());
const Opm::WellProductionProperties& p = WCONPROD::properties(WCONPROD::orat_CMODE_other_defaulted());
BOOST_CHECK( p.hasProductionControl(Opm::WellProducer::ORAT));
BOOST_CHECK( p.hasProductionControl(Opm::WellProducer::WRAT));