Merge pull request #668 from joakim-hove/udq-fieldset

UDQ field and group variables
This commit is contained in:
Bård Skaflestad
2019-06-03 12:01:37 +02:00
committed by GitHub
25 changed files with 540 additions and 332 deletions

View File

@@ -132,7 +132,6 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParser.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQAssign.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp
src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.cpp
@@ -552,7 +551,6 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunction.hpp
opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.hpp

View File

@@ -24,7 +24,7 @@
#include <string>
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
@@ -36,7 +36,7 @@ public:
double value() const;
UDQVarType var_type() const;
const std::vector<std::string>& selector() const;
UDQWellSet eval_wells(const std::vector<std::string>& wells) const;
UDQSet eval(const std::vector<std::string>& wells) const;
private:
std::string m_keyword;
UDQVarType m_var_type;

View File

@@ -35,9 +35,11 @@ namespace Opm {
UDQContext(const UDQFunctionTable& udqft, const SummaryState& summary_state);
double get(const std::string& key) const;
double get_well_var(const std::string& well, const std::string& var) const;
double get_group_var(const std::string& group, const std::string& var) const;
void add(const std::string& key, double value);
const UDQFunctionTable& function_table() const;
std::vector<std::string> wells() const;
std::vector<std::string> groups() const;
private:
const UDQFunctionTable& udqft;
const SummaryState& summary_state;

View File

@@ -25,7 +25,7 @@
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.hpp>
@@ -55,7 +55,6 @@ public:
T&& errors);
UDQWellSet eval_wells(const UDQContext& context) const;
UDQSet eval(const UDQContext& context) const;
const std::string& keyword() const;
const std::vector<std::string>& tokens() const;

View File

