UDQ: Ensure that scalar right hand side is accepted into sets

This commit is contained in:
Joakim Hove 2019-06-13 16:40:12 +02:00
parent 83cb209ad8
commit 772bd3cee5
4 changed files with 140 additions and 34 deletions

View File

@ -103,48 +103,61 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const
if (this->type == UDQTokenType::ecl_expr) {
if (this->var_type == UDQVarType::WELL_VAR) {
const auto& wells = context.wells();
auto res = UDQSet::wells(this->string_value, wells);
if (this->selector.size() > 0) {
int fnmatch_flags = 0;
const std::string& well_pattern = this->selector[0];
if (well_pattern.find("*") == std::string::npos)
throw std::invalid_argument("When evaluating a well UDQ you can not use fully qualified well variables");
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, this->string_value));
/*
The well name has been fully qualified - i.e. this
evaulates to a scalar, which will then subsequently be
scattered to all wells.
*/
return UDQSet::scalar(this->string_value, context.get_well_var(well_pattern, this->string_value));
else {
auto res = UDQSet::wells(this->string_value, wells);
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, this->string_value));
}
return res;
}
} else {
auto res = UDQSet::wells(this->string_value, wells);
for (const auto& well : wells)
res.assign(well, context.get_well_var(well, this->string_value));
return res;
}
return res;
}
if (this->var_type == UDQVarType::GROUP_VAR) {
const auto& groups = context.groups();
auto res = UDQSet::groups(this->string_value, groups);
if (this->selector.size() > 0) {
int fnmatch_flags = 0;
const std::string& group_pattern = this->selector[0];
if (group_pattern.find("*") == std::string::npos)
throw std::invalid_argument("When evaluating a group UDQ you can not use fully qualified group variables");
for (const auto& group : groups) {
if (fnmatch(group_pattern.c_str(), group.c_str(), fnmatch_flags) == 0)
res.assign(group, context.get_group_var(group, this->string_value));
/*
The group name has been fully qualified - i.e. this
evaulates to a scalar, which will then subsequently be
scattered to all groups.
*/
return UDQSet::scalar(this->string_value, context.get_group_var(group_pattern, this->string_value));
else {
auto res = UDQSet::groups(this->string_value, groups);
for (const auto& group : groups) {
if (fnmatch(group_pattern.c_str(), group.c_str(), fnmatch_flags) == 0)
res.assign(group, context.get_group_var(group, this->string_value));
}
return res;
}
} else {
auto res = UDQSet::groups(this->string_value, groups);
for (const auto& group : groups)
res.assign(group, context.get_group_var(group, this->string_value));
return res;
}
return res;
}
throw std::invalid_argument("When evaluating general inner kernel only Wxxx end Gxxx xpressions are allowed - for now.");
}

View File

@ -133,6 +133,45 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
std::string msg = "Invalid runtime type conversion detected when evaluating UDQ";
throw std::invalid_argument(msg);
}
if (res.var_type() == UDQVarType::SCALAR) {
/*
If the right hand side evaluates to a scalar that scalar value should
be set for all wells in the wellset:
UDQ
DEFINE WUINJ1 SUM(WOPR) * 1.25 /
DEFINE WUINJ2 WOPR OP1 * 5.0 /
/
Both the expressions "SUM(WOPR)" and "WOPR OP1" evaluate to a scalar,
this should then be copied all wells, so that WUINJ1:$WELL should
evaulate to the same numerical value for all wells; the same should
also apply for group sets.
*/
double scalar_value = res[0].value();
if (this->var_type() == UDQVarType::WELL_VAR) {
const std::vector<std::string> wells = context.wells();
UDQSet well_res = UDQSet::wells(this->m_keyword, wells);
for (const auto& well : wells)
well_res.assign(well, scalar_value);
return well_res;
}
if (this->var_type() == UDQVarType::GROUP_VAR) {
const std::vector<std::string> groups = context.groups();
UDQSet group_res = UDQSet::groups(this->m_keyword, groups);
for (const auto& group : groups)
group_res.assign(group, scalar_value);
return group_res;
}
}
return res;
}

View File

