Initialize Group2 structure during Schedule construction

This commit is contained in:
Joakim Hove
2019-07-24 08:38:39 +02:00
parent 8a52da5851
commit 12294cb637
7 changed files with 415 additions and 56 deletions

View File

@@ -23,15 +23,87 @@
#include <string>
#include <opm/parser/eclipse/EclipseState/Util/IOrderSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
namespace Opm {
class Group2 {
public:
explicit Group2(const std::string& group_name);
struct GroupInjectionProperties {
Phase phase = Phase::WATER;
GroupInjection::ControlEnum cmode = GroupInjection::NONE;
double surface_max_rate = 0;
double resv_max_rate = 0;
double target_reinj_fraction = 0;
double target_void_fraction = 0;
bool operator==(const GroupInjectionProperties& other) const;
bool operator!=(const GroupInjectionProperties& other) const;
};
struct GroupProductionProperties {
GroupProduction::ControlEnum cmode = GroupProduction::NONE;
GroupProductionExceedLimit::ActionEnum exceed_action = GroupProductionExceedLimit::NONE;
double oil_target = 0;
double water_target = 0;
double gas_target = 0;
double liquid_target = 0;
double resv_target = 0;
bool operator==(const GroupProductionProperties& other) const;
bool operator!=(const GroupProductionProperties& other) const;
};
Group2(const std::string& group_name, std::size_t insert_index_arg, std::size_t init_step_arg);
bool defined(std::size_t timeStep) const;
std::size_t insert_index() const;
const std::string& name() const;
const GroupProductionProperties& productionProperties() const;
const GroupInjectionProperties& injectionProperties() const;
int getGroupNetVFPTable() const;
bool updateNetVFPTable(int vfp_arg);
bool update_gefac(double gefac, bool transfer_gefac);
bool updateInjection(const GroupInjectionProperties& injection);
bool updateProduction(const GroupProductionProperties& production);
bool isProductionGroup() const;
bool isInjectionGroup() const;
void setProductionGroup();
void setInjectionGroup();
double getGroupEfficiencyFactor() const;
bool getTransferGroupEfficiencyFactor() const;
std::size_t numWells() const;
bool addGroup(const std::string& group_name);
bool hasGroup(const std::string& group_name) const;
void delGroup(const std::string& group_name);
bool addWell(const std::string& well_name);
bool hasWell(const std::string& well_name) const;
void delWell(const std::string& well_name);
const std::vector<std::string>& wells() const;
const std::vector<std::string>& groups() const;
private:
std::string name;
bool hasType(GroupType gtype) const;
void addType(GroupType new_gtype);
std::string m_name;
std::size_t m_insert_index;
std::size_t init_step;
GroupType group_type;
double gefac;
bool transfer_gefac;
int vfp_table;
IOrderSet<std::string> m_wells;
IOrderSet<std::string> m_groups;
GroupInjectionProperties injection_properties;
GroupProductionProperties production_properties;
};
}

View File