@@ -24,14 +24,16 @@
namespace Opm {
enum class UDQVarType {
WELL_VAR = 1,
CONNECTION_VAR= 2,
FIELD_VAR = 3,
GROUP_VAR = 4,
REGION_VAR = 5,
SEGMENT_VAR = 6,
AQUIFER_VAR = 7,
BLOCK_VAR = 8
NONE = 0,
SCALAR = 1,
WELL_VAR = 2,
CONNECTION_VAR= 3,
FIELD_VAR = 4,
GROUP_VAR = 5,
REGION_VAR = 6,
SEGMENT_VAR = 7,
AQUIFER_VAR = 8,
BLOCK_VAR = 9
};
@@ -101,6 +103,8 @@ enum class UDQAction {
namespace UDQ {
bool compatibleTypes(UDQVarType lhs, UDQVarType rhs);
UDQVarType targetType(const std::string& keyword);
UDQVarType varType(const std::string& keyword);
UDQAction actionType(const std::string& action_string);
UDQTokenType funcType(const std::string& func_name);
@@ -108,6 +112,7 @@ namespace UDQ {
bool elementalUnaryFunc(UDQTokenType token_type);
bool scalarFunc(UDQTokenType token_type);
bool cmpFunc(UDQTokenType token_type);
}
}

View File

@@ -44,22 +44,22 @@ private:
class UDQScalarFunction : public UDQFunction {
public:
UDQScalarFunction(const std::string&name, std::function<UDQScalar(const UDQSet& arg)> f);
UDQScalar eval(const UDQSet& arg) const;
UDQScalarFunction(const std::string&name, std::function<UDQSet(const UDQSet& arg)> f);
UDQSet eval(const UDQSet& arg) const;
static UDQScalar SUM(const UDQSet& arg);
static UDQScalar AVEA(const UDQSet& arg);
static UDQScalar AVEG(const UDQSet& arg);
static UDQScalar AVEH(const UDQSet& arg);
static UDQScalar MIN(const UDQSet& arg);
static UDQScalar MAX(const UDQSet& arg);
static UDQScalar NORM1(const UDQSet& arg);
static UDQScalar NORM2(const UDQSet& arg);
static UDQScalar NORMI(const UDQSet& arg);
static UDQScalar PROD(const UDQSet& arg);
static UDQSet SUM(const UDQSet& arg);
static UDQSet AVEA(const UDQSet& arg);
static UDQSet AVEG(const UDQSet& arg);
static UDQSet AVEH(const UDQSet& arg);
static UDQSet MIN(const UDQSet& arg);
static UDQSet MAX(const UDQSet& arg);
static UDQSet NORM1(const UDQSet& arg);
static UDQSet NORM2(const UDQSet& arg);
static UDQSet NORMI(const UDQSet& arg);
static UDQSet PROD(const UDQSet& arg);
private:
std::function<UDQScalar(const UDQSet& arg)> func;
std::function<UDQSet(const UDQSet& arg)> func;
};

View File

@@ -23,6 +23,9 @@
#include <stdexcept>
#include <vector>
#include <string>
#include <unordered_map>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
@@ -53,8 +56,17 @@ public:
class UDQSet {
public:
UDQSet(const std::string& name, std::size_t size);
static UDQSet scalar(const std::string& name, double value);
static UDQSet empty(const std::string& name);
static UDQSet wells(const std::string& name, const std::vector<std::string>& wells);
static UDQSet wells(const std::string& name, const std::vector<std::string>& wells, double scalar_value);
static UDQSet groups(const std::string& name, const std::vector<std::string>& groups);
static UDQSet groups(const std::string& name, const std::vector<std::string>& groups, double scalar_value);
static UDQSet field(const std::string& name, double scalar_value);
void assign(double value);
void assign(std::size_t index, double value);
void assign(const std::string& wgname, double value);
std::size_t size() const;
void operator+=(const UDQSet& rhs);
@@ -67,14 +79,22 @@ public:
void operator/=(double rhs);
const UDQScalar& operator[](std::size_t index) const;
const UDQScalar& operator[](const std::string& wgname) const;
std::vector<UDQScalar>::const_iterator begin() const;
std::vector<UDQScalar>::const_iterator end() const;
std::vector<double> defined_values() const;
std::size_t defined_size() const;
const std::string& name() const;
UDQVarType var_type() const;
private:
UDQSet() = default;
UDQSet(const std::string& name, UDQVarType var_type, std::size_t size);
std::string m_name;
UDQVarType m_var_type;
std::unordered_map<std::string, std::size_t> wgname_index;
std::vector<UDQScalar> values;
};

View File

@@ -1,50 +0,0 @@
/*
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 UDQWELLSET_HPP
#define UDQWELLSET_HPP
#include <vector>
#include <string>
#include <unordered_map>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
namespace Opm {
class UDQWellSet : public UDQSet {
public:
UDQWellSet(const std::string& name, const std::vector<std::string>& wells);
UDQWellSet(const std::string& name, const std::vector<std::string>& wells, const UDQSet& values);
UDQWellSet(const std::string& name, const std::vector<std::string>& wells, double scalar_value);
void assign(const std::string& well, double value);
void assign(double value);
const UDQScalar& operator[](const std::string& well) const;
private:
std::size_t wellIndex(const std::string& well) const;
std::unordered_map<std::string, std::size_t> well_index;
};
}
#endif

View File

@@ -254,6 +254,7 @@ namespace Opm {
const static std::string UNSUPPORTED_TERMINATE_IF_BHP;
const static std::string UDQ_PARSE_ERROR;
const static std::string UDQ_TYPE_ERROR;
/*
If the third item in the THPRES keyword is defaulted the

View File

@@ -1177,7 +1177,7 @@ void eval_udq(const Schedule& schedule, std::size_t sim_step, SummaryState& st)
wells.push_back(well_name);
for (const auto& assign : udq.assignments(UDQVarType::WELL_VAR)) {
auto ws = assign.eval_wells(wells);
auto ws = assign.eval(wells);
for (const auto& well : wells) {
const auto& udq_value = ws[well];
if (udq_value)
@@ -1186,13 +1186,19 @@ void eval_udq(const Schedule& schedule, std::size_t sim_step, SummaryState& st)
}
for (const auto& def : udq.definitions(UDQVarType::WELL_VAR)) {
auto ws = def.eval_wells(context);
auto ws = def.eval(context);
for (const auto& well : wells) {
const auto& udq_value = ws[well];
if (udq_value)
st.update_well_var(well, def.keyword(), udq_value.value());
}
}
for (const auto& def : udq.definitions(UDQVarType::FIELD_VAR)) {
auto field_udq = def.eval(context);
if (field_udq[0])
st.update(def.keyword(), field_udq[0].value());
}
}
}

View File

@@ -26,13 +26,11 @@
namespace Opm {
UDQASTNode::UDQASTNode() :
type(UDQTokenType::error)
{}
UDQASTNode::UDQASTNode(UDQTokenType type) :
type(type)
type(type),
var_type(UDQVarType::NONE)
{
if (type == UDQTokenType::error)
return;
@@ -45,6 +43,7 @@ UDQASTNode::UDQASTNode(UDQTokenType type) :
UDQASTNode::UDQASTNode(double scalar_value) :
type(UDQTokenType::number),
var_type(UDQVarType::SCALAR),
scalar_value(scalar_value)
{}
@@ -57,6 +56,11 @@ UDQASTNode::UDQASTNode(UDQTokenType type_arg,
type(type_arg),
string_value(func_name)
{
if (UDQ::scalarFunc(type_arg))
this->var_type = UDQVarType::SCALAR;
else if (UDQ::elementalUnaryFunc(type_arg))
this->var_type = arg.var_type;
this->arglist.push_back(arg);
}
@@ -66,6 +70,7 @@ UDQASTNode::UDQASTNode(UDQTokenType type_arg,
const UDQASTNode& left,
const UDQASTNode& right) :
type(type_arg),
var_type((left.var_type == UDQVarType::SCALAR) ? right.var_type : left.var_type ),
string_value(func_name)
{
this->arglist.push_back(left);
@@ -80,67 +85,110 @@ UDQASTNode::UDQASTNode(UDQTokenType type_arg,
const std::string& string_value,
const std::vector<std::string>& selector) :
type(type_arg),
var_type(UDQ::targetType(string_value)),
string_value(string_value),
selector(selector)
{
if (type_arg == UDQTokenType::number)
this->scalar_value = std::stod(string_value);
if (type_arg == UDQTokenType::ecl_expr)
this->var_type = UDQ::targetType(string_value);
}
UDQWellSet UDQASTNode::eval_wells(const UDQContext& context) {
const auto& wells = context.wells();
if (this->type == UDQTokenType::ecl_expr) {
auto res = UDQWellSet(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)
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));
}
} else {
for (const auto& well : wells)
res.assign(well, context.get_well_var(well, this->string_value));
}
} else {
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));
}
} else {
for (const auto& group : groups)
res.assign(group, context.get_group_var(group, this->string_value));
}
return res;
}
throw std::invalid_argument("When evaluating general inner kernel only Wxxx end Gxxx xpressions are allowed - for now.");
}
if (UDQ::scalarFunc(this->type))
throw std::invalid_argument("Can not invoke scalar function for well set");
if (UDQ::scalarFunc(this->type)) {
const auto& udqft = context.function_table();
const UDQScalarFunction& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(this->string_value));
return func.eval( this->arglist[0].eval(target_type, context) );
}
if (UDQ::elementalUnaryFunc(this->type)) {
auto input_arg = this->arglist[0];
auto func_arg = input_arg.eval_wells(context);
auto func_arg = input_arg.eval(target_type, context);
const auto& udqft = context.function_table();
const UDQUnaryElementalFunction& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(this->string_value));
auto udq_set = func.eval(func_arg);
return UDQWellSet(this->string_value, wells, udq_set);
return func.eval(func_arg);
}
if (UDQ::binaryFunc(this->type)) {
auto left_arg = this->arglist[0].eval_wells(context);
auto right_arg = this->arglist[1].eval_wells(context);
auto left_arg = this->arglist[0].eval(target_type, context);
auto right_arg = this->arglist[1].eval(target_type, context);
const auto& udqft = context.function_table();
const UDQBinaryFunction& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(this->string_value));
auto udq_set = func.eval(left_arg, right_arg);
return UDQWellSet(this->string_value, wells, udq_set);
auto res = func.eval(left_arg, right_arg);
return func.eval(left_arg, right_arg);
}
if (this->type == UDQTokenType::number)
return UDQWellSet(this->string_value, wells, this->scalar_value);
if (this->type == UDQTokenType::number) {
switch(target_type) {
case UDQVarType::WELL_VAR:
return UDQSet::wells(this->string_value, context.wells(), this->scalar_value);
case UDQVarType::SCALAR:
return UDQSet::scalar(this->string_value, this->scalar_value);
case UDQVarType::FIELD_VAR:
return UDQSet::field(this->string_value, this->scalar_value);
default:
throw std::invalid_argument("Unsupported target_type: " + std::to_string(static_cast<int>(target_type)));
}
}
throw std::invalid_argument("UDQASTNode::eval_wells: not implemented function type: " + std::to_string(static_cast<int>(this->type)));
throw std::invalid_argument("Should not be here ...");
}
}

View File

@@ -23,7 +23,7 @@
#include <string>
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
@@ -33,17 +33,18 @@ namespace Opm {
class UDQASTNode {
public:
UDQASTNode();
UDQASTNode(UDQTokenType type_arg);
UDQASTNode(double scalar_value);
UDQASTNode(UDQTokenType type_arg, const std::string& string_value, const std::vector<std::string>& selector);
UDQASTNode(UDQTokenType type_arg, const std::string& func_name, const UDQASTNode& arg);
UDQASTNode(UDQTokenType type_arg, const std::string& func_name, const UDQASTNode& left, const UDQASTNode& right);
UDQWellSet eval_wells(const UDQContext& context);
UDQTokenType type;
UDQSet eval(UDQVarType eval_target, const UDQContext& context) const;
UDQTokenType type;
UDQVarType var_type = UDQVarType::NONE;
private:
std::string string_value;
double scalar_value;
std::vector<std::string> selector;

View File

@@ -46,17 +46,17 @@ UDQVarType UDQAssign::var_type() const {
return this->m_var_type;
}
UDQWellSet UDQAssign::eval_wells(const std::vector<std::string>& wells) const {
if (this->m_var_type != UDQVarType::WELL_VAR)
throw std::runtime_error("This is a bug - eval_wells called for UDQ variable which is not a well quantity.");
UDQSet UDQAssign::eval(const std::vector<std::string>& wells) const {
if (this->m_var_type == UDQVarType::WELL_VAR) {
UDQSet ws= UDQSet::wells(this->m_keyword, wells);
UDQWellSet ws(this->m_keyword, wells);
if (this->m_selector.empty())
ws.assign(this->m_value);
else
ws.assign(this->m_selector[0], this->m_value);
if (this->m_selector.empty())
ws.assign(this->m_value);
else
ws.assign(this->m_selector[0], this->m_value);
return ws;
return ws;
}
throw std::invalid_argument("Not yet implemented");
}
}

View File

@@ -63,10 +63,17 @@ namespace Opm {
return this->summary_state.get_well_var(well, var);
}
double UDQContext::get_group_var(const std::string& group, const std::string& var) const {
return this->summary_state.get_group_var(group, var);
}
std::vector<std::string> UDQContext::wells() const {
return this->summary_state.wells();
}
std::vector<std::string> UDQContext::groups() const {
return this->summary_state.groups();
}
const UDQFunctionTable& UDQContext::function_table() const {
return this->udqft;

View File

@@ -121,24 +121,23 @@ UDQDefine::UDQDefine(const UDQParams& udq_params,
}
}
this->ast = std::make_shared<UDQASTNode>( UDQParser::parse(this->udq_params, tokens, parseContext, errors) );
std::cout << keyword << " = ";
this->ast = std::make_shared<UDQASTNode>( UDQParser::parse(this->udq_params, this->m_var_type, tokens, parseContext, errors) );
this->input_tokens = tokens;
}
UDQWellSet UDQDefine::eval_wells(const UDQContext& context) const {
return this->ast->eval_wells(context);
}
UDQSet UDQDefine::eval(const UDQContext& context) const {
switch (this->m_var_type) {
case UDQVarType::WELL_VAR:
return this->eval_wells(context);
default:
throw std::invalid_argument("UDQ subtype: not supported");
UDQSet res = this->ast->eval(this->m_var_type, context);
if (!UDQ::compatibleTypes(this->var_type(), res.var_type())) {
std::string msg = "Invalid runtime type conversion detected when evaluating UDQ";
throw std::invalid_argument(msg);
}
return res;
}
UDQVarType UDQDefine::var_type() const {
return this->m_var_type;
}

View File

@@ -124,6 +124,38 @@ namespace {
{"PROD", UDQTokenType::scalar_func_prod}};
}
UDQVarType targetType(const std::string& keyword) {
char first_char = keyword[0];
switch(first_char) {
case 'W':
return UDQVarType::WELL_VAR;
case 'G':
return UDQVarType::GROUP_VAR;
case 'C':
return UDQVarType::CONNECTION_VAR;
case 'R':
return UDQVarType::REGION_VAR;
case 'F':
return UDQVarType::FIELD_VAR;
case 'S':
return UDQVarType::SEGMENT_VAR;
case 'A':
return UDQVarType::AQUIFER_VAR;
case 'B':
return UDQVarType::BLOCK_VAR;
default:
try {
std::stod(keyword);
return UDQVarType::SCALAR;
} catch(const std::invalid_argument& exc) {
return UDQVarType::NONE;
}
}
}
UDQVarType varType(const std::string& keyword) {
if (keyword[1] != 'U')
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
@@ -197,5 +229,18 @@ UDQTokenType funcType(const std::string& func_name) {
return UDQTokenType::error;
}
bool compatibleTypes(UDQVarType lhs, UDQVarType rhs) {
if (lhs == rhs)
return true;
if (lhs == UDQVarType::FIELD_VAR && rhs == UDQVarType::SCALAR)
return true;
return false;
}
}
}

View File

@@ -41,7 +41,7 @@ const std::string& UDQFunction::name() const {
return this->m_name;
}
UDQScalarFunction::UDQScalarFunction(const std::string&name, std::function<UDQScalar(const UDQSet& arg)> f) :
UDQScalarFunction::UDQScalarFunction(const std::string&name, std::function<UDQSet(const UDQSet& arg)> f) :
UDQFunction(name),
func(std::move(f))
{
@@ -49,7 +49,7 @@ UDQScalarFunction::UDQScalarFunction(const std::string&name, std::function<UDQSc
UDQScalar UDQScalarFunction::eval(const UDQSet& arg) const {
UDQSet UDQScalarFunction::eval(const UDQSet& arg) const {
return this->func(arg);
}
@@ -59,76 +59,91 @@ UDQSet UDQUnaryElementalFunction::eval(const UDQSet& arg) const {
}
/*****************************************************************/
UDQScalar UDQScalarFunction::MIN(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
UDQSet UDQScalarFunction::MIN(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return {};
return UDQSet::empty("MIN");
return *std::min_element(defined_values.begin(), defined_values.end());
return UDQSet::scalar("MIN", *std::min_element(defined_values.begin(), defined_values.end()));
}
UDQScalar UDQScalarFunction::MAX(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
UDQSet UDQScalarFunction::MAX(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return {};
return UDQSet::empty("MAX");
return *std::max_element(defined_values.begin(), defined_values.end());
return UDQSet::scalar("MAX", *std::max_element(defined_values.begin(), defined_values.end()));
}
UDQScalar UDQScalarFunction::SUM(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
return std::accumulate(defined_values.begin(), defined_values.end(), 0.0);
}
UDQScalar UDQScalarFunction::PROD(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
return std::accumulate(defined_values.begin(), defined_values.end(), 1.0, std::multiplies<double>{});
}
UDQScalar UDQScalarFunction::AVEA(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
UDQSet UDQScalarFunction::SUM(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return {};
return std::accumulate( defined_values.begin(), defined_values.end(), 0.0) / defined_values.size();
return UDQSet::empty("SUM");
return UDQSet::scalar("SUM", std::accumulate(defined_values.begin(), defined_values.end(), 0.0));
}
UDQScalar UDQScalarFunction::AVEG(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
UDQSet UDQScalarFunction::PROD(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return {};
return UDQSet::empty("PROD");
return UDQSet::scalar("PROD", std::accumulate(defined_values.begin(), defined_values.end(), 1.0, std::multiplies<double>{}));
}
UDQSet UDQScalarFunction::AVEA(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return UDQSet::empty("AVEA");
return UDQSet::scalar("AVEA", std::accumulate( defined_values.begin(), defined_values.end(), 0.0) / defined_values.size());
}
UDQSet UDQScalarFunction::AVEG(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return UDQSet::empty("AVEG");
if (std::find_if(defined_values.begin(), defined_values.end(), [](double x) { return x <= 0; }) != defined_values.end())
throw std::invalid_argument("Function AVEG must have only positive arguments");
double log_mean = std::accumulate( defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return x + std::log(std::fabs(y)); }) / defined_values.size();
return std::exp( log_mean );
double log_mean = std::accumulate( defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return x + std::log(y); }) / defined_values.size();
return UDQSet::scalar("AVEG", std::exp(log_mean));
}
UDQScalar UDQScalarFunction::AVEH(const UDQSet& arg) {
std::vector<double> defined_values = arg.defined_values();
UDQSet UDQScalarFunction::AVEH(const UDQSet& arg) {
auto defined_values = arg.defined_values();
if (defined_values.empty())
return {};
return UDQSet::empty("AVEH");
return defined_values.size() / std::accumulate(defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return x + 1.0/y; });
return UDQSet::scalar("AVEH", defined_values.size() / std::accumulate(defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return x + 1.0/y; }));
}
UDQScalar UDQScalarFunction::NORM1(const UDQSet& arg) {
UDQSet UDQScalarFunction::NORMI(const UDQSet& arg) {
auto defined_values = arg.defined_values();
return std::accumulate( defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return x + std::fabs(y);});
if (defined_values.empty())
return UDQSet::empty("NORMI");
return UDQSet::scalar("NORMI", std::accumulate( defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return std::max(x, std::fabs(y));}));
}
UDQScalar UDQScalarFunction::NORM2(const UDQSet& arg) {
UDQSet UDQScalarFunction::NORM1(const UDQSet& arg) {
auto defined_values = arg.defined_values();
return std::sqrt(std::inner_product(defined_values.begin(), defined_values.end(), defined_values.begin(), 0.0));
if (defined_values.empty())
return UDQSet::empty("NORM1");
return UDQSet::scalar("NORM1", std::accumulate( defined_values.begin(), defined_values.end(), 0.0, [](double x, double y) { return x + std::fabs(y);}));
}
UDQScalar UDQScalarFunction::NORMI(const UDQSet& arg) {
UDQSet UDQScalarFunction::NORM2(const UDQSet& arg) {
auto defined_values = arg.defined_values();
return std::accumulate( defined_values.begin(), defined_values.end(), 0.0, [](const double x, const double y) { return std::max(x, std::fabs(y));});
}
if (defined_values.empty())
return UDQSet::empty("NORM2");
return UDQSet::scalar("NORM2", std::sqrt(std::inner_product(defined_values.begin(), defined_values.end(), defined_values.begin(), 0.0)));
}
UDQUnaryElementalFunction::UDQUnaryElementalFunction(const std::string&name, std::function<UDQSet(const UDQSet& arg)> f) :
UDQFunction(name),
@@ -263,7 +278,7 @@ namespace {
UDQSet udq_union(const UDQSet& arg1, const UDQSet& arg2) {
if (arg1.size() != arg2.size())
throw std::invalid_argument("UDQ sets have incoimpatible size");
throw std::invalid_argument("UDQ sets have incompatible size");
UDQSet result = arg1;
for (std::size_t index = 0; index < result.size(); index++) {

View File

@@ -235,7 +235,7 @@ UDQASTNode UDQParser::parse_cmp() {
UDQASTNode UDQParser::parse(const UDQParams& udq_params, const std::vector<std::string>& tokens, const ParseContext& parseContext, ErrorGuard& errors)
UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type, const std::vector<std::string>& tokens, const ParseContext& parseContext, ErrorGuard& errors)
{
UDQParser parser(udq_params, tokens);
parser.next();
@@ -257,6 +257,16 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, const std::vector<std::
return UDQASTNode( udq_params.undefinedValue() );
}
if (!UDQ::compatibleTypes(target_type, tree.var_type)) {
std::string msg = "Invalid compile-time type conversion detected in UDQ expression target type: " + std::to_string(static_cast<int>(target_type)) + " expr type: " + std::to_string(static_cast<int>(tree.var_type));
for (const auto& token : tokens)
std::cout << token << " ";
std::cout << std::endl;
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg, errors);
return UDQASTNode( udq_params.undefinedValue() );
}
return tree;
}

View File

@@ -39,26 +39,31 @@ struct UDQParseNode {
type(type_arg),
value(value_arg),
selector(selector)
{}
{
if (type_arg == UDQTokenType::ecl_expr)
this->var_type = UDQ::targetType(value_arg);
}
UDQParseNode(UDQTokenType type_arg, const std::string& value_arg) :
UDQParseNode(type_arg, value_arg, {})
{}
// Implicit converting constructor.
UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "")
{}
UDQTokenType type;
std::string value;
std::vector<std::string> selector;
UDQVarType var_type = UDQVarType::NONE;
};
class UDQParser {
public:
static UDQASTNode parse(const UDQParams& udq_params, const std::vector<std::string>& tokens, const ParseContext& parseContext, ErrorGuard& errors);
static UDQASTNode parse(const UDQParams& udq_params, UDQVarType target_type, const std::vector<std::string>& tokens, const ParseContext& parseContext, ErrorGuard& errors);
private:
UDQParser(const UDQParams& udq_params, const std::vector<std::string>& tokens) :

View File

@@ -16,6 +16,7 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fnmatch.h>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
@@ -100,18 +101,97 @@ const std::string& UDQSet::name() const {
return this->m_name;
}
UDQSet::UDQSet(const std::string& name, UDQVarType var_type, std::size_t size) :
m_name(name),
m_var_type(var_type)
{
this->values.resize(size);
}
UDQSet::UDQSet(const std::string& name, std::size_t size) :
m_name(name)
{
this->values.resize(size);
}
UDQSet UDQSet::scalar(const std::string& name, double scalar_value)
{
UDQSet us(name, UDQVarType::SCALAR, 1);
us.assign(scalar_value);
return us;
}
UDQSet UDQSet::empty(const std::string& name)
{
return UDQSet(name, 0);
}
UDQSet UDQSet::field(const std::string& name, double scalar_value)
{
UDQSet us(name, UDQVarType::FIELD_VAR, 1);
us.assign(scalar_value);
return us;
}
UDQSet UDQSet::wells(const std::string& name, const std::vector<std::string>& wells) {
UDQSet us(name, UDQVarType::WELL_VAR, wells.size());
std::size_t index = 0;
for (const auto& well : wells) {
us.wgname_index[well] = index;
index += 1;
}
return us;
}
UDQSet UDQSet::wells(const std::string& name, const std::vector<std::string>& wells, double scalar_value) {
UDQSet us = UDQSet::wells(name, wells);
us.assign(scalar_value);
return us;
}
UDQSet UDQSet::groups(const std::string& name, const std::vector<std::string>& groups) {
UDQSet us(name, UDQVarType::GROUP_VAR, groups.size());
std::size_t index = 0;
for (const auto& group : groups) {
us.wgname_index[group] = index;
index += 1;
}
return us;
}
UDQSet UDQSet::groups(const std::string& name, const std::vector<std::string>& groups, double scalar_value) {
UDQSet us = UDQSet::groups(name, groups);
us.assign(scalar_value);
return us;
}
std::size_t UDQSet::size() const {
return this->values.size();
}
void UDQSet::assign(const std::string& wgname, double value) {
if (wgname.find('*') == std::string::npos) {
std::size_t index = this->wgname_index.at(wgname);
UDQSet::assign(index, value);
} else {
int flags = 0;
for (const auto& pair : this->wgname_index) {
if (fnmatch(wgname.c_str(), pair.first.c_str(), flags) == 0)
UDQSet::assign(pair.second, value);
}
}
}
void UDQSet::assign(double value) {
for (auto& v : this->values)
v.assign(value);
@@ -123,6 +203,14 @@ void UDQSet::assign(std::size_t index, double value) {
}
UDQVarType UDQSet::var_type() const {
return this->m_var_type;
}
/************************************************************************/
void UDQSet::operator+=(const UDQSet& rhs) {
if (this->size() != rhs.size())
throw std::invalid_argument("Incompatible size");
@@ -197,6 +285,11 @@ const UDQScalar& UDQSet::operator[](std::size_t index) const {
return this->values[index];
}
const UDQScalar& UDQSet::operator[](const std::string& well) const {
std::size_t index = this->wgname_index.at(well);
return this->operator[](index);
}
std::vector<UDQScalar>::const_iterator UDQSet::begin() const {
return this->values.begin();

View File

@@ -1,89 +0,0 @@
/*
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 <fnmatch.h>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp>
namespace Opm {
UDQWellSet::UDQWellSet(const std::string& name, const std::vector<std::string>& wells) :
UDQSet(name, wells.size())
{
for (std::size_t index = 0; index < wells.size(); index++)
this->well_index.emplace( std::make_pair(wells[index], index));
}
UDQWellSet::UDQWellSet(const std::string& name, const std::vector<std::string>& wells, const UDQSet& values) :
UDQWellSet(name, wells)
{
if (wells.size() != values.size())
throw std::invalid_argument("Size mismatch");
for (std::size_t index = 0; index < values.size(); index++) {
const auto& value = values[index];
if (value)
UDQSet::assign(index, values[index].value());
}
}
UDQWellSet::UDQWellSet(const std::string& name, const std::vector<std::string>& wells, double scalar_value) :
UDQWellSet(name, wells)
{
if (wells.size() != this->size())
throw std::invalid_argument("Size mismatch");
for (std::size_t index = 0; index < wells.size(); index++)
UDQSet::assign(index, scalar_value);
}
void UDQWellSet::assign(const std::string& well, double value) {
if (well.find('*') == std::string::npos) {
std::size_t index = this->wellIndex(well);
UDQSet::assign(index, value);
} else {
int flags = 0;
for (const auto& pair : this->well_index) {
if (fnmatch(well.c_str(), pair.first.c_str(), flags) == 0)
UDQSet::assign(pair.second, value);
}
}
}
void UDQWellSet::assign(double value) {
UDQSet::assign(value);
}
const UDQScalar& UDQWellSet::operator[](const std::string& well) const {
std::size_t index = this->wellIndex(well);
return UDQSet::operator[](index);
}
std::size_t UDQWellSet::wellIndex(const std::string& well) const {
const auto& pair_ptr = this->well_index.find(well);
if (pair_ptr == this->well_index.end())
throw std::invalid_argument("No such well: " + well);
return pair_ptr->second;
}
}

View File

@@ -108,7 +108,8 @@ namespace Opm {
addKey(SIMULATOR_KEYWORD_NOT_SUPPORTED, InputError::WARN);
addKey(SIMULATOR_KEYWORD_ITEM_NOT_SUPPORTED, InputError::WARN);
addKey(UDQ_PARSE_ERROR, InputError::THROW_EXCEPTION);
this->addKey(UDQ_PARSE_ERROR, InputError::THROW_EXCEPTION);
this->addKey(UDQ_TYPE_ERROR, InputError::THROW_EXCEPTION);
this->addKey(SCHEDULE_WELL_ERROR, InputError::THROW_EXCEPTION);
this->addKey(SCHEDULE_COMPSEGS_INVALID, InputError::THROW_EXCEPTION);
this->addKey(SCHEDULE_COMPSEGS_NOT_SUPPORTED, InputError::THROW_EXCEPTION);
@@ -345,6 +346,7 @@ namespace Opm {
const std::string ParseContext::SIMULATOR_KEYWORD_ITEM_NOT_SUPPORTED = "SIMULATOR_KEYWORD_ITEM_NOT_SUPPORTED";
const std::string ParseContext::UDQ_PARSE_ERROR = "UDQ_PARSE_ERROR";
const std::string ParseContext::UDQ_TYPE_ERROR = "UDQ_TYPE_ERROR";
const std::string ParseContext::SCHEDULE_WELL_ERROR = "SCHEDULE_WELL_ERROR";
const std::string ParseContext::SCHEDULE_COMPSEGS_INVALID = "SCHEDULE_COMPSEG_INVALID";

View File

@@ -356,6 +356,12 @@ WUOPR
/
WUWCT
/
FOPR
FUOPR
SCHEDULE
-- -------------------------------------------------------------------------
RPTSCHED
@@ -374,6 +380,8 @@ UDQ
UNITS WUOPR 'SM3/DAY' /
DEFINE WUWCT WWPR / (WWPR + WOPR) /
UNITS WUWCT '1' /
DEFINE FUOPR SUM(WOPR) /
UNITS FUOPR 'SM3/DAY' /
/

View File

@@ -273,19 +273,25 @@ BOOST_AUTO_TEST_CASE(UDQ_WUWCT) {
const auto& base_name = td.state.getIOConfig().getBaseName();
ecl_sum_type * ecl_sum = ecl_sum_fread_alloc_case( base_name.c_str(), ":");
for (const auto& well : {"P1", "P2", "P3", "P4"}) {
std::string wwct_key = std::string("WWCT:") + well;
std::string wuwct_key = std::string("WUWCT:") + well;
BOOST_CHECK( ecl_sum_has_general_var(ecl_sum, wwct_key.c_str()));
BOOST_CHECK( ecl_sum_has_general_var(ecl_sum, wuwct_key.c_str()));
for (int step = 0; step < ecl_sum_get_data_length(ecl_sum); step++) {
double wopr_sum = 0;
for (const auto& well : {"P1", "P2", "P3", "P4"}) {
std::string wwct_key = std::string("WWCT:") + well;
std::string wuwct_key = std::string("WUWCT:") + well;
std::string wopr_key = std::string("WOPR:") + well;
for (int step = 0; step < ecl_sum_get_data_length(ecl_sum); step++)
BOOST_CHECK_EQUAL( ecl_sum_get_general_var(ecl_sum, step, wwct_key.c_str()),
ecl_sum_get_general_var(ecl_sum, step, wuwct_key.c_str()));
wopr_sum += ecl_sum_get_general_var(ecl_sum, step , wopr_key.c_str());
}
BOOST_CHECK_EQUAL( ecl_sum_get_general_var(ecl_sum, step, "FOPR"),
ecl_sum_get_general_var(ecl_sum, step, "FUOPR"));
BOOST_CHECK_EQUAL( wopr_sum, ecl_sum_get_general_var(ecl_sum, step, "FOPR"));
}
test_work_area_free(work_area);
}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 Statoil ASA.
Copyright 2018 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
@@ -28,7 +28,6 @@
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQWellSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQAssign.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunction.hpp>
@@ -58,7 +57,7 @@ BOOST_AUTO_TEST_CASE(MIX_SCALAR) {
st.update_well_var("P1", "WOPR", 1);
auto res_add = def_add.eval_wells(context);
auto res_add = def_add.eval(context);
BOOST_CHECK_EQUAL( res_add["P1"].value() , 2);
}
@@ -70,11 +69,33 @@ BOOST_AUTO_TEST_CASE(UDQ_TABLE_EXCEPTION) {
BOOST_AUTO_TEST_CASE(UDQFieldSetTest) {
std::vector<std::string> wells = {"P1", "P2", "P3", "P4"};
UDQParams udqp;
UDQFunctionTable udqft(udqp);
UDQDefine def_fxxx(udqp, "FU_SCALAR", {"123"});
UDQDefine def_fopr(udqp, "FUOPR", {"SUM", "(", "WOPR", ")"});
SummaryState st;
UDQContext context(udqft, st);
st.update_well_var("P1", "WOPR", 1.0);
st.update_well_var("P2", "WOPR", 2.0);
st.update_well_var("P3", "WOPR", 3.0);
st.update_well_var("P4", "WOPR", 4.0);
auto fxxx_res = def_fxxx.eval(context);
BOOST_CHECK_EQUAL( fxxx_res[0].value(), 123.0 );
BOOST_CHECK( fxxx_res.var_type() == UDQVarType::FIELD_VAR);
auto fopr_res = def_fopr.eval(context);
BOOST_CHECK_EQUAL( fopr_res[0].value(), 10.0 );
}
BOOST_AUTO_TEST_CASE(UDQWellSetTest) {
std::vector<std::string> wells = {"P1", "P2", "I1", "I2"};
UDQWellSet ws("NAME", wells);
UDQWellSet ws2("NAME", wells, 100.0);
UDQSet ws = UDQSet::wells("NAME", wells);
UDQSet ws2 = UDQSet::wells("NAME", wells, 100.0);
BOOST_CHECK_EQUAL(4, ws.size());
ws.assign("P1", 1.0);
@@ -83,7 +104,7 @@ BOOST_AUTO_TEST_CASE(UDQWellSetTest) {
BOOST_CHECK_EQUAL(value.value(), 1.0);
BOOST_CHECK_EQUAL(ws["P1"].value(), 1.0);
BOOST_REQUIRE_THROW(ws.assign("NO_SUCH_WELL", 1.0), std::invalid_argument);
BOOST_REQUIRE_THROW(ws.assign("NO_SUCH_WELL", 1.0), std::out_of_range);
ws.assign("*", 2.0);
for (const auto& w : wells)
@@ -104,16 +125,44 @@ BOOST_AUTO_TEST_CASE(UDQWellSetTest) {
for (const auto& w : wells)
BOOST_CHECK_EQUAL(ws2[w].value(), 100.0);
UDQSet us("NAME", wells.size());
for (std::size_t i=0; i < wells.size(); i++)
us.assign(i, 1.0 * i);
UDQSet scalar = UDQSet::scalar("NAME", 1.0);
BOOST_CHECK_EQUAL(scalar.size() , 1);
BOOST_CHECK_EQUAL(scalar[0].value(), 1.0);
UDQWellSet ws3("name", wells, us);
for (std::size_t i=0; i < wells.size(); i++)
BOOST_CHECK_EQUAL(ws3[wells[i]].value(), i*1.0);
UDQSet empty = UDQSet::empty("EMPTY");
BOOST_CHECK_EQUAL(empty.size() , 0);
}
BOOST_AUTO_TEST_CASE(UDQ_GROUP_TEST) {
std::vector<std::string> groups = {"G1", "G2", "G3", "G4"};
UDQSet gs = UDQSet::groups("NAME", groups);
BOOST_CHECK_EQUAL(4, gs.size());
gs.assign("G1", 1.0);
const auto& value = gs["G1"];
BOOST_CHECK_EQUAL(value.value(), 1.0);
{
UDQParams udqp;
UDQFunctionTable udqft(udqp);
UDQDefine def_fopr(udqp, "FUOPR", {"SUM", "(", "GOPR", ")"});
SummaryState st;
UDQContext context(udqft, st);
st.update_group_var("G1", "GOPR", 1.0);
st.update_group_var("G2", "GOPR", 2.0);
st.update_group_var("G3", "GOPR", 3.0);
st.update_group_var("G4", "GOPR", 4.0);
auto res = def_fopr.eval(context);
BOOST_CHECK_EQUAL(res[0].value(), 10.0);
}
}
BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
UDQParams udqp;
UDQFunctionTable udqft(udqp);
@@ -125,7 +174,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
st.update_well_var("W1", "WBHP", 11);
st.update_well_var("W2", "WBHP", 2);
st.update_well_var("W3", "WBHP", 3);
auto res = def.eval_wells(context);
auto res = def.eval(context);
BOOST_CHECK_EQUAL(res.size(), 3);
BOOST_CHECK_EQUAL( res["W1"].value(), 11 );
BOOST_CHECK_EQUAL( res["W2"].value(), 2 );
@@ -141,7 +190,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
st.update_well_var("P2", "WBHP", 2);
st.update_well_var("I1", "WBHP", 1);
st.update_well_var("I2", "WBHP", 2);
auto res = def.eval_wells(context);
auto res = def.eval(context);
BOOST_CHECK_EQUAL(res.size(), 4);
BOOST_CHECK_EQUAL( res["P1"].value(), 1 );
BOOST_CHECK_EQUAL( res["P2"].value(), 2 );
@@ -155,7 +204,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
st.update_well_var("P1", "WBHP", 1);
BOOST_CHECK_THROW( def.eval_wells( context ), std::invalid_argument);
BOOST_CHECK_THROW( def.eval( context ), std::invalid_argument);
}
{
@@ -167,25 +216,12 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
st.update_well_var("I1", "WBHP", 2);
st.update_well_var("I2", "WBHP", 1);
auto res = def.eval_wells(context);
auto res = def.eval(context);
BOOST_CHECK_EQUAL( res["P1"].value(), 4 );
BOOST_CHECK_EQUAL( res["P2"].value(), 3 );
BOOST_CHECK_EQUAL( res["I1"].value(), 2 );
BOOST_CHECK_EQUAL( res["I2"].value(), 1 );
}
// This should eventually fail because the SUM() function evaluates to
// scalar context and that is not appropriate for the WUBHP variable which
// should evaluate to a full well set.
{
UDQDefine def(udqp, "WUBHP", {"SUM" , "(", "WBHP", ")"});
SummaryState st;
UDQContext context(udqft, st);
st.update_well_var("P1", "WBHP", 1);
BOOST_CHECK_THROW( def.eval_wells( context ), std::invalid_argument);
}
}
@@ -235,6 +271,14 @@ BOOST_AUTO_TEST_CASE(ENUM_CONVERSION) {
BOOST_CHECK(UDQ::varType("AUBHP") == UDQVarType::AQUIFER_VAR);
BOOST_CHECK(UDQ::varType("SUBHP") == UDQVarType::SEGMENT_VAR);
BOOST_CHECK(UDQ::targetType("WBHP") == UDQVarType::WELL_VAR);
BOOST_CHECK(UDQ::targetType("GBHP") == UDQVarType::GROUP_VAR);
BOOST_CHECK(UDQ::targetType("CBHP") == UDQVarType::CONNECTION_VAR);
BOOST_CHECK(UDQ::targetType("FBHP") == UDQVarType::FIELD_VAR);
BOOST_CHECK(UDQ::targetType("RBHP") == UDQVarType::REGION_VAR);
BOOST_CHECK(UDQ::targetType("ABHP") == UDQVarType::AQUIFER_VAR);
BOOST_CHECK(UDQ::targetType("SBHP") == UDQVarType::SEGMENT_VAR);
BOOST_REQUIRE_THROW( UDQ::actionType("INVALID_ACTION"), std::invalid_argument);
BOOST_CHECK(UDQ::actionType("DEFINE") == UDQAction::DEFINE );
BOOST_CHECK(UDQ::actionType("UNITS") == UDQAction::UNITS );
@@ -482,47 +526,47 @@ BOOST_AUTO_TEST_CASE(UDQ_FUNCTION_TABLE) {
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("SUM"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 7);
BOOST_CHECK_EQUAL(result[0].value(), 7);
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("NORM1"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 7);
BOOST_CHECK_EQUAL(result[0].value(), 7);
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("NORM2"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), std::sqrt(1 + 4+ 16));
BOOST_CHECK_EQUAL(result[0].value(), std::sqrt(1 + 4+ 16));
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("NORMI"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 4);
BOOST_CHECK_EQUAL(result[0].value(), 4);
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("MIN"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 1);
BOOST_CHECK_EQUAL(result[0].value(), 1);
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("MAX"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 4);
BOOST_CHECK_EQUAL(result[0].value(), 4);
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("AVEA"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 7.0/3);
BOOST_CHECK_EQUAL(result[0].value(), 7.0/3);
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("AVEG"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), std::exp((std::log(1) + std::log(2.0) + std::log(4))/3));
BOOST_CHECK_EQUAL(result[0].value(), std::exp((std::log(1) + std::log(2.0) + std::log(4))/3));
}
{
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("PROD"));
auto result = func.eval(arg);
BOOST_CHECK_EQUAL(result.value(), 8.0);
BOOST_CHECK_EQUAL(result[0].value(), 8.0);
}
{
UDQSet arg2("NAME", 4);
@@ -531,7 +575,7 @@ BOOST_AUTO_TEST_CASE(UDQ_FUNCTION_TABLE) {
arg2.assign(3,4);
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get("AVEH"));
auto result = func.eval(arg2);
BOOST_CHECK_EQUAL(result.value(), 2.0);
BOOST_CHECK_EQUAL(result[0].value(), 2.0);
}
}
@@ -787,18 +831,18 @@ BOOST_AUTO_TEST_CASE(UDQASSIGN_TEST) {
UDQAssign as3("WUPR", {"P1"}, 4.0);
std::vector<std::string> ws1 = {"P1", "P2", "I1", "I2"};
auto res1 = as1.eval_wells(ws1);
auto res1 = as1.eval(ws1);
BOOST_CHECK_EQUAL(res1.size(), 4);
BOOST_CHECK_EQUAL(res1["P1"].value(), 1.0);
BOOST_CHECK_EQUAL(res1["I2"].value(), 1.0);
auto res2 = as2.eval_wells(ws1);
auto res2 = as2.eval(ws1);
BOOST_CHECK_EQUAL(res2["P1"].value(), 2.0);
BOOST_CHECK_EQUAL(res2["P2"].value(), 2.0);
BOOST_CHECK(!res2["I1"].defined());
BOOST_CHECK(!res2["I2"].defined());
auto res3 = as3.eval_wells(ws1);
auto res3 = as3.eval(ws1);
BOOST_CHECK_EQUAL(res3["P1"].value(), 4.0);
BOOST_CHECK(!res3["P2"].defined());
BOOST_CHECK(!res3["I1"].defined());
@@ -819,8 +863,8 @@ BOOST_AUTO_TEST_CASE(UDQ_POW_TEST) {
st.update_well_var("P1", "WWIR", 4);
st.update_well_var("P1", "WOPT", 7);
auto res_pow1 = def_pow1.eval_wells(context);
auto res_pow2 = def_pow2.eval_wells(context);
auto res_pow1 = def_pow1.eval(context);
auto res_pow2 = def_pow2.eval(context);
BOOST_CHECK_EQUAL( res_pow1["P1"].value() , 1 + 2 * std::pow(3,4));
BOOST_CHECK_EQUAL( res_pow2["P1"].value() , std::pow(1 + 2, 1 + 3*4 - 7));
}
@@ -842,7 +886,7 @@ BOOST_AUTO_TEST_CASE(UDQ_CMP_TEST) {
st.update_well_var("P2", "WGOR", 4);
st.update_well_var("P2", "WWIR", 1);
auto res_cmp = def_cmp.eval_wells(context);
auto res_cmp = def_cmp.eval(context);
BOOST_CHECK_EQUAL( res_cmp["P1"].value() , 1.0);
BOOST_CHECK_EQUAL( res_cmp["P2"].value() , 0.0);
}
@@ -876,42 +920,42 @@ BOOST_AUTO_TEST_CASE(UDQ_BASIC_MATH_TEST) {
st.update_well_var("P3", "WWPR", 3);
st.update_well_var("P4", "WWPR", 4);
auto res_add = def_add.eval_wells(context);
auto res_add = def_add.eval(context);
BOOST_CHECK_EQUAL( res_add.size(), 4);
BOOST_CHECK_EQUAL( res_add["P1"].value(), 2);
BOOST_CHECK_EQUAL( res_add["P2"].value(), 4);
BOOST_CHECK_EQUAL( res_add["P3"].value(), 6);
BOOST_CHECK_EQUAL( res_add["P4"].value(), 8);
auto res_sub = def_sub.eval_wells(context);
auto res_sub = def_sub.eval(context);
BOOST_CHECK_EQUAL( res_sub.size(), 4);
BOOST_CHECK_EQUAL( res_sub["P1"].value(), 0);
BOOST_CHECK_EQUAL( res_sub["P2"].value(), 0);
BOOST_CHECK_EQUAL( res_sub["P3"].value(), 0);
BOOST_CHECK_EQUAL( res_sub["P4"].value(), 0);
auto res_div = def_div.eval_wells(context);
auto res_div = def_div.eval(context);
BOOST_CHECK_EQUAL( res_div.size(), 4);
BOOST_CHECK_EQUAL( res_div["P1"].value(), 1);
BOOST_CHECK_EQUAL( res_div["P2"].value(), 1);
BOOST_CHECK_EQUAL( res_div["P3"].value(), 1);
BOOST_CHECK_EQUAL( res_div["P4"].value(), 1);
auto res_mul = def_mul.eval_wells(context);
auto res_mul = def_mul.eval(context);
BOOST_CHECK_EQUAL( res_mul.size(), 4);
BOOST_CHECK_EQUAL( res_mul["P1"].value(), 1);
BOOST_CHECK_EQUAL( res_mul["P2"].value(), 4);
BOOST_CHECK_EQUAL( res_mul["P3"].value(), 9);
BOOST_CHECK_EQUAL( res_mul["P4"].value(),16);
auto res_muladd = def_muladd.eval_wells(context);
auto res_muladd = def_muladd.eval(context);
BOOST_CHECK_EQUAL( res_muladd.size(), 4);
BOOST_CHECK_EQUAL( res_muladd["P1"].value(), 1 + 1);
BOOST_CHECK_EQUAL( res_muladd["P2"].value(), 4 + 2);
BOOST_CHECK_EQUAL( res_muladd["P3"].value(), 9 + 3);
BOOST_CHECK_EQUAL( res_muladd["P4"].value(),16 + 4);
auto res_wuwct= def_wuwct.eval_wells(context);
auto res_wuwct= def_wuwct.eval(context);
BOOST_CHECK_EQUAL( res_wuwct.size(), 4);
BOOST_CHECK_EQUAL( res_wuwct["P1"].value(),0.50);
BOOST_CHECK_EQUAL( res_wuwct["P2"].value(),0.50);
@@ -935,7 +979,7 @@ BOOST_AUTO_TEST_CASE(UDQPARSE_TEST1) {
}
BOOST_AUTO_TEST_CASE(UDQPARSE_PARSECONTEXT) {
BOOST_AUTO_TEST_CASE(UDQ_PARSE_ERROR) {
UDQParams udqp;
ParseContext parseContext;
ErrorGuard errors;
@@ -946,9 +990,8 @@ BOOST_AUTO_TEST_CASE(UDQPARSE_PARSECONTEXT) {
SummaryState st;
UDQContext context(UDQFunctionTable(udqp), st);
st.update_well_var("P1", "WBHP", 1);
printf("Have returned with def1 \n");
auto res = def1.eval_wells(context);
auto res = def1.eval(context);
BOOST_CHECK_EQUAL(res["P1"].value(), udqp.undefinedValue());
}
@@ -956,6 +999,40 @@ BOOST_AUTO_TEST_CASE(UDQPARSE_PARSECONTEXT) {
BOOST_CHECK_THROW( UDQDefine(udqp, "WUBHP", tokens, parseContext, errors), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
UDQParams udqp;
ParseContext parseContext;
ErrorGuard errors;
std::vector<std::string> tokens1 = {"WBHP", "+", "1"};
std::vector<std::string> tokens2 = {"SUM", "(", "WBHP", ")"};
parseContext.update(ParseContext::UDQ_TYPE_ERROR, InputError::IGNORE);
{
UDQDefine def1(udqp, "FUBHP", tokens1, parseContext, errors);
UDQDefine def2(udqp, "WUBHP", tokens2, parseContext, errors);
SummaryState st;
UDQContext context(UDQFunctionTable(udqp), st);
st.update_well_var("P1", "WBHP", 1);
auto res1 = def1.eval(context);
BOOST_CHECK_EQUAL(res1[0].value(), udqp.undefinedValue());
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());
}
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);
}
BOOST_AUTO_TEST_CASE(UDA_VALUE) {