diff --git a/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp b/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp index 33b303073..e8f998aac 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp @@ -20,6 +20,10 @@ #ifndef UDQASTNODE_HPP #define UDQASTNODE_HPP +#include +#include +#include + #include #include #include @@ -27,16 +31,13 @@ #include #include -#include -#include -#include - - - 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 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& summary_keys) const; - template + template void serializeOp(Serializer& serializer) { serializer(var_type); @@ -76,13 +76,34 @@ public: private: UDQTokenType type; - void func_tokens(std::set& tokens) const; std::variant value; double sign = 1.0; std::vector selector; std::shared_ptr left; std::shared_ptr 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& tokens) const; }; UDQASTNode operator*(const UDQASTNode&lhs, double rhs); diff --git a/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp b/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp index 65adfb01e..18cb21294 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp @@ -20,20 +20,22 @@ #ifndef UDQINPUT_HPP_ #define UDQINPUT_HPP_ -#include -#include -#include -#include - -#include -#include #include +#include #include -#include #include +#include +#include + #include #include +#include +#include +#include +#include +#include +#include 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& summary_keys) const; - template 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 m_definitions; std::unordered_map m_assignments; std::unordered_map units; diff --git a/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp b/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp index ba746716c..8dacd17a1 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp @@ -17,30 +17,38 @@ along with OPM. If not, see . */ - #ifndef UDQ_DEFINE_HPP #define UDQ_DEFINE_HPP +#include +#include +#include +#include +#include + +#include + +#include +#include #include #include #include #include +#include #include -#include -#include -#include -#include -#include -#include - 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 func_tokens() const; void required_summary(std::unordered_set& 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 + template void serializeOp(Serializer& serializer) { serializer(m_keyword); @@ -104,8 +112,7 @@ private: UDQUpdate m_update_status; mutable std::optional string_data; }; -} +} // Namespace Opm - -#endif +#endif // UDQ_DEFINE_HPP diff --git a/opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp b/opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp index b62b550ee..fd23c2ae0 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp @@ -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 diff --git a/opm/input/eclipse/Schedule/UDQ/UDQInput.hpp b/opm/input/eclipse/Schedule/UDQ/UDQInput.hpp index 5495885c2..95c04b7cf 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQInput.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQInput.hpp @@ -17,32 +17,33 @@ along with OPM. If not, see . */ - #ifndef UDQINPUT__HPP_ #define UDQINPUT__HPP_ -#include - -#include -#include #include +#include +#include + +#include +#include +#include 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 + template 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 + template const T& get() const; - template + template 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 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_ diff --git a/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp b/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp index 3cbd42013..5d7ddd72d 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp @@ -20,17 +20,19 @@ #ifndef UDQSET_HPP #define UDQSET_HPP +#include + +#include #include #include #include #include #include -#include - 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& 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& 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; diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp index ea16ef6a8..361fb6267 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp @@ -16,91 +16,131 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . */ + #include + +#include #include #include -#include - -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 +#include +#include +#include +#include +#include +#include +#include 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& 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& value_arg) + : var_type(init_type(type_arg)) + , type (type_arg) + , value (value_arg) +{} + +UDQASTNode::UDQASTNode(const UDQTokenType type_arg, const std::variant& 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(left_arg); } - -UDQASTNode::UDQASTNode(UDQTokenType type_arg, +UDQASTNode::UDQASTNode(const UDQTokenType type_arg, const std::variant& 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& value_arg, + const std::vector& 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(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(left); return result; } -UDQASTNode::UDQASTNode(UDQTokenType type_arg, - const std::variant& value_arg, - const std::vector& 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(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( 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( this->value ); - const auto& udqft = context.function_table(); - const UDQScalarFunction& func = dynamic_cast(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( this->value ); - auto func_arg = this->left->eval(target_type, context); - - const auto& udqft = context.function_table(); - const UDQUnaryElementalFunction& func = dynamic_cast(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( this->value ); - - const auto& udqft = context.function_table(); - const UDQBinaryFunction& func = dynamic_cast(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(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(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(this->type))); + throw std::invalid_argument { + "Should not be here ... this->type: " + std::to_string(static_cast(this->type)) + }; } -void UDQASTNode::func_tokens(std::set& 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 UDQASTNode::func_tokens() const { - std::set tokens; +std::set UDQASTNode::func_tokens() const +{ + auto tokens = std::set{}; 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(arg); this->update_type(arg); } -void UDQASTNode::set_right(const UDQASTNode& arg) { +void UDQASTNode::set_right(const UDQASTNode& arg) +{ this->right = std::make_unique(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& summary_keys) const { +void UDQASTNode::required_summary(std::unordered_set& summary_keys) const +{ if (this->type == UDQTokenType::ecl_expr) { if (std::holds_alternative(this->value)) { const auto& keyword = std::get(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(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(this->value); + const auto& udqft = context.function_table(); + + const auto& func = dynamic_cast(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(this->value); + const auto func_arg = this->left->eval(target_type, context); + + const auto& udqft = context.function_table(); + const auto& func = dynamic_cast(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(this->value); + + const auto& udqft = context.function_table(); + const auto& func = dynamic_cast(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(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(target_type)) + }; + } +} + +void UDQASTNode::func_tokens(std::set& 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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp index b18d5e573..9bdb6a467 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp @@ -17,45 +17,69 @@ along with OPM. If not, see . */ -#include +#include #include + #include #include -#include + #include -#include #include #include #include +#include // UDQ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +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& selector, double value, std::size_t report_step) { + void UDQConfig::add_assign(const std::string& quantity, + const std::vector& 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& selector, double value, std::size_t report_step) { + void UDQConfig::add_assign(const std::string& quantity, + const std::unordered_set& 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& expression, std::size_t report_step) { + void UDQConfig::add_define(const std::string& quantity, + const KeywordLocation& location, + const std::vector& 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& 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& 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().get(0)); + const auto& quantity = record.getItem().get(0); + const auto data = RawString::strings(record.getItem().getData()); - void UDQConfig::add_record(const DeckRecord& record, const KeywordLocation& location, std::size_t report_step) { - auto action = UDQ::actionType(record.getItem("ACTION").get(0)); - const auto& quantity = record.getItem("QUANTITY").get(0); - const auto& data = RawString::strings( record.getItem("DATA").getData() ); - - 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(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 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(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 UDQConfig::definitions() const { + std::vector UDQConfig::definitions() const + { std::vector ret; for (const auto& index_pair : this->input_index) { @@ -193,164 +276,184 @@ namespace Opm { return ret; } - - std::vector UDQConfig::definitions(UDQVarType var_type) const { + std::vector UDQConfig::definitions(const UDQVarType var_type) const + { std::vector 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 UDQConfig::input() const { + std::vector UDQConfig::input() const + { std::vector 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 UDQConfig::assignments() const { + std::vector UDQConfig::assignments() const + { std::vector 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 UDQConfig::assignments(UDQVarType var_type) const { + std::vector UDQConfig::assignments(const UDQVarType var_type) const + { std::vector 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& name_index) - { - const auto& [_, index] = name_index; - (void)_; - return index.insert_index == insert_index; - }); + [insert_index](const std::pair& 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& summary_keys) const { + void UDQConfig::required_summary(std::unordered_set& 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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp index 42c7631ad..ca3317233 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp @@ -16,127 +16,126 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include + +#include +#include + +#include #include #include -#include + +#include +#include #include "../../Parser/raw/RawConsts.hpp" #include "UDQParser.hpp" -namespace Opm { - +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace { -std::vector quote_split(const std::string& item) { +std::vector quote_split(const std::string& item) +{ char quote_char = '\''; std::vector 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 make_tokens(const std::vector& string_tokens) { - if (string_tokens.empty()) +std::vector +make_tokens(const std::vector& string_tokens) +{ + if (string_tokens.empty()) { return {}; + } - std::vector tokens; + std::vector 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 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 -UDQDefine::UDQDefine(const UDQParams& udq_params_arg, - const std::string& keyword, - std::size_t report_step, - const KeywordLocation& location, - const std::vector& 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& 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& splitters) { +std::string +next_token(const std::string& item, + std::size_t& offset, + const std::vector& 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 +UDQDefine::UDQDefine(const UDQParams& udq_params_arg, + const std::string& keyword, + const std::size_t report_step, + const KeywordLocation& location, const std::vector& 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& 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& 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 string_tokens; + const auto splitters = std::vector { + " ", "TU*[]", "(", ")", "[", "]", ",", + "+", "-", "/", "*", + "==", "!=", "^", ">=", "<=", ">", "<", + }; + + auto string_tokens = std::vector{}; 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 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( UDQParser::parse(udq_params, this->m_var_type, this->m_keyword, this->m_location, this->m_tokens, parseContext, errors) ); + + this->ast = std::make_shared + (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& summary_keys) const { +void UDQDefine::required_summary(std::unordered_set& 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 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 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 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 UDQDefine::func_tokens() const { +std::set UDQDefine::func_tokens() const +{ return this->ast->func_tokens(); } -std::pair UDQDefine::status() const { +std::pair UDQDefine::status() const +{ return std::make_pair(this->m_update_status, this->m_report_step); } -const std::vector UDQDefine::tokens() const { +const std::vector 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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQEnums.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQEnums.cpp index 3cefbacfd..dfaabf0c1 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQEnums.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQEnums.cpp @@ -28,367 +28,407 @@ #include #include -namespace Opm { namespace UDQ { - namespace { - const std::set 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 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 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::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 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::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::binary_op_uadd, + Opm::UDQTokenType::binary_op_umul, + Opm::UDQTokenType::binary_op_umin, + Opm::UDQTokenType::binary_op_umax, + }; - const std::set 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::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::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 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 { + {"+" , 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& 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& 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(t1)) + + " and " + std::to_string(static_cast(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(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(control)) + - "- internal error" + ") - internal error" }; } @@ -683,5 +723,4 @@ std::string controlName(const UDAControl control) }; } - -}} // Opm::UDQ +}} // namespace Opm::UDQ diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQInput.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQInput.cpp index c5212e2d6..4d3356daa 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQInput.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQInput.cpp @@ -17,78 +17,91 @@ along with OPM. If not, see . */ - #include +#include +#include + +#include +#include +#include + 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() const { +bool UDQInput::is() const +{ return std::holds_alternative(this->value); } - template<> -bool UDQInput::is() const { +bool UDQInput::is() const +{ return std::holds_alternative(this->value); } template<> -const UDQAssign& UDQInput::get() const { - if (this->is()) +const UDQAssign& UDQInput::get() const +{ + if (this->is()) { return std::get(this->value); + } throw std::runtime_error("Invalid get"); } - template<> -const UDQDefine& UDQInput::get() const { - if (this->is()) +const UDQDefine& UDQInput::get() const +{ + if (this->is()) { return std::get(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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQParser.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQParser.cpp index 161a10b19..81bb6fea4 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQParser.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQParser.cpp @@ -17,77 +17,131 @@ along with OPM. If not, see . */ -#include -#include +#include "UDQParser.hpp" + +#include + +#include + #include +#include +#include +#include +#include #include -#include -#include +namespace { -#include "UDQParser.hpp" + void dump_tokens(const std::string& target_var, + const std::vector& 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(this->current_pos) == this->tokens.size()); +bool UDQParser::empty() const +{ + return static_cast(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(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 nodes; { std::unique_ptr 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(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 nodes; + { std::unique_ptr 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 + (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& 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& 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& 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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQParser.hpp b/src/opm/input/eclipse/Schedule/UDQ/UDQParser.hpp index 6aa498a71..bd3d6eeed 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQParser.hpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQParser.hpp @@ -16,70 +16,85 @@ OPM. If not, see . */ - #ifndef UDQPARSER_HPP #define UDQPARSER_HPP +#include +#include +#include +#include +#include + #include #include #include -#include -#include -#include -#include -#include - namespace Opm { class ParseContext; class ErrorGuard; class KeywordLocation; -struct UDQParseNode { - UDQParseNode(UDQTokenType type_arg, const std::variant& value_arg, const std::vector& 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& value_arg, + const std::vector& 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(value_arg), selector_arg); + } } - - UDQParseNode(UDQTokenType type_arg, const std::variant& value_arg) : - UDQParseNode(type_arg, value_arg, {}) + UDQParseNode(UDQTokenType type_arg, const std::variant& 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(this->value)) + std::string string() const + { + if (std::holds_alternative(this->value)) { return std::get(this->value); - else - return std::to_string( std::get(this->value)); + } + else { + return std::to_string(std::get(this->value)); + } } - UDQTokenType type; std::variant value; std::vector 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& 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& tokens_, + const ParseContext& parseContext, + ErrorGuard& errors); private: - UDQParser(const UDQParams& udq_params1, const std::vector& tokens_) : - udq_params(udq_params1), - udqft(UDQFunctionTable(udq_params)), - tokens(tokens_) + UDQParser(const UDQParams& udq_params1, + const std::vector& 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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp index 4935767b6..33fd8dda2 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp @@ -16,12 +16,21 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . */ -#include -#include -#include + +#include #include -#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include namespace Opm { @@ -216,12 +225,13 @@ UDQSet UDQSet::groups(const std::string& name, const std::vector& 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 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 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(lhs.var_type()), - rhs.name(), rhs.size(), static_cast(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 diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQToken.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQToken.cpp index e9979c99c..3d0f1b633 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQToken.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQToken.cpp @@ -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& selector_): - token_type(UDQTokenType::ecl_expr), - m_value(string_token), - m_selector(selector_) +UDQToken::UDQToken(const std::string& string_token, + const std::vector& selector_) + : token_type(UDQTokenType::ecl_expr) + , m_value (string_token) + , m_selector(selector_) +{} + +const std::variant& UDQToken::value() const { -} - -const std::variant& UDQToken::value() const { return this->m_value; } -const std::vector& UDQToken::selector() const { +const std::vector& 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(this->m_value)) { - if (this->m_selector.empty()) + if (this->m_selector.empty()) { return std::get(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(this->m_value) + quoted_selector; - } else + } + else { return format_double(std::get(this->m_value)); + } } } // namespace Opm