@@ -29,6 +29,7 @@
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicVector.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GroupTree.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
@@ -148,6 +149,8 @@ namespace Opm
bool hasGroup(const std::string& groupName) const;
const Group& getGroup(const std::string& groupName) const;
Group& getGroup(const std::string& groupName);
const Group2& getGroup2(const std::string& groupName, size_t timeStep) const;
const Tuning& getTuning() const;
const MessageLimits& getMessageLimits() const;
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword) const;
@@ -174,6 +177,7 @@ namespace Opm
TimeMap m_timeMap;
OrderedMap< std::string, Group > m_groups;
OrderedMap< std::string, DynamicState<std::shared_ptr<Well2>>> wells_static;
OrderedMap< std::string, DynamicState<std::shared_ptr<Group2>>> groups;
DynamicState< GroupTree > m_rootGroupTree;
DynamicState< OilVaporizationProperties > m_oilvaporizationproperties;
Events m_events;
@@ -194,6 +198,8 @@ namespace Opm
std::vector< Group* > getGroups(const std::string& groupNamePattern);
std::map<std::string,Events> well_events;
void updateGroup(std::shared_ptr<Group2> group, size_t reportStep);
bool checkGroups(const ParseContext& parseContext, ErrorGuard& errors);
bool updateWellStatus( const std::string& well, size_t reportStep , WellCommon::StatusEnum status);
void addWellToGroup( Group& newGroup , const std::string& wellName , size_t timeStep);
void iterateScheduleSection(const ParseContext& parseContext , ErrorGuard& errors, const SCHEDULESection& , const EclipseGrid& grid,

View File

@@ -25,7 +25,7 @@
#include <stdexcept>
#include <string>
#include <unordered_set>
#include <list>
#include <vector>
namespace Opm {

View File

@@ -22,9 +22,219 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
namespace Opm {
Group2::Group2(const std::string& group_name) :
name(group_name)
Group2::Group2(const std::string& name, std::size_t insert_index_arg, std::size_t init_step_arg) :
m_name(name),
m_insert_index(insert_index_arg),
init_step(init_step_arg),
group_type(GroupType::NONE),
gefac(1),
transfer_gefac(true),
vfp_table(0)
{}
std::size_t Group2::insert_index() const {
return this->m_insert_index;
}
bool Group2::defined(size_t timeStep) const {
if (timeStep < this->init_step)
return false;
else
return true;
}
const std::string& Group2::name() const {
return this->m_name;
}
const Group2::GroupProductionProperties& Group2::productionProperties() const {
return this->production_properties;
}
const Group2::GroupInjectionProperties& Group2::injectionProperties() const {
return this->injection_properties;
}
int Group2::getGroupNetVFPTable() const {
return this->vfp_table;
}
bool Group2::updateNetVFPTable(int vfp_arg) {
if (this->vfp_table != vfp_arg) {
this->vfp_table = vfp_arg;
return true;
} else
return false;
}
bool Group2::updateInjection(const GroupInjectionProperties& injection) {
bool update = false;
if (this->injection_properties != injection) {
this->injection_properties = injection;
update = true;
}
if (!this->hasType(GroupType::INJECTION)) {
this->addType(GroupType::INJECTION);
update = true;
}
return update;
}
bool Group2::updateProduction(const GroupProductionProperties& production) {
bool update = false;
if (this->production_properties != production) {
this->production_properties = production;
update = true;
}
if (!this->hasType(GroupType::PRODUCTION)) {
this->addType(GroupType::PRODUCTION);
update = true;
}
return update;
}
bool Group2::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->target_void_fraction == other.target_void_fraction;
}
bool Group2::GroupInjectionProperties::operator!=(const GroupInjectionProperties& other) const {
return !(*this == other);
}
bool Group2::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.oil_target &&
this->gas_target == other.gas_target &&
this->liquid_target == other.liquid_target &&
this->resv_target == other.resv_target;
}
bool Group2::GroupProductionProperties::operator!=(const GroupProductionProperties& other) const {
return !(*this == other);
}
bool Group2::hasType(GroupType gtype) const {
return ((this->group_type & gtype) == gtype);
}
void Group2::addType(GroupType new_gtype) {
this->group_type = this->group_type | new_gtype;
}
bool Group2::isProductionGroup() const {
return this->hasType(GroupType::PRODUCTION);
}
bool Group2::isInjectionGroup() const {
return this->hasType(GroupType::INJECTION);
}
void Group2::setProductionGroup() {
this->addType(GroupType::PRODUCTION);
}
void Group2::setInjectionGroup() {
this->addType(GroupType::INJECTION);
}
std::size_t Group2::numWells() const {
return this->m_wells.size();
}
const std::vector<std::string>& Group2::wells() const {
return this->m_wells.data();
}
const std::vector<std::string>& Group2::groups() const {
return this->m_groups.data();
}
bool Group2::addWell(const std::string& well_name) {
if (!this->m_groups.empty())
throw std::logic_error("Groups can not mix group and well children");
if (this->m_wells.count(well_name) == 0) {
this->m_wells.insert(well_name);
return true;
}
return false;
}
bool Group2::hasWell(const std::string& well_name) const {
return (this->m_wells.count(well_name) == 1);
}
void Group2::delWell(const std::string& well_name) {
auto rm_count = this->m_wells.erase(well_name);
if (rm_count == 0)
throw std::invalid_argument("Group does not have well: " + well_name);
}
bool Group2::addGroup(const std::string& group_name) {
if (!this->m_wells.empty())
throw std::logic_error("Groups can not mix group and well children");
if (this->m_groups.count(group_name) == 0) {
this->m_groups.insert(group_name);
return true;
}
return false;
}
bool Group2::hasGroup(const std::string& group_name) const {
return (this->m_groups.count(group_name) == 1);
}
void Group2::delGroup(const std::string& group_name) {
auto rm_count = this->m_groups.erase(group_name);
if (rm_count == 0)
throw std::invalid_argument("Group does not have group: " + group_name);
}
bool Group2::update_gefac(double gf, bool transfer_gf) {
bool update = false;
if (this->gefac != gf) {
this->gefac = gf;
update = true;
}
if (this->transfer_gefac != transfer_gf) {
this->transfer_gefac = transfer_gf;
update = true;
}
return update;
}
double Group2::getGroupEfficiencyFactor() const {
return this->gefac;
}
bool Group2::getTransferGroupEfficiencyFactor() const {
return this->transfer_gefac;
}
}

