Merge pull request #1797 from joakim-hove/GPMAINT

Add code to internalize GPMAINT keyword in Group objects
This commit is contained in:
Joakim Hove
2020-06-12 12:19:20 +02:00
committed by GitHub
9 changed files with 287 additions and 2 deletions

View File

@@ -99,6 +99,7 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GPMaint.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/Group.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.cpp
@@ -701,6 +702,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp
opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.hpp
opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GPMaint.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.hpp

View File

@@ -0,0 +1,75 @@
/*
Copyright 2020 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GPMAINT_HPP
#define GPMAINT_HPP
#include <optional>
#include <string>
namespace Opm {
class DeckRecord;
class GPMaint {
public:
enum class FlowTarget {
RESV_PROD = 0,
RESV_OINJ = 1,
RESV_WINJ = 2,
RESV_GINJ = 3,
SURF_OINJ = 4,
SURF_WINJ = 5,
SURF_GINJ = 6,
};
GPMaint() = default;
explicit GPMaint(const DeckRecord& record);
static GPMaint serializeObject();
double pressure_target() const;
double prop_constant() const;
double time_constant() const;
std::optional<std::pair<std::string, int>> region() const;
FlowTarget flow_target() const;
bool operator==(const GPMaint& other) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializeOp(m_flow_target);
serializeOp(m_region_number);
serializeOp(m_region_name);
serializeOp(m_pressure_target);
serializeOp(m_prop_constant);
serializeOp(m_time_constant);
}
private:
static FlowTarget FlowTargetFromString(const std::string& stringvalue);
FlowTarget m_flow_target;
int m_region_number;
std::string m_region_name;
double m_pressure_target;
double m_prop_constant;
double m_time_constant;
};
}
#endif

View File

@@ -28,6 +28,7 @@
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
#include <opm/parser/eclipse/EclipseState/Util/IOrderSet.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GPMaint.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
namespace Opm {
@@ -263,6 +264,9 @@ struct ProductionControls {
bool has_control(InjectionCMode control) const;
bool productionGroupControlAvailable() const;
bool injectionGroupControlAvailable(const Phase phase) const;
const std::optional<GPMaint>& gpmaint() const;
void set_gpmaint(GPMaint gpmaint);
void set_gpmaint();
bool operator==(const Group& data) const;
const Phase& topup_phase() const;
@@ -286,6 +290,7 @@ struct ProductionControls {
serializer.map(injection_properties);
production_properties.serializeOp(serializer);
serializer(m_topup_phase);
serializer(m_gpmaint);
}
private:
@@ -309,6 +314,7 @@ private:
std::map<Phase, GroupInjectionProperties> injection_properties;
GroupProductionProperties production_properties;
std::pair<Phase, bool> m_topup_phase{Phase::WATER, false};
std::optional<GPMaint> m_gpmaint;
};
Group::GroupType operator |(Group::GroupType lhs, Group::GroupType rhs);

View File

@@ -438,6 +438,7 @@ namespace Opm
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
void handlePYACTION( std::shared_ptr<const Python> python, const std::string& input_path, const DeckKeyword& keyword, size_t currentStep);
void handleNUPCOL( const DeckKeyword& keyword, size_t currentStep);
void handleGPMAINT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors);
void handleGRUPNET( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system);
void handleWRFT( const DeckKeyword& keyword, size_t currentStep);

View File

@@ -0,0 +1,101 @@
/*
Copyright 2020 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GPMaint.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/G.hpp>
namespace Opm {
GPMaint::GPMaint(const DeckRecord& record)
{
using GP = ParserKeywords::GPMAINT;
this->m_flow_target = FlowTargetFromString( record.getItem<GP::FLOW_TARGET>().get<std::string>(0) );
this->m_region_number = record.getItem<GP::REGION>().get<int>(0);
this->m_region_name = record.getItem<GP::FIP_FAMILY>().get<std::string>(0);
this->m_pressure_target = record.getItem<GP::PRESSURE_TARGET>().getSIDouble(0);
this->m_prop_constant = record.getItem<GP::PROP_CONSTANT>().getSIDouble(0);
this->m_time_constant = record.getItem<GP::TIME_CONSTANT>().getSIDouble(0);
}
GPMaint::FlowTarget GPMaint::flow_target() const {
return this->m_flow_target;
}
double GPMaint::pressure_target() const {
return this->m_pressure_target;
}
double GPMaint::prop_constant() const {
return this->m_prop_constant;
}
double GPMaint::time_constant() const {
return this->m_time_constant;
}
GPMaint GPMaint::serializeObject() {
GPMaint gpm;
gpm.m_flow_target = FlowTarget::SURF_GINJ;
gpm.m_region_name = "FIPNUM";
gpm.m_region_number = 26;
return gpm;
}
std::optional<std::pair<std::string, int>> GPMaint::region() const {
if (this->m_region_number == 0)
return {};
return std::make_pair(this->m_region_name, this->m_region_number);
}
GPMaint::FlowTarget GPMaint::FlowTargetFromString(const std::string& string_value) {
if (string_value == "PROD")
return GPMaint::FlowTarget::RESV_PROD;
if (string_value == "OINJ")
return GPMaint::FlowTarget::RESV_OINJ;
if (string_value == "WINJ")
return GPMaint::FlowTarget::RESV_WINJ;
if (string_value == "GINJ")
return GPMaint::FlowTarget::RESV_GINJ;
if (string_value == "OINS")
return GPMaint::FlowTarget::SURF_OINJ;
if (string_value == "WINS")
return GPMaint::FlowTarget::SURF_WINJ;
if (string_value == "GINS")
return GPMaint::FlowTarget::SURF_GINJ;
throw std::invalid_argument("The string: " + string_value + " could not be converted to a valid FLOW target");
}
bool GPMaint::operator==(const GPMaint& other) const {
return this->m_flow_target == other.m_flow_target &&
this->m_region_name == other.m_region_name &&
this->m_region_number == other.m_region_number;
}
}

View File

@@ -486,6 +486,18 @@ bool Group::has_control(Group::ProductionCMode control) const {
return detail::has_control(production_properties.production_controls, control);
}
const std::optional<GPMaint>& Group::gpmaint() const {
return this->m_gpmaint;
}
void Group::set_gpmaint(GPMaint gpmaint) {
this->m_gpmaint = std::move(gpmaint);
}
void Group::set_gpmaint() {
this->m_gpmaint = std::nullopt;
}
const std::string Group::ExceedAction2String( ExceedAction enumValue ) {
switch(enumValue) {
@@ -665,6 +677,7 @@ bool Group::operator==(const Group& data) const
this->m_groups == data.m_groups &&
this->m_topup_phase == data.m_topup_phase &&
this->injection_properties == data.injection_properties &&
this->m_gpmaint == data.m_gpmaint &&
this->productionProperties() == data.productionProperties();
}

View File

@@ -410,6 +410,9 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
else if (keyword.name() == "GRUPTREE")
handleGRUPTREE(keyword, currentStep, unit_system, parseContext, errors);
else if (keyword.name() == "GPMAINT")
handleGPMAINT(keyword, currentStep, parseContext, errors);
else if (keyword.name() == "GRUPNET")
handleGRUPNET(keyword, currentStep, unit_system);
@@ -2145,7 +2148,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
}
}
void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors) {
void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors) {
for( const auto& record : keyword ) {
const std::string& childName = trim_wgname(keyword, record.getItem("CHILD_GROUP").get<std::string>(0), parseContext, errors);
const std::string& parentName = trim_wgname(keyword, record.getItem("PARENT_GROUP").get<std::string>(0), parseContext, errors);
@@ -2161,6 +2164,30 @@ void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, c
}
void Schedule::handleGPMAINT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors) {
for( const auto& record : keyword ) {
const std::string& groupNamePattern = record.getItem("GROUP").getTrimmedString(0);
const auto group_names = this->groupNames(groupNamePattern);
if (group_names.empty())
invalidNamePattern(groupNamePattern, currentStep, parseContext, errors, keyword);
using GP = ParserKeywords::GPMAINT;
for (const auto& group_name : group_names) {
auto group_ptr = std::make_shared<Group>(this->getGroup(group_name, currentStep));
const auto& target_string = record.getItem<GP::FLOW_TARGET>().get<std::string>(0);
if (target_string == "NONE")
group_ptr->set_gpmaint();
else {
GPMaint gpmaint(record);
group_ptr->set_gpmaint(std::move(gpmaint));
}
this->updateGroup(std::move(group_ptr), currentStep);
}
}
}
void Schedule::handleGRUPNET( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system) {
for( const auto& record : keyword ) {
const auto& groupName = record.getItem("NAME").getTrimmedString(0);

View File

@@ -18,7 +18,8 @@
},
{
"name": "FIP_FAMILY",
"value_type": "STRING"
"value_type": "STRING",
"default": "FIPNUM"
},
{
"name": "PRESSURE_TARGET",

View File

@@ -537,3 +537,62 @@ BOOST_AUTO_TEST_CASE(GCONINJE_GCONPROD) {
BOOST_CHECK( g2.injectionGroupControlAvailable(Phase::GAS));
}
}
BOOST_AUTO_TEST_CASE(GPMAINT) {
const auto input = R"(
SCHEDULE
GRUPTREE
'PROD' 'FIELD' /
'M5S' 'PLAT-A' /
'M5N' 'PLAT-A' /
'C1' 'M5N' /
'F1' 'M5N' /
'B1' 'M5S' /
'G1' 'M5S' /
/
GPMAINT
'PROD' 'WINJ' 2 1* 100 0.25 1.0 /
'C1' 'GINJ' 0 1* 100 0.25 1.0 /
/
TSTEP
10 /
GPMAINT
'PROD' 'NONE' /
/
)";
Opm::UnitSystem unitSystem = UnitSystem( UnitSystem::UnitType::UNIT_TYPE_METRIC );
double siFactorG = unitSystem.parse("GasSurfaceVolume/Time").getSIScaling();
const auto sched = create_schedule(input);
{
const auto& prod_group = sched.getGroup("PROD", 0);
const auto& plat_group = sched.getGroup("PLAT-A", 0);
const auto& c1_group = sched.getGroup("C1", 0);
const auto& gpm_prod = prod_group.gpmaint();
BOOST_CHECK( gpm_prod );
BOOST_CHECK(gpm_prod->flow_target() == GPMaint::FlowTarget::RESV_WINJ);
auto [name, number] = *gpm_prod->region();
BOOST_CHECK_EQUAL(number, 2);
BOOST_CHECK_EQUAL(name, "FIPNUM");
const auto& gpm_c1 = c1_group.gpmaint();
BOOST_CHECK(!gpm_c1->region());
const auto& plat_prod = plat_group.gpmaint();
BOOST_CHECK( !plat_prod );
}
{
const auto& prod_group = sched.getGroup("PROD", 1);
const auto& gpm_prod = prod_group.gpmaint();
BOOST_CHECK( !gpm_prod );
}
}