Merge pull request #1712 from joakim-hove/group-control2

Separate flags for available_for_group_control for injectors and producers
This commit is contained in:
Atgeirr Flø Rasmussen 2020-04-17 16:40:23 +02:00 committed by GitHub
commit 4b1609b20a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 120 deletions

View File

@ -114,6 +114,7 @@ struct GroupInjectionProperties {
UDAValue target_void_fraction;
std::string reinj_group;
std::string voidage_group;
bool available_group_control;
static GroupInjectionProperties serializeObject();
@ -133,6 +134,7 @@ struct GroupInjectionProperties {
serializer(reinj_group);
serializer(voidage_group);
serializer(injection_controls);
serializer(available_group_control);
}
};
@ -159,7 +161,7 @@ struct GroupProductionProperties {
double guide_rate;
GuideRateTarget guide_rate_def;
double resv_target = 0;
bool available_group_control = true;
static GroupProductionProperties serializeObject();
int production_controls = 0;
@ -178,10 +180,12 @@ struct GroupProductionProperties {
serializer(guide_rate);
serializer(guide_rate_def);
serializer(resv_target);
serializer(available_group_control);
serializer(production_controls);
}
};
struct ProductionControls {
ProductionCMode cmode;
ExceedAction exceed_action;
@ -224,8 +228,6 @@ struct ProductionControls {
void setInjectionGroup();
double getGroupEfficiencyFactor() const;
bool getTransferGroupEfficiencyFactor() const;
bool isAvailableForGroupControl() const;
void setAvailableForGroupControl(const bool available);
std::size_t numWells() const;
bool addGroup(const std::string& group_name);
@ -249,6 +251,8 @@ struct ProductionControls {
Phase injection_phase() const;
bool has_control(ProductionCMode control) const;
bool has_control(InjectionCMode control) const;
bool productionGroupControlAvailable() const;
bool injectionGroupControlAvailable(const Phase phase) const;
bool operator==(const Group& data) const;
const Phase& topup_phase() const;
@ -265,7 +269,6 @@ struct ProductionControls {
serializer(group_type);
serializer(gefac);
serializer(transfer_gefac);
serializer(available_for_group_control);
serializer(vfp_table);
serializer(parent_group);
m_wells.serializeOp(serializer);
@ -287,7 +290,6 @@ private:
GroupType group_type;
double gefac;
bool transfer_gefac;
bool available_for_group_control;
int vfp_table;
std::string parent_group;

View File

@ -39,7 +39,6 @@ Group::Group(const std::string& name, std::size_t insert_index_arg, std::size_t
group_type(GroupType::NONE),
gefac(1),
transfer_gefac(true),
available_for_group_control(name == "FIELD" ? false : true),
vfp_table(0)
{
// All groups are initially created as children of the "FIELD" group.
@ -58,7 +57,6 @@ Group Group::serializeObject()
result.group_type = GroupType::PRODUCTION;
result.gefac = 4.0;
result.transfer_gefac = true;
result.available_for_group_control = false;
result.vfp_table = 5;
result.parent_group = "test2";
result.m_wells = {{"test3", "test4"}, {"test5", "test6"}};
@ -186,15 +184,16 @@ Group::GroupInjectionProperties Group::GroupInjectionProperties::serializeObject
bool Group::GroupInjectionProperties::operator==(const GroupInjectionProperties& other) const {
return
this->phase == other.phase &&
this->cmode == other.cmode &&
this->surface_max_rate == other.surface_max_rate &&
this->resv_max_rate == other.resv_max_rate &&
this->target_reinj_fraction == other.target_reinj_fraction &&
this->injection_controls == other.injection_controls &&
this->target_void_fraction == other.target_void_fraction &&
this->reinj_group == other.reinj_group &&
this->voidage_group == other.voidage_group;
this->phase == other.phase &&
this->cmode == other.cmode &&
this->surface_max_rate == other.surface_max_rate &&
this->resv_max_rate == other.resv_max_rate &&
this->target_reinj_fraction == other.target_reinj_fraction &&
this->injection_controls == other.injection_controls &&
this->target_void_fraction == other.target_void_fraction &&
this->reinj_group == other.reinj_group &&
this->available_group_control == other.available_group_control &&
this->voidage_group == other.voidage_group;
}
@ -223,18 +222,35 @@ Group::GroupProductionProperties Group::GroupProductionProperties::serializeObje
bool Group::GroupProductionProperties::operator==(const GroupProductionProperties& other) const {
return
this->cmode == other.cmode &&
this->exceed_action == other.exceed_action &&
this->oil_target == other.oil_target &&
this->water_target == other.water_target &&
this->gas_target == other.gas_target &&
this->liquid_target == other.liquid_target &&
this->guide_rate == other.guide_rate &&
this->guide_rate_def == other.guide_rate_def &&
this->production_controls == other.production_controls &&
this->resv_target == other.resv_target;
this->cmode == other.cmode &&
this->exceed_action == other.exceed_action &&
this->oil_target == other.oil_target &&
this->water_target == other.water_target &&
this->gas_target == other.gas_target &&
this->liquid_target == other.liquid_target &&
this->guide_rate == other.guide_rate &&
this->guide_rate_def == other.guide_rate_def &&
this->production_controls == other.production_controls &&
this->available_group_control == other.available_group_control &&
this->resv_target == other.resv_target;
}
bool Group::productionGroupControlAvailable() const {
if (this->m_name == "FIELD")
return false;
return this->production_properties.available_group_control;
}
bool Group::injectionGroupControlAvailable(const Phase phase) const {
if (this->m_name == "FIELD")
return false;
auto inj_iter = this->injection_properties.find(phase);
if (inj_iter == this->injection_properties.end())
return true;
return inj_iter->second.available_group_control;
}
bool Group::GroupProductionProperties::operator!=(const GroupProductionProperties& other) const {
return !(*this == other);
@ -348,14 +364,6 @@ bool Group::getTransferGroupEfficiencyFactor() const {
return this->transfer_gefac;
}
bool Group::isAvailableForGroupControl() const {
return this->available_for_group_control;
}
void Group::setAvailableForGroupControl(const bool available) {
this->available_for_group_control = available;
}
const std::string& Group::parent() const {
return this->parent_group;
}

View File

@ -1676,6 +1676,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
injection.injection_controls = 0;
injection.reinj_group = reinj_group;
injection.voidage_group = voidage_group;
injection.available_group_control = availableForGroupControl;
if (!record.getItem("SURFACE_TARGET").defaultApplied(0))
injection.injection_controls += static_cast<int>(Group::InjectionCMode::RATE);
@ -1689,9 +1690,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
if (!record.getItem("VOIDAGE_TARGET").defaultApplied(0))
injection.injection_controls += static_cast<int>(Group::InjectionCMode::VREP);
const bool must_update_avail = group_ptr->isAvailableForGroupControl() != availableForGroupControl;
if (group_ptr->updateInjection(injection) || must_update_avail) {
group_ptr->setAvailableForGroupControl(availableForGroupControl);
if (group_ptr->updateInjection(injection)) {
this->updateGroup(std::move(group_ptr), currentStep);
m_events.addEvent( ScheduleEvents::GROUP_INJECTION_UPDATE , currentStep);
this->addWellGroupEvent(group_name, ScheduleEvents::GROUP_INJECTION_UPDATE, currentStep);
@ -1750,6 +1749,8 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
production.guide_rate = guide_rate;
production.guide_rate_def = guide_rate_def;
production.resv_target = resv_target;
production.available_group_control = availableForGroupControl;
if ((production.cmode == Group::ProductionCMode::ORAT) ||
(production.cmode == Group::ProductionCMode::WRAT) ||
(production.cmode == Group::ProductionCMode::GRAT) ||
@ -1775,9 +1776,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
if (!record.getItem("RESERVOIR_FLUID_TARGET").defaultApplied(0))
production.production_controls += static_cast<int>(Group::ProductionCMode::RESV);
const bool must_update_avail = group_ptr->isAvailableForGroupControl() != availableForGroupControl;
if (group_ptr->updateProduction(production) || must_update_avail) {
group_ptr->setAvailableForGroupControl(availableForGroupControl);
if (group_ptr->updateProduction(production)) {
auto new_config = std::make_shared<GuideRateConfig>( this->guideRateConfig(currentStep) );
new_config->update_group(*group_ptr);
this->guide_rate_config.update( currentStep, std::move(new_config) );

View File

@ -45,6 +45,17 @@
using namespace Opm;
Opm::Schedule create_schedule(const std::string& deck_string) {
Opm::Parser parser;
auto python = std::make_shared<Python>();
auto deck = parser.parseString(deck_string);
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
return Opm::Schedule(deck, grid, fp, runspec, python);
}
BOOST_AUTO_TEST_CASE(CreateGroup_CorrectNameAndDefaultValues) {
Opm::Group group("G1" , 1, 0, 0, UnitSystem::newMETRIC());
@ -92,7 +103,6 @@ BOOST_AUTO_TEST_CASE(GroupDoesNotHaveWell) {
BOOST_AUTO_TEST_CASE(createDeckWithGEFAC) {
Opm::Parser parser;
std::string input =
"START -- 0 \n"
"19 JUN 2007 / \n"
@ -112,13 +122,7 @@ BOOST_AUTO_TEST_CASE(createDeckWithGEFAC) {
" 'PRODUC' 0.85 / \n"
"/\n";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
Runspec runspec (deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Opm::Schedule schedule(deck, grid, fp, runspec, python);
auto schedule = create_schedule(input);
auto group_names = schedule.groupNames("PRODUC");
BOOST_CHECK_EQUAL(group_names.size(), 1);
@ -136,8 +140,6 @@ BOOST_AUTO_TEST_CASE(createDeckWithWGRUPCONandWCONPROD) {
/* Test deck with well guide rates for group control:
GRUPCON (well guide rates for group control)
WCONPROD (conrol data for production wells) with GRUP control mode */
Opm::Parser parser;
std::string input =
"START -- 0 \n"
"19 JUN 2007 / \n"
@ -166,13 +168,7 @@ BOOST_AUTO_TEST_CASE(createDeckWithWGRUPCONandWCONPROD) {
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
Opm::Schedule schedule(deck, grid, fp, runspec, python);
auto schedule = create_schedule(input);
const auto& currentWell = schedule.getWell("B-37T2", 0);
const Opm::Well::WellProductionProperties& wellProductionProperties = currentWell.getProductionProperties();
BOOST_CHECK(wellProductionProperties.controlMode == Opm::Well::ProducerCMode::GRUP);
@ -181,8 +177,6 @@ BOOST_AUTO_TEST_CASE(createDeckWithWGRUPCONandWCONPROD) {
BOOST_CHECK_EQUAL(currentWell.getGuideRate(), 30);
BOOST_CHECK(currentWell.getGuideRatePhase() == Opm::Well::GuideRateTarget::OIL);
BOOST_CHECK_EQUAL(currentWell.getGuideRateScalingFactor(), 1.0);
}
@ -190,8 +184,7 @@ BOOST_AUTO_TEST_CASE(createDeckWithWGRUPCONandWCONPROD) {
BOOST_AUTO_TEST_CASE(createDeckWithGRUPNET) {
Opm::Parser parser;
std::string input =
std::string input =
"START -- 0 \n"
"31 AUG 1993 / \n"
"SCHEDULE\n"
@ -211,20 +204,15 @@ BOOST_AUTO_TEST_CASE(createDeckWithGRUPNET) {
" 'MANI-E2' 1* 9 4* / \n"
"/\n";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
Opm::Schedule schedule(deck, grid, fp, runspec, python);
const auto& group1 = schedule.getGroup("PROD", 0);
const auto& group2 = schedule.getGroup("MANI-E2", 0);
const auto& group3 = schedule.getGroup("MANI-K1", 0);
BOOST_CHECK_EQUAL(group1.getGroupNetVFPTable(), 0);
BOOST_CHECK_EQUAL(group2.getGroupNetVFPTable(), 9);
BOOST_CHECK_EQUAL(group3.getGroupNetVFPTable(), 9999);
auto schedule = create_schedule(input);
const auto& group1 = schedule.getGroup("PROD", 0);
const auto& group2 = schedule.getGroup("MANI-E2", 0);
const auto& group3 = schedule.getGroup("MANI-K1", 0);
BOOST_CHECK_EQUAL(group1.getGroupNetVFPTable(), 0);
BOOST_CHECK_EQUAL(group2.getGroupNetVFPTable(), 9);
BOOST_CHECK_EQUAL(group3.getGroupNetVFPTable(), 9999);
}
@ -254,7 +242,6 @@ BOOST_AUTO_TEST_CASE(GroupCreate) {
}
BOOST_AUTO_TEST_CASE(createDeckWithGCONPROD) {
Opm::Parser parser;
std::string input = R"(
START -- 0
31 AUG 1993 /
@ -270,13 +257,7 @@ BOOST_AUTO_TEST_CASE(createDeckWithGCONPROD) {
'G2' 'RESV' 10000 3* 'CON' /
/)";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
Opm::Schedule schedule(deck, grid, fp, runspec, python);
auto schedule = create_schedule(input);
SummaryState st(std::chrono::system_clock::now());
const auto& group1 = schedule.getGroup("G1", 0);
@ -300,7 +281,6 @@ BOOST_AUTO_TEST_CASE(TESTGuideRateModel) {
}
BOOST_AUTO_TEST_CASE(TESTGuideRateLINCOM) {
Parser parser;
std::string input = R"(
START -- 0
31 AUG 1993 /
@ -324,19 +304,12 @@ BOOST_AUTO_TEST_CASE(TESTGuideRateLINCOM) {
)";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
/* The 'COMB' target mode is not supported */
BOOST_CHECK_THROW(Opm::Schedule schedule(deck, grid, fp, runspec, python), std::logic_error);
BOOST_CHECK_THROW(create_schedule(input), std::logic_error);
}
BOOST_AUTO_TEST_CASE(TESTGuideRate) {
Parser parser;
std::string input = R"(
START -- 0
31 AUG 1993 /
@ -362,19 +335,11 @@ BOOST_AUTO_TEST_CASE(TESTGuideRate) {
1 1 1 1 1 1 1 1 1 1 1 /
)";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
Schedule schedule(deck, grid, fp, runspec, python);
auto schedule = create_schedule(input);
GuideRate gr(schedule);
}
BOOST_AUTO_TEST_CASE(TESTGCONSALE) {
Parser parser;
std::string input = R"(
START -- 0
31 AUG 1993 /
@ -396,14 +361,7 @@ BOOST_AUTO_TEST_CASE(TESTGCONSALE) {
)";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck, Phases{true, true, true}, grid, table);
Runspec runspec (deck );
Schedule schedule(deck, grid, fp, runspec, python);
auto schedule = create_schedule(input);
double metric_to_si = 1.0 / (24.0 * 3600.0); //cubic meters / day
const auto& gconsale = schedule.gConSale(0);
@ -438,7 +396,6 @@ BOOST_AUTO_TEST_CASE(TESTGCONSALE) {
}
BOOST_AUTO_TEST_CASE(GCONINJE_MULTIPLE_PHASES) {
Parser parser;
std::string input = R"(
START -- 0
31 AUG 1993 /
@ -466,13 +423,7 @@ BOOST_AUTO_TEST_CASE(GCONINJE_MULTIPLE_PHASES) {
)";
auto deck = parser.parseString(input);
auto python = std::make_shared<Python>();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
FieldPropsManager fp( deck , Phases{true, true, true}, grid, table);
Runspec runspec (deck );
Schedule schedule(deck, grid, fp, runspec, python);
auto schedule = create_schedule(input);
SummaryState st(std::chrono::system_clock::now());
// Step 0
{
@ -480,7 +431,10 @@ BOOST_AUTO_TEST_CASE(GCONINJE_MULTIPLE_PHASES) {
BOOST_CHECK( g1.hasInjectionControl(Phase::WATER));
BOOST_CHECK( g1.hasInjectionControl(Phase::GAS));
BOOST_CHECK( !g1.hasInjectionControl(Phase::OIL));
BOOST_CHECK( g1.isAvailableForGroupControl() );
BOOST_CHECK( g1.injectionGroupControlAvailable(Phase::WATER) );
BOOST_CHECK( g1.injectionGroupControlAvailable(Phase::GAS) );
BOOST_CHECK( g1.productionGroupControlAvailable() );
g1.injectionControls(Phase::WATER, st);
g1.injectionControls(Phase::GAS, st);
@ -493,7 +447,7 @@ BOOST_AUTO_TEST_CASE(GCONINJE_MULTIPLE_PHASES) {
const auto& g2 = schedule.getGroup("G2", 0);
BOOST_CHECK(!g2.has_topup_phase());
BOOST_CHECK_THROW(g2.topup_phase(), std::logic_error);
BOOST_CHECK( g2.isAvailableForGroupControl() );
BOOST_CHECK( g2.injectionGroupControlAvailable(Phase::WATER) );
}
// Step 1
{
@ -501,7 +455,7 @@ BOOST_AUTO_TEST_CASE(GCONINJE_MULTIPLE_PHASES) {
BOOST_CHECK( g2.hasInjectionControl(Phase::WATER));
BOOST_CHECK( g2.hasInjectionControl(Phase::GAS));
BOOST_CHECK( !g2.hasInjectionControl(Phase::OIL));
BOOST_CHECK( !g2.isAvailableForGroupControl() );
BOOST_CHECK( !g2.injectionGroupControlAvailable(Phase::GAS) );
g2.injectionControls(Phase::WATER, st);
g2.injectionControls(Phase::GAS, st);
@ -514,6 +468,72 @@ BOOST_AUTO_TEST_CASE(GCONINJE_MULTIPLE_PHASES) {
const auto& g1 = schedule.getGroup("G1", 1);
BOOST_CHECK(!g1.has_topup_phase());
BOOST_CHECK_THROW(g1.topup_phase(), std::logic_error);
BOOST_CHECK( g1.isAvailableForGroupControl() );
}
}
BOOST_AUTO_TEST_CASE(GCONINJE_GCONPROD) {
std::string input = R"(
START -- 0
31 AUG 1993 /
SCHEDULE
GRUPTREE
'G1' 'FIELD' /
'G2' 'FIELD' /
/
GCONPROD
'G1' 'ORAT' 10000 3* 'CON' 'NO'/
'G2' 'ORAT' 10000 3* 'CON' /
/
GCONINJE
'G1' 'WATER' 1* 1000 /
'G2' 'WATER' 1* 1* 2000 1* 1* 'NO'/
/
TSTEP
1 /
GCONPROD
'G1' 'ORAT' 10000 3* 'CON' /
'G2' 'ORAT' 10000 3* 'CON' 'NO'/
/
GCONINJE
'G1' 'WATER' 1* 1000 3* 'NO' /
'G2' 'WATER' 1* 1* 2000 /
/
)";
auto schedule = create_schedule(input);
{
const auto& f = schedule.getGroup("FIELD", 0);
const auto& g1 = schedule.getGroup("G1", 0);
const auto& g2 = schedule.getGroup("G2", 0);
BOOST_CHECK(!f.productionGroupControlAvailable() );
BOOST_CHECK(!f.injectionGroupControlAvailable(Phase::WATER));
BOOST_CHECK(!f.injectionGroupControlAvailable(Phase::GAS));
BOOST_CHECK(!g1.productionGroupControlAvailable() );
BOOST_CHECK( g2.productionGroupControlAvailable() );
BOOST_CHECK( g1.injectionGroupControlAvailable(Phase::WATER));
BOOST_CHECK(!g2.injectionGroupControlAvailable(Phase::WATER));
BOOST_CHECK( g1.injectionGroupControlAvailable(Phase::GAS));
BOOST_CHECK( g2.injectionGroupControlAvailable(Phase::GAS));
}
{
const auto& g1 = schedule.getGroup("G1", 1);
const auto& g2 = schedule.getGroup("G2", 1);
BOOST_CHECK( g1.productionGroupControlAvailable() );
BOOST_CHECK(!g2.productionGroupControlAvailable() );
BOOST_CHECK(!g1.injectionGroupControlAvailable(Phase::WATER));
BOOST_CHECK( g2.injectionGroupControlAvailable(Phase::WATER));
BOOST_CHECK( g1.injectionGroupControlAvailable(Phase::GAS));
BOOST_CHECK( g2.injectionGroupControlAvailable(Phase::GAS));
}
}