Merge pull request #968 from joakim-hove/guiderate-model

Adds GuideRateModel
This commit is contained in:
Joakim Hove
2019-08-23 10:05:40 +02:00
committed by GitHub
8 changed files with 253 additions and 0 deletions

View File

@@ -88,6 +88,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/Group/Group2.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/injection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/MessageLimits.cpp
@@ -555,6 +556,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp
opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.hpp
opm/parser/eclipse/EclipseState/Schedule/MessageLimits.hpp
opm/parser/eclipse/EclipseState/Schedule/Events.hpp
opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp

View File

@@ -0,0 +1,68 @@
/*
Copyright 2019 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 GUIDE_RATE_MODEL_HPP
#define GUIDE_RATE_MODEL_HPP
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
namespace Opm {
class GuideRateModel {
public:
GuideRateModel(double time_interval_arg,
GuideRateTarget phase_arg,
double A_arg,
double B_arg,
double C_arg,
double D_arg,
double E_arg,
double F_arg,
bool allow_increase_arg,
double damping_factor_arg,
bool use_free_gas_arg);
GuideRateModel() = default;
double eval(double pot, double R1, double R2) const;
double update_delay() const;
bool operator==(const GuideRateModel& other) const;
bool operator!=(const GuideRateModel& other) const;
private:
/*
Unfortunately the default values will give a GuideRateModel which can not
be evaluated, due to a division by zero problem.
*/
double time_interval = 0;
GuideRateTarget phase = GuideRateTarget::NONE;
double A = 0;
double B = 0;
double C = 0;
double D = 0;
double E = 0;
double F = 0;
bool allow_increase = true;
double damping_factor = 1.0;
bool use_free_gas = false;
bool default_model = true;
};
}
#endif

View File

@@ -30,6 +30,7 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
@@ -195,6 +196,7 @@ namespace Opm
const Tuning& getTuning() const;
const MessageLimits& getMessageLimits() const;
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword) const;
const GuideRateModel& guideRateModel(size_t timeStep) const;
const RFTConfig& rftConfig() const;
const Events& getEvents() const;
@@ -230,6 +232,7 @@ namespace Opm
DynamicState<std::shared_ptr<WListManager>> wlist_manager;
DynamicState<std::shared_ptr<UDQConfig>> udq_config;
DynamicState<std::shared_ptr<UDQActive>> udq_active;
DynamicState<std::shared_ptr<GuideRateModel>> guide_rate_model;
DynamicState<WellProducer::ControlModeEnum> global_whistctl_mode;
RFTConfig rft_config;
@@ -275,6 +278,7 @@ namespace Opm
void handleGCONINJE( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleGUIDERAT( const DeckKeyword& keyword, size_t currentStep);
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors);

View File