@ -235,7 +235,7 @@ bool compatibleTypes(UDQVarType lhs, UDQVarType rhs) {
if (lhs == rhs)
return true;
if (lhs == UDQVarType::FIELD_VAR && rhs == UDQVarType::SCALAR)
if (rhs == UDQVarType::SCALAR)
return true;
return false;

View File

@ -197,16 +197,6 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
BOOST_CHECK_EQUAL( res["I1"].defined(), false);
BOOST_CHECK_EQUAL( res["I1"].defined(), false);
}
{
UDQDefine def(udqp, "WUBHP", {"WBHP" , "'P1'"});
SummaryState st;
UDQContext context(udqft, st);
st.update_well_var("P1", "WBHP", 1);
BOOST_CHECK_THROW( def.eval( context ), std::invalid_argument);
}
{
UDQDefine def(udqp, "WUBHP", {"NINT" , "(", "WBHP", ")"});
SummaryState st;
@ -897,6 +887,70 @@ BOOST_AUTO_TEST_CASE(UDQ_CMP_TEST) {
}
*/
BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
UDQParams udqp;
UDQFunctionTable udqft;
SummaryState st;
UDQContext context(udqft, st);
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("P1", "WWPR", 1);
st.update_well_var("P2", "WWPR", 2);
st.update_well_var("P3", "WWPR", 3);
st.update_well_var("P4", "WWPR", 4);
{
UDQDefine def(udqp, "WUOPR", {"WOPR", "'*1'"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4, res.size());
auto well1 = res["P1"];
BOOST_CHECK( well1.defined() );
BOOST_CHECK_EQUAL(well1.value() , 1);
auto well2 = res["P2"];
BOOST_CHECK( !well2.defined() );
auto well4 = res["P4"];
BOOST_CHECK( !well4.defined() );
}
{
UDQDefine def(udqp, "WUOPR", {"1"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4, res.size());
auto well1 = res["P1"];
BOOST_CHECK( well1.defined() );
BOOST_CHECK_EQUAL(well1.value() , 1);
auto well2 = res["P2"];
BOOST_CHECK( well2.defined() );
BOOST_CHECK_EQUAL(well2.value() , 1);
auto well4 = res["P4"];
BOOST_CHECK( well4.defined() );
BOOST_CHECK_EQUAL(well4.value() , 1);
}
{
UDQDefine def(udqp, "WUOPR", {"WOPR", "'P1'"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4, res.size());
auto well1 = res["P1"];
BOOST_CHECK( well1.defined() );
BOOST_CHECK_EQUAL(well1.value() , 1);
auto well2 = res["P2"];
BOOST_CHECK( well2.defined() );
BOOST_CHECK_EQUAL(well2.value() , 1);
auto well4 = res["P4"];
BOOST_CHECK( well4.defined() );
BOOST_CHECK_EQUAL(well4.value() , 1);
}
}
BOOST_AUTO_TEST_CASE(UDQ_BASIC_MATH_TEST) {
UDQParams udqp;
@ -988,7 +1042,8 @@ BOOST_AUTO_TEST_CASE(UDQ_PARSE_ERROR) {
{
UDQDefine def1(udqp, "WUBHP", tokens, parseContext, errors);
SummaryState st;
UDQContext context(UDQFunctionTable(udqp), st);
UDQFunctionTable udqft(udqp);
UDQContext context(udqft, st);
st.update_well_var("P1", "WBHP", 1);
auto res = def1.eval(context);
@ -1011,8 +1066,10 @@ BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
UDQDefine def2(udqp, "WUBHP", tokens2, parseContext, errors);
SummaryState st;
UDQContext context(UDQFunctionTable(udqp), st);
UDQFunctionTable udqft(udqp);
UDQContext context(udqft, st);
st.update_well_var("P1", "WBHP", 1);
st.update_well_var("P2", "WBHP", 2);
auto res1 = def1.eval(context);
BOOST_CHECK_EQUAL(res1[0].value(), udqp.undefinedValue());
@ -1020,16 +1077,13 @@ BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
auto res2 = def2.eval(context);
BOOST_CHECK_EQUAL(res2.size(), st.num_wells());
for (std::size_t index = 0; index < res2.size(); index++)
BOOST_CHECK_EQUAL(res2[index].value(), udqp.undefinedValue());
BOOST_CHECK_EQUAL(res2[index].value(), 3);
}
parseContext.update(ParseContext::UDQ_TYPE_ERROR, InputError::THROW_EXCEPTION);
// This fails because the well expression (WBHP + 1) is assigned to the field variable FUBHP
BOOST_CHECK_THROW( UDQDefine(udqp, "FUBHP", tokens1, parseContext, errors), std::invalid_argument);
// This fails because the scalar expression SUM(WBHP) is assigned to the well variable WUBHP
BOOST_CHECK_THROW( UDQDefine(udqp, "WUBHP", tokens2, parseContext, errors), std::invalid_argument);
}