Internalize keywords for gas lift optimization
This commit is contained in:
@@ -98,6 +98,7 @@ if(ENABLE_ECL_INPUT)
|
|||||||
src/opm/parser/eclipse/EclipseState/Schedule/Action/Condition.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/Action/Condition.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp
|
||||||
|
src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/Group/Group.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/GuideRate.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.cpp
|
||||||
@@ -668,6 +669,7 @@ if(ENABLE_ECL_INPUT)
|
|||||||
opm/parser/eclipse/EclipseState/Schedule/Action/ASTNode.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Action/ASTNode.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/Action/PyAction.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Action/PyAction.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp
|
opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp
|
||||||
|
opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/Network/Branch.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Network/Branch.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/Network/ExtNetwork.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Network/ExtNetwork.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/Network/Node.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Network/Node.hpp
|
||||||
|
|||||||
251
opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp
Normal file
251
opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
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 GAS_LIFT_OPT_HPP
|
||||||
|
#define GAS_LIFT_OPT_HPP
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace Opm {
|
||||||
|
|
||||||
|
class GasLiftOpt {
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Group {
|
||||||
|
public:
|
||||||
|
Group() = default;
|
||||||
|
|
||||||
|
Group(const std::string& name) :
|
||||||
|
m_name(name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const std::optional<double>& max_lift_gas() const {
|
||||||
|
return this->m_max_lift_gas;
|
||||||
|
}
|
||||||
|
|
||||||
|
void max_lift_gas(double value) {
|
||||||
|
if (value >= 0)
|
||||||
|
this->m_max_lift_gas = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::optional<double>& max_total_gas() const {
|
||||||
|
return this->m_max_total_gas;
|
||||||
|
}
|
||||||
|
|
||||||
|
void max_total_gas(double value) {
|
||||||
|
if (value >= 0)
|
||||||
|
this->m_max_total_gas = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& name() const {
|
||||||
|
return this->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Serializer>
|
||||||
|
void serializeOp(Serializer& serializer)
|
||||||
|
{
|
||||||
|
serializer(m_name);
|
||||||
|
serializer(m_max_lift_gas);
|
||||||
|
serializer(m_max_total_gas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Group serializeObject() {
|
||||||
|
Group group;
|
||||||
|
group.m_name = "GR";
|
||||||
|
group.m_max_lift_gas = 100;
|
||||||
|
group.m_max_total_gas = 200;
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool operator==(const Group& other) const {
|
||||||
|
return this->m_name == other.m_name &&
|
||||||
|
this->m_max_lift_gas == other.m_max_lift_gas &&
|
||||||
|
this->m_max_total_gas == other.m_max_total_gas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
std::optional<double> m_max_lift_gas;
|
||||||
|
std::optional<double> m_max_total_gas;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Well {
|
||||||
|
public:
|
||||||
|
Well() = default;
|
||||||
|
Well(const std::string& name, bool use_glo) :
|
||||||
|
m_name(name),
|
||||||
|
m_use_glo(use_glo)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const std::string& name() const {
|
||||||
|
return this->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_glo() const {
|
||||||
|
return this->m_use_glo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void max_rate(double value) {
|
||||||
|
this->m_max_rate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The semantics of the max_rate is quite complicated:
|
||||||
|
|
||||||
|
1. If the std::optional<double> has a value that value should be
|
||||||
|
used as the maximum rate and all is fine.
|
||||||
|
|
||||||
|
2. If the std::optional<double> does not a have well we must check
|
||||||
|
the value of Well::use_glo():
|
||||||
|
|
||||||
|
False: The maximum gas lift should have been set with WCONPROD /
|
||||||
|
WELTARG - this code does not provide a value in that case.
|
||||||
|
|
||||||
|
True: If the well should be controlled with gas lift optimization
|
||||||
|
the value to use should be the largest ALQ value in the wells
|
||||||
|
VFP table.
|
||||||
|
*/
|
||||||
|
const std::optional<double>& max_rate() const {
|
||||||
|
return this->m_max_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void weight_factor(double value) {
|
||||||
|
if (this->m_use_glo)
|
||||||
|
this->m_weight = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double weight_factor() const {
|
||||||
|
return this->m_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc_weight_factor(double value) {
|
||||||
|
if (this->m_use_glo)
|
||||||
|
this->m_inc_weight = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double inc_weight_factor() const {
|
||||||
|
return this->m_inc_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void min_rate(double value) {
|
||||||
|
if (this->m_use_glo)
|
||||||
|
this->m_min_rate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double min_rate() const {
|
||||||
|
return this->m_min_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void alloc_extra_gas(bool value) {
|
||||||
|
if (this->m_use_glo)
|
||||||
|
this->m_alloc_extra_gas = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool alloc_extra_gas() const {
|
||||||
|
return this->m_alloc_extra_gas;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Serializer>
|
||||||
|
void serializeOp(Serializer& serializer)
|
||||||
|
{
|
||||||
|
serializer(m_name);
|
||||||
|
serializer(m_use_glo);
|
||||||
|
serializer(m_max_rate);
|
||||||
|
serializer(m_min_rate);
|
||||||
|
serializer(m_weight);
|
||||||
|
serializer(m_inc_weight);
|
||||||
|
serializer(m_alloc_extra_gas);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Well serializeObject() {
|
||||||
|
Well well;
|
||||||
|
well.m_name = "WELL";
|
||||||
|
well.m_max_rate = 2000;
|
||||||
|
well.m_min_rate = 56;
|
||||||
|
well.m_use_glo = true;
|
||||||
|
well.m_weight = 1.25;
|
||||||
|
well.m_inc_weight = 0.25;
|
||||||
|
well.m_alloc_extra_gas = false;
|
||||||
|
return well;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Well& other) const {
|
||||||
|
return this->m_name == other.m_name &&
|
||||||
|
this->m_max_rate == other.m_max_rate &&
|
||||||
|
this->m_min_rate == other.m_min_rate &&
|
||||||
|
this->m_use_glo == other.m_use_glo &&
|
||||||
|
this->m_weight == other.m_weight &&
|
||||||
|
this->m_inc_weight == other.m_inc_weight &&
|
||||||
|
this->m_alloc_extra_gas == other.m_alloc_extra_gas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
std::optional<double> m_max_rate;
|
||||||
|
double m_min_rate = 0;
|
||||||
|
bool m_use_glo;
|
||||||
|
double m_weight = 1;
|
||||||
|
double m_inc_weight = 0;
|
||||||
|
bool m_alloc_extra_gas = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
GasLiftOpt() = default;
|
||||||
|
|
||||||
|
const Group& group(const std::string& gname) const;
|
||||||
|
const Well& well(const std::string& wname) const;
|
||||||
|
|
||||||
|
void gaslift_increment(double gaslift_increment);
|
||||||
|
void min_eco_gradient(double min_eco_gradient);
|
||||||
|
void min_wait(double min_wait);
|
||||||
|
void all_newton(double all_newton);
|
||||||
|
void add_group(const Group& group);
|
||||||
|
void add_well(const Well& well);
|
||||||
|
bool active() const;
|
||||||
|
|
||||||
|
static GasLiftOpt serializeObject();
|
||||||
|
bool operator==(const GasLiftOpt& other) const;
|
||||||
|
|
||||||
|
template<class Serializer>
|
||||||
|
void serializeOp(Serializer& serializer)
|
||||||
|
{
|
||||||
|
serializer(m_increment);
|
||||||
|
serializer(m_min_eco_gradient);
|
||||||
|
serializer(m_min_wait);
|
||||||
|
serializer(m_all_newton);
|
||||||
|
serializer.map(m_groups);
|
||||||
|
serializer.map(m_wells);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
double m_increment = 0;
|
||||||
|
double m_min_eco_gradient;
|
||||||
|
double m_min_wait;
|
||||||
|
bool m_all_newton = true;
|
||||||
|
|
||||||
|
std::map<std::string, GasLiftOpt::Group> m_groups;
|
||||||
|
std::map<std::string, GasLiftOpt::Well> m_wells;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
||||||
|
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicVector.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicVector.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
|
||||||
@@ -266,6 +267,7 @@ namespace Opm
|
|||||||
|
|
||||||
|
|
||||||
const Network::ExtNetwork& network(std::size_t report_step) const;
|
const Network::ExtNetwork& network(std::size_t report_step) const;
|
||||||
|
const GasLiftOpt& glo(std::size_t report_step) const;
|
||||||
|
|
||||||
bool operator==(const Schedule& data) const;
|
bool operator==(const Schedule& data) const;
|
||||||
std::shared_ptr<const Python> python() const;
|
std::shared_ptr<const Python> python() const;
|
||||||
@@ -310,6 +312,7 @@ namespace Opm
|
|||||||
global_whistctl_mode.template serializeOp<Serializer, false>(serializer);
|
global_whistctl_mode.template serializeOp<Serializer, false>(serializer);
|
||||||
m_actions.serializeOp(serializer);
|
m_actions.serializeOp(serializer);
|
||||||
m_network.serializeOp(serializer);
|
m_network.serializeOp(serializer);
|
||||||
|
m_glo.serializeOp(serializer);
|
||||||
rft_config.serializeOp(serializer);
|
rft_config.serializeOp(serializer);
|
||||||
m_nupcol.template serializeOp<Serializer, false>(serializer);
|
m_nupcol.template serializeOp<Serializer, false>(serializer);
|
||||||
restart_config.serializeOp(serializer);
|
restart_config.serializeOp(serializer);
|
||||||
@@ -346,6 +349,7 @@ namespace Opm
|
|||||||
DynamicState<Well::ProducerCMode> global_whistctl_mode;
|
DynamicState<Well::ProducerCMode> global_whistctl_mode;
|
||||||
DynamicState<std::shared_ptr<Action::Actions>> m_actions;
|
DynamicState<std::shared_ptr<Action::Actions>> m_actions;
|
||||||
DynamicState<std::shared_ptr<Network::ExtNetwork>> m_network;
|
DynamicState<std::shared_ptr<Network::ExtNetwork>> m_network;
|
||||||
|
DynamicState<std::shared_ptr<GasLiftOpt>> m_glo;
|
||||||
RFTConfig rft_config;
|
RFTConfig rft_config;
|
||||||
DynamicState<int> m_nupcol;
|
DynamicState<int> m_nupcol;
|
||||||
RestartConfig restart_config;
|
RestartConfig restart_config;
|
||||||
@@ -429,7 +433,9 @@ namespace Opm
|
|||||||
|
|
||||||
void handleBRANPROP( const DeckKeyword& keyword, size_t currentStep);
|
void handleBRANPROP( const DeckKeyword& keyword, size_t currentStep);
|
||||||
void handleNODEPROP( const DeckKeyword& keyword, size_t currentStep);
|
void handleNODEPROP( const DeckKeyword& keyword, size_t currentStep);
|
||||||
|
void handleLIFTOPT(const DeckKeyword& keyword, std::size_t currentStep);
|
||||||
|
void handleGLIFTOPT(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
|
||||||
|
void handleWLIFTOPT(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
|
||||||
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
|
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 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 handleNUPCOL( const DeckKeyword& keyword, size_t currentStep);
|
||||||
|
|||||||
100
src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp
Normal file
100
src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
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 <stdexcept>
|
||||||
|
|
||||||
|
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
||||||
|
|
||||||
|
namespace Opm {
|
||||||
|
|
||||||
|
bool GasLiftOpt::active() const {
|
||||||
|
return (this->m_increment > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GasLiftOpt::gaslift_increment(double gaslift_increment) {
|
||||||
|
this->m_increment = gaslift_increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GasLiftOpt::min_eco_gradient(double min_eco_gradient) {
|
||||||
|
this->m_min_eco_gradient = min_eco_gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GasLiftOpt::min_wait(double min_wait) {
|
||||||
|
this->m_min_wait = min_wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GasLiftOpt::all_newton(double all_newton) {
|
||||||
|
this->m_all_newton = all_newton;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GasLiftOpt::Group& GasLiftOpt::group(const std::string& gname) const {
|
||||||
|
const auto iter = this->m_groups.find(gname);
|
||||||
|
if (iter == this->m_groups.end())
|
||||||
|
throw std::out_of_range("No such group: " + gname + " configured for gas lift optimization");
|
||||||
|
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GasLiftOpt::add_group(const Group& group) {
|
||||||
|
auto iter = this->m_groups.find(group.name());
|
||||||
|
if (iter == this->m_groups.end())
|
||||||
|
this->m_groups.insert( std::make_pair(group.name(), group) );
|
||||||
|
else
|
||||||
|
iter->second = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GasLiftOpt::add_well(const Well& well) {
|
||||||
|
auto iter = this->m_wells.find(well.name());
|
||||||
|
if (iter == this->m_wells.end())
|
||||||
|
this->m_wells.insert( std::make_pair(well.name(), well) );
|
||||||
|
else
|
||||||
|
iter->second = well;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const GasLiftOpt::Well& GasLiftOpt::well(const std::string& wname) const {
|
||||||
|
const auto iter = this->m_wells.find(wname);
|
||||||
|
if (iter == this->m_wells.end())
|
||||||
|
throw std::out_of_range("No such well: " + wname + " configured for gas lift optimization");
|
||||||
|
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
GasLiftOpt GasLiftOpt::serializeObject() {
|
||||||
|
GasLiftOpt glo;
|
||||||
|
glo.m_increment = 0;
|
||||||
|
glo.m_min_eco_gradient = 100;
|
||||||
|
glo.m_min_wait = 1;
|
||||||
|
glo.m_all_newton = true;
|
||||||
|
return glo;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GasLiftOpt::operator==(const GasLiftOpt& other) const {
|
||||||
|
return this->m_increment == other.m_increment &&
|
||||||
|
this->m_min_eco_gradient == other.m_min_eco_gradient &&
|
||||||
|
this->m_min_wait == other.m_min_wait &&
|
||||||
|
this->m_all_newton == other.m_all_newton &&
|
||||||
|
this->m_groups == other.m_groups &&
|
||||||
|
this->m_wells == other.m_wells;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -149,6 +149,7 @@ std::pair<std::time_t, std::size_t> restart_info(const RestartIO::RstState * rst
|
|||||||
global_whistctl_mode(this->m_timeMap, Well::ProducerCMode::CMODE_UNDEFINED),
|
global_whistctl_mode(this->m_timeMap, Well::ProducerCMode::CMODE_UNDEFINED),
|
||||||
m_actions(this->m_timeMap, std::make_shared<Action::Actions>()),
|
m_actions(this->m_timeMap, std::make_shared<Action::Actions>()),
|
||||||
m_network(this->m_timeMap, std::make_shared<Network::ExtNetwork>()),
|
m_network(this->m_timeMap, std::make_shared<Network::ExtNetwork>()),
|
||||||
|
m_glo(this->m_timeMap, std::make_shared<GasLiftOpt>()),
|
||||||
rft_config(this->m_timeMap),
|
rft_config(this->m_timeMap),
|
||||||
m_nupcol(this->m_timeMap, ParserKeywords::NUPCOL::NUM_ITER::defaultValue),
|
m_nupcol(this->m_timeMap, ParserKeywords::NUPCOL::NUM_ITER::defaultValue),
|
||||||
restart_config(m_timeMap, deck, parseContext, errors),
|
restart_config(m_timeMap, deck, parseContext, errors),
|
||||||
@@ -263,6 +264,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
|
|||||||
result.wlist_manager = {{std::make_shared<WListManager>(WListManager::serializeObject())}, 1};
|
result.wlist_manager = {{std::make_shared<WListManager>(WListManager::serializeObject())}, 1};
|
||||||
result.udq_config = {{std::make_shared<UDQConfig>(UDQConfig::serializeObject())}, 1};
|
result.udq_config = {{std::make_shared<UDQConfig>(UDQConfig::serializeObject())}, 1};
|
||||||
result.m_network = {{std::make_shared<Network::ExtNetwork>(Network::ExtNetwork::serializeObject())}, 1};
|
result.m_network = {{std::make_shared<Network::ExtNetwork>(Network::ExtNetwork::serializeObject())}, 1};
|
||||||
|
result.m_glo = {{std::make_shared<GasLiftOpt>(GasLiftOpt::serializeObject())}, 1};
|
||||||
result.udq_active = {{std::make_shared<UDQActive>(UDQActive::serializeObject())}, 1};
|
result.udq_active = {{std::make_shared<UDQActive>(UDQActive::serializeObject())}, 1};
|
||||||
result.guide_rate_config = {{std::make_shared<GuideRateConfig>(GuideRateConfig::serializeObject())}, 1};
|
result.guide_rate_config = {{std::make_shared<GuideRateConfig>(GuideRateConfig::serializeObject())}, 1};
|
||||||
result.gconsale = {{std::make_shared<GConSale>(GConSale::serializeObject())}, 1};
|
result.gconsale = {{std::make_shared<GConSale>(GConSale::serializeObject())}, 1};
|
||||||
@@ -492,6 +494,15 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext&
|
|||||||
else if (keyword.name() == "BRANPROP")
|
else if (keyword.name() == "BRANPROP")
|
||||||
handleBRANPROP(keyword, currentStep);
|
handleBRANPROP(keyword, currentStep);
|
||||||
|
|
||||||
|
else if (keyword.name() == "LIFTOPT")
|
||||||
|
handleLIFTOPT(keyword, currentStep);
|
||||||
|
|
||||||
|
else if (keyword.name() == "GLIFTOPT")
|
||||||
|
handleGLIFTOPT(keyword, currentStep, parseContext, errors);
|
||||||
|
|
||||||
|
else if (keyword.name() == "WLIFTOPT")
|
||||||
|
handleWLIFTOPT(keyword, currentStep, parseContext, errors);
|
||||||
|
|
||||||
else if (keyword.name() == "PYACTION")
|
else if (keyword.name() == "PYACTION")
|
||||||
handlePYACTION(python, input_path, keyword, currentStep);
|
handlePYACTION(python, input_path, keyword, currentStep);
|
||||||
|
|
||||||
@@ -3031,6 +3042,7 @@ void Schedule::invalidNamePattern( const std::string& namePattern, std::size_t
|
|||||||
compareMap(this->vfpprod_tables, data.vfpprod_tables) &&
|
compareMap(this->vfpprod_tables, data.vfpprod_tables) &&
|
||||||
compareMap(this->vfpinj_tables, data.vfpinj_tables) &&
|
compareMap(this->vfpinj_tables, data.vfpinj_tables) &&
|
||||||
compareDynState(this->m_network, data.m_network) &&
|
compareDynState(this->m_network, data.m_network) &&
|
||||||
|
compareDynState(this->m_glo, data.m_glo) &&
|
||||||
compareDynState(this->wtest_config, data.wtest_config) &&
|
compareDynState(this->wtest_config, data.wtest_config) &&
|
||||||
compareDynState(this->wlist_manager, data.wlist_manager) &&
|
compareDynState(this->wlist_manager, data.wlist_manager) &&
|
||||||
compareDynState(this->udq_config, data.udq_config) &&
|
compareDynState(this->udq_config, data.udq_config) &&
|
||||||
@@ -3175,6 +3187,93 @@ void Schedule::handleNODEPROP(const DeckKeyword& keyword, std::size_t report_ste
|
|||||||
this->updateNetwork(ext_network, report_step);
|
this->updateNetwork(ext_network, report_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GasLiftOpt& Schedule::glo(std::size_t report_step) const {
|
||||||
|
return *this->m_glo[report_step];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schedule::handleLIFTOPT(const DeckKeyword& keyword, std::size_t report_step) {
|
||||||
|
using LO = ParserKeywords::LIFTOPT;
|
||||||
|
auto glo = std::make_shared<GasLiftOpt>( this->glo(report_step) );
|
||||||
|
const auto& record = keyword.getRecord(0);
|
||||||
|
double gaslift_increment = record.getItem<LO::INCREMENT_SIZE>().getSIDouble(0);
|
||||||
|
double min_eco_gradient = record.getItem<LO::MIN_ECONOMIC_GRADIENT>().getSIDouble(0);
|
||||||
|
double min_wait = record.getItem<LO::MIN_INTERVAL_BETWEEN_GAS_LIFT_OPTIMIZATIONS>().getSIDouble(0);
|
||||||
|
bool all_newton = DeckItem::to_bool( record.getItem<LO::OPTIMISE_GAS_LIFT>().get<std::string>(0) );
|
||||||
|
|
||||||
|
glo->gaslift_increment(gaslift_increment);
|
||||||
|
glo->min_eco_gradient(min_eco_gradient);
|
||||||
|
glo->min_wait(min_wait);
|
||||||
|
glo->all_newton(all_newton);
|
||||||
|
|
||||||
|
this->m_glo.update(report_step, std::move(glo));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Schedule::handleGLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
|
using GLO = ParserKeywords::GLIFTOPT;
|
||||||
|
auto glo = std::make_shared<GasLiftOpt>( this->glo(report_step) );
|
||||||
|
for (const auto& record : keyword) {
|
||||||
|
const std::string& groupNamePattern = record.getItem<GLO::GROUP_NAME>().getTrimmedString(0);
|
||||||
|
const auto group_names = this->groupNames(groupNamePattern);
|
||||||
|
if (group_names.empty())
|
||||||
|
invalidNamePattern(groupNamePattern, report_step, parseContext, errors, keyword);
|
||||||
|
|
||||||
|
const auto& max_total_item = record.getItem<GLO::MAX_TOTAL_GAS_RATE>();
|
||||||
|
const auto& max_gas_item = record.getItem<GLO::MAX_LIFT_GAS_SUPPLY>();
|
||||||
|
double max_lift_gas_value = -1;
|
||||||
|
double max_total_gas_value = -1;
|
||||||
|
|
||||||
|
if (max_gas_item.hasValue(0))
|
||||||
|
max_lift_gas_value = max_gas_item.getSIDouble(0);
|
||||||
|
|
||||||
|
if (max_total_item.hasValue(0))
|
||||||
|
max_total_gas_value = max_total_item.getSIDouble(0);
|
||||||
|
|
||||||
|
for (const auto& gname : group_names) {
|
||||||
|
auto group = GasLiftOpt::Group(gname);
|
||||||
|
group.max_lift_gas(max_lift_gas_value);
|
||||||
|
group.max_total_gas(max_total_gas_value);
|
||||||
|
|
||||||
|
glo->add_group(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->m_glo.update(report_step, std::move(glo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schedule::handleWLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
|
using WLO = ParserKeywords::WLIFTOPT;
|
||||||
|
auto glo = std::make_shared<GasLiftOpt>( this->glo(report_step) );
|
||||||
|
|
||||||
|
for (const auto& record : keyword) {
|
||||||
|
const std::string& wellNamePattern = record.getItem<WLO::WELL>().getTrimmedString(0);
|
||||||
|
bool use_glo = DeckItem::to_bool( record.getItem<WLO::USE_OPTIMIZER>().get<std::string>(0));
|
||||||
|
bool alloc_extra_gas = DeckItem::to_bool( record.getItem<WLO::ALLOCATE_EXTRA_LIFT_GAS>().get<std::string>(0));
|
||||||
|
double weight_factor = record.getItem<WLO::WEIGHT_FACTOR>().get<double>(0);
|
||||||
|
double inc_weight_factor = record.getItem<WLO::DELTA_GAS_RATE_WEIGHT_FACTOR>().get<double>(0);
|
||||||
|
double min_rate = record.getItem<WLO::MIN_LIFT_GAS_RATE>().getSIDouble(0);
|
||||||
|
const auto& max_rate_item = record.getItem<WLO::MAX_LIFT_GAS_RATE>();
|
||||||
|
|
||||||
|
const auto well_names = this->wellNames(wellNamePattern);
|
||||||
|
if (well_names.empty())
|
||||||
|
invalidNamePattern(wellNamePattern, report_step, parseContext, errors, keyword);
|
||||||
|
|
||||||
|
for (const auto& wname : well_names) {
|
||||||
|
auto well = GasLiftOpt::Well(wname, use_glo);
|
||||||
|
|
||||||
|
if (max_rate_item.hasValue(0))
|
||||||
|
well.max_rate( max_rate_item.getSIDouble(0) );
|
||||||
|
|
||||||
|
well.weight_factor(weight_factor);
|
||||||
|
well.inc_weight_factor(inc_weight_factor);
|
||||||
|
well.min_rate(min_rate);
|
||||||
|
well.alloc_extra_gas(alloc_extra_gas);
|
||||||
|
|
||||||
|
glo->add_well(well);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_glo.update(report_step, std::move(glo));
|
||||||
|
}
|
||||||
|
|
||||||
void Schedule::handleBRANPROP(const DeckKeyword& keyword, std::size_t report_step) {
|
void Schedule::handleBRANPROP(const DeckKeyword& keyword, std::size_t report_step) {
|
||||||
using BP = ParserKeywords::BRANPROP;
|
using BP = ParserKeywords::BRANPROP;
|
||||||
|
|||||||
@@ -11,11 +11,13 @@
|
|||||||
{
|
{
|
||||||
"name": "MAX_LIFT_GAS_SUPPLY",
|
"name": "MAX_LIFT_GAS_SUPPLY",
|
||||||
"value_type": "DOUBLE",
|
"value_type": "DOUBLE",
|
||||||
|
"dimension" : "GasSurfaceVolume/Time",
|
||||||
"default": -1e+20
|
"default": -1e+20
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "MAX_TOTAL_GAS_RATE",
|
"name": "MAX_TOTAL_GAS_RATE",
|
||||||
"value_type": "DOUBLE",
|
"value_type": "DOUBLE",
|
||||||
|
"dimension" : "GasSurfaceVolume/Time",
|
||||||
"default": -1e+20
|
"default": -1e+20
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,15 +7,18 @@
|
|||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"name": "INCREMENT_SIZE",
|
"name": "INCREMENT_SIZE",
|
||||||
"value_type": "DOUBLE"
|
"value_type": "DOUBLE",
|
||||||
|
"dimension" : "GasSurfaceVolume/Time"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "MIN_ECONOMIC_GRADIENT",
|
"name": "MIN_ECONOMIC_GRADIENT",
|
||||||
"value_type": "DOUBLE"
|
"value_type": "DOUBLE",
|
||||||
|
"dimension" : "LiquidSurfaceVolume/GasSurfaceVolume"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "MIN_INTERVAL_BETWEEN_GAS_LIFT_OPTIMIZATIONS",
|
"name": "MIN_INTERVAL_BETWEEN_GAS_LIFT_OPTIMIZATIONS",
|
||||||
"value_type": "DOUBLE",
|
"value_type": "DOUBLE",
|
||||||
|
"dimension" : "Time",
|
||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
|
||||||
|
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
|
||||||
|
|
||||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||||
@@ -3604,3 +3605,85 @@ BOOST_AUTO_TEST_CASE(SKIPREST_VFP) {
|
|||||||
const auto& tables = sched.getVFPProdTables(3);
|
const auto& tables = sched.getVFPProdTables(3);
|
||||||
BOOST_CHECK( !tables.empty() );
|
BOOST_CHECK( !tables.empty() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(GASLIFT_OPT) {
|
||||||
|
GasLiftOpt glo;
|
||||||
|
BOOST_CHECK(!glo.active());
|
||||||
|
BOOST_CHECK_THROW(glo.group("NO_SUCH_GROUP"), std::out_of_range);
|
||||||
|
BOOST_CHECK_THROW(glo.well("NO_SUCH_WELL"), std::out_of_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(GASLIFT_OPT_DECK) {
|
||||||
|
const auto input = R"(-- Turns on gas lift optimization
|
||||||
|
SCHEDULE
|
||||||
|
|
||||||
|
GRUPTREE
|
||||||
|
'PROD' 'FIELD' /
|
||||||
|
|
||||||
|
'M5S' 'PLAT-A' /
|
||||||
|
'M5N' 'PLAT-A' /
|
||||||
|
|
||||||
|
'C1' 'M5N' /
|
||||||
|
'F1' 'M5N' /
|
||||||
|
'B1' 'M5S' /
|
||||||
|
'G1' 'M5S' /
|
||||||
|
/
|
||||||
|
|
||||||
|
LIFTOPT
|
||||||
|
12500 5E-3 0.0 YES /
|
||||||
|
|
||||||
|
|
||||||
|
-- Group lift gas limits for gas lift optimization
|
||||||
|
GLIFTOPT
|
||||||
|
'PLAT-A' 200000 / --
|
||||||
|
/
|
||||||
|
|
||||||
|
WELSPECS
|
||||||
|
--WELL GROUP IHEEL JHEEL DREF PHASE DRAD INFEQ SIINS XFLOW PRTAB DENS
|
||||||
|
'B-1H' 'B1' 11 3 1* OIL 1* 1* SHUT 1* 1* 1* /
|
||||||
|
'B-2H' 'B1' 4 7 1* OIL 1* 1* SHUT 1* 1* 1* /
|
||||||
|
'B-3H' 'B1' 11 12 1* OIL 1* 1* SHUT 1* 1* 1* /
|
||||||
|
'C-1H' 'C1' 13 20 1* OIL 1* 1* SHUT 1* 1* 1* /
|
||||||
|
'C-2H' 'C1' 12 27 1* OIL 1* 1* SHUT 1* 1* 1* /
|
||||||
|
/
|
||||||
|
|
||||||
|
-- well savailable for gass lift
|
||||||
|
-- minimum gas lift rate, enough to keep well flowing
|
||||||
|
WLIFTOPT
|
||||||
|
'B-1H' YES 150000 1.01 -1.0 /
|
||||||
|
'B-2H' YES 150000 1.01 -1.0 /
|
||||||
|
'B-3H' YES 150000 1.01 -1.0 /
|
||||||
|
'C-1H' YES 150000 1.01 -1.0 1.0 YES/
|
||||||
|
'C-2H' NO 150000 1.01 -1.0 /
|
||||||
|
/
|
||||||
|
)";
|
||||||
|
Opm::UnitSystem unitSystem = UnitSystem( UnitSystem::UnitType::UNIT_TYPE_METRIC );
|
||||||
|
double siFactorG = unitSystem.parse("GasSurfaceVolume/Time").getSIScaling();
|
||||||
|
const auto sched = make_schedule(input);
|
||||||
|
const auto& glo = sched.glo(0);
|
||||||
|
const auto& plat_group = glo.group("PLAT-A");
|
||||||
|
BOOST_CHECK_EQUAL( *plat_group.max_lift_gas(), siFactorG * 200000);
|
||||||
|
BOOST_CHECK(!plat_group.max_total_gas().has_value());
|
||||||
|
|
||||||
|
|
||||||
|
const auto& w1 = glo.well("B-1H");
|
||||||
|
BOOST_CHECK(w1.use_glo());
|
||||||
|
BOOST_CHECK_EQUAL(*w1.max_rate(), 150000 * siFactorG);
|
||||||
|
BOOST_CHECK_EQUAL(w1.weight_factor(), 1.01);
|
||||||
|
|
||||||
|
const auto& w2 = glo.well("C-2H");
|
||||||
|
BOOST_CHECK_EQUAL(w2.weight_factor(), 1.00);
|
||||||
|
BOOST_CHECK_EQUAL(w2.min_rate(), 0.00);
|
||||||
|
BOOST_CHECK_EQUAL(w2.inc_weight_factor(), 0.00);
|
||||||
|
BOOST_CHECK(!w2.alloc_extra_gas());
|
||||||
|
|
||||||
|
const auto& w3 = glo.well("C-1H");
|
||||||
|
BOOST_CHECK_EQUAL(w3.min_rate(), -1.00 * siFactorG);
|
||||||
|
BOOST_CHECK_EQUAL(w3.inc_weight_factor(), 1.00);
|
||||||
|
BOOST_CHECK(w3.alloc_extra_gas());
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user