@@ -203,6 +203,18 @@ namespace Opm {
GroupType operator |(GroupType lhs, GroupType rhs);
GroupType operator &(GroupType lhs, GroupType rhs);
enum class GuideRateTarget {
OIL = 0,
LIQ = 1,
GAS = 2,
RES = 3,
COMB = 4,
NONE = 5
};
GuideRateTarget GuideRateTargetFromString(const std::string& s);
namespace GroupProduction {
enum ControlEnum {

View File

@@ -0,0 +1,103 @@
/*
Copyright 2019 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 <cmath>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.hpp>
namespace Opm {
GuideRateModel::GuideRateModel(double time_interval_arg,
GuideRateTarget phase_arg,
double A_arg,
double B_arg,
double C_arg,
double D_arg,
double E_arg,
double F_arg,
bool allow_increase_arg,
double damping_factor_arg,
bool use_free_gas_arg) :
time_interval(time_interval_arg),
phase(phase_arg),
A(A_arg),
B(B_arg),
C(C_arg),
D(D_arg),
E(E_arg),
F(F_arg),
allow_increase(allow_increase_arg),
damping_factor(damping_factor_arg),
use_free_gas(use_free_gas_arg),
default_model(false)
{
if (this->A > 3 || this->A < -3)
throw std::invalid_argument("Invalid value for A must be in interval [-3,3]");
if (this->B < 0)
throw std::invalid_argument("Invalid value for B must be > 0");
if (this->D > 3 || this->D < -3)
throw std::invalid_argument("Invalid value for D must be in interval [-3,3]");
if (this->F > 3 || this->F < -3)
throw std::invalid_argument("Invalid value for F must be in interval [-3,3]");
}
double GuideRateModel::update_delay() const {
return this->time_interval;
}
double GuideRateModel::eval(double pot, double R1, double R2) const {
if (this->default_model)
throw std::invalid_argument("The default GuideRateModel can not be evaluated - must enter GUIDERAT information explicitly.");
double denom = this->B + this->C*std::pow(R1, this->D) + this->E*std::pow(R2, this->F);
/*
The values pot, R1 and R2 are runtime simulation results, so here
basically anything could happen. Quite dangerous to have hard error
handling here?
*/
if (denom <= 0)
throw std::range_error("Invalid denominator: " + std::to_string(denom));
return std::pow(pot, this->A) / denom;
}
bool GuideRateModel::operator==(const GuideRateModel& other) const {
return (this->time_interval == other.time_interval) &&
(this->phase == other.phase) &&
(this->A == other.A) &&
(this->B == other.B) &&
(this->C == other.C) &&
(this->D == other.D) &&
(this->E == other.E) &&
(this->F == other.F) &&
(this->allow_increase == other.allow_increase) &&
(this->damping_factor == other.damping_factor) &&
(this->use_free_gas == other.use_free_gas);
}
bool GuideRateModel::operator!=(const GuideRateModel& other) const {
return !(*this == other);
}
}

View File

@@ -34,6 +34,7 @@
#include <opm/parser/eclipse/Deck/Section.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/C.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/G.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/V.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/W.hpp>
@@ -120,6 +121,7 @@ namespace {
wlist_manager( this->m_timeMap, std::make_shared<WListManager>()),
udq_config(this->m_timeMap, std::make_shared<UDQConfig>(deck)),
udq_active(this->m_timeMap, std::make_shared<UDQActive>()),
guide_rate_model(this->m_timeMap, std::make_shared<GuideRateModel>()),
global_whistctl_mode(this->m_timeMap, WellProducer::CMODE_UNDEFINED),
rft_config(this->m_timeMap)
{
@@ -332,6 +334,9 @@ namespace {
else if (keyword.name() == "GEFAC")
handleGEFAC(keyword, currentStep, parseContext, errors);
else if (keyword.name() == "GUIDERAT")
handleGUIDERAT(keyword, currentStep);
else if (keyword.name() == "TUNING")
handleTUNING(keyword, currentStep);
@@ -1561,6 +1566,27 @@ namespace {
}
}
void Schedule::handleGUIDERAT( const DeckKeyword& keyword, size_t currentStep) {
const auto& record = keyword.getRecord(0);
double min_calc_delay = record.getItem<ParserKeywords::GUIDERAT::MIN_CALC_TIME>().getSIDouble(0);
auto phase = GuideRateTargetFromString(record.getItem<ParserKeywords::GUIDERAT::NOMINATED_PHASE>().getTrimmedString(0));
double A = record.getItem<ParserKeywords::GUIDERAT::A>().get<double>(0);
double B = record.getItem<ParserKeywords::GUIDERAT::B>().get<double>(0);
double C = record.getItem<ParserKeywords::GUIDERAT::C>().get<double>(0);
double D = record.getItem<ParserKeywords::GUIDERAT::D>().get<double>(0);
double E = record.getItem<ParserKeywords::GUIDERAT::E>().get<double>(0);
double F = record.getItem<ParserKeywords::GUIDERAT::F>().get<double>(0);
bool allow_increase = DeckItem::to_bool( record.getItem<ParserKeywords::GUIDERAT::ALLOW_INCREASE>().getTrimmedString(0));
double damping_factor = record.getItem<ParserKeywords::GUIDERAT::DAMPING_FACTOR>().get<double>(0);
bool use_free_gas = DeckItem::to_bool( record.getItem<ParserKeywords::GUIDERAT::USE_FREE_GAS>().getTrimmedString(0));
auto new_model = std::make_shared<GuideRateModel>(min_calc_delay, phase, A, B, C, D, E, F, allow_increase, damping_factor, use_free_gas);
const auto& current_model = this->guide_rate_model.get(currentStep);
if (*current_model != *new_model)
this->guide_rate_model.update( currentStep, new_model );
}
void Schedule::handleTUNING( const DeckKeyword& keyword, size_t currentStep) {
@@ -2494,6 +2520,13 @@ void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, c
return *ptr;
}
const GuideRateModel& Schedule::guideRateModel(size_t timeStep) const {
const auto& ptr = this->guide_rate_model.get(timeStep);
if (ptr == nullptr)
throw std::runtime_error("Tried to dereference invalid GuideRateModel - internal error in opm/flow");
return *ptr;
}
size_t Schedule::size() const {
return this->m_timeMap.size();

View File

@@ -760,4 +760,25 @@ namespace Opm {
return static_cast<GroupType>(static_cast<std::underlying_type<GroupType>::type>(lhs) & static_cast<std::underlying_type<GroupType>::type>(rhs));
}
GuideRateTarget GuideRateTargetFromString(const std::string& s) {
if (s == "OIL")
return GuideRateTarget::OIL;
if (s == "LIQ")
return GuideRateTarget::LIQ;
if (s == "GAS")
return GuideRateTarget::GAS;
if (s == "RES")
return GuideRateTarget::RES;
if (s == "COMB")
return GuideRateTarget::COMB;
if (s == "NONE")
return GuideRateTarget::NONE;
throw std::invalid_argument("Could not convert: " + s + " to a valid GuideRateTarget enum value");
}
}

View File

@@ -32,6 +32,7 @@
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group2.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp>
@@ -295,3 +296,12 @@ BOOST_AUTO_TEST_CASE(createDeckWithGCONPROD) {
BOOST_CHECK_EQUAL(ctrl2.exceed_action, GroupProductionExceedLimit::CON);
}
BOOST_AUTO_TEST_CASE(TESTGuideRateModel) {
Opm::GuideRateModel grc_default;
BOOST_CHECK_THROW(Opm::GuideRateModel(0.0,GuideRateTarget::NONE, -5,0,0,0,0,0,true,1,true), std::invalid_argument);
BOOST_CHECK_THROW(grc_default.eval(1,0.50,0.50), std::invalid_argument);
Opm::GuideRateModel grc_delay(10, GuideRateTarget::NONE, 1,1,0,0,0,0,true,1,true);
BOOST_CHECK_NO_THROW(grc_delay.eval(1.0, 0.5, 0.5));
}