Reduce Level of Nesting in UDQASTNode::eval

In particular, introduce a number of helper functions for evaluating
expressions, well variables, group variables, unary and binary
function expressions, and direct number values.  This also, I
believe, fixes a latent error in one group variable case which
appears not to apply the 'sign' correctly.

While here, also wrap some long lines throughout this component.
This is in preparation of adding support for UDQs at the segment
level.
This commit is contained in:
Bård Skaflestad 2022-11-14 17:12:30 +01:00
parent 845b00c27a
commit 8e90acf070
15 changed files with 1683 additions and 1167 deletions

View File

@ -20,6 +20,10 @@
#ifndef UDQASTNODE_HPP
#define UDQASTNODE_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <memory>
#include <set>
#include <string>
@ -27,16 +31,13 @@
#include <variant>
#include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
class UDQASTNode {
class UDQASTNode
{
public:
UDQVarType var_type = UDQVarType::NONE;
UDQASTNode();
explicit UDQASTNode(UDQTokenType type_arg);
explicit UDQASTNode(double scalar_value);
@ -48,21 +49,20 @@ public:
static UDQASTNode serializationTestObject();
UDQSet eval(UDQVarType eval_target, const UDQContext& context) const;
bool valid() const;
UDQVarType var_type = UDQVarType::NONE;
std::set<UDQTokenType> func_tokens() const;
void update_type(const UDQASTNode& arg);
void set_left(const UDQASTNode& arg);
void set_right(const UDQASTNode& arg);
UDQASTNode* get_left() const;
UDQASTNode* get_right() const;
void scale(double sign_factor);
UDQASTNode* get_left() const;
UDQASTNode* get_right() const;
bool operator==(const UDQASTNode& data) const;
void required_summary(std::unordered_set<std::string>& summary_keys) const;
template<class Serializer>
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(var_type);
@ -76,13 +76,34 @@ public:
private:
UDQTokenType type;
void func_tokens(std::set<UDQTokenType>& tokens) const;
std::variant<std::string, double> value;
double sign = 1.0;
std::vector<std::string> selector;
std::shared_ptr<UDQASTNode> left;
std::shared_ptr<UDQASTNode> right;
UDQSet eval_expression(const UDQContext& context) const;
UDQSet eval_well_expression(const std::string& string_value,
const UDQContext& context) const;
UDQSet eval_group_expression(const std::string& string_value,
const UDQContext& context) const;
UDQSet eval_scalar_function(const UDQVarType target_type,
const UDQContext& context) const;
UDQSet eval_elemental_unary_function(const UDQVarType target_type,
const UDQContext& context) const;
UDQSet eval_binary_function(const UDQVarType target_type,
const UDQContext& context) const;
UDQSet eval_number(const UDQVarType target_type,
const UDQContext& context) const;
void func_tokens(std::set<UDQTokenType>& tokens) const;
};
UDQASTNode operator*(const UDQASTNode&lhs, double rhs);

View File

@ -20,20 +20,22 @@
#ifndef UDQINPUT_HPP_
#define UDQINPUT_HPP_
#include <string>
#include <unordered_map>
#include <map>
#include <unordered_set>
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/EclipseState/Util/OrderedMap.hpp>
#include <opm/input/eclipse/EclipseState/Util/IOrderSet.hpp>
#include <cstddef>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace Opm {
@ -43,12 +45,16 @@ namespace Opm {
class KeywordLocation;
class WellMatcher;
namespace RestartIO {
struct RstState;
}
} // namespace Opm
namespace Opm { namespace RestartIO {
struct RstState;
}} // namespace Opm::RestartIO
class UDQConfig {
namespace Opm {
class UDQConfig
{
public:
UDQConfig() = default;
explicit UDQConfig(const UDQParams& params);
@ -91,7 +97,6 @@ namespace Opm {
bool operator==(const UDQConfig& config) const;
void required_summary(std::unordered_set<std::string>& summary_keys) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
@ -113,20 +118,16 @@ namespace Opm {
void eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const;
void eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const;
UDQParams udq_params;
UDQFunctionTable udqft;
/*
The choices of datastructures are strongly motivated by the
constraints imposed by the Eclipse formatted restart files; for
writing restart files it is essential to keep meticolous control over
the ordering of the keywords. In this class the ordering is mainly
maintained by the input_index map which keeps track of the insert
order of each keyword, and whether the keyword is currently DEFINE'ed
or ASSIGN'ed.
*/
// The choices of data structures are strongly motivated by the
// constraints imposed by the ECLIPSE formatted restart files; for
// writing restart files it is essential to keep meticulous control
// over the ordering of the keywords. In this class the ordering is
// mainly maintained by the input_index map which keeps track of the
// insert order of each keyword, and whether the keyword is
// currently DEFINE'ed or ASSIGN'ed.
std::unordered_map<std::string, UDQDefine> m_definitions;
std::unordered_map<std::string, UDQAssign> m_assignments;
std::unordered_map<std::string, std::string> units;

View File

@ -17,30 +17,38 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDQ_DEFINE_HPP
#define UDQ_DEFINE_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <cstddef>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
namespace Opm {
class UDQASTNode;
class ParseContext;
class ErrorGuard;
class UDQDefine{
} // Namespace Opm
namespace Opm {
class UDQDefine
{
public:
UDQDefine();
@ -73,7 +81,7 @@ public:
const std::string& keyword() const;
const std::string& input_string() const;
const KeywordLocation& location() const;
UDQVarType var_type() const;
UDQVarType var_type() const;
std::set<UDQTokenType> func_tokens() const;
void required_summary(std::unordered_set<std::string>& summary_keys) const;
void update_status(UDQUpdate update_status, std::size_t report_step);
@ -82,7 +90,7 @@ public:
bool operator==(const UDQDefine& data) const;
template<class Serializer>
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(m_keyword);
@ -104,8 +112,7 @@ private:
UDQUpdate m_update_status;
mutable std::optional<std::string> string_data;
};
}
} // Namespace Opm
#endif
#endif // UDQ_DEFINE_HPP

View File

@ -25,40 +25,41 @@
namespace Opm {
/*
The UDQ variables can be of of many different types. In addition they can be
either scalars or vector sets. The arch example of a vector set is well
variables - in the expressions:
// The UDQ variables can be of many different types. Additionally they can
// be either scalars or vector sets. The archetypal example of a vector set
// is well variables. For instance, in the expressions:
//
// UDQ
// DEFINE WUBHP WBHP * 1.15 /
// DEFINE WUORAT 1000 /
// /
//
// we define two UDQ values 'WUBHP' and 'WUORAT'. Both of these UDQ values
// will apply to all wells; the WUBHP vector will correspond to the normal
// BHP scaled up 15%, the WUORAT has the scalar value 1000 for all wells.
// The well sets can be constrained with a well name. If the well name is a
// template, we get a well set. Otherwise, i.e., if the well name is fully
// qualified we have a scalar:
//
// UDQ
// DEFINE WUWCT WWCT 'OP*' /
// DEFINE FUORAT WOPR 'OPX' * 100 /
// /
//
// Here the UDQ WUCWT corresponds to the well WWCT for all wells matching
// the template 'OP*', and it is undefined for other wells. The UDQ FUORAT
// is a scalar, given by the WOPR of well 'OPX' - multiplied by 100.
//
// There are clearly rules for how the different variable types can be
// combined in expressions, and what will be resulting type from an
// expression - unfortunately that is not yet very well implemented in the
// opm codebase. In UDQParser.cpp there is a function static_type_check and
// in UDQDefine there is a function dynamic_type_check - these functions try
// to verfiy that the type conversions are legitimate, but currently they
// are woefully inadequate.
UDQ
DEFINE WUBHP WBHP * 1.15 /
DEFINE WUORAT 1000 /
/
we define two UDQ values 'WUBHP' and 'WUORAT'. Both of these UDQ values will
apply to all wells; the WUBHP vector will correspond to the normal BHP scaled
up 15%, the WUORAT has the scalar value 1000 for all the wells. The well sets
can be qualified with a wellname, if the wellname has a wildcard we will get a
well set, if the wellname is fully qualified we have a scalar:
UDQ
DEFINE WUWCT WWCT 'OP*' /
DEFINE FUORAT WOPR 'OPX' * 100 /
/
Here the UDQ WUCWT corresponds to the well WWCT for all wells matching the
name 'OP*', and it is undefined for the remaing wells. The UDQ FUORAT is a
scalar, given by the WOPR of well 'OPX' - multiplied by 100.
There are clearly rules for how the different variable types can be combined
in expressions, and what will be resulting type from an expression -
unfortunately that is not yet very well implemented in the opm codebase. In
UDQParser.cpp there is a function static_type_check and in UDQDefine there is
a function dynamic_type_check - these functions try to verfiy that the type
conversions are legitimate, but currently they are woefully inadequate.
*/
enum class UDQVarType {
enum class UDQVarType
{
NONE = 0,
SCALAR = 1,
CONNECTION_VAR = 2,
@ -68,10 +69,11 @@ enum class UDQVarType {
AQUIFER_VAR = 6,
BLOCK_VAR = 7,
WELL_VAR = 8,
GROUP_VAR = 9
GROUP_VAR = 9,
};
enum class UDQTokenType{
enum class UDQTokenType
{
error = 0,
number = 1,
open_paren = 2,
@ -123,23 +125,26 @@ enum class UDQTokenType{
//
table_lookup = 47,
//
end = 100
end = 100,
};
enum class UDQAction {
enum class UDQAction
{
ASSIGN,
DEFINE,
UNITS,
UPDATE
UPDATE,
};
enum class UDQUpdate {
enum class UDQUpdate
{
ON,
OFF,
NEXT
NEXT,
};
enum class UDAControl {
enum class UDAControl
{
WCONPROD_ORAT,
WCONPROD_WRAT,
WCONPROD_GRAT,
@ -173,7 +178,8 @@ enum class UDAControl {
WELTARG_LIFT,
};
enum class UDAKeyword {
enum class UDAKeyword
{
WCONPROD,
WCONINJE,
WELTARG,
@ -187,11 +193,15 @@ namespace UDQ {
UDQVarType targetType(const std::string& keyword);
UDQVarType varType(const std::string& keyword);
UDQVarType coerce(UDQVarType t1, UDQVarType t2);
UDQAction actionType(const std::string& action_string);
UDQUpdate updateType(const std::string& update_string);
UDQUpdate updateType(int int_value);
UDQTokenType tokenType(const std::string& func_name);
UDQTokenType funcType(const std::string& func_name);
bool binaryFunc(UDQTokenType token_type);
bool elementalUnaryFunc(UDQTokenType token_type);
bool scalarFunc(UDQTokenType token_type);
@ -208,12 +218,15 @@ namespace UDQ {
std::string typeName(UDQVarType var_type);
std::string controlName(UDAControl control);
UDAKeyword keyword(UDAControl control);
int udaCode(UDAControl control);
UDAControl udaControl(int uda_code);
constexpr double restart_default = -0.3E+21;
} // UDQ
} // Opm
#endif // UDQ_ENUMS_HPP
} // namespace UDQ
} // namespace Opm
#endif // UDQ_ENUMS_HPP

View File

@ -17,32 +17,33 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDQINPUT__HPP_
#define UDQINPUT__HPP_
#include <variant>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <cstddef>
#include <string>
#include <variant>
namespace Opm {
class UDQAssign;
class UDQDefine;
class UDQIndex {
class UDQIndex
{
public:
UDQIndex() = default;
UDQIndex(std::size_t insert_index_arg, std::size_t typed_insert_index_arg, UDQAction action_arg, UDQVarType var_type_arg) :
insert_index(insert_index_arg),
typed_insert_index(typed_insert_index_arg),
action(action_arg),
var_type(var_type_arg)
{
}
UDQIndex(const std::size_t insert_index_arg,
const std::size_t typed_insert_index_arg,
const UDQAction action_arg,
const UDQVarType var_type_arg)
: insert_index (insert_index_arg)
, typed_insert_index(typed_insert_index_arg)
, action (action_arg)
, var_type (var_type_arg)
{}
static UDQIndex serializationTestObject()
{
@ -55,14 +56,16 @@ public:
return result;
}
bool operator==(const UDQIndex& data) const {
return insert_index == data.insert_index &&
typed_insert_index == data.typed_insert_index &&
action == data.action &&
var_type == data.var_type;
bool operator==(const UDQIndex& data) const
{
return (insert_index == data.insert_index)
&& (typed_insert_index == data.typed_insert_index)
&& (action == data.action)
&& (var_type == data.var_type)
;
}
template<class Serializer>
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(insert_index);
@ -77,16 +80,16 @@ public:
UDQVarType var_type;
};
class UDQInput{
class UDQInput
{
public:
UDQInput(const UDQIndex& index, const UDQDefine& udq_define, const std::string& unit);
UDQInput(const UDQIndex& index, const UDQAssign& udq_assign, const std::string& unit);
template<typename T>
template <typename T>
const T& get() const;
template<typename T>
template <typename T>
bool is() const;
const std::string& keyword() const;
@ -95,14 +98,14 @@ public:
const UDQIndex index;
bool operator==(const UDQInput& other) const;
private:
std::variant<UDQDefine, UDQAssign> value;
const std::string m_keyword;
std::string m_keyword;
UDQVarType m_var_type;
const std::string m_unit;
std::string m_unit;
};
}
} // namespace Opm
#endif
#endif // UDQINPUT__HPP_

View File

@ -20,17 +20,19 @@
#ifndef UDQSET_HPP
#define UDQSET_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
class UDQScalar {
class UDQScalar
{
public:
UDQScalar() = default;
explicit UDQScalar(double value);
@ -60,12 +62,14 @@ public:
};
class UDQSet {
class UDQSet
{
public:
UDQSet(const std::string& name, UDQVarType var_type);
UDQSet(const std::string& name, UDQVarType var_type, const std::vector<std::string>& wgnames);
UDQSet(const std::string& name, UDQVarType var_type, std::size_t size);
UDQSet(const std::string& name, std::size_t size);
static UDQSet scalar(const std::string& name, const std::optional<double>& scalar_value);
static UDQSet scalar(const std::string& name, double value);
static UDQSet empty(const std::string& name);
@ -84,6 +88,7 @@ public:
bool has(const std::string& name) const;
std::size_t size() const;
void operator+=(const UDQSet& rhs);
void operator+=(double rhs);
void operator-=(const UDQSet& rhs);
@ -105,6 +110,7 @@ public:
void name(const std::string& name);
UDQVarType var_type() const;
bool operator==(const UDQSet& other) const;
private:
UDQSet() = default;

View File

@ -16,91 +16,131 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunction.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
UDQASTNode::UDQASTNode() :
UDQASTNode(UDQTokenType::error)
{}
UDQASTNode::UDQASTNode(UDQTokenType type_arg) :
var_type(UDQVarType::NONE),
type(type_arg)
{
if (type == UDQTokenType::error)
return;
if (type == UDQTokenType::binary_op_add)
return;
if (type == UDQTokenType::binary_op_sub)
return;
throw std::invalid_argument("The one argument constructor is only available for error and end");
}
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_set>
#include <variant>
#include <vector>
namespace {
UDQVarType init_type(UDQTokenType token_type)
bool is_udq(const std::string& key)
{
if (token_type == UDQTokenType::number)
return UDQVarType::SCALAR;
if (UDQ::scalarFunc(token_type))
return UDQVarType::SCALAR;
return UDQVarType::NONE;
return (key.size() >= std::string::size_type{2})
&& (key[1] == 'U');
}
Opm::UDQVarType init_type(const Opm::UDQTokenType token_type)
{
if (token_type == Opm::UDQTokenType::number) {
return Opm::UDQVarType::SCALAR;
}
if (Opm::UDQ::scalarFunc(token_type)) {
return Opm::UDQVarType::SCALAR;
}
return Opm::UDQVarType::NONE;
}
} // Anonymous namespace
UDQASTNode::UDQASTNode(double numeric_value) :
var_type(init_type(UDQTokenType::number)),
type(UDQTokenType::number),
value(numeric_value)
namespace Opm {
UDQASTNode::UDQASTNode()
: UDQASTNode(UDQTokenType::error)
{}
UDQASTNode::UDQASTNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) :
var_type(init_type(type_arg)),
type(type_arg),
value(value_arg)
UDQASTNode::UDQASTNode(const UDQTokenType type_arg)
: var_type(UDQVarType::NONE)
, type (type_arg)
{
if ((this->type == UDQTokenType::error) ||
(this->type == UDQTokenType::binary_op_add) ||
(this->type == UDQTokenType::binary_op_sub))
{
return;
}
throw std::invalid_argument {
"Single argument AST node constructor available only "
"for error and binary addition/subtraction tokens"
};
}
UDQASTNode::UDQASTNode(double numeric_value)
: var_type(init_type(UDQTokenType::number))
, type (UDQTokenType::number)
, value (numeric_value)
{}
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg)
: var_type(init_type(type_arg))
, type (type_arg)
, value (value_arg)
{}
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const UDQASTNode& left_arg)
const UDQASTNode& left_arg)
: UDQASTNode(type_arg, value_arg)
{
if (UDQ::scalarFunc(type_arg))
if (UDQ::scalarFunc(type_arg)) {
this->var_type = UDQVarType::SCALAR;
else
}
else {
this->var_type = left_arg.var_type;
}
this->left = std::make_unique<UDQASTNode>(left_arg);
}
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const UDQASTNode& left_arg,
const UDQASTNode& right_arg) :
var_type(init_type(type_arg)),
type(type_arg),
value(value_arg)
const UDQASTNode& left_arg,
const UDQASTNode& right_arg)
: var_type(init_type(type_arg))
, type (type_arg)
, value (value_arg)
{
this->set_left(left_arg);
this->set_right(right_arg);
}
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const std::vector<std::string>& selector_arg)
: var_type(init_type(type_arg))
, type (type_arg)
, value (value_arg)
, selector(selector_arg)
{
if (type_arg == UDQTokenType::ecl_expr) {
this->var_type = UDQ::targetType(std::get<std::string>(this->value), this->selector);
}
if ((this->var_type == UDQVarType::CONNECTION_VAR) ||
(this->var_type == UDQVarType::REGION_VAR) ||
(this->var_type == UDQVarType::SEGMENT_VAR) ||
(this->var_type == UDQVarType::AQUIFER_VAR) ||
(this->var_type == UDQVarType::BLOCK_VAR))
{
throw std::invalid_argument {
"UDQ variable of type: " + UDQ::typeName(this->var_type) + " not yet supported in flow"
};
}
}
UDQASTNode UDQASTNode::serializationTestObject()
{
@ -110,257 +150,323 @@ UDQASTNode UDQASTNode::serializationTestObject()
result.value = "test1";
result.selector = {"test2"};
result.sign = -1;
UDQASTNode left = result;
result.left = std::make_shared<UDQASTNode>(left);
return result;
}
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const std::vector<std::string>& selector_arg) :
var_type(init_type(type_arg)),
type(type_arg),
value(value_arg),
selector(selector_arg)
UDQSet
UDQASTNode::eval(const UDQVarType target_type,
const UDQContext& context) const
{
if (type_arg == UDQTokenType::ecl_expr)
this->var_type = UDQ::targetType(std::get<std::string>(this->value), this->selector);
if (this->var_type == UDQVarType::CONNECTION_VAR ||
this->var_type == UDQVarType::REGION_VAR ||
this->var_type == UDQVarType::SEGMENT_VAR ||
this->var_type == UDQVarType::AQUIFER_VAR ||
this->var_type == UDQVarType::BLOCK_VAR)
throw std::logic_error("UDQ variable of type: " + UDQ::typeName(this->var_type) + " not yet supported in flow");
}
UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const {
if (this->type == UDQTokenType::ecl_expr) {
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& all_wells = context.wells();
if (this->selector.empty()) {
auto res = UDQSet::wells(string_value, all_wells);
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.
*/
return this->sign * UDQSet::scalar(string_value, 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.
*/
auto res = UDQSet::wells(string_value, all_wells);
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) {
if (this->selector.size() > 0) {
const std::string& group_pattern = this->selector[0];
if (group_pattern.find("*") == std::string::npos)
return UDQSet::scalar(string_value, context.get_group_var(group_pattern, string_value));
else
throw std::logic_error("Group names with wildcards is not yet supported");
} else {
const auto& groups = context.groups();
auto res = UDQSet::groups(string_value, groups);
for (const auto& group : groups)
res.assign(group, context.get_group_var(group, string_value));
return this->sign * res;
}
}
if (data_type == UDQVarType::FIELD_VAR)
return this->sign * UDQSet::scalar(string_value, context.get(string_value));
auto scalar = context.get(string_value);
if (scalar.has_value())
return this->sign * UDQSet::scalar(string_value, scalar.value());
throw std::logic_error("Should not be here: var_type: " + UDQ::typeName(data_type) + " stringvalue:" + string_value);
return this->sign * this->eval_expression(context);
}
if (UDQ::scalarFunc(this->type)) {
const auto& string_value = std::get<std::string>( this->value );
const auto& udqft = context.function_table();
const UDQScalarFunction& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(string_value));
return this->sign * func.eval( this->left->eval(target_type, context) );
return this->sign * this->eval_scalar_function(target_type, context);
}
if (UDQ::elementalUnaryFunc(this->type)) {
const auto& string_value = std::get<std::string>( this->value );
auto func_arg = this->left->eval(target_type, context);
const auto& udqft = context.function_table();
const UDQUnaryElementalFunction& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(string_value));
return this->sign * func.eval(func_arg);
return this->sign * this->eval_elemental_unary_function(target_type, context);
}
if (UDQ::binaryFunc(this->type)) {
auto left_arg = this->left->eval(target_type, context);
auto right_arg = this->right->eval(target_type, context);
const auto& string_value = std::get<std::string>( this->value );
const auto& udqft = context.function_table();
const UDQBinaryFunction& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(string_value));
auto res = func.eval(left_arg, right_arg);
return this->sign * res;
return this->sign * this->eval_binary_function(target_type, context);
}
if (this->type == UDQTokenType::number) {
const std::string dummy_name = "DUMMY";
double numeric_value = std::get<double>(this->value);
switch(target_type) {
case UDQVarType::WELL_VAR:
return this->sign * UDQSet::wells(dummy_name, context.wells(), numeric_value);
case UDQVarType::GROUP_VAR:
return this->sign * UDQSet::groups(dummy_name, context.groups(), numeric_value);
case UDQVarType::SCALAR:
return this->sign * UDQSet::scalar(dummy_name, numeric_value);
case UDQVarType::FIELD_VAR:
return this->sign * UDQSet::field(dummy_name, numeric_value);
default:
throw std::invalid_argument("Unsupported target_type: " + std::to_string(static_cast<int>(target_type)));
}
return this->sign * this->eval_number(target_type, context);
}
throw std::invalid_argument("Should not be here ... this->type: " + std::to_string(static_cast<int>(this->type)));
throw std::invalid_argument {
"Should not be here ... this->type: " + std::to_string(static_cast<int>(this->type))
};
}
void UDQASTNode::func_tokens(std::set<UDQTokenType>& tokens) const {
tokens.insert( this->type );
if (this->left)
this->left->func_tokens(tokens);
if (this->right)
this->right->func_tokens(tokens);
bool UDQASTNode::valid() const
{
return this->type != UDQTokenType::error;
}
std::set<UDQTokenType> UDQASTNode::func_tokens() const {
std::set<UDQTokenType> tokens;
std::set<UDQTokenType> UDQASTNode::func_tokens() const
{
auto tokens = std::set<UDQTokenType>{};
this->func_tokens(tokens);
return tokens;
}
UDQASTNode* UDQASTNode::get_left() const {
return this->left.get();
}
UDQASTNode* UDQASTNode::get_right() const {
return this->right.get();
}
void UDQASTNode::update_type(const UDQASTNode& arg) {
if (this->var_type == UDQVarType::NONE)
void UDQASTNode::update_type(const UDQASTNode& arg)
{
if (this->var_type == UDQVarType::NONE) {
this->var_type = arg.var_type;
else
}
else {
this->var_type = UDQ::coerce(this->var_type, arg.var_type);
}
}
bool UDQASTNode::valid() const {
return (this->type != UDQTokenType::error);
}
void UDQASTNode::set_left(const UDQASTNode& arg) {
void UDQASTNode::set_left(const UDQASTNode& arg)
{
this->left = std::make_unique<UDQASTNode>(arg);
this->update_type(arg);
}
void UDQASTNode::set_right(const UDQASTNode& arg) {
void UDQASTNode::set_right(const UDQASTNode& arg)
{
this->right = std::make_unique<UDQASTNode>(arg);
this->update_type(arg);
}
void UDQASTNode::scale(double sign_factor) {
void UDQASTNode::scale(double sign_factor)
{
this->sign *= sign_factor;
}
bool UDQASTNode::operator==(const UDQASTNode& data) const {
UDQASTNode* UDQASTNode::get_left() const
{
return this->left.get();
}
UDQASTNode* UDQASTNode::get_right() const
{
return this->right.get();
}
bool UDQASTNode::operator==(const UDQASTNode& data) const
{
if ((this->left && !data.left) ||
(!this->left && data.left))
{
return false;
}
if (this->left && !(*this->left == *data.left))
if (this->left && !(*this->left == *data.left)) {
return false;
}
if ((this->right && !data.right) ||
(!this->right && data.right))
{
return false;
}
if (this->right && !(*this->right == *data.right))
if (this->right && !(*this->right == *data.right)) {
return false;
}
return type == data.type &&
var_type == data.var_type &&
value == data.value &&
selector == data.selector;
return (type == data.type)
&& (var_type == data.var_type)
&& (value == data.value)
&& (selector == data.selector)
;
}
namespace {
bool is_udq(const std::string& key) {
if (key.size() < 2)
return false;
if (key[1] != 'U')
return false;
return true;
}
}
void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const {
void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const
{
if (this->type == UDQTokenType::ecl_expr) {
if (std::holds_alternative<std::string>(this->value)) {
const auto& keyword = std::get<std::string>(this->value);
if (!is_udq(keyword))
if (!is_udq(keyword)) {
summary_keys.insert(keyword);
}
}
}
if (this->left)
if (this->left) {
this->left->required_summary(summary_keys);
}
if (this->right)
if (this->right) {
this->right->required_summary(summary_keys);
}
}
UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor) {
UDQSet
UDQASTNode::eval_expression(const UDQContext& context) const
{
const auto& string_value = std::get<std::string>(this->value);
const auto data_type = UDQ::targetType(string_value);
if (data_type == UDQVarType::WELL_VAR) {
return this->eval_well_expression(string_value, context);
}
if (data_type == UDQVarType::GROUP_VAR) {
return this->eval_group_expression(string_value, context);
}
if (data_type == UDQVarType::FIELD_VAR) {
return UDQSet::scalar(string_value, context.get(string_value));
}
if (const auto scalar = context.get(string_value); scalar.has_value()) {
return UDQSet::scalar(string_value, scalar.value());
}
throw std::logic_error {
"Should not be here: var_type: '"
+ UDQ::typeName(data_type)
+ "' stringvalue: '"
+ string_value + '\''
};
}
UDQSet
UDQASTNode::eval_well_expression(const std::string& string_value,
const UDQContext& context) const
{
const auto& all_wells = context.wells();
if (this->selector.empty()) {
auto res = UDQSet::wells(string_value, all_wells);
for (const auto& well : all_wells) {
res.assign(well, context.get_well_var(well, string_value));
}
return res;
}
const auto& well_pattern = this->selector.front();
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.
return UDQSet::scalar(string_value, 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.
auto res = UDQSet::wells(string_value, all_wells);
for (const auto& wname : context.wells(well_pattern)) {
res.assign(wname, context.get_well_var(wname, string_value));
}
return res;
}
}
UDQSet
UDQASTNode::eval_group_expression(const std::string& string_value,
const UDQContext& context) const
{
if (! this->selector.empty()) {
const std::string& group_pattern = this->selector[0];
if (group_pattern.find("*") == std::string::npos) {
return UDQSet::scalar(string_value, context.get_group_var(group_pattern, string_value));
}
throw std::logic_error("Group names with wildcards is not yet supported");
}
const auto& groups = context.groups();
auto res = UDQSet::groups(string_value, groups);
for (const auto& group : groups) {
res.assign(group, context.get_group_var(group, string_value));
}
return res;
}
UDQSet
UDQASTNode::eval_scalar_function(const UDQVarType target_type,
const UDQContext& context) const
{
const auto& string_value = std::get<std::string>(this->value);
const auto& udqft = context.function_table();
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(string_value));
return func.eval(this->left->eval(target_type, context));
}
UDQSet
UDQASTNode::eval_elemental_unary_function(const UDQVarType target_type,
const UDQContext& context) const
{
const auto& string_value = std::get<std::string>(this->value);
const auto func_arg = this->left->eval(target_type, context);
const auto& udqft = context.function_table();
const auto& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(string_value));
return func.eval(func_arg);
}
UDQSet
UDQASTNode::eval_binary_function(const UDQVarType target_type,
const UDQContext& context) const
{
const auto left_arg = this->left->eval(target_type, context);
const auto right_arg = this->right->eval(target_type, context);
const auto& string_value = std::get<std::string>(this->value);
const auto& udqft = context.function_table();
const auto& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(string_value));
return func.eval(left_arg, right_arg);
}
UDQSet
UDQASTNode::eval_number(const UDQVarType target_type,
const UDQContext& context) const
{
const auto dummy_name = std::string { "DUMMY" };
const auto numeric_value = std::get<double>(this->value);
switch (target_type) {
case UDQVarType::WELL_VAR:
return UDQSet::wells(dummy_name, context.wells(), numeric_value);
case UDQVarType::GROUP_VAR:
return UDQSet::groups(dummy_name, context.groups(), numeric_value);
case UDQVarType::SCALAR:
return UDQSet::scalar(dummy_name, numeric_value);
case UDQVarType::FIELD_VAR:
return UDQSet::field(dummy_name, numeric_value);
default:
throw std::invalid_argument {
"Unsupported target_type: " + std::to_string(static_cast<int>(target_type))
};
}
}
void UDQASTNode::func_tokens(std::set<UDQTokenType>& tokens) const
{
tokens.insert(this->type);
if (this->left) {
this->left->func_tokens(tokens);
}
if (this->right) {
this->right->func_tokens(tokens);
}
}
UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor)
{
UDQASTNode prod = lhs;
prod.scale(sign_factor);
return prod;
}
UDQASTNode operator*(double lhs, const UDQASTNode& rhs) {
UDQASTNode operator*(double lhs, const UDQASTNode& rhs)
{
return rhs * lhs;
}
}
} // namespace Opm

View File

@ -17,45 +17,69 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/io/eclipse/rst/state.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/U.hpp> // UDQ
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <algorithm>
#include <cstddef>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include <vector>
#include <fmt/format.h>
namespace {
std::string strip_quotes(const std::string& s)
{
if (s[0] == '\'') {
return s.substr(1, s.size() - 2);
}
else {
return s;
}
}
} // Anonymous namespace
namespace Opm {
namespace {
std::string strip_quotes(const std::string& s) {
if (s[0] == '\'')
return s.substr(1, s.size() - 2);
else
return s;
}
}
UDQConfig::UDQConfig(const UDQParams& params) :
udq_params(params),
udqft(this->udq_params)
UDQConfig::UDQConfig(const UDQParams& params)
: udq_params(params)
, udqft(this->udq_params)
{}
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state) :
UDQConfig(params)
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state)
: UDQConfig(params)
{
for (const auto& rst_udq : rst_state.udqs) {
if (rst_udq.is_define()) {
KeywordLocation location("UDQ", "Restart file", 0);
this->add_define(rst_udq.name, location, {rst_udq.expression()}, rst_state.header.report_step);
} else
this->add_assign(rst_udq.name, rst_udq.assign_selector(), rst_udq.assign_value(), rst_state.header.report_step);
this->add_define(rst_udq.name,
location,
{ rst_udq.expression() },
rst_state.header.report_step);
}
else {
this->add_assign(rst_udq.name,
rst_udq.assign_selector(),
rst_udq.assign_value(),
rst_state.header.report_step);
}
this->add_unit(rst_udq.name, rst_udq.unit);
}
}
@ -74,113 +98,172 @@ namespace Opm {
return result;
}
const UDQParams& UDQConfig::params() const {
const UDQParams& UDQConfig::params() const
{
return this->udq_params;
}
void UDQConfig::add_node( const std::string& quantity, UDQAction action) {
void UDQConfig::add_node(const std::string& quantity, const UDQAction action)
{
auto index_iter = this->input_index.find(quantity);
if (this->input_index.find(quantity) == this->input_index.end()) {
auto var_type = UDQ::varType(quantity);
auto insert_index = this->input_index.size();
this->type_count[var_type] += 1;
this->input_index[quantity] = UDQIndex(insert_index, this->type_count[var_type], action, var_type);
} else
}
else {
index_iter->second.action = action;
}
}
void UDQConfig::add_assign(const std::string& quantity, const std::vector<std::string>& selector, double value, std::size_t report_step) {
void UDQConfig::add_assign(const std::string& quantity,
const std::vector<std::string>& selector,
const double value,
const std::size_t report_step)
{
this->add_node(quantity, UDQAction::ASSIGN);
auto assignment = this->m_assignments.find(quantity);
if (assignment == this->m_assignments.end())
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step )));
else
if (assignment == this->m_assignments.end()) {
this->m_assignments.emplace(std::piecewise_construct,
std::forward_as_tuple(quantity),
std::forward_as_tuple(quantity, selector,
value, report_step));
}
else {
assignment->second.add_record(selector, value, report_step);
}
}
void UDQConfig::add_assign(const std::string& quantity, const std::unordered_set<std::string>& selector, double value, std::size_t report_step) {
void UDQConfig::add_assign(const std::string& quantity,
const std::unordered_set<std::string>& selector,
const double value,
const std::size_t report_step)
{
this->add_node(quantity, UDQAction::ASSIGN);
auto assignment = this->m_assignments.find(quantity);
if (assignment == this->m_assignments.end())
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step )));
else
if (assignment == this->m_assignments.end()) {
this->m_assignments.emplace(std::piecewise_construct,
std::forward_as_tuple(quantity),
std::forward_as_tuple(quantity, selector,
value, report_step));
}
else {
assignment->second.add_record(selector, value, report_step);
}
}
void UDQConfig::add_define(const std::string& quantity, const KeywordLocation& location, const std::vector<std::string>& expression, std::size_t report_step) {
void UDQConfig::add_define(const std::string& quantity,
const KeywordLocation& location,
const std::vector<std::string>& expression,
const std::size_t report_step)
{
this->add_node(quantity, UDQAction::DEFINE);
auto defined_iter = this->m_definitions.find( quantity );
if (defined_iter != this->m_definitions.end())
this->m_definitions.erase( defined_iter );
this->m_definitions.insert( std::make_pair(quantity, UDQDefine(this->udq_params, quantity, report_step, location, expression)));
this->m_definitions.insert_or_assign(quantity,
UDQDefine {
this->udq_params,
quantity,
report_step,
location,
expression
});
this->define_order.insert(quantity);
}
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit) {
const std::string unit = strip_quotes(quoted_unit);
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit)
{
const auto unit = strip_quotes(quoted_unit);
const auto pair_ptr = this->units.find(keyword);
if (pair_ptr != this->units.end()) {
if (pair_ptr->second != unit)
if (pair_ptr->second != unit) {
throw std::invalid_argument("Illegal to change unit of UDQ keyword runtime");
}
return;
}
this->units[keyword] = unit;
}
void UDQConfig::add_update(const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& data)
{
if (data.empty()) {
throw OpmInputError {
fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword),
location
};
}
void UDQConfig::add_update(const std::string& keyword, std::size_t report_step, const KeywordLocation& location, const std::vector<std::string>& data) {
if (data.empty())
throw OpmInputError( fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword), location);
if (this->m_definitions.count(keyword) == 0) {
throw OpmInputError {
fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword),
location
};
}
if (this->m_definitions.count(keyword) == 0)
throw OpmInputError( fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword), location);
const auto update_status = UDQ::updateType(data[0]);
auto update_status = UDQ::updateType(data[0]);
auto& define = this->m_definitions[keyword];
define.update_status( update_status, report_step );
define.update_status(update_status, report_step);
}
void UDQConfig::add_record(const DeckRecord& record,
const KeywordLocation& location,
const std::size_t report_step)
{
using KW = ParserKeywords::UDQ;
const auto action = UDQ::actionType(record.getItem<KW::ACTION>().get<RawString>(0));
const auto& quantity = record.getItem<KW::QUANTITY>().get<std::string>(0);
const auto data = RawString::strings(record.getItem<KW::DATA>().getData<RawString>());
void UDQConfig::add_record(const DeckRecord& record, const KeywordLocation& location, std::size_t report_step) {
auto action = UDQ::actionType(record.getItem("ACTION").get<RawString>(0));
const auto& quantity = record.getItem("QUANTITY").get<std::string>(0);
const auto& data = RawString::strings( record.getItem("DATA").getData<RawString>() );
if (action == UDQAction::UPDATE)
if (action == UDQAction::UPDATE) {
this->add_update(quantity, report_step, location, data);
else if (action == UDQAction::UNITS)
this->add_unit( quantity, data[0] );
}
else if (action == UDQAction::UNITS) {
this->add_unit(quantity, data.front());
}
else if (action == UDQAction::ASSIGN) {
const auto selector = std::vector<std::string>(data.begin(), data.end() - 1);
const auto value = std::stod(data.back());
this->add_assign(quantity, selector, value, report_step);
}
else if (action == UDQAction::DEFINE) {
this->add_define(quantity, location, data, report_step);
}
else {
if (action == UDQAction::ASSIGN) {
std::vector<std::string> selector(data.begin(), data.end() - 1);
double value = std::stod(data.back());
this->add_assign(quantity, selector, value, report_step);
} else if (action == UDQAction::DEFINE)
this->add_define(quantity, location, data, report_step);
else
throw std::runtime_error("Internal error - should not be here");
throw std::runtime_error {
"Unknown UDQ Operation " + std::to_string(static_cast<int>(action))
};
}
}
const UDQAssign& UDQConfig::assign(const std::string& key) const {
const UDQAssign& UDQConfig::assign(const std::string& key) const
{
return this->m_assignments.at(key);
}
const UDQDefine& UDQConfig::define(const std::string& key) const {
const UDQDefine& UDQConfig::define(const std::string& key) const
{
return this->m_definitions.at(key);
}
UDQAction UDQConfig::action_type(const std::string& udq_key) const {
UDQAction UDQConfig::action_type(const std::string& udq_key) const
{
auto action_iter = this->input_index.find(udq_key);
return action_iter->second.action;
}
std::vector<UDQDefine> UDQConfig::definitions() const {
std::vector<UDQDefine> UDQConfig::definitions() const
{
std::vector<UDQDefine> ret;
for (const auto& index_pair : this->input_index) {
@ -193,164 +276,184 @@ namespace Opm {
return ret;
}
std::vector<UDQDefine> UDQConfig::definitions(UDQVarType var_type) const {
std::vector<UDQDefine> UDQConfig::definitions(const UDQVarType var_type) const
{
std::vector<UDQDefine> filtered_defines;
for (const auto& index_pair : this->input_index) {
if (index_pair.second.action == UDQAction::DEFINE) {
const std::string& key = index_pair.first;
const auto& udq_define = this->m_definitions.at(key);
if (udq_define.var_type() == var_type)
if (udq_define.var_type() == var_type) {
filtered_defines.push_back(udq_define);
}
}
}
return filtered_defines;
}
std::vector<UDQInput> UDQConfig::input() const {
std::vector<UDQInput> UDQConfig::input() const
{
std::vector<UDQInput> res;
for (const auto& index_pair : this->input_index) {
const UDQIndex& index = index_pair.second;
std::string u;
if (this->has_unit(index_pair.first))
if (this->has_unit(index_pair.first)) {
u = this->unit(index_pair.first);
}
if (index.action == UDQAction::DEFINE) {
const std::string& key = index_pair.first;
res.push_back(UDQInput(index, this->m_definitions.at(key), u));
} else if (index_pair.second.action == UDQAction::ASSIGN) {
}
else if (index_pair.second.action == UDQAction::ASSIGN) {
const std::string& key = index_pair.first;
res.push_back(UDQInput(index, this->m_assignments.at(key), u));
}
}
return res;
}
std::size_t UDQConfig::size() const {
std::size_t s = 0;
for (const auto& index_pair : this->input_index) {
if (index_pair.second.action == UDQAction::DEFINE)
s += 1;
else if (index_pair.second.action == UDQAction::ASSIGN)
s += 1;
}
return s;
std::size_t UDQConfig::size() const
{
return std::count_if(this->input_index.begin(), this->input_index.end(),
[](const auto& index_pair)
{
const auto action = index_pair.second.action;
return (action == UDQAction::DEFINE)
|| (action == UDQAction::ASSIGN);
});
}
std::vector<UDQAssign> UDQConfig::assignments() const {
std::vector<UDQAssign> UDQConfig::assignments() const
{
std::vector<UDQAssign> ret;
for (const auto& index_pair : this->input_index) {
if (index_pair.second.action == UDQAction::ASSIGN) {
const std::string& key = index_pair.first;
ret.push_back(this->m_assignments.at(key));
}
}
return ret;
}
std::vector<UDQAssign> UDQConfig::assignments(UDQVarType var_type) const {
std::vector<UDQAssign> UDQConfig::assignments(const UDQVarType var_type) const
{
std::vector<UDQAssign> filtered_assigns;
for (const auto& index_pair : this->input_index) {
const std::string& key = index_pair.first;
const auto& assign_iter = this->m_assignments.find(key);
if (assign_iter != this->m_assignments.end()) {
if (assign_iter->second.var_type() == var_type)
if (assign_iter->second.var_type() == var_type) {
filtered_assigns.push_back(assign_iter->second);
}
}
}
return filtered_assigns;
}
const std::string& UDQConfig::unit(const std::string& key) const {
const std::string& UDQConfig::unit(const std::string& key) const
{
const auto pair_ptr = this->units.find(key);
if (pair_ptr == this->units.end())
if (pair_ptr == this->units.end()) {
throw std::invalid_argument("No such UDQ quantity: " + key);
}
return pair_ptr->second;
}
bool UDQConfig::has_unit(const std::string& keyword) const {
bool UDQConfig::has_unit(const std::string& keyword) const
{
return (this->units.count(keyword) > 0);
}
bool UDQConfig::has_keyword(const std::string& keyword) const {
if (this->m_assignments.count(keyword) > 0)
return true;
if (this->m_definitions.count(keyword) > 0)
return true;
return false;
bool UDQConfig::has_keyword(const std::string& keyword) const
{
return (this->m_assignments.find(keyword) != this->m_assignments.end())
|| (this->m_definitions.find(keyword) != this->m_definitions.end());
}
UDQInput UDQConfig::operator[](const std::string& keyword) const {
UDQInput UDQConfig::operator[](const std::string& keyword) const
{
const auto index_iter = this->input_index.find(keyword);
if (index_iter == this->input_index.end())
throw std::invalid_argument("Keyword: " + keyword + " not recognized as ASSIGN/DEFINE UDQ");
if (index_iter == this->input_index.end()) {
throw std::invalid_argument("Keyword: '" + keyword +
"' not recognized as ASSIGN/DEFINE UDQ");
}
std::string u;
if (this->has_unit(keyword))
u = this->unit(keyword);
const auto u = this->has_unit(keyword)
? this->unit(keyword) : std::string{};
if (index_iter->second.action == UDQAction::ASSIGN)
if (index_iter->second.action == UDQAction::ASSIGN) {
return UDQInput(this->input_index.at(keyword), this->m_assignments.at(keyword), u);
}
if (index_iter->second.action == UDQAction::DEFINE)
if (index_iter->second.action == UDQAction::DEFINE) {
return UDQInput(this->input_index.at(keyword), this->m_definitions.at(keyword), u);
}
throw std::logic_error("Internal error - should not be here");
}
UDQInput UDQConfig::operator[](std::size_t insert_index) const {
UDQInput UDQConfig::operator[](const std::size_t insert_index) const
{
auto index_iter = std::find_if(this->input_index.begin(), this->input_index.end(),
[&insert_index](const std::pair<std::string, UDQIndex>& name_index)
{
const auto& [_, index] = name_index;
(void)_;
return index.insert_index == insert_index;
});
[insert_index](const std::pair<std::string, UDQIndex>& name_index)
{
return name_index.second.insert_index == insert_index;
});
if (index_iter == this->input_index.end())
if (index_iter == this->input_index.end()) {
throw std::invalid_argument("Insert index not recognized");
}
const auto& [keyword, index] = *index_iter;
std::string u;
if (this->has_unit(keyword))
if (this->has_unit(keyword)) {
u = this->unit(keyword);
}
if (index.action == UDQAction::ASSIGN)
if (index.action == UDQAction::ASSIGN) {
return UDQInput(index, this->m_assignments.at(keyword), u);
}
if (index.action == UDQAction::DEFINE)
if (index.action == UDQAction::DEFINE) {
return UDQInput(index, this->m_definitions.at(keyword), u);
}
throw std::logic_error("Internal error - should not be here");
}
const UDQFunctionTable& UDQConfig::function_table() const {
const UDQFunctionTable& UDQConfig::function_table() const
{
return this->udqft;
}
bool UDQConfig::operator==(const UDQConfig& data) const {
return this->params() == data.params() &&
this->function_table() == data.function_table() &&
this->m_definitions == data.m_definitions &&
this->m_assignments == data.m_assignments &&
this->units == data.units &&
this->input_index == data.input_index &&
this->type_count == data.type_count;
bool UDQConfig::operator==(const UDQConfig& data) const
{
return (this->params() == data.params())
&& (this->function_table() == data.function_table())
&& (this->m_definitions == data.m_definitions)
&& (this->m_assignments == data.m_assignments)
&& (this->units == data.units)
&& (this->input_index == data.input_index)
&& (this->type_count == data.type_count)
;
}
void UDQConfig::eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const {
void UDQConfig::eval_assign(const std::size_t report_step,
SummaryState& st,
UDQState& udq_state,
UDQContext& context) const
{
for (const auto& assign : this->assignments(UDQVarType::WELL_VAR)) {
if (udq_state.assign(report_step, assign.keyword())) {
auto ws = assign.eval(st.wells());
@ -373,8 +476,10 @@ namespace Opm {
}
}
void UDQConfig::eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const {
void UDQConfig::eval_define(const std::size_t report_step,
UDQState& udq_state,
UDQContext& context) const
{
for (const auto& def : this->definitions(UDQVarType::WELL_VAR)) {
if (udq_state.define(def.keyword(), def.status())) {
auto ws = def.eval(context);
@ -397,26 +502,31 @@ namespace Opm {
}
}
void UDQConfig::eval(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const {
void UDQConfig::eval(const std::size_t report_step,
const WellMatcher& wm,
SummaryState& st,
UDQState& udq_state) const
{
UDQContext context(this->function_table(), wm, st, udq_state);
this->eval_assign(report_step, st, udq_state, context);
this->eval_define(report_step, udq_state, context);
}
void UDQConfig::eval_assign(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const {
void UDQConfig::eval_assign(const std::size_t report_step,
const WellMatcher& wm,
SummaryState& st,
UDQState& udq_state) const
{
UDQContext context(this->function_table(), wm, st, udq_state);
this->eval_assign(report_step, st, udq_state, context);
}
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const {
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const
{
for (const auto& def_pair : this->m_definitions) {
const auto& udq_def = def_pair.second;
udq_def.required_summary(summary_keys);
}
}
}
} // namespace Opm

View File

@ -16,127 +16,126 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <cstring>
#include <tuple>
#include <fmt/format.h>
#include <exception>
#include <opm/common/utility/String.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/utility/String.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include "../../Parser/raw/RawConsts.hpp"
#include "UDQParser.hpp"
namespace Opm {
#include <cstddef>
#include <cstring>
#include <exception>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_set>
#include <vector>
#include <fmt/format.h>
namespace {
std::vector<std::string> quote_split(const std::string& item) {
std::vector<std::string> quote_split(const std::string& item)
{
char quote_char = '\'';
std::vector<std::string> items;
std::size_t offset = 0;
while (true) {
auto quote_pos1 = item.find(quote_char, offset);
if (quote_pos1 == std::string::npos) {
if (offset < item.size())
if (offset < item.size()) {
items.push_back(item.substr(offset));
}
break;
}
auto quote_pos2 = item.find(quote_char, quote_pos1 + 1);
if (quote_pos2 == std::string::npos)
if (quote_pos2 == std::string::npos) {
throw std::invalid_argument("Unbalanced quotes in: " + item);
}
if (quote_pos1 > offset)
if (quote_pos1 > offset) {
items.push_back(item.substr(offset, quote_pos1 - offset));
}
items.push_back(item.substr(quote_pos1, 1 + quote_pos2 - quote_pos1));
offset = quote_pos2 + 1;
}
return items;
}
std::vector<UDQToken> make_tokens(const std::vector<std::string>& string_tokens) {
if (string_tokens.empty())
std::vector<Opm::UDQToken>
make_tokens(const std::vector<std::string>& string_tokens)
{
if (string_tokens.empty()) {
return {};
}
std::vector<UDQToken> tokens;
std::vector<Opm::UDQToken> tokens;
std::size_t token_index = 0;
while (true) {
const auto& string_token = string_tokens[token_index];
auto token_type = UDQ::tokenType(string_tokens[token_index]);
auto token_type = Opm::UDQ::tokenType(string_tokens[token_index]);
token_index += 1;
if (token_type == UDQTokenType::ecl_expr) {
if (token_type == Opm::UDQTokenType::ecl_expr) {
std::vector<std::string> selector;
while (true) {
if (token_index == string_tokens.size())
if (token_index == string_tokens.size()) {
break;
}
auto next_type = UDQ::tokenType(string_tokens[token_index]);
if (next_type == UDQTokenType::ecl_expr) {
auto next_type = Opm::UDQ::tokenType(string_tokens[token_index]);
if (next_type == Opm::UDQTokenType::ecl_expr) {
const auto& select_token = string_tokens[token_index];
if (RawConsts::is_quote()(select_token[0]))
if (Opm::RawConsts::is_quote()(select_token[0])) {
selector.push_back(select_token.substr(1, select_token.size() - 2));
else
}
else {
selector.push_back(select_token);
token_index += 1;
} else
break;
}
tokens.emplace_back( string_token, selector );
} else
tokens.emplace_back( string_token, token_type );
}
if (token_index == string_tokens.size())
token_index += 1;
}
else {
break;
}
}
tokens.emplace_back(string_token, selector);
}
else {
tokens.emplace_back(string_token, token_type);
}
if (token_index == string_tokens.size()) {
break;
}
}
return tokens;
}
}
UDQDefine::UDQDefine()
: m_var_type(UDQVarType::NONE)
{}
template <typename T>
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data,
const ParseContext& parseContext,
T&& errors) :
UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, parseContext, errors)
{}
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data) :
UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, ParseContext(), ErrorGuard())
{}
namespace {
std::string next_token(const std::string& item, std::size_t& offset, const std::vector<std::string>& splitters) {
std::string
next_token(const std::string& item,
std::size_t& offset,
const std::vector<std::string>& splitters)
{
if (std::isdigit(item[offset])) {
auto substring = item.substr(offset);
char * end_ptr;
char* end_ptr;
std::ignore = std::strtod(substring.c_str(), &end_ptr);
std::size_t token_size = end_ptr - substring.c_str();
@ -153,32 +152,86 @@ std::string next_token(const std::string& item, std::size_t& offset, const std::
auto pos = item.find(splitter, offset);
if (pos < min_pos) {
min_pos = pos;
if (pos == offset)
if (pos == offset) {
token = splitter;
else
}
else {
token = item.substr(offset, pos - offset);
}
}
}
offset += token.size();
return trim_copy(token);
return Opm::trim_copy(token);
}
// This function unconditionally returns true and is therefore not a real
// predicate at the moment. We nevertheless keep the predicate here in the
// hope that it is possible to actually make it useful in the future. See
// the comment in UDQEnums.hpp about 'UDQ type system'.
bool dynamic_type_check(const Opm::UDQVarType lhs,
const Opm::UDQVarType rhs)
{
if (lhs == rhs) {
return true;
}
if (rhs == Opm::UDQVarType::SCALAR) {
return true;
}
return true;
}
} // Anonymous namespace
UDQDefine::UDQDefine(const UDQParams& udq_params,
const std::string& keyword,
std::size_t report_step,
const KeywordLocation& location,
namespace Opm {
UDQDefine::UDQDefine()
: m_var_type(UDQVarType::NONE)
{}
template <typename T>
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data,
const ParseContext& parseContext,
ErrorGuard& errors) :
m_keyword(keyword),
m_var_type(UDQ::varType(keyword)),
m_location(location),
m_report_step(report_step),
m_update_status(UDQUpdate::ON)
const ParseContext& parseContext,
T&& errors)
: UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, parseContext, errors)
{}
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data)
: UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, ParseContext(), ErrorGuard())
{}
UDQDefine::UDQDefine(const UDQParams& udq_params,
const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data,
const ParseContext& parseContext,
ErrorGuard& errors)
: m_keyword (keyword)
, m_var_type (UDQ::varType(keyword))
, m_location (location)
, m_report_step (report_step)
, m_update_status(UDQUpdate::ON)
{
std::vector<std::string> string_tokens;
const auto splitters = std::vector<std::string> {
" ", "TU*[]", "(", ")", "[", "]", ",",
"+", "-", "/", "*",
"==", "!=", "^", ">=", "<=", ">", "<",
};
auto string_tokens = std::vector<std::string>{};
for (const std::string& deck_item : deck_data) {
for (const std::string& item : quote_split(deck_item)) {
if (RawConsts::is_quote()(item[0])) {
@ -186,26 +239,35 @@ UDQDefine::UDQDefine(const UDQParams& udq_params,
continue;
}
const std::vector<std::string> splitters = {" ", "TU*[]", "(", ")", "[", "]", ",", "+", "-", "/", "*", "==", "!=", "^", ">=", "<=", ">", "<"};
size_t offset = 0;
std::size_t offset = 0;
while (offset < item.size()) {
auto token = next_token(item, offset, splitters);
if (!token.empty())
string_tokens.push_back( token );
if (!token.empty()) {
string_tokens.push_back(std::move(token));
}
}
}
}
this->m_tokens = make_tokens(string_tokens);
this->ast = std::make_shared<UDQASTNode>( UDQParser::parse(udq_params, this->m_var_type, this->m_keyword, this->m_location, this->m_tokens, parseContext, errors) );
this->ast = std::make_shared<UDQASTNode>
(UDQParser::parse(udq_params,
this->m_var_type,
this->m_keyword,
this->m_location,
this->m_tokens,
parseContext,
errors));
}
void UDQDefine::update_status(UDQUpdate update, std::size_t report_step) {
void UDQDefine::update_status(const UDQUpdate update,
const std::size_t report_step)
{
this->m_update_status = update;
this->m_report_step = report_step;
}
UDQDefine UDQDefine::serializationTestObject()
{
UDQDefine result;
@ -219,76 +281,63 @@ UDQDefine UDQDefine::serializationTestObject()
return result;
}
namespace {
/*
This function unconditinally returns true and is of-course quite useless at
the moment; it is retained here in the hope that it is possible to actually
make it useful in the future. See the comment in UDQEnums.hpp about 'UDQ type
system'.
*/
bool dynamic_type_check(UDQVarType lhs, UDQVarType rhs) {
if (lhs == rhs)
return true;
if (rhs == UDQVarType::SCALAR)
return true;
return true;
}
}
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const {
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const
{
this->ast->required_summary(summary_keys);
}
UDQSet UDQDefine::eval(const UDQContext& context) const {
UDQSet UDQDefine::eval(const UDQContext& context) const
{
std::optional<UDQSet> res;
try {
res = this->ast->eval(this->m_var_type, context);
res->name( this->m_keyword );
res->name(this->m_keyword);
if (!dynamic_type_check(this->var_type(), res->var_type())) {
std::string msg = "Invalid runtime type conversion detected when evaluating UDQ";
throw std::invalid_argument(msg);
throw std::invalid_argument {
"Invalid runtime type conversion detected when evaluating UDQ"
};
}
} catch (const std::exception& exc) {
auto msg = fmt::format("Problem evaluating UDQ {}\n"
"In {} line {}\n"
"Internal error: {}", this->m_keyword, this->m_location.filename, this->m_location.lineno, exc.what());
}
catch (const std::exception& exc) {
const auto msg = fmt::format("Problem evaluating UDQ {}\n"
"In {} line {}\n"
"Internal error: {}",
this->m_keyword,
this->m_location.filename,
this->m_location.lineno,
exc.what());
OpmLog::error(msg);
std::throw_with_nested(exc);
}
if (!res)
throw std::logic_error("Bug in UDQDefine::eval()");
if (!res) {
throw std::logic_error("Bug in UDQDefine::eval()");
}
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:
// 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. We implement the same behavior for group sets - but there
// is lots of uncertainty regarding the semantics of group sets.
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. We implement the
same behavior for group sets - but there is lots of uncertainty
regarding the semantics of group sets.
*/
const auto& scalar_value = res->operator[](0).value();
const auto& 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)
for (const auto& well : wells) {
well_res.assign(well, scalar_value);
}
return well_res;
}
@ -297,8 +346,9 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
const std::vector<std::string> groups = context.groups();
UDQSet group_res = UDQSet::groups(this->m_keyword, groups);
for (const auto& group : groups)
for (const auto& group : groups) {
group_res.assign(group, scalar_value);
}
return group_res;
}
@ -307,72 +357,85 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
return *res;
}
const KeywordLocation& UDQDefine::location() const {
const KeywordLocation& UDQDefine::location() const
{
return this->m_location;
}
UDQVarType UDQDefine::var_type() const {
UDQVarType UDQDefine::var_type() const
{
return this->m_var_type;
}
const std::string& UDQDefine::keyword() const {
const std::string& UDQDefine::keyword() const
{
return this->m_keyword;
}
const std::string& UDQDefine::input_string() const {
const std::string& UDQDefine::input_string() const
{
if (!this->string_data.has_value()) {
std::string s;
/*
A string representation equivalent to the input string is assembled by
joining tokens and sprinkle with ' ' at semi random locations. The
main use of this function is to output the definition string in form
usable for the restart file.
*/
// A string representation equivalent to the input string is
// assembled by joining tokens and sprinkle with ' ' at semi random
// locations. The main use of this function is to output the
// definition string in form usable for the restart file.
for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) {
const auto& token = this->m_tokens[token_index];
if (UDQ::leadingSpace(token.type()))
if (UDQ::leadingSpace(token.type())) {
s += " ";
}
s += token.str();
if (token_index == (this->m_tokens.size() - 1))
if (token_index == (this->m_tokens.size() - 1)) {
continue;
}
if (UDQ::trailingSpace(token.type())) {
s += " ";
continue;
}
}
this->string_data = s;
this->string_data = s;
}
return this->string_data.value();
}
std::set<UDQTokenType> UDQDefine::func_tokens() const {
std::set<UDQTokenType> UDQDefine::func_tokens() const
{
return this->ast->func_tokens();
}
std::pair<UDQUpdate, std::size_t> UDQDefine::status() const {
std::pair<UDQUpdate, std::size_t> UDQDefine::status() const
{
return std::make_pair(this->m_update_status, this->m_report_step);
}
const std::vector<UDQToken> UDQDefine::tokens() const {
const std::vector<UDQToken> UDQDefine::tokens() const
{
return this->m_tokens;
}
bool UDQDefine::operator==(const UDQDefine& data) const {
if ((ast && !data.ast) || (!ast && data.ast))
return false;
if (ast && !(*ast == *data.ast))
bool UDQDefine::operator==(const UDQDefine& data) const
{
if ((ast && !data.ast) || (!ast && data.ast)) {
return false;
}
return this->keyword() == data.keyword() &&
this->m_location == data.location() &&
this->var_type() == data.var_type() &&
this->status() == data.status() &&
this->input_string() == data.input_string();
if (ast && !(*ast == *data.ast)) {
return false;
}
return (this->keyword() == data.keyword())
&& (this->m_location == data.location())
&& (this->var_type() == data.var_type())
&& (this->status() == data.status())
&& (this->input_string() == data.input_string())
;
}
}
} // namespace Opm

View File

@ -28,367 +28,407 @@
#include <unordered_map>
#include <vector>
namespace Opm { namespace UDQ {
namespace {
const std::set<UDQTokenType> cmp_func = {UDQTokenType::binary_cmp_eq,
UDQTokenType::binary_cmp_ne,
UDQTokenType::binary_cmp_le,
UDQTokenType::binary_cmp_ge,
UDQTokenType::binary_cmp_lt,
UDQTokenType::binary_cmp_gt};
bool is_no_mix(const Opm::UDQVarType t)
{
return (t == Opm::UDQVarType::CONNECTION_VAR)
|| (t == Opm::UDQVarType::REGION_VAR)
|| (t == Opm::UDQVarType::SEGMENT_VAR)
|| (t == Opm::UDQVarType::AQUIFER_VAR)
|| (t == Opm::UDQVarType::BLOCK_VAR)
|| (t == Opm::UDQVarType::WELL_VAR)
|| (t == Opm::UDQVarType::GROUP_VAR)
;
}
const std::set<UDQTokenType> binary_func = {UDQTokenType::binary_op_add,
UDQTokenType::binary_op_mul,
UDQTokenType::binary_op_sub,
UDQTokenType::binary_op_div,
UDQTokenType::binary_op_pow,
UDQTokenType::binary_op_uadd,
UDQTokenType::binary_op_umul,
UDQTokenType::binary_op_umin,
UDQTokenType::binary_op_umax,
UDQTokenType::binary_cmp_eq,
UDQTokenType::binary_cmp_ne,
UDQTokenType::binary_cmp_le,
UDQTokenType::binary_cmp_ge,
UDQTokenType::binary_cmp_lt,
UDQTokenType::binary_cmp_gt};
bool is_valid_vartype(const Opm::UDQVarType t)
{
return is_no_mix(t)
|| (t == Opm::UDQVarType::NONE)
|| (t == Opm::UDQVarType::SCALAR)
|| (t == Opm::UDQVarType::FIELD_VAR)
;
}
const std::set<UDQTokenType> set_func = {UDQTokenType::binary_op_uadd,
UDQTokenType::binary_op_umul,
UDQTokenType::binary_op_umin,
UDQTokenType::binary_op_umax};
const auto cmp_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::binary_cmp_eq,
Opm::UDQTokenType::binary_cmp_ne,
Opm::UDQTokenType::binary_cmp_le,
Opm::UDQTokenType::binary_cmp_ge,
Opm::UDQTokenType::binary_cmp_lt,
Opm::UDQTokenType::binary_cmp_gt,
};
const std::set<UDQTokenType> scalar_func = {UDQTokenType::scalar_func_sum,
UDQTokenType::scalar_func_avea,
UDQTokenType::scalar_func_aveg,
UDQTokenType::scalar_func_aveh,
UDQTokenType::scalar_func_max,
UDQTokenType::scalar_func_min,
UDQTokenType::scalar_func_norm1,
UDQTokenType::scalar_func_norm2,
UDQTokenType::scalar_func_normi,
UDQTokenType::scalar_func_prod};
const auto binary_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::binary_op_add,
Opm::UDQTokenType::binary_op_mul,
Opm::UDQTokenType::binary_op_sub,
Opm::UDQTokenType::binary_op_div,
Opm::UDQTokenType::binary_op_pow,
Opm::UDQTokenType::binary_op_uadd,
Opm::UDQTokenType::binary_op_umul,
Opm::UDQTokenType::binary_op_umin,
Opm::UDQTokenType::binary_op_umax,
Opm::UDQTokenType::binary_cmp_eq,
Opm::UDQTokenType::binary_cmp_ne,
Opm::UDQTokenType::binary_cmp_le,
Opm::UDQTokenType::binary_cmp_ge,
Opm::UDQTokenType::binary_cmp_lt,
Opm::UDQTokenType::binary_cmp_gt,
};
const auto set_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::binary_op_uadd,
Opm::UDQTokenType::binary_op_umul,
Opm::UDQTokenType::binary_op_umin,
Opm::UDQTokenType::binary_op_umax,
};
const std::set<UDQTokenType> unary_elemental_func = {UDQTokenType::elemental_func_randn,
UDQTokenType::elemental_func_randu,
UDQTokenType::elemental_func_rrandn,
UDQTokenType::elemental_func_rrandu,
UDQTokenType::elemental_func_abs,
UDQTokenType::elemental_func_def,
UDQTokenType::elemental_func_exp,
UDQTokenType::elemental_func_idv,
UDQTokenType::elemental_func_ln,
UDQTokenType::elemental_func_log,
UDQTokenType::elemental_func_nint,
UDQTokenType::elemental_func_sorta,
UDQTokenType::elemental_func_sortd,
UDQTokenType::elemental_func_undef};
const auto scalar_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::scalar_func_sum,
Opm::UDQTokenType::scalar_func_avea,
Opm::UDQTokenType::scalar_func_aveg,
Opm::UDQTokenType::scalar_func_aveh,
Opm::UDQTokenType::scalar_func_max,
Opm::UDQTokenType::scalar_func_min,
Opm::UDQTokenType::scalar_func_norm1,
Opm::UDQTokenType::scalar_func_norm2,
Opm::UDQTokenType::scalar_func_normi,
Opm::UDQTokenType::scalar_func_prod,
};
const auto unary_elemental_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::elemental_func_randn,
Opm::UDQTokenType::elemental_func_randu,
Opm::UDQTokenType::elemental_func_rrandn,
Opm::UDQTokenType::elemental_func_rrandu,
Opm::UDQTokenType::elemental_func_abs,
Opm::UDQTokenType::elemental_func_def,
Opm::UDQTokenType::elemental_func_exp,
Opm::UDQTokenType::elemental_func_idv,
Opm::UDQTokenType::elemental_func_ln,
Opm::UDQTokenType::elemental_func_log,
Opm::UDQTokenType::elemental_func_nint,
Opm::UDQTokenType::elemental_func_sorta,
Opm::UDQTokenType::elemental_func_sortd,
Opm::UDQTokenType::elemental_func_undef,
};
const std::unordered_map<std::string, UDQTokenType> func_type = {{"+", UDQTokenType::binary_op_add},
{"-", UDQTokenType::binary_op_sub},
{"/", UDQTokenType::binary_op_div},
{"DIV", UDQTokenType::binary_op_div},
{"*", UDQTokenType::binary_op_mul},
{"^", UDQTokenType::binary_op_pow},
{"UADD", UDQTokenType::binary_op_uadd},
{"UMUL", UDQTokenType::binary_op_umul},
{"UMIN", UDQTokenType::binary_op_umin},
{"UMAX", UDQTokenType::binary_op_umax},
{"==", UDQTokenType::binary_cmp_eq},
{"!=", UDQTokenType::binary_cmp_ne},
{"<=", UDQTokenType::binary_cmp_le},
{">=", UDQTokenType::binary_cmp_ge},
{"<", UDQTokenType::binary_cmp_lt},
{">", UDQTokenType::binary_cmp_gt},
{"RANDN", UDQTokenType::elemental_func_randn},
{"RANDU", UDQTokenType::elemental_func_randu},
{"RRNDN", UDQTokenType::elemental_func_rrandn},
{"RRNDU", UDQTokenType::elemental_func_rrandu},
{"ABS", UDQTokenType::elemental_func_abs},
{"DEF", UDQTokenType::elemental_func_def},
{"EXP", UDQTokenType::elemental_func_exp},
{"IDV", UDQTokenType::elemental_func_idv},
{"LN", UDQTokenType::elemental_func_ln},
{"LOG", UDQTokenType::elemental_func_log},
{"NINT", UDQTokenType::elemental_func_nint},
{"SORTA", UDQTokenType::elemental_func_sorta},
{"SORTD", UDQTokenType::elemental_func_sortd},
{"UNDEF", UDQTokenType::elemental_func_undef},
{"SUM", UDQTokenType::scalar_func_sum},
{"AVEA", UDQTokenType::scalar_func_avea},
{"AVEG", UDQTokenType::scalar_func_aveg},
{"AVEH", UDQTokenType::scalar_func_aveh},
{"MAX", UDQTokenType::scalar_func_max},
{"MIN", UDQTokenType::scalar_func_min},
{"NORM1", UDQTokenType::scalar_func_norm1},
{"NORM2", UDQTokenType::scalar_func_norm2},
{"NORMI", UDQTokenType::scalar_func_normi},
{"PROD", UDQTokenType::scalar_func_prod}};
const auto func_type = std::unordered_map<std::string, Opm::UDQTokenType> {
{"+" , Opm::UDQTokenType::binary_op_add},
{"-" , Opm::UDQTokenType::binary_op_sub},
{"/" , Opm::UDQTokenType::binary_op_div},
{"DIV" , Opm::UDQTokenType::binary_op_div},
{"*" , Opm::UDQTokenType::binary_op_mul},
{"^" , Opm::UDQTokenType::binary_op_pow},
{"UADD" , Opm::UDQTokenType::binary_op_uadd},
{"UMUL" , Opm::UDQTokenType::binary_op_umul},
{"UMIN" , Opm::UDQTokenType::binary_op_umin},
{"UMAX" , Opm::UDQTokenType::binary_op_umax},
{"==" , Opm::UDQTokenType::binary_cmp_eq},
{"!=" , Opm::UDQTokenType::binary_cmp_ne},
{"<=" , Opm::UDQTokenType::binary_cmp_le},
{">=" , Opm::UDQTokenType::binary_cmp_ge},
{"<" , Opm::UDQTokenType::binary_cmp_lt},
{">" , Opm::UDQTokenType::binary_cmp_gt},
{"RANDN", Opm::UDQTokenType::elemental_func_randn},
{"RANDU", Opm::UDQTokenType::elemental_func_randu},
{"RRNDN", Opm::UDQTokenType::elemental_func_rrandn},
{"RRNDU", Opm::UDQTokenType::elemental_func_rrandu},
{"ABS" , Opm::UDQTokenType::elemental_func_abs},
{"DEF" , Opm::UDQTokenType::elemental_func_def},
{"EXP" , Opm::UDQTokenType::elemental_func_exp},
{"IDV" , Opm::UDQTokenType::elemental_func_idv},
{"LN" , Opm::UDQTokenType::elemental_func_ln},
{"LOG" , Opm::UDQTokenType::elemental_func_log},
{"NINT" , Opm::UDQTokenType::elemental_func_nint},
{"SORTA", Opm::UDQTokenType::elemental_func_sorta},
{"SORTD", Opm::UDQTokenType::elemental_func_sortd},
{"UNDEF", Opm::UDQTokenType::elemental_func_undef},
{"SUM" , Opm::UDQTokenType::scalar_func_sum},
{"AVEA" , Opm::UDQTokenType::scalar_func_avea},
{"AVEG" , Opm::UDQTokenType::scalar_func_aveg},
{"AVEH" , Opm::UDQTokenType::scalar_func_aveh},
{"MAX" , Opm::UDQTokenType::scalar_func_max},
{"MIN" , Opm::UDQTokenType::scalar_func_min},
{"NORM1", Opm::UDQTokenType::scalar_func_norm1},
{"NORM2", Opm::UDQTokenType::scalar_func_norm2},
{"NORMI", Opm::UDQTokenType::scalar_func_normi},
{"PROD" , Opm::UDQTokenType::scalar_func_prod},
};
} // Anonymous namespace
}
namespace Opm { namespace UDQ {
UDQVarType targetType(const std::string& keyword) {
UDQVarType targetType(const std::string& keyword)
{
const char first_char = keyword[0];
switch (first_char) {
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;
case 'W': return UDQVarType::WELL_VAR;
case 'G': return UDQVarType::GROUP_VAR;
char first_char = keyword[0];
switch(first_char) {
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;
case 'W':
return UDQVarType::WELL_VAR;
case 'G':
return UDQVarType::GROUP_VAR;
default:
const auto& double_value = try_parse_double(keyword);
if (double_value.has_value())
if (const auto double_value = try_parse_double(keyword);
double_value.has_value())
{
return UDQVarType::SCALAR;
}
return UDQVarType::NONE;
}
}
UDQVarType targetType(const std::string& keyword, const std::vector<std::string>& selector) {
auto tt = targetType(keyword);
if (tt == UDQVarType::WELL_VAR || tt == UDQVarType::GROUP_VAR) {
if (selector.empty())
UDQVarType targetType(const std::string& keyword,
const std::vector<std::string>& selector)
{
const auto tt = targetType(keyword);
if ((tt == UDQVarType::WELL_VAR) || (tt == UDQVarType::GROUP_VAR)) {
if (selector.empty() || (selector.front().find("*") != std::string::npos)) {
return tt;
else {
const auto& wgname = selector[0];
if (wgname.find("*") != std::string::npos)
return tt;
}
}
return UDQVarType::SCALAR;
}
UDQVarType varType(const std::string& keyword)
{
if ((keyword.size() < std::string::size_type{2}) || (keyword[1] != 'U')) {
throw std::invalid_argument("Keyword: '" + keyword + "' is not of UDQ type");
}
UDQVarType varType(const std::string& keyword) {
if (keyword[1] != 'U')
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
const 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;
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:
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
}
}
UDQAction actionType(const std::string& action_string) {
if (action_string == "ASSIGN")
UDQAction actionType(const std::string& action_string)
{
if (action_string == "ASSIGN") {
return UDQAction::ASSIGN;
}
if (action_string == "DEFINE")
if (action_string == "DEFINE") {
return UDQAction::DEFINE;
}
if (action_string == "UNITS")
if (action_string == "UNITS") {
return UDQAction::UNITS;
}
if (action_string == "UPDATE")
if (action_string == "UPDATE") {
return UDQAction::UPDATE;
}
throw std::invalid_argument("Invalid action string " + action_string);
}
UDQUpdate updateType(const std::string& update_string) {
if (update_string == "ON")
UDQUpdate updateType(const std::string& update_string)
{
if (update_string == "ON") {
return UDQUpdate::ON;
}
if (update_string == "OFF")
if (update_string == "OFF") {
return UDQUpdate::OFF;
}
if (update_string == "NEXT")
if (update_string == "NEXT") {
return UDQUpdate::NEXT;
}
throw std::invalid_argument("Invalid status update string " + update_string);
}
UDQUpdate updateType(int int_value) {
UDQUpdate updateType(const int int_value)
{
switch (int_value) {
case 0: return UDQUpdate::OFF;
case 1: return UDQUpdate::NEXT;
case 2: return UDQUpdate::ON;
default:
throw std::logic_error("Invalid integer for UDQUpdate type");
}
}
bool binaryFunc(UDQTokenType token_type) {
return (binary_func.count(token_type) > 0);
bool binaryFunc(const UDQTokenType token_type)
{
return binary_func.find(token_type) != binary_func.end();
}
bool scalarFunc(UDQTokenType token_type) {
return (scalar_func.count(token_type) > 0);
bool scalarFunc(const UDQTokenType token_type)
{
return scalar_func.find(token_type) != scalar_func.end();
}
bool elementalUnaryFunc(UDQTokenType token_type) {
return (unary_elemental_func.count(token_type) > 0);
bool elementalUnaryFunc(const UDQTokenType token_type)
{
return unary_elemental_func.find(token_type) != unary_elemental_func.end();
}
bool cmpFunc(UDQTokenType token_type) {
return (cmp_func.count(token_type) > 0);
bool cmpFunc(const UDQTokenType token_type)
{
return cmp_func.find(token_type) != cmp_func.end();
}
bool setFunc(UDQTokenType token_type) {
return (set_func.count(token_type) > 0);
bool setFunc(const UDQTokenType token_type)
{
return set_func.find(token_type) != set_func.end();
}
UDQTokenType funcType(const std::string& func_name)
{
{
auto func = func_type.find(func_name);
if (func != func_type.end()) {
return func->second;
}
}
UDQTokenType funcType(const std::string& func_name) {
if (func_type.count(func_name) > 0)
return func_type.at(func_name);
if (func_name.substr(0,2) == "TU") {
if (func_name.substr(0, 2) == "TU") {
return UDQTokenType::table_lookup;
}
return UDQTokenType::error;
}
UDQTokenType tokenType(const std::string& token) {
auto token_type = funcType(token);
if (token_type == UDQTokenType::error) {
if (token == "(")
token_type = UDQTokenType::open_paren;
else if (token == ")")
token_type = UDQTokenType::close_paren;
else {
auto value = try_parse_double(token);
if (value.has_value())
token_type = UDQTokenType::number;
else
token_type = UDQTokenType::ecl_expr;
}
UDQTokenType tokenType(const std::string& token)
{
if (const auto token_type = funcType(token);
token_type != UDQTokenType::error)
{
return token_type;
}
return token_type;
if (token == "(") {
return UDQTokenType::open_paren;
}
if (token == ")") {
return UDQTokenType::close_paren;
}
if (const auto number = try_parse_double(token);
number.has_value())
{
return UDQTokenType::number;
}
return UDQTokenType::ecl_expr;
}
UDQVarType coerce(const UDQVarType t1, const UDQVarType t2)
{
if (! (is_valid_vartype(t1) && is_valid_vartype(t2))) {
// Note: Can't use typeName() here since that would throw another
// exception.
throw std::logic_error {
"Cannot coerce between " + std::to_string(static_cast<int>(t1))
+ " and " + std::to_string(static_cast<int>(t2))
};
}
UDQVarType coerce(UDQVarType t1, UDQVarType t2) {
if (t1 == t2)
return t1;
if (t1 == UDQVarType::WELL_VAR ) {
if (t2 == UDQVarType::GROUP_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
if (t1 == t2) {
return t1;
}
if (t1 == UDQVarType::GROUP_VAR ) {
if (t2 == UDQVarType::WELL_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
const auto is_restricted_t1 = is_no_mix(t1);
const auto is_restricted_t2 = is_no_mix(t2);
if (is_restricted_t1 && is_restricted_t2) {
// t1 != t2, but neither can be coerced into the other.
throw std::logic_error {
"Cannot coerce between " + typeName(t1) + " and " + typeName(t2)
};
}
if (is_restricted_t1) {
return t1;
}
if (t2 == UDQVarType::WELL_VAR ) {
if (t1 == UDQVarType::GROUP_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
if (is_restricted_t2) {
return t2;
}
if (t2 == UDQVarType::GROUP_VAR ) {
if (t1 == UDQVarType::WELL_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
if (t1 == UDQVarType::NONE) {
return t2;
}
if (t1 == UDQVarType::NONE)
return t2;
if (t2 == UDQVarType::NONE)
if (t2 == UDQVarType::NONE) {
return t1;
}
return t1;
}
std::string typeName(UDQVarType var_type) {
std::string typeName(const UDQVarType var_type)
{
switch (var_type) {
case UDQVarType::NONE:
return "NONE";
case UDQVarType::SCALAR:
return "SCALAR";
case UDQVarType::WELL_VAR:
return "WELL_VAR";
case UDQVarType::CONNECTION_VAR:
return "CONNECTION_VAR";
case UDQVarType::FIELD_VAR:
return "FIELD_VAR";
case UDQVarType::GROUP_VAR:
return "GROUP_VAR";
case UDQVarType::REGION_VAR:
return "REGION_VAR";
case UDQVarType::SEGMENT_VAR:
return "SEGMENT_VAR";
case UDQVarType::AQUIFER_VAR:
return "AQUIFER_VAR";
case UDQVarType::BLOCK_VAR:
return "BLOCK_VAR";
default:
throw std::runtime_error("Should not be here: " + std::to_string(static_cast<int>(var_type)));
}
}
bool trailingSpace(UDQTokenType token_type) {
if (binaryFunc(token_type))
return true;
if (cmpFunc(token_type))
return true;
return false;
bool trailingSpace(const UDQTokenType token_type)
{
return binaryFunc(token_type)
|| cmpFunc(token_type);
}
bool leadingSpace(UDQTokenType token_type) {
if (binaryFunc(token_type))
return true;
if (cmpFunc(token_type))
return true;
return false;
bool leadingSpace(const UDQTokenType token_type)
{
return binaryFunc(token_type)
|| cmpFunc(token_type);
}
namespace {
@ -401,7 +441,7 @@ namespace {
throw std::logic_error {
"Unrecognized enum type (" +
std::to_string(static_cast<int>(control)) +
"- internal error"
") - internal error"
};
}
@ -683,5 +723,4 @@ std::string controlName(const UDAControl control)
};
}
}} // Opm::UDQ
}} // namespace Opm::UDQ

View File

@ -17,78 +17,91 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <stdexcept>
#include <string>
#include <variant>
namespace Opm {
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQDefine& udq_define, const std::string& unit_arg) :
index(index_arg),
value(udq_define),
m_keyword(udq_define.keyword()),
m_var_type(udq_define.var_type()),
m_unit(unit_arg)
UDQInput::UDQInput(const UDQIndex& index_arg,
const UDQDefine& udq_define,
const std::string& unit_arg)
: index (index_arg)
, value (udq_define)
, m_keyword (udq_define.keyword())
, m_var_type(udq_define.var_type())
, m_unit (unit_arg)
{}
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQAssign& udq_assign, const std::string& unit_arg):
index(index_arg),
value(udq_assign),
m_keyword(udq_assign.keyword()),
m_var_type(udq_assign.var_type()),
m_unit(unit_arg)
UDQInput::UDQInput(const UDQIndex& index_arg,
const UDQAssign& udq_assign,
const std::string& unit_arg)
: index (index_arg)
, value (udq_assign)
, m_keyword (udq_assign.keyword())
, m_var_type(udq_assign.var_type())
, m_unit (unit_arg)
{}
const std::string& UDQInput::unit() const {
const std::string& UDQInput::unit() const
{
return this->m_unit;
}
const std::string& UDQInput::keyword() const {
const std::string& UDQInput::keyword() const
{
return this->m_keyword;
}
const UDQVarType& UDQInput::var_type() const {
const UDQVarType& UDQInput::var_type() const
{
return this->m_var_type;
}
template<>
bool UDQInput::is<UDQAssign>() const {
bool UDQInput::is<UDQAssign>() const
{
return std::holds_alternative<UDQAssign>(this->value);
}
template<>
bool UDQInput::is<UDQDefine>() const {
bool UDQInput::is<UDQDefine>() const
{
return std::holds_alternative<UDQDefine>(this->value);
}
template<>
const UDQAssign& UDQInput::get<UDQAssign>() const {
if (this->is<UDQAssign>())
const UDQAssign& UDQInput::get<UDQAssign>() const
{
if (this->is<UDQAssign>()) {
return std::get<UDQAssign>(this->value);
}
throw std::runtime_error("Invalid get");
}
template<>
const UDQDefine& UDQInput::get<UDQDefine>() const {
if (this->is<UDQDefine>())
const UDQDefine& UDQInput::get<UDQDefine>() const
{
if (this->is<UDQDefine>()) {
return std::get<UDQDefine>(this->value);
}
throw std::runtime_error("Invalid get");
}
bool UDQInput::operator==(const UDQInput& other) const {
return this->value == other.value &&
this->m_keyword == other.m_keyword &&
this->m_var_type == other.m_var_type &&
this->m_unit == other.m_unit;
bool UDQInput::operator==(const UDQInput& other) const
{
return (this->value == other.value)
&& (this->m_keyword == other.m_keyword)
&& (this->m_var_type == other.m_var_type)
&& (this->m_unit == other.m_unit)
;
}
}
} // namespace Opm

View File

@ -17,77 +17,131 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <cstring>
#include "UDQParser.hpp"
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <memory>
#include <fmt/format.h>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
namespace {
#include "UDQParser.hpp"
void dump_tokens(const std::string& target_var,
const std::vector<Opm::UDQToken>& tokens)
{
std::cout << target_var << " = ";
for (const auto& token : tokens) {
std::cout << token.str();
}
std::cout << std::endl;
}
// This function is extremely weak - hopefully it can be improved in the
// future. See the comment in UDQEnums.hpp about 'UDQ type system'.
bool static_type_check(const Opm::UDQVarType lhs,
const Opm::UDQVarType rhs)
{
if (lhs == rhs) {
return true;
}
if (rhs == Opm::UDQVarType::SCALAR) {
return true;
}
// This does not check if the rhs evaluates to a scalar.
if (rhs == Opm::UDQVarType::WELL_VAR) {
return lhs == Opm::UDQVarType::WELL_VAR;
}
return false;
}
} // Anonymous namespace
namespace Opm {
UDQTokenType UDQParser::get_type(const std::string& arg) const {
UDQTokenType UDQParser::get_type(const std::string& arg) const
{
auto func_type = UDQ::funcType(arg);
if (func_type == UDQTokenType::table_lookup)
throw std::invalid_argument("Table lookup function TU*[] is not supported in UDQ");
if (func_type == UDQTokenType::table_lookup) {
throw std::invalid_argument {
"Table lookup function TU*[] is not supported in UDQ"
};
}
if (func_type != UDQTokenType::error)
if (func_type != UDQTokenType::error) {
return func_type;
}
if (arg == "(")
if (arg == "(") {
return UDQTokenType::open_paren;
}
if (arg == ")")
if (arg == ")") {
return UDQTokenType::close_paren;
}
{
char * end_ptr;
char* end_ptr;
std::strtod(arg.c_str(), &end_ptr);
if (std::strlen(end_ptr) == 0)
if (std::strlen(end_ptr) == 0) {
return UDQTokenType::number;
}
}
return UDQTokenType::ecl_expr;
}
bool UDQParser::empty() const {
return (static_cast<size_t>(this->current_pos) == this->tokens.size());
bool UDQParser::empty() const
{
return static_cast<std::size_t>(this->current_pos) == this->tokens.size();
}
UDQParseNode UDQParser::next() {
UDQParseNode UDQParser::next()
{
this->current_pos += 1;
return this->current();
}
UDQParseNode UDQParser::current() const {
if (this->empty())
UDQParseNode UDQParser::current() const
{
if (this->empty()) {
return UDQTokenType::end;
}
const auto& token = this->tokens[current_pos];
if (token.type() == UDQTokenType::number)
if (token.type() == UDQTokenType::number) {
return UDQParseNode(UDQTokenType::number, token.value());
}
if (token.type() == UDQTokenType::ecl_expr)
if (token.type() == UDQTokenType::ecl_expr) {
return UDQParseNode(UDQTokenType::ecl_expr, token.value(), token.selector());
}
return UDQParseNode(this->get_type(std::get<std::string>(token.value())), token.value());
}
UDQASTNode UDQParser::parse_factor() {
UDQASTNode UDQParser::parse_factor()
{
double sign = 1.0;
auto current = this->current();
if (current.type == UDQTokenType::binary_op_add || current.type == UDQTokenType::binary_op_sub) {
if (current.type == UDQTokenType::binary_op_sub)
if ((current.type == UDQTokenType::binary_op_add) ||
(current.type == UDQTokenType::binary_op_sub))
{
if (current.type == UDQTokenType::binary_op_sub) {
sign = -1.0;
}
this->next();
current = this->current();
}
@ -98,8 +152,9 @@ UDQASTNode UDQParser::parse_factor() {
auto inner_expr = this->parse_set();
current = this->current();
if (current.type != UDQTokenType::close_paren)
if (current.type != UDQTokenType::close_paren) {
return UDQASTNode(UDQTokenType::error);
}
this->next();
return sign * inner_expr;
@ -113,30 +168,37 @@ UDQASTNode UDQParser::parse_factor() {
auto arg_expr = this->parse_set();
current = this->current();
if (current.type != UDQTokenType::close_paren)
if (current.type != UDQTokenType::close_paren) {
return UDQASTNode(UDQTokenType::error);
}
this->next();
return sign * UDQASTNode(func_node.type, func_node.value, arg_expr);
} else
}
else {
return UDQASTNode(UDQTokenType::error);
}
}
UDQASTNode node(current.type, current.value, current.selector);
this->next();
return sign * node;
}
UDQASTNode UDQParser::parse_pow() {
UDQASTNode UDQParser::parse_pow()
{
auto left = this->parse_factor();
if (this->empty())
if (this->empty()) {
return left;
}
auto current = this->current();
if (current.type == UDQTokenType::binary_op_pow) {
this->next();
if (this->empty())
if (this->empty()) {
return UDQASTNode(UDQTokenType::error);
}
auto right = this->parse_mul();
return UDQASTNode(current.type, current.value, left, right);
@ -145,9 +207,8 @@ UDQASTNode UDQParser::parse_pow() {
return left;
}
UDQASTNode UDQParser::parse_mul() {
UDQASTNode UDQParser::parse_mul()
{
std::vector<UDQASTNode> nodes;
{
std::unique_ptr<UDQASTNode> current_node;
@ -156,36 +217,48 @@ UDQASTNode UDQParser::parse_mul() {
if (current_node) {
current_node->set_right(node);
nodes.push_back(*current_node);
} else
}
else {
nodes.push_back(node);
}
if (this->empty())
if (this->empty()) {
break;
}
auto current_token = this->current();
if (current_token.type == UDQTokenType::binary_op_mul || current_token.type == UDQTokenType::binary_op_div) {
current_node.reset( new UDQASTNode(current_token.type, current_token.value) );
if ((current_token.type == UDQTokenType::binary_op_mul) ||
(current_token.type == UDQTokenType::binary_op_div))
{
current_node = std::make_unique<UDQASTNode>(current_token.type, current_token.value);
this->next();
if (this->empty())
if (this->empty()) {
return UDQASTNode( UDQTokenType::error );
} else break;
}
}
else {
break;
}
}
}
UDQASTNode top_node = nodes.back();
if (nodes.size() > 1) {
UDQASTNode * current = &top_node;
UDQASTNode* current = &top_node;
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
current->set_left(nodes[index - 1]);
current = current->get_left();
}
}
return top_node;
}
UDQASTNode UDQParser::parse_add() {
UDQASTNode UDQParser::parse_add()
{
std::vector<UDQASTNode> nodes;
{
std::unique_ptr<UDQASTNode> current_node;
while (true) {
@ -193,119 +266,117 @@ UDQASTNode UDQParser::parse_add() {
if (current_node) {
current_node->set_right(node);
nodes.push_back(*current_node);
} else
}
else {
nodes.push_back(node);
}
if (this->empty())
if (this->empty()) {
break;
}
auto current_token = this->current();
if (current_token.type == UDQTokenType::binary_op_add || current_token.type == UDQTokenType::binary_op_sub) {
current_node.reset( new UDQASTNode(current_token.type, current_token.value) );
if ((current_token.type == UDQTokenType::binary_op_add) ||
(current_token.type == UDQTokenType::binary_op_sub))
{
current_node = std::make_unique<UDQASTNode>
(current_token.type, current_token.value);
this->next();
if (this->empty())
return UDQASTNode( UDQTokenType::error );
} else if (current_token.type == UDQTokenType::close_paren || UDQ::cmpFunc(current_token.type) || UDQ::setFunc(current_token.type))
if (this->empty()) {
return UDQASTNode(UDQTokenType::error);
}
}
else if ((current_token.type == UDQTokenType::close_paren) ||
UDQ::cmpFunc(current_token.type) ||
UDQ::setFunc(current_token.type))
{
break;
else
return UDQASTNode( UDQTokenType::error );
}
else {
return UDQASTNode(UDQTokenType::error);
}
}
}
UDQASTNode top_node = nodes.back();
if (nodes.size() > 1) {
UDQASTNode * current = &top_node;
UDQASTNode* current = &top_node;
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
current->set_left(nodes[index - 1]);
current = current->get_left();
}
}
return top_node;
}
// A bit uncertain on the presedence of the comparison operators. In normal
// C the comparion operators bind weaker than addition, i.e. for the
// assignment:
//
// auto cmp = a + b < c;
//
// The sum (a+b) is evaluated and then compared with c, that is the order of
// presedence implemented here. But reading the eclipse UDQ manual one can
// get the imporession that the relation operators should bind "very
// strong", i.e. that (b < c) should be evaluated first, and then the
// result of the comparison added to a.
/*
A bit uncertain on the presedence of the comparison operators. In normal C the
comparion operators bind weaker than addition, i.e. for the assignment:
auto cmp = a + b < c;
The sum (a+b) is evaluated and then compared with c, that is the order of
presedence implemented here. But reading the eclipse UDQ manual one can get
the imporession that the relation operators should bind "very strong", i.e.
that (b < c) should be evaluated first, and then the result of the comparison
added to a.
*/
UDQASTNode UDQParser::parse_cmp() {
UDQASTNode UDQParser::parse_cmp()
{
auto left = this->parse_add();
if (this->empty())
if (this->empty()) {
return left;
}
auto current = this->current();
if (UDQ::cmpFunc(current.type)) {
auto func_node = current;
this->next();
if (this->empty())
if (this->empty()) {
return UDQASTNode(UDQTokenType::error);
}
auto right = this->parse_cmp();
return UDQASTNode(current.type, current.value, left, right);
}
return left;
}
UDQASTNode UDQParser::parse_set() {
UDQASTNode UDQParser::parse_set()
{
auto left = this->parse_cmp();
if (this->empty())
if (this->empty()) {
return left;
}
auto current = this->current();
if (UDQ::setFunc(current.type)) {
auto func_node = current;
this->next();
if (this->empty())
if (this->empty()) {
return UDQASTNode(UDQTokenType::error);
}
auto right = this->parse_set();
return UDQASTNode(current.type, current.value, left, right);
}
return left;
}
namespace {
void dump_tokens(const std::string& target_var, const std::vector<UDQToken>& tokens) {
std::cout << target_var << " = ";
for (const auto& token : tokens)
std::cout << token.str();
std::cout << std::endl;
}
/*
This function is extremely weak - hopefully it can be improved in the future.
See the comment in UDQEnums.hpp about 'UDQ type system'.
*/
bool static_type_check(UDQVarType lhs, UDQVarType rhs) {
if (lhs == rhs)
return true;
if (rhs == UDQVarType::SCALAR)
return true;
/*
This does not check if the rhs evaluates to a scalar.
*/
if (rhs == UDQVarType::WELL_VAR)
return (lhs == UDQVarType::WELL_VAR);
return false;
}
}
UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type, const std::string& target_var, const KeywordLocation& location, const std::vector<UDQToken>& tokens, const ParseContext& parseContext, ErrorGuard& errors)
UDQASTNode
UDQParser::parse(const UDQParams& udq_params,
const UDQVarType target_type,
const std::string& target_var,
const KeywordLocation& location,
const std::vector<UDQToken>& tokens,
const ParseContext& parseContext,
ErrorGuard& errors)
{
UDQParser parser(udq_params, tokens);
parser.next();
@ -315,20 +386,26 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
auto current = parser.current();
std::string msg_fmt = fmt::format("Problem parsing UDQ {}\n"
"In {{file}} line {{line}}.\n"
"Extra unhandled data starting with item {}.", target_var, current.string());
"Extra unhandled data starting with item {}.",
target_var, current.string());
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
return UDQASTNode( udq_params.undefinedValue() );
}
if (!tree.valid()) {
std::string token_string;
for (const auto& token : tokens)
for (const auto& token : tokens) {
token_string += token.str() + " ";
}
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
"In {{file}} line {{line}}.\n"
"This can be a bug in flow or a bug in the UDQ input string.\n"
"UDQ input: '{}'", target_var, token_string);
"This can be a bug in flow or a "
"bug in the UDQ input string.\n"
"UDQ input: '{}'",
target_var, token_string);
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
return UDQASTNode( udq_params.undefinedValue() );
}
@ -336,27 +413,35 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
if (!static_type_check(target_type, tree.var_type)) {
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
"In {{file}} line {{line}}.\n"
"Invalid type conversion detected in UDQ expression expected: {} got: {}", target_var, UDQ::typeName(target_type), UDQ::typeName(tree.var_type));
"Invalid type conversion detected "
"in UDQ expression expected: {}, got: {}",
target_var,
UDQ::typeName(target_type),
UDQ::typeName(tree.var_type));
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
dump_tokens(target_var, tokens);
}
return UDQASTNode( udq_params.undefinedValue() );
return UDQASTNode(udq_params.undefinedValue());
}
if (tree.var_type == UDQVarType::NONE) {
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
"In {{file}} line {{line}}.\n"
"Could not determine expression type.", target_var);
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
dump_tokens(target_var, tokens);
"Could not determine "
"expression type.", target_var);
return UDQASTNode( udq_params.undefinedValue() );
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
dump_tokens(target_var, tokens);
}
return UDQASTNode(udq_params.undefinedValue());
}
return tree;
}
}
} // namespace Opm

View File

@ -16,70 +16,85 @@
OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDQPARSER_HPP
#define UDQPARSER_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
#include <string>
#include <variant>
#include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
namespace Opm {
class ParseContext;
class ErrorGuard;
class KeywordLocation;
struct UDQParseNode {
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg, const std::vector<std::string>& selector_arg) :
type(type_arg),
value(value_arg),
selector(selector_arg)
} // namespace Opm
namespace Opm {
struct UDQParseNode
{
UDQParseNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const std::vector<std::string>& selector_arg)
: type(type_arg)
, value(value_arg)
, selector(selector_arg)
{
if (type_arg == UDQTokenType::ecl_expr)
if (type_arg == UDQTokenType::ecl_expr) {
this->var_type = UDQ::targetType(std::get<std::string>(value_arg), selector_arg);
}
}
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) :
UDQParseNode(type_arg, value_arg, {})
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg)
: UDQParseNode(type_arg, value_arg, {})
{}
// Implicit converting constructor.
UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "")
{}
std::string string() const {
if (std::holds_alternative<std::string>(this->value))
std::string string() const
{
if (std::holds_alternative<std::string>(this->value)) {
return std::get<std::string>(this->value);
else
return std::to_string( std::get<double>(this->value));
}
else {
return std::to_string(std::get<double>(this->value));
}
}
UDQTokenType type;
std::variant<std::string, double> value;
std::vector<std::string> selector;
UDQVarType var_type = UDQVarType::NONE;
};
class UDQParser {
class UDQParser
{
public:
static UDQASTNode parse(const UDQParams& udq_params, UDQVarType target_type, const std::string& target_var, const KeywordLocation& location, const std::vector<UDQToken>& tokens_, const ParseContext& parseContext, ErrorGuard& errors);
static UDQASTNode
parse(const UDQParams& udq_params,
UDQVarType target_type,
const std::string& target_var,
const KeywordLocation& location,
const std::vector<UDQToken>& tokens_,
const ParseContext& parseContext,
ErrorGuard& errors);
private:
UDQParser(const UDQParams& udq_params1, const std::vector<UDQToken>& tokens_) :
udq_params(udq_params1),
udqft(UDQFunctionTable(udq_params)),
tokens(tokens_)
UDQParser(const UDQParams& udq_params1,
const std::vector<UDQToken>& tokens_)
: udq_params(udq_params1)
, udqft(UDQFunctionTable(udq_params))
, tokens(tokens_)
{}
UDQASTNode parse_set();
@ -101,7 +116,6 @@ private:
ssize_t current_pos = -1;
};
} // namespace Opm
}
#endif
#endif // UDQPARSER_HPP

View File

@ -16,12 +16,21 @@
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 <cmath>
#include <fmt/format.h>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/common/utility/shmatch.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include <fmt/format.h>
namespace Opm {
@ -216,12 +225,13 @@ UDQSet UDQSet::groups(const std::string& name, const std::vector<std::string>& g
}
bool UDQSet::has(const std::string& name) const {
for (const auto& res : this->values) {
if (res.wgname() == name)
return true;
}
return false;
bool UDQSet::has(const std::string& name) const
{
return std::any_of(this->values.begin(), this->values.end(),
[&name](const UDQScalar& value)
{
return value.wgname() == name;
});
}
std::size_t UDQSet::size() const {
@ -342,25 +352,36 @@ std::vector<double> UDQSet::defined_values() const {
}
std::size_t UDQSet::defined_size() const {
std::size_t dsize = 0;
for (const auto& v : this->values) {
if (v)
dsize += 1;
}
return dsize;
std::size_t UDQSet::defined_size() const
{
return std::count_if(this->values.begin(), this->values.end(),
[](const UDQScalar& value)
{
return value.defined();
});
}
const UDQScalar& UDQSet::operator[](std::size_t index) const {
if (index >= this->size())
const UDQScalar& UDQSet::operator[](std::size_t index) const
{
if (index >= this->size()) {
throw std::out_of_range("Index out of range in UDQset::operator[]");
}
return this->values[index];
}
const UDQScalar& UDQSet::operator[](const std::string& wgname) const {
auto value_iter = std::find_if( this->values.begin(), this->values.end(), [&wgname](const UDQScalar& value) { return (value.wgname() == wgname );});
if (value_iter == this->values.end())
const UDQScalar& UDQSet::operator[](const std::string& wgname) const
{
auto value_iter = std::find_if(this->values.begin(), this->values.end(),
[&wgname](const UDQScalar& value)
{
return value.wgname() == wgname;
});
if (value_iter == this->values.end()) {
throw std::out_of_range("No such well/group: " + wgname);
}
return *value_iter;
}
@ -453,54 +474,58 @@ UDQScalar operator/(double lhs, const UDQScalar& rhs) {
namespace {
bool is_scalar(const UDQSet& udq_set) {
if (udq_set.var_type() == UDQVarType::SCALAR)
return true;
bool is_scalar(const UDQSet& udq_set)
{
const auto vtype = udq_set.var_type();
if (udq_set.var_type() == UDQVarType::FIELD_VAR)
return true;
return false;
return (vtype == UDQVarType::SCALAR)
|| (vtype == UDQVarType::FIELD_VAR);
}
/*
If one result set is scalar and the other represents a set of wells/groups,
the scalar result is promoted to a set of the right type.
This function is quite subconcious about FIELD / SCALAR.
*/
// If one result set is scalar and the other represents a set of
// wells/groups, the scalar result is promoted to a set of the right type.
//
// This function is quite subconscious about FIELD / SCALAR.
std::pair<UDQSet, UDQSet> udq_cast(const UDQSet& lhs, const UDQSet& rhs)
{
if (lhs.var_type() == rhs.var_type())
return std::make_pair(lhs,rhs);
if (lhs.var_type() == rhs.var_type()) {
return { lhs, rhs };
}
if (lhs.size() == rhs.size())
return std::make_pair(lhs,rhs);
if (is_scalar(lhs) && is_scalar(rhs)) {
return { lhs, rhs };
}
if (is_scalar(lhs)) {
if (rhs.var_type() == UDQVarType::WELL_VAR)
return std::make_pair(UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs);
if (rhs.var_type() == UDQVarType::WELL_VAR) {
return { UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
}
if (rhs.var_type() == UDQVarType::GROUP_VAR)
return std::make_pair(UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs);
if (rhs.var_type() == UDQVarType::GROUP_VAR) {
return { UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
}
}
if (is_scalar(rhs)) {
if (lhs.var_type() == UDQVarType::WELL_VAR)
return std::make_pair(lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()));
if (lhs.var_type() == UDQVarType::WELL_VAR) {
return { lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()) };
}
if (lhs.var_type() == UDQVarType::GROUP_VAR)
return std::make_pair(lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get()));
if (lhs.var_type() == UDQVarType::GROUP_VAR) {
return { lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get()) };
}
}
auto msg = fmt::format("Type/size mismatch when combining UDQs {}(size={}, type={}) and {}(size={}, type={})",
lhs.name(), lhs.size(), static_cast<int>(lhs.var_type()),
rhs.name(), rhs.size(), static_cast<int>(rhs.var_type()));
throw std::logic_error(msg);
throw std::logic_error {
fmt::format("Type/size mismatch when combining UDQs "
"{}(size={}, type={}) and "
"{}(size={}, type={})",
lhs.name(), lhs.size(), UDQ::typeName(lhs.var_type()),
rhs.name(), rhs.size(), UDQ::typeName(rhs.var_type()))
};
}
}
} // Anonymous namespace
UDQSet operator+(const UDQSet&lhs, const UDQSet& rhs) {
auto [left,right] = udq_cast(lhs, rhs);
@ -584,4 +609,4 @@ bool UDQSet::operator==(const UDQSet& other) const {
this->values == other.values;
}
}
} // namespace Opm

View File

@ -36,47 +36,57 @@ namespace {
namespace Opm {
UDQToken::UDQToken(const std::string& string_token, UDQTokenType token_type_) :
token_type(token_type_)
UDQToken::UDQToken(const std::string& string_token,
const UDQTokenType token_type_)
: token_type(token_type_)
{
if (this->token_type == UDQTokenType::number)
if (this->token_type == UDQTokenType::number) {
this->m_value = stod(string_token);
else
}
else {
this->m_value = string_token;
}
}
UDQToken::UDQToken(const std::string& string_token, const std::vector<std::string>& selector_):
token_type(UDQTokenType::ecl_expr),
m_value(string_token),
m_selector(selector_)
UDQToken::UDQToken(const std::string& string_token,
const std::vector<std::string>& selector_)
: token_type(UDQTokenType::ecl_expr)
, m_value (string_token)
, m_selector(selector_)
{}
const std::variant<std::string, double>& UDQToken::value() const
{
}
const std::variant<std::string, double>& UDQToken::value() const {
return this->m_value;
}
const std::vector<std::string>& UDQToken::selector() const {
const std::vector<std::string>& UDQToken::selector() const
{
return this->m_selector;
}
UDQTokenType UDQToken::type() const {
UDQTokenType UDQToken::type() const
{
return this->token_type;
}
std::string UDQToken::str() const {
std::string UDQToken::str() const
{
if (std::holds_alternative<std::string>(this->m_value)) {
if (this->m_selector.empty())
if (this->m_selector.empty()) {
return std::get<std::string>(this->m_value);
}
std::string quoted_selector;
for (const auto& s : this->m_selector)
for (const auto& s : this->m_selector) {
quoted_selector += " '" + s + "'";
}
return std::get<std::string>(this->m_value) + quoted_selector;
} else
}
else {
return format_double(std::get<double>(this->m_value));
}
}
} // namespace Opm