View File

@@ -1418,28 +1418,37 @@ namespace {
invalidNamePattern(groupNamePattern, parseContext, errors, keyword);
for (const auto& group_name : group_names){
auto& group = this->getGroup(group_name);
{
Phase phase = get_phase( record.getItem("PHASE").getTrimmedString(0) );
group.setInjectionPhase( currentStep , phase );
}
{
GroupInjection::ControlEnum controlMode = GroupInjection::ControlEnumFromString( record.getItem("CONTROL_MODE").getTrimmedString(0) );
group.setInjectionControlMode( currentStep , controlMode );
}
Phase wellPhase = get_phase( record.getItem("PHASE").getTrimmedString(0));
GroupInjection::ControlEnum controlMode = GroupInjection::ControlEnumFromString( record.getItem("CONTROL_MODE").getTrimmedString(0) );
Phase phase = get_phase( record.getItem("PHASE").getTrimmedString(0));
double surfaceInjectionRate = record.getItem("SURFACE_TARGET").get< UDAValue >(0).get<double>();
surfaceInjectionRate = injection::rateToSI(surfaceInjectionRate, wellPhase, section.unitSystem());
double reservoirInjectionRate = record.getItem("RESV_TARGET").get<UDAValue>(0).get<double>();
double reinj_target = record.getItem("REINJ_TARGET").get<UDAValue>(0).get<double>();
double voidage_target = record.getItem("VOIDAGE_TARGET").get<UDAValue>(0).get<double>();
group.setSurfaceMaxRate( currentStep , surfaceInjectionRate);
group.setReservoirMaxRate( currentStep , reservoirInjectionRate);
group.setTargetReinjectFraction( currentStep , record.getItem("REINJ_TARGET").get<UDAValue>(0).get<double>());
group.setTargetVoidReplacementFraction( currentStep , record.getItem("VOIDAGE_TARGET").get<UDAValue>(0).get<double>());
surfaceInjectionRate = injection::rateToSI(surfaceInjectionRate, phase, section.unitSystem());
{
auto& group = this->getGroup(group_name);
group.setInjectionPhase( currentStep , phase );
group.setInjectionControlMode( currentStep , controlMode );
group.setSurfaceMaxRate( currentStep, surfaceInjectionRate);
group.setReservoirMaxRate( currentStep, reservoirInjectionRate);
group.setTargetReinjectFraction( currentStep, reinj_target);
group.setTargetVoidReplacementFraction( currentStep, voidage_target);
group.setInjectionGroup(currentStep);
}
{
auto group_ptr = std::make_shared<Group2>(this->getGroup2(group_name, currentStep));
Group2::GroupInjectionProperties injection;
injection.phase = phase;
injection.cmode = controlMode;
injection.surface_max_rate = surfaceInjectionRate;
injection.resv_max_rate = reservoirInjectionRate;
injection.target_reinj_fraction = reinj_target;
injection.target_void_fraction = voidage_target;
group.setInjectionGroup(currentStep);
if (group_ptr->updateInjection(injection))
this->updateGroup(group_ptr, currentStep);
}
}
}
}
@@ -1453,22 +1462,39 @@ namespace {
invalidNamePattern(groupNamePattern, parseContext, errors, keyword);
for (const auto& group_name : group_names){
auto& group = this->getGroup(group_name);
{
GroupProduction::ControlEnum controlMode = GroupProduction::ControlEnumFromString( record.getItem("CONTROL_MODE").getTrimmedString(0) );
group.setProductionControlMode( currentStep , controlMode );
}
group.setOilTargetRate( currentStep , record.getItem("OIL_TARGET").get<UDAValue>(0).get<double>());
group.setGasTargetRate( currentStep , record.getItem("GAS_TARGET").get<UDAValue>(0).get<double>());
group.setWaterTargetRate( currentStep , record.getItem("WATER_TARGET").get<UDAValue>(0).get<double>());
group.setLiquidTargetRate( currentStep , record.getItem("LIQUID_TARGET").get<UDAValue>(0).get<double>());
group.setReservoirVolumeTargetRate( currentStep , record.getItem("RESERVOIR_FLUID_TARGET").getSIDouble(0));
{
GroupProductionExceedLimit::ActionEnum exceedAction = GroupProductionExceedLimit::ActionEnumFromString(record.getItem("EXCEED_PROC").getTrimmedString(0) );
group.setProductionExceedLimitAction( currentStep , exceedAction );
}
GroupProduction::ControlEnum controlMode = GroupProduction::ControlEnumFromString( record.getItem("CONTROL_MODE").getTrimmedString(0) );
GroupProductionExceedLimit::ActionEnum exceedAction = GroupProductionExceedLimit::ActionEnumFromString(record.getItem("EXCEED_PROC").getTrimmedString(0) );
auto oil_target = record.getItem("OIL_TARGET").get<UDAValue>(0).get<double>();
auto gas_target = record.getItem("GAS_TARGET").get<UDAValue>(0).get<double>();
auto water_target = record.getItem("WATER_TARGET").get<UDAValue>(0).get<double>();
auto liquid_target = record.getItem("LIQUID_TARGET").get<UDAValue>(0).get<double>();
auto resv_target = record.getItem("RESERVOIR_FLUID_TARGET").getSIDouble(0);
group.setProductionGroup(currentStep);
{
auto& group = this->getGroup(group_name);
group.setProductionControlMode( currentStep , controlMode );
group.setOilTargetRate( currentStep , oil_target);
group.setGasTargetRate( currentStep , gas_target);
group.setWaterTargetRate( currentStep , water_target);
group.setLiquidTargetRate( currentStep , liquid_target);
group.setReservoirVolumeTargetRate( currentStep , resv_target);
group.setProductionExceedLimitAction( currentStep , exceedAction );
group.setProductionGroup(currentStep);
}
{
auto group_ptr = std::make_shared<Group2>(this->getGroup2(group_name, currentStep));
Group2::GroupProductionProperties production;
production.cmode = controlMode;
production.oil_target = oil_target;
production.gas_target = gas_target;
production.water_target = water_target;
production.liquid_target = liquid_target;
production.resv_target = resv_target;
production.exceed_action = exceedAction;
if (group_ptr->updateProduction(production))
this->updateGroup(group_ptr, currentStep);
}
}
}
}
@@ -1483,12 +1509,19 @@ namespace {
invalidNamePattern(groupNamePattern, parseContext, errors, keyword);
for (const auto& group_name : group_names){
auto& group = this->getGroup(group_name);
const std::string& transfer_str = record.getItem("TRANSFER_EXT_NET").getTrimmedString(0);
bool transfer = (transfer_str == "YES") ? true : false;
bool transfer = DeckItem::to_bool(record.getItem("TRANSFER_EXT_NET").getTrimmedString(0));
auto gefac = record.getItem("EFFICIENCY_FACTOR").get< double >(0);
{
auto& group = this->getGroup(group_name);
group.setGroupEfficiencyFactor(currentStep, record.getItem("EFFICIENCY_FACTOR").get< double >(0));
group.setTransferGroupEfficiencyFactor(currentStep, transfer);
group.setGroupEfficiencyFactor(currentStep, gefac);
group.setTransferGroupEfficiencyFactor(currentStep, transfer);
}
{
auto group_ptr = std::make_shared<Group2>(this->getGroup2(group_name, currentStep));
if (group_ptr->update_gefac(gefac, transfer))
this->updateGroup(group_ptr, currentStep);
}
}
}
}
@@ -1770,6 +1803,7 @@ namespace {
m_rootGroupTree.update(currentStep, newTree);
}
void Schedule::handleGRUPNET( const DeckKeyword& keyword, size_t currentStep) {
for( const auto& record : keyword ) {
const auto& groupName = record.getItem("NAME").getTrimmedString(0);
@@ -1777,9 +1811,16 @@ namespace {
if (!hasGroup(groupName))
addGroup(groupName , currentStep);
auto& group = this->m_groups.at( groupName );
int table = record.getItem("VFP_TABLE").get< int >(0);
group.setGroupNetVFPTable(currentStep, table);
{
auto& group = this->m_groups.at( groupName );
group.setGroupNetVFPTable(currentStep, table);
}
{
auto group_ptr = std::make_shared<Group2>( this->getGroup2(groupName, currentStep) );
if (group_ptr->updateNetVFPTable(table))
this->updateGroup(group_ptr, currentStep);
}
}
}
@@ -2006,6 +2047,22 @@ namespace {
return *well_ptr;
}
const Group2& Schedule::getGroup2(const std::string& groupName, size_t timeStep) const {
if (this->groups.count(groupName) == 0)
throw std::invalid_argument("No such group: " + groupName);
const auto& dynamic_state = this->groups.at(groupName);
auto& group_ptr = dynamic_state.get(timeStep);
if (!group_ptr)
throw std::invalid_argument("Group: " + groupName + " not yet defined at step: " + std::to_string(timeStep));
return *group_ptr;
}
void Schedule::updateGroup(std::shared_ptr<Group2> group, size_t reportStep) {
auto& dynamic_state = this->groups.at(group->name());
dynamic_state.update(reportStep, group);
}
/*
There are many SCHEDULE keyword which take a wellname as argument. In
@@ -2158,7 +2215,15 @@ namespace {
void Schedule::addGroup(const std::string& groupName, size_t timeStep) {
const size_t gseqIndex = m_groups.size();
// Old group
m_groups.insert( std::make_pair( groupName, Group { groupName, gseqIndex, m_timeMap, timeStep } ));
// New group
groups.insert( std::make_pair( groupName, DynamicState<std::shared_ptr<Group2>>(this->m_timeMap, nullptr)));
auto group_ptr = std::make_shared<Group2>(groupName, gseqIndex, timeStep);
auto& dynamic_state = this->groups.at(groupName);
dynamic_state.update(timeStep, group_ptr);
m_events.addEvent( ScheduleEvents::NEW_GROUP , timeStep );
}

View File

@@ -82,15 +82,6 @@ BOOST_AUTO_TEST_CASE(CreateGroup_SetInjectorProducer_CorrectStatusSet) {
group2.setProductionGroup(3);
BOOST_CHECK(group2.isProductionGroup(4));
group2.setInjectionGroup(4);
BOOST_CHECK(group2.isInjectionGroup(5));
// Testing that a group can be both; that seems slightly dubious - but was the old behavior
group2.setProductionGroup(4);
BOOST_CHECK(group2.isProductionGroup(5));
BOOST_CHECK(group2.isInjectionGroup(5));
}
@@ -435,5 +426,18 @@ BOOST_AUTO_TEST_CASE(createDeckWithGRUPNET) {
BOOST_AUTO_TEST_CASE(Group2Create) {
Opm::Group2 group("NAME");
Opm::Group2 g1("NAME", 1, 1);
Opm::Group2 g2("NAME", 1, 1);
BOOST_CHECK( g1.addWell("W1") );
BOOST_CHECK( !g1.addWell("W1") );
BOOST_CHECK( g1.addWell("W2") );
BOOST_CHECK( g2.addGroup("G1") );
BOOST_CHECK( !g2.addGroup("G1") );
BOOST_CHECK( g2.addGroup("G2") );
// The children must be either all wells - or all groups.
BOOST_CHECK_THROW(g1.addGroup("G1"), std::logic_error);
BOOST_CHECK_THROW(g2.addWell("W1"), std::logic_error);
}

View File

@@ -137,6 +137,8 @@ BOOST_AUTO_TEST_CASE(test_IOrderSet) {
Opm::IOrderSet<int> iset2;
for (int i=10; i >= 0; i--)
iset2.insert(i);