Add class WellMatcher and use it UDQ evaluation

This commit is contained in:
Joakim Hove 2020-10-30 13:36:41 +01:00
parent 279871df05
commit 7ef7e3017e
14 changed files with 289 additions and 80 deletions

View File

@ -134,6 +134,7 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/Well/injection.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellMatcher.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WList.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.cpp
src/opm/parser/eclipse/EclipseState/Schedule/Well/WellEconProductionLimits.cpp
@ -704,6 +705,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/Well/InjectionControls.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WList.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellMatcher.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellEconProductionLimits.hpp
opm/parser/eclipse/EclipseState/Schedule/Well/WellFoamProperties.hpp

View File

@ -121,7 +121,7 @@ void msim::run_step(const Schedule& schedule, Action::State& action_state, Summa
group_nwrk_data,
{});
schedule.getUDQConfig( report_step ).eval(report_step, st, udq_state);
schedule.getUDQConfig( report_step ).eval(report_step, schedule.wellMatcher(report_step), st, udq_state);
this->output(action_state,
st,

View File

@ -44,6 +44,7 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Network/ExtNetwork.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellTestConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellMatcher.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/Actions.hpp>
#include <opm/common/utility/ActiveGridCells.hpp>
@ -193,6 +194,7 @@ namespace Opm
bool hasWell(const std::string& wellName) const;
bool hasWell(const std::string& wellName, std::size_t timeStep) const;
WellMatcher wellMatcher(std::size_t report_step) const;
std::vector<std::string> wellNames(const std::string& pattern, std::size_t timeStep, const std::vector<std::string>& matching_wells = {}) const;
std::vector<std::string> wellNames(const std::string& pattern) const;
std::vector<std::string> wellNames(std::size_t timeStep) const;

View File

@ -43,6 +43,7 @@ namespace Opm {
class SummaryState;
class UDQState;
class KeywordLocation;
class WellMatcher;
class UDQConfig {
public:
@ -61,7 +62,7 @@ namespace Opm {
void add_assign(const std::string& quantity, const std::vector<std::string>& selector, double value, std::size_t report_step);
void add_define(const std::string& quantity, const KeywordLocation& location, const std::vector<std::string>& expression);
void eval(std::size_t report_step, SummaryState& st, UDQState& udq_state) const;
void eval(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const;
const UDQDefine& define(const std::string& key) const;
std::vector<UDQDefine> definitions() const;
std::vector<UDQDefine> definitions(UDQVarType var_type) const;

View File

@ -29,6 +29,7 @@
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellMatcher.hpp>
namespace Opm {
class SummaryState;
@ -37,7 +38,7 @@ namespace Opm {
class UDQContext{
public:
UDQContext(const UDQFunctionTable& udqft, SummaryState& summary_state, UDQState& udq_state);
UDQContext(const UDQFunctionTable& udqft, const WellMatcher& wm, SummaryState& summary_state, UDQState& udq_state);
std::optional<double> get(const std::string& key) const;
std::optional<double> get_well_var(const std::string& well, const std::string& var) const;
std::optional<double> get_group_var(const std::string& group, const std::string& var) const;
@ -46,9 +47,11 @@ namespace Opm {
void update_define(const std::string& keyword, const UDQSet& udq_result);
const UDQFunctionTable& function_table() const;
std::vector<std::string> wells() const;
std::vector<std::string> wells(const std::string& pattern) const;
std::vector<std::string> groups() const;
private:
const UDQFunctionTable& udqft;
WellMatcher well_matcher;
SummaryState& summary_state;
UDQState& udq_state;
//std::unordered_map<std::string, UDQSet> udq_results;

View File

@ -0,0 +1,43 @@
/*
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 WELL_MATCHER_HPP
#define WELL_MATCHER_HPP
#include <vector>
#include <string>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.hpp>
namespace Opm {
class WellMatcher {
public:
WellMatcher() = default;
explicit WellMatcher(const std::vector<std::string>& wells);
WellMatcher(const std::vector<std::string>& wells, const WListManager& wlm);
const std::vector<std::string>& wells() const;
std::vector<std::string> wells(const std::string& pattern) const;
private:
std::vector<std::string> m_wells;
WListManager m_wlm;
};
}
#endif

View File

@ -1086,6 +1086,18 @@ private:
return {};
}
WellMatcher Schedule::wellMatcher(std::size_t report_step) const {
std::vector<std::string> wnames;
for (const auto& well_pair : this->wells_static) {
const auto& dynamic_state = well_pair.second;
if (dynamic_state.get(report_step))
wnames.push_back(well_pair.first);
}
return WellMatcher(wnames, this->getWListManager(report_step));
}
std::vector<std::string> Schedule::wellNames(const std::string& pattern) const {
return this->wellNames(pattern, this->size() - 1);
}

View File

@ -145,28 +145,34 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const
const auto& string_value = std::get<std::string>( this->value );
auto data_type = UDQ::targetType(string_value);
if (data_type == UDQVarType::WELL_VAR) {
const auto& wells = context.wells();
const auto& all_wells = context.wells();
auto res = UDQSet::wells(string_value, all_wells);
if (this->selector.size() > 0) {
const std::string& well_pattern = this->selector[0];
if (well_pattern.find("*") == std::string::npos)
return this->sign * UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value));
else {
auto res = UDQSet::wells(string_value, wells);
int fnmatch_flags = 0;
for (const auto& well : wells) {
if (fnmatch(well_pattern.c_str(), well.c_str(), fnmatch_flags) == 0)
res.assign(well, context.get_well_var(well, string_value));
}
return this->sign * res;
}
} else {
auto res = UDQSet::wells(string_value, wells);
for (const auto& well : wells)
if (this->selector.empty()) {
for (const auto& well : all_wells)
res.assign(well, context.get_well_var(well, string_value));
return this->sign * res;
} else {
const std::string& well_pattern = this->selector[0];
if (well_pattern.find('*') == std::string::npos)
/*
The right hand side is a fully qualified well name without
any '*', in this case the right hand side evaluates to a
*scalar* - and that scalar value is distributed among all
the wells in the result set.
*/
res.assign( context.get_well_var(well_pattern, string_value));
else {
/*
The right hand side is a set of wells. The result set will
be updated for all wells in the right hand set, wells
missing in the right hand set will be undefined in the
result set.
*/
for (const auto& wname : context.wells(well_pattern))
res.assign(wname, context.get_well_var(wname, string_value));
}
}
return this->sign * res;
}
if (data_type == UDQVarType::GROUP_VAR) {

View File

@ -302,9 +302,9 @@ namespace Opm {
this->type_count == data.type_count;
}
void UDQConfig::eval(std::size_t report_step, SummaryState& st, UDQState& udq_state) const {
void UDQConfig::eval(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const {
const auto& func_table = this->function_table();
UDQContext context(func_table, st, udq_state);
UDQContext context(func_table, wm, st, udq_state);
for (const auto& assign : this->assignments(UDQVarType::WELL_VAR)) {
if (udq_state.assign(report_step, assign.keyword())) {

View File

@ -41,8 +41,9 @@ bool is_udq(const std::string& key) {
}
UDQContext::UDQContext(const UDQFunctionTable& udqft_arg, SummaryState& summary_state_arg, UDQState& udq_state_arg) :
UDQContext::UDQContext(const UDQFunctionTable& udqft_arg, const WellMatcher& wm, SummaryState& summary_state_arg, UDQState& udq_state_arg) :
udqft(udqft_arg),
well_matcher(wm),
summary_state(summary_state_arg),
udq_state(udq_state_arg)
{
@ -117,7 +118,11 @@ bool is_udq(const std::string& key) {
}
std::vector<std::string> UDQContext::wells() const {
return this->summary_state.wells();
return this->well_matcher.wells();
}
std::vector<std::string> UDQContext::wells(const std::string& pattern) const {
return this->well_matcher.wells(pattern);
}
std::vector<std::string> UDQContext::groups() const {

View File

@ -0,0 +1,66 @@
/*
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 <algorithm>
#include <fnmatch.h>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellMatcher.hpp>
namespace Opm {
WellMatcher::WellMatcher(const std::vector<std::string>& wells) :
m_wells(wells)
{}
WellMatcher::WellMatcher(const std::vector<std::string>& wells, const WListManager &wlm) :
m_wells(wells),
m_wlm(wlm)
{}
const std::vector<std::string>& WellMatcher::wells() const {
return this->m_wells;
}
std::vector<std::string> WellMatcher::wells(const std::string& pattern) const {
if (pattern.size() == 0)
return {};
// WLIST
if (pattern[0] == '*' && pattern.size() > 1)
return this->m_wlm.wells(pattern);
// Normal pattern matching
auto star_pos = pattern.find('*');
if (star_pos != std::string::npos) {
std::vector<std::string> names;
for (const auto& wname : this->m_wells) {
int flags = 0;
if (fnmatch(pattern.c_str(), wname.c_str(), flags) == 0)
names.push_back(wname);
}
return names;
}
auto name_iter = std::find(this->m_wells.begin(), this->m_wells.end(), pattern);
if (name_iter != this->m_wells.end())
return { pattern };
return {};
}
}

View File

@ -41,6 +41,7 @@
#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/Well/WellMatcher.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
@ -3305,6 +3306,36 @@ BOOST_AUTO_TEST_CASE(WellNames) {
auto abs_all = schedule.wellNames();
BOOST_CHECK_EQUAL(abs_all.size(), 9U);
WellMatcher wm0( {}, WListManager{});
const auto& wml0 = wm0.wells();
BOOST_CHECK(wml0.empty());
WellMatcher wm1( {"W1", "W2", "W3", "P1", "P2", "P3"}, WListManager{});
const std::vector<std::string> pwells = {"P1", "P2", "P3"};
BOOST_CHECK( pwells == wm1.wells("P*"));
auto wm2 = schedule.wellMatcher(4);
const auto& all_wells = wm2.wells();
BOOST_CHECK_EQUAL(all_wells.size(), 9);
for (const auto& w : std::vector<std::string>{"W1", "W2", "W3", "I1", "I2", "I3", "DEFAULT", "ALLOW", "BAN"})
BOOST_CHECK(has(all_wells, w));
const std::vector<std::string> wwells = {"W1", "W2", "W3"};
BOOST_CHECK( wwells == wm2.wells("W*"));
BOOST_CHECK( wm2.wells("XYZ*").empty() );
BOOST_CHECK( wm2.wells("XYZ").empty() );
auto def = wm2.wells("DEFAULT");
BOOST_CHECK_EQUAL(def.size() , 1);
BOOST_CHECK_EQUAL(def[0], "DEFAULT");
auto l2 = wm2.wells("*ILIST");
BOOST_CHECK_EQUAL( l2.size(), 2U);
BOOST_CHECK( has(l2, "I1"));
BOOST_CHECK( has(l2, "I2"));
}

View File

@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(GROUP_VARIABLES)
UDQDefine def_group(udqp, "GUOPRL", location, {"(", "5000", "-", "GOPR", "LOWER", "*", "0.13", "-", "GOPR", "UPPER", "*", "0.15", ")" , "*", "0.89"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, {}, st, udq_state);
double gopr_lower = 1234;
double gopr_upper = 4321;
@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(SUBTRACT)
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1"}), st, udq_state);
st.update_well_var("P1", "WOPR", 4);
auto res = def.eval(context);
@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(TEST)
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1", "P2"}), st, udq_state);
st.update_group_var("MAU", "GOPR", 4);
st.update_group_var("XXX", "GOPR", 5);
@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(MIX_SCALAR) {
UDQDefine def_add(udqp, "WU", location, {"WOPR", "+", "1"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1"}), st, udq_state);
st.update_well_var("P1", "WOPR", 1);
@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(UDQFieldSetTest) {
UDQFunctionTable udqft(udqp);
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1", "P2", "P3", "P4"}), st, udq_state);
st.update_well_var("P1", "WOPR", 1.0);
st.update_well_var("P2", "WOPR", 2.0);
@ -303,7 +303,7 @@ BOOST_AUTO_TEST_CASE(UDQ_GROUP_TEST) {
UDQDefine def_fopr(udqp, "FUOPR", location, {"SUM", "(", "GOPR", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, {}, st, udq_state);
st.update_group_var("G1", "GOPR", 1.0);
st.update_group_var("G2", "GOPR", 2.0);
@ -326,7 +326,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
UDQDefine def(udqp, "WUBHP", location, {"WBHP"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"W1", "W2", "W3"}), st, udq_state);
st.update_well_var("W1", "WBHP", 11);
st.update_well_var("W2", "WBHP", 2);
@ -345,7 +345,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
UDQDefine def(udqp, "WUBHP", location, {"WBHP" , "'P*'"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"I1", "I2", "P1", "P2"}), st, udq_state);
st.update_well_var("P1", "WBHP", 1);
@ -363,7 +363,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
UDQDefine def(udqp, "WUBHP", location, {"NINT" , "(", "WBHP", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1", "P2", "I1", "I2"}), st, udq_state);
st.update_well_var("P1", "WBHP", 4);
st.update_well_var("P2", "WBHP", 3);
st.update_well_var("I1", "WBHP", 2);
@ -579,7 +579,7 @@ BOOST_AUTO_TEST_CASE(UDQ_CONTEXT) {
UDQFunctionTable func_table;
UDQParams udqp;
UDQState udq_state(udqp.undefinedValue());
UDQContext ctx(func_table, st, udq_state);
UDQContext ctx(func_table, {}, st, udq_state);
BOOST_CHECK_EQUAL(*ctx.get("JAN"), 1.0);
BOOST_CHECK_THROW(ctx.get("NO_SUCH_KEY"), std::out_of_range);
@ -990,7 +990,7 @@ BOOST_AUTO_TEST_CASE(UDQ_POW_TEST) {
UDQDefine def_pow2(udqp, "WU", location, {"(", "WOPR", "+", "WWPR", ")", "^", "(", "WOPR", "+" , "WGOR", "*", "WWIR", "-", "WBHP", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1"}), st, udq_state);
st.update_well_var("P1", "WOPR", 1);
st.update_well_var("P1", "WWPR", 2);
@ -1011,7 +1011,7 @@ BOOST_AUTO_TEST_CASE(UDQ_CMP_TEST) {
UDQDefine def_cmp(udqp, "WU", location, {"WOPR", ">", "WWPR", "+", "WGOR", "*", "WWIR"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1", "P2"}), st, udq_state);
st.update_well_var("P1", "WOPR", 0);
st.update_well_var("P1", "WWPR", 10);
@ -1040,61 +1040,61 @@ BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
UDQFunctionTable udqft;
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"PA1", "PB2", "PC3", "PD4"}), st, udq_state);
st.update_well_var("P1", "WOPR", 1);
st.update_well_var("P2", "WOPR", 2);
st.update_well_var("P3", "WOPR", 3);
st.update_well_var("P4", "WOPR", 4);
st.update_well_var("PA1", "WOPR", 1);
st.update_well_var("PB2", "WOPR", 2);
st.update_well_var("PC3", "WOPR", 3);
st.update_well_var("PD4", "WOPR", 4);
st.update_well_var("P1", "WWPR", 1);
st.update_well_var("P2", "WWPR", 2);
st.update_well_var("P3", "WWPR", 3);
st.update_well_var("P4", "WWPR", 4);
st.update_well_var("PA1", "WWPR", 1);
st.update_well_var("PB2", "WWPR", 2);
st.update_well_var("PC3", "WWPR", 3);
st.update_well_var("PD4", "WWPR", 4);
{
UDQDefine def(udqp, "WUOPR", location, {"WOPR", "'*1'"});
UDQDefine def(udqp, "WUOPR", location, {"WOPR", "'PA*'"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4U, res.size());
auto well1 = res["P1"];
auto well1 = res["PA1"];
BOOST_CHECK( well1.defined() );
BOOST_CHECK_EQUAL(well1.get() , 1);
auto well2 = res["P2"];
auto well2 = res["PB2"];
BOOST_CHECK( !well2.defined() );
auto well4 = res["P4"];
auto well4 = res["PD4"];
BOOST_CHECK( !well4.defined() );
}
{
UDQDefine def(udqp, "WUOPR", location, {"1"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4U, res.size());
auto well1 = res["P1"];
auto well1 = res["PA1"];
BOOST_CHECK( well1.defined() );
BOOST_CHECK_EQUAL(well1.get() , 1);
auto well2 = res["P2"];
auto well2 = res["PB2"];
BOOST_CHECK( well2.defined() );
BOOST_CHECK_EQUAL(well2.get() , 1);
auto well4 = res["P4"];
auto well4 = res["PD4"];
BOOST_CHECK( well4.defined() );
BOOST_CHECK_EQUAL(well4.get() , 1);
}
{
UDQDefine def(udqp, "WUOPR", location, {"WOPR", "'P1'"});
UDQDefine def(udqp, "WUOPR", location, {"WOPR", "'PA1'"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4U, res.size());
auto well1 = res["P1"];
auto well1 = res["PA1"];
BOOST_CHECK( well1.defined() );
BOOST_CHECK_EQUAL(well1.get() , 1);
auto well2 = res["P2"];
auto well2 = res["PB2"];
BOOST_CHECK( well2.defined() );
BOOST_CHECK_EQUAL(well2.get() , 1);
auto well4 = res["P4"];
auto well4 = res["PD4"];
BOOST_CHECK( well4.defined() );
BOOST_CHECK_EQUAL(well4.get() , 1);
@ -1110,7 +1110,7 @@ BOOST_AUTO_TEST_CASE(UDQ_SORTD_NAN) {
UDQDefine def_sort(udqp , "WUPR3", location, {"SORTD", "(", "WUPR1", ")" });
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"OP1", "OP2", "OP3", "OP4"}), st, udq_state);
st.update_well_var("OP1", "WWIR", 1.0);
st.update_well_var("OP2", "WWIR", 2.0);
@ -1156,7 +1156,7 @@ BOOST_AUTO_TEST_CASE(UDQ_SORTA) {
UDQDefine def_sort(udqp , "WUPR3", location, {"SORTA", "(", "WUPR1", ")" });
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"OPL01", "OPL02", "OPU01", "OPU02"}), st, udq_state);
st.update_well_var("OPL01", "WWCT", 0.7);
st.update_well_var("OPL02", "WWCT", 0.8);
@ -1186,7 +1186,7 @@ BOOST_AUTO_TEST_CASE(UDQ_BASIC_MATH_TEST) {
UDQDefine def_wuwct(udqp , "WUWCT", location, {"WWPR", "/", "(", "WOPR", "+", "WWPR", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1", "P2", "P3", "P4"}), st, udq_state);
st.update_well_var("P1", "WOPR", 1);
st.update_well_var("P2", "WOPR", 2);
@ -1248,7 +1248,7 @@ BOOST_AUTO_TEST_CASE(DECK_TEST) {
UDQDefine def(udqp, "WUOPRL", location, {"(", "WOPR", "OP1", "-", "150", ")", "*", "0.90"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"OP1", "OP2", "OP3"}), st, udq_state);
st.update_well_var("OP1", "WOPR", 300);
st.update_well_var("OP2", "WOPR", 3000);
@ -1284,7 +1284,7 @@ BOOST_AUTO_TEST_CASE(UDQ_PARSE_ERROR) {
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1"}), st, udq_state);
st.update_well_var("P1", "WBHP", 1);
auto res = def1.eval(context);
@ -1310,7 +1310,7 @@ BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"P1", "P2"}), st, udq_state);
st.update_well_var("P1", "WBHP", 1);
st.update_well_var("P2", "WBHP", 2);
@ -1693,7 +1693,7 @@ UDQ
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, {}, st, udq_state);
auto res0 = def0.eval(context);
BOOST_CHECK_CLOSE( res0[0].get(), -0.00125*3, 1e-6);
@ -1719,7 +1719,7 @@ UDQ
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, {}, st, udq_state);
const double fwpr = 7;
const double fopr = 4;
const double fgpr = 7;
@ -1761,7 +1761,7 @@ UDQ
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, WellMatcher({"W1", "W2", "W3"}), st, udq_state);
st.update_well_var("W1", "WOPR", 1);
st.update_well_var("W2", "WOPR", 2);
st.update_well_var("W3", "WOPR", 3);
@ -1800,7 +1800,7 @@ UDQ
SummaryState st(std::chrono::system_clock::now());
auto undefined_value = udq.params().undefinedValue();
UDQState udq_state(undefined_value);
udq.eval(0, st, udq_state);
udq.eval(0, {}, st, udq_state);
BOOST_CHECK_EQUAL( st.get("FU_UADD"), 12); // 10 + 2
@ -1827,7 +1827,7 @@ DEFINE FU_PAR2 FU_PAR3 /
auto undefined_value = udq.params().undefinedValue();
UDQState udq_state(undefined_value);
st.update("FMWPR", 100);
udq.eval(0, st, udq_state);
udq.eval(0, {}, st, udq_state);
BOOST_CHECK_EQUAL(st.get("FU_PAR2"), 100);
}
@ -1845,7 +1845,7 @@ DEFINE FU_PAR3 FU_PAR2 + 1/
SummaryState st(std::chrono::system_clock::now());
auto undefined_value = udq.params().undefinedValue();
UDQState udq_state(undefined_value);
udq.eval(0, st, udq_state);
udq.eval(0, {}, st, udq_state);
BOOST_CHECK_EQUAL(st.get("FU_PAR2"), undefined_value);
BOOST_CHECK_EQUAL(st.get("FU_PAR3"), undefined_value);
@ -1963,7 +1963,7 @@ DEFINE WUGASRA 750000 - WGLIR '*' /
st.update_well_var("W2", "WGLIR", 2);
st.update_well_var("W3", "WGLIR", 3);
udq.eval(0, st, udq_state);
udq.eval(0, WellMatcher({"W1", "W2", "W3"}), st, udq_state);
{
std::unordered_set<std::string> required_keys;
udq.required_summary(required_keys);
@ -2168,7 +2168,7 @@ DEFINE FU_VAR91 GOPR TEST /
st.update_well_var("W3", "WGLIR", 3);
st.update_group_var("TEST", "GOPR", 1);
udq.eval(0, st, udq_state);
udq.eval(0, {}, st, udq_state);
}
@ -2189,7 +2189,7 @@ UDQ
UDQState udq_state(undefined_value);
SummaryState st(std::chrono::system_clock::now());
BOOST_CHECK_THROW(udq.eval(0, st, udq_state), std::exception);
BOOST_CHECK_THROW(udq.eval(0, {}, st, udq_state), std::exception);
}
@ -2215,7 +2215,7 @@ UDQ
BOOST_CHECK(required_keys.empty());
}
udq.eval(0, st, udq_state);
udq.eval(0, {}, st, udq_state);
BOOST_CHECK_EQUAL(st.get("FU_VAR1"), 10);
}
@ -2256,7 +2256,7 @@ TSTEP
// Counting: 1,2,3,4,5
for (std::size_t report_step = 0; report_step < 5; report_step++) {
const auto& udq = schedule.getUDQConfig(report_step);
udq.eval(report_step, st, udq_state);
udq.eval(report_step, schedule.wellMatcher(report_step), st, udq_state);
auto fu_var1 = st.get("FU_VAR1");
BOOST_CHECK_EQUAL(fu_var1, report_step + 1);
}
@ -2264,7 +2264,7 @@ TSTEP
// Reset to zero and count: 1,2,3,4,5
for (std::size_t report_step = 5; report_step < 10; report_step++) {
const auto& udq = schedule.getUDQConfig(report_step);
udq.eval(report_step, st, udq_state);
udq.eval(report_step, schedule.wellMatcher(report_step), st, udq_state);
auto fu_var1 = st.get("FU_VAR1");
BOOST_CHECK_EQUAL(fu_var1, report_step - 4);
}
@ -2272,7 +2272,7 @@ TSTEP
// Reset to zero and stay there.
for (std::size_t report_step = 10; report_step < 15; report_step++) {
const auto& udq = schedule.getUDQConfig(report_step);
udq.eval(report_step, st, udq_state);
udq.eval(report_step, schedule.wellMatcher(report_step),st, udq_state);
auto fu_var1 = st.get("FU_VAR1");
BOOST_CHECK_EQUAL(fu_var1, 0);
}
@ -2286,7 +2286,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DIV_TEST) {
UDQDefine def_div(udqp, "FU", location, {"128", "/", "2", "/", "4", "/", "8"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
UDQContext context(udqft, {}, st, udq_state);
auto res_div = def_div.eval(context);
BOOST_CHECK_EQUAL( res_div[0].get() , 2.0);
@ -2314,7 +2314,7 @@ UDQ
SummaryState st(std::chrono::system_clock::now());
const auto& udq = schedule.getUDQConfig(0);
udq.eval(0, st, udq_state);
udq.eval(0, {}, st, udq_state);
auto fu_var1 = st.get("FU_VAR1");
auto fu_var2 = st.get("FU_VAR2");
auto fu_var3 = st.get("FU_VAR3");
@ -2327,3 +2327,41 @@ UDQ
BOOST_CHECK_CLOSE(fu_var5, -0.00000041232 * 4 + 0.0010395 * 3 + 0.16504, 1e-5);
}
BOOST_AUTO_TEST_CASE(UDQ_WLIST) {
std::string deck_string = R"(
SCHEDULE
WELSPECS
'P1' 'OP' 20 51 3.92 'OIL' 3* NO /
'P2' 'OP' 20 51 3.92 'OIL' 3* NO /
'P3' 'OP' 20 51 3.92 'OIL' 3* NO /
'P4' 'OP' 20 51 3.92 'OIL' 3* NO /
/
WLIST
'*ILIST' 'NEW' P1 P2 P3 /
/
UDQ
DEFINE FU_VAR1 SUM(WOPR '*ILIST') /
DEFINE FU_VAR2 SUM(WOPR '*') /
/
)";
auto schedule = make_schedule(deck_string);
UDQState udq_state(0);
SummaryState st(std::chrono::system_clock::now());
const auto& udq = schedule.getUDQConfig(0);
st.update_well_var("P1", "WOPR", 1);
st.update_well_var("P2", "WOPR", 2);
st.update_well_var("P3", "WOPR", 3);
st.update_well_var("P4", "WOPR", 4);
udq.eval(0, schedule.wellMatcher(0), st, udq_state);
auto fu_var1 = st.get("FU_VAR1");
auto fu_var2 = st.get("FU_VAR2");
BOOST_CHECK_EQUAL(fu_var1, 6);
BOOST_CHECK_EQUAL(fu_var2, 10);
}

View File

@ -399,7 +399,7 @@ RestartValue first_sim(const Setup& setup, Action::State& action_state, SummaryS
RestartValue restart_value(sol, wells, groups);
init_st(st);
udq.eval(report_step, st, udq_state);
udq.eval(report_step, setup.schedule.wellMatcher(report_step), st, udq_state);
eclWriter.writeTimeStep( action_state,
st,
udq_state,