Merge pull request #2495 from bska/walq

Implement WALQ Summary Vector
This commit is contained in:
Bård Skaflestad 2021-08-20 21:41:31 +02:00 committed by GitHub
commit 981e977da4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 18 deletions

View File

@ -591,11 +591,13 @@ namespace {
sWell[Ix::HistBHPTarget] = sWell[Ix::BHPTarget];
if (pc.alq_value != 0.0) {
auto vfpTable = sched[sim_step].vfpprod(pc.vfp_table_number);
if (vfpTable.getALQType() == Opm::VFPProdTable::ALQ_TYPE::ALQ_GRAT) {
const auto alqType = sched[sim_step].vfpprod(pc.vfp_table_number).getALQType();
if (alqType == Opm::VFPProdTable::ALQ_TYPE::ALQ_GRAT) {
sWell[Ix::Alq_value] = static_cast<float>(units.from_si(M::gas_surface_rate, pc.alq_value));
}
else if ((vfpTable.getALQType() == Opm::VFPProdTable::ALQ_TYPE::ALQ_IGLR) || (vfpTable.getALQType() == Opm::VFPProdTable::ALQ_TYPE::ALQ_TGLR)) {
else if ((alqType == Opm::VFPProdTable::ALQ_TYPE::ALQ_IGLR) ||
(alqType == Opm::VFPProdTable::ALQ_TYPE::ALQ_TGLR))
{
sWell[Ix::Alq_value] = static_cast<float>(units.from_si(M::gas_oil_ratio, pc.alq_value));
}
else {

View File

@ -34,10 +34,12 @@
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.hpp>
@ -461,6 +463,7 @@ struct fn_args
const Opm::data::GroupAndNetworkValues& grp_nwrk;
const Opm::out::RegionCache& regionCache;
const Opm::EclipseGrid& grid;
const Opm::Schedule& schedule;
const std::vector< std::pair< std::string, double > > eff_factors;
const Opm::Inplace& initial_inplace;
const Opm::Inplace& inplace;
@ -532,14 +535,55 @@ double efac( const std::vector<std::pair<std::string,double>>& eff_factors, cons
return (it != eff_factors.end()) ? it->second : 1.0;
}
/*
This is bit dangerous, exactly how the ALQ value should be interpreted varies
between the different VFP tables. The code here assumes - without checking -
that it represents gas lift rate.
*/
inline quantity glir( const fn_args& args ) {
double alq_rate = 0;
inline quantity artificial_lift_quantity( const fn_args& args ) {
// Note: This function is intentionally supported only at the well level
// (meaning there's no loop over args.schedule_wells by intention). Its
// purpose is to calculate WALQ only.
auto alq = quantity { 0.0, measure::identity };
if (args.schedule_wells.empty()) {
return alq;
}
const auto* well = args.schedule_wells.front();
if (well->isInjector()) {
return alq;
}
auto xwPos = args.wells.find(well->name());
if ((xwPos == args.wells.end()) ||
(xwPos->second.dynamicStatus == Opm::Well::Status::SHUT))
{
return alq;
}
alq.value = well->productionControls(args.st).alq_value;
return alq;
}
inline bool
has_alq_type(const Opm::ScheduleState& sched_state,
const Opm::Well::ProductionControls& pc)
{
return sched_state.vfpprod.has(pc.vfp_table_number);
}
inline Opm::VFPProdTable::ALQ_TYPE
alq_type(const Opm::ScheduleState& sched_state,
const Opm::Well::ProductionControls& pc)
{
return sched_state.vfpprod(pc.vfp_table_number).getALQType();
}
inline quantity glir( const fn_args& args ) {
if (args.schedule_wells.empty()) {
return { 0.0, measure::gas_surface_rate };
}
const auto& sched_state = args.schedule[args.sim_step];
double alq_rate = 0.0;
for (const auto* well : args.schedule_wells) {
if (well->isInjector()) {
continue;
@ -552,8 +596,17 @@ inline quantity glir( const fn_args& args ) {
continue;
}
const double eff_fac = efac(args.eff_factors, well->name());
const auto& production = well->productionControls(args.st);
if (! has_alq_type(sched_state, production)) {
continue;
}
const auto thisAlqType = alq_type(sched_state, production);
if (thisAlqType != Opm::VFPProdTable::ALQ_TYPE::ALQ_GRAT) {
continue;
}
const double eff_fac = efac(args.eff_factors, well->name());
alq_rate += eff_fac * xwPos->second.rates.get(rt::alq, production.alq_value);
}
@ -1526,6 +1579,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "WEPR", rate< rt::energy, producer > },
{ "WTPRHEA", rate< rt::energy, producer > },
{ "WGLIR", glir},
{ "WALQ", artificial_lift_quantity },
{ "WNPR", rate< rt::solvent, producer > },
{ "WCPR", rate< rt::polymer, producer > },
{ "WSPR", rate< rt::brine, producer > },
@ -2373,8 +2427,10 @@ namespace Evaluator {
wells, this->group_name(), this->node_.keyword, stepSize, static_cast<int>(sim_step),
std::max(0, this->node_.number),
this->node_.fip_region,
st, simRes.wellSol, simRes.grpNwrkSol, input.reg, input.grid,
std::move(efac.factors), input.initial_inplace, simRes.inplace, input.sched.getUnits()
st, simRes.wellSol, simRes.grpNwrkSol,
input.reg, input.grid, input.sched,
std::move(efac.factors), input.initial_inplace, simRes.inplace,
input.sched.getUnits()
};
const auto& usys = input.es.getUnits();
@ -2435,7 +2491,6 @@ namespace Evaluator {
}
};
class AquiferValue: public Base
{
public:
@ -2674,9 +2729,10 @@ namespace Evaluator {
explicit Factory(const Opm::EclipseState& es,
const Opm::EclipseGrid& grid,
const Opm::Schedule& sched,
const Opm::SummaryState& st,
const Opm::UDQConfig& udq)
: es_(es), grid_(grid), st_(st), udq_(udq)
: es_(es), sched_(sched), grid_(grid), st_(st), udq_(udq)
{}
~Factory() = default;
@ -2690,6 +2746,7 @@ namespace Evaluator {
private:
const Opm::EclipseState& es_;
const Opm::Schedule& sched_;
const Opm::EclipseGrid& grid_;
const Opm::SummaryState& st_;
const Opm::UDQConfig& udq_;
@ -2943,7 +3000,7 @@ namespace Evaluator {
const fn_args args {
{}, "", this->node_->keyword, 0.0, 0, std::max(0, this->node_->number),
this->node_->fip_region,
this->st_, {}, {}, reg, this->grid_,
this->st_, {}, {}, reg, this->grid_, this->sched_,
{}, {}, {}, Opm::UnitSystem(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC)
};
@ -3296,7 +3353,7 @@ SummaryImplementation(const EclipseState& es,
};
Evaluator::Factory evaluatorFactory {
es, grid, st, sched.getUDQConfig(sched.size() - 1)
es, grid, sched, st, sched.getUDQConfig(sched.size() - 1)
};
this->configureTimeVectors(es, sumcfg);

View File

@ -193,7 +193,6 @@
"WGPRFP",
"WTHPFP",
"WBHPFP",
"WGLIR",
"WOGLR",
"WGCV",
"WGQ",

View File

@ -10291,6 +10291,9 @@ WWPRH
WGLIR
'B-*' 'C-*' /
WALQ
'B-*' /
-- Production cumulatives
WOPT
'B-*' 'C-*' /

View File

@ -1155,7 +1155,63 @@ BOOST_AUTO_TEST_CASE(group_group) {
}
}
namespace {
data::Wells glir_alq_data()
{
auto wells = data::Wells{};
using opt = data::Rates::opt;
auto& b1h = wells["B-1H"];
auto& b2h = wells["B-2H"];
auto& b3h = wells["B-3H"];
b1h.rates.set(opt::alq, 1234.56*unit::cubic(unit::meter)/unit::day);
b2h.rates.set(opt::alq, 2345.67*unit::cubic(unit::meter)/unit::day);
b3h.rates.set(opt::alq, 3456.78*unit::cubic(unit::meter)/unit::day);
return wells;
}
}
BOOST_AUTO_TEST_CASE(GLIR_and_ALQ)
{
const auto deck = Parser{}.parseFile("2_WLIFT_MODEL5_NOINC.DATA");
const auto es = EclipseState { deck };
const auto sched = Schedule { deck, es, std::make_shared<Python>() };
const auto cfg = SummaryConfig { deck, sched, es.fieldProps(), es.aquifer() };
const auto name = "glir_and_alq";
WorkArea ta{ "summary_test" };
ta.makeSubDir(name);
const auto wellData = glir_alq_data();
auto st = SummaryState { TimeService::now() };
auto writer = out::Summary{ es, cfg, es.getInputGrid(), sched, name };
writer.eval(st, 0, 0*day, wellData, {}, {}, {}, {}, {});
writer.add_timestep(st, 0, false);
writer.eval(st, 1, 1*day, wellData, {}, {}, {}, {}, {});
writer.add_timestep(st, 1, false);
writer.eval(st, 2, 2*day, wellData, {}, {}, {}, {}, {});
writer.add_timestep(st, 2, false);
writer.write();
auto res = readsum(name);
const auto* resp = res.get();
BOOST_CHECK_CLOSE(1234.56, ecl_sum_get_well_var(resp, 1, "B-1H", "WGLIR"), 1.0e-5);
BOOST_CHECK_CLOSE(2345.67, ecl_sum_get_well_var(resp, 1, "B-2H", "WGLIR"), 1.0e-5);
BOOST_CHECK_CLOSE(3456.78, ecl_sum_get_well_var(resp, 1, "B-3H", "WGLIR"), 1.0e-5);
BOOST_CHECK_CLOSE(1234.56 + 2345.67 + 3456.78,
ecl_sum_get_group_var(resp, 1, "B1", "GGLIR"), 1.0e-5);
BOOST_CHECK_CLOSE(0.0, ecl_sum_get_well_var(resp, 1, "B-1H", "WALQ"), 1.0e-5);
BOOST_CHECK_CLOSE(0.0, ecl_sum_get_well_var(resp, 1, "B-2H", "WALQ"), 1.0e-5);
BOOST_CHECK_CLOSE(0.0, ecl_sum_get_well_var(resp, 1, "B-3H", "WALQ"), 1.0e-5);
}
BOOST_AUTO_TEST_CASE(connection_kewords) {
setup cfg( "test_summary_connection" );