From 0994a1a2fe2f883da2b2fd4d340b24199c79e520 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Sun, 25 Oct 2020 20:45:09 +0100 Subject: [PATCH 1/3] Add sign member to UDQASTNode and implement operator* --- .../EclipseState/Schedule/UDQ/UDQASTNode.hpp | 8 +++- .../EclipseState/Schedule/UDQ/UDQASTNode.cpp | 42 +++++++++++++------ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.hpp b/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.hpp index 3266a6692..3fe46079b 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.hpp @@ -40,7 +40,7 @@ public: UDQASTNode(); explicit UDQASTNode(UDQTokenType type_arg); explicit UDQASTNode(double scalar_value); - UDQASTNode(UDQTokenType type_arg, const std::variant& value_arg, const UDQASTNode& arg); + UDQASTNode(UDQTokenType type_arg, const std::variant& value_arg, const UDQASTNode& left_arg); UDQASTNode(UDQTokenType type_arg, const std::variant& value_arg, const UDQASTNode& left, const UDQASTNode& right); UDQASTNode(UDQTokenType type_arg, const std::variant& value_arg); UDQASTNode(UDQTokenType type_arg, const std::variant& value_arg, const std::vector& selector); @@ -57,6 +57,7 @@ public: void set_right(const UDQASTNode& arg); UDQASTNode* get_left() const; UDQASTNode* get_right() const; + void scale(double sign_factor); bool operator==(const UDQASTNode& data) const; void required_summary(std::unordered_set& summary_keys) const; @@ -67,6 +68,7 @@ public: serializer(var_type); serializer(type); serializer(value); + serializer(sign); serializer(selector); serializer(left); serializer(right); @@ -77,11 +79,15 @@ private: 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; }; +UDQASTNode operator*(const UDQASTNode&lhs, double rhs); +UDQASTNode operator*(double lhs, const UDQASTNode& rhs); + } #endif diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.cpp index 262607cbf..971477339 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQASTNode.cpp @@ -111,6 +111,7 @@ UDQASTNode UDQASTNode::serializeObject() result.type = UDQTokenType::error; result.value = "test1"; result.selector = {"test2"}; + result.sign = -1; UDQASTNode left = result; result.left = std::make_shared(left); @@ -149,7 +150,7 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const if (this->selector.size() > 0) { const std::string& well_pattern = this->selector[0]; if (well_pattern.find("*") == std::string::npos) - return UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value)); + return this->sign * UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value)); else { auto res = UDQSet::wells(string_value, wells); int fnmatch_flags = 0; @@ -157,14 +158,14 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const if (fnmatch(well_pattern.c_str(), well.c_str(), fnmatch_flags) == 0) res.assign(well, context.get_well_var(well, string_value)); } - return res; + return this->sign * res; } } else { auto res = UDQSet::wells(string_value, wells); for (const auto& well : wells) res.assign(well, context.get_well_var(well, string_value)); - return res; + return this->sign * res; } } @@ -180,16 +181,16 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const auto res = UDQSet::groups(string_value, groups); for (const auto& group : groups) res.assign(group, context.get_group_var(group, string_value)); - return res; + return this->sign * res; } } if (data_type == UDQVarType::FIELD_VAR) - return UDQSet::scalar(string_value, context.get(string_value)); + return this->sign * UDQSet::scalar(string_value, context.get(string_value)); auto scalar = context.get(string_value); if (scalar.has_value()) - return UDQSet::scalar(string_value, scalar.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); } @@ -199,7 +200,7 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const const auto& string_value = std::get( this->value ); const auto& udqft = context.function_table(); const UDQScalarFunction& func = dynamic_cast(udqft.get(string_value)); - return func.eval( this->left->eval(target_type, context) ); + return this->sign * func.eval( this->left->eval(target_type, context) ); } @@ -209,7 +210,7 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const const auto& udqft = context.function_table(); const UDQUnaryElementalFunction& func = dynamic_cast(udqft.get(string_value)); - return func.eval(func_arg); + return this->sign * func.eval(func_arg); } if (UDQ::binaryFunc(this->type)) { @@ -220,7 +221,7 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const const auto& udqft = context.function_table(); const UDQBinaryFunction& func = dynamic_cast(udqft.get(string_value)); auto res = func.eval(left_arg, right_arg); - return res; + return this->sign * res; } if (this->type == UDQTokenType::number) { @@ -228,13 +229,13 @@ UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const double numeric_value = std::get(this->value); switch(target_type) { case UDQVarType::WELL_VAR: - return UDQSet::wells(dummy_name, context.wells(), numeric_value); + return this->sign * UDQSet::wells(dummy_name, context.wells(), numeric_value); case UDQVarType::GROUP_VAR: - return UDQSet::groups(dummy_name, context.groups(), numeric_value); + return this->sign * UDQSet::groups(dummy_name, context.groups(), numeric_value); case UDQVarType::SCALAR: - return UDQSet::scalar(dummy_name, numeric_value); + return this->sign * UDQSet::scalar(dummy_name, numeric_value); case UDQVarType::FIELD_VAR: - return UDQSet::field(dummy_name, numeric_value); + return this->sign * UDQSet::field(dummy_name, numeric_value); default: throw std::invalid_argument("Unsupported target_type: " + std::to_string(static_cast(target_type))); } @@ -290,6 +291,10 @@ void UDQASTNode::set_right(const UDQASTNode& arg) { this->update_type(arg); } +void UDQASTNode::scale(double sign_factor) { + this->sign *= sign_factor; +} + bool UDQASTNode::operator==(const UDQASTNode& data) const { if ((this->left && !data.left) || (!this->left && data.left)) @@ -341,4 +346,15 @@ void UDQASTNode::required_summary(std::unordered_set& summary_keys) this->right->required_summary(summary_keys); } +UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor) { + UDQASTNode prod = lhs; + prod.scale(sign_factor); + return prod; +} + + +UDQASTNode operator*(double lhs, const UDQASTNode& rhs) { + return rhs * lhs; +} + } From e9dadcf93e0a318b1b1c5375af554433b7e48642 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Sun, 25 Oct 2020 20:46:23 +0100 Subject: [PATCH 2/3] Extract leading sign when extract UDQ factor --- .../EclipseState/Schedule/UDQ/UDQParser.cpp | 14 ++++++-- tests/parser/UDQTests.cpp | 34 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParser.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParser.cpp index 2624b79c7..60a4ebefb 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParser.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParser.cpp @@ -83,7 +83,15 @@ UDQParseNode UDQParser::current() const { 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) + sign = -1.0; + this->next(); + current = this->current(); + } + if (current.type == UDQTokenType::open_paren) { this->next(); @@ -94,7 +102,7 @@ UDQASTNode UDQParser::parse_factor() { return UDQASTNode(UDQTokenType::error); this->next(); - return inner_expr; + return sign * inner_expr; } if (UDQ::scalarFunc(current.type) || UDQ::elementalUnaryFunc(current.type)) { @@ -109,14 +117,14 @@ UDQASTNode UDQParser::parse_factor() { return UDQASTNode(UDQTokenType::error); this->next(); - return UDQASTNode(func_node.type, func_node.value, arg_expr); + return sign * UDQASTNode(func_node.type, func_node.value, arg_expr); } else return UDQASTNode(UDQTokenType::error); } UDQASTNode node(current.type, current.value, current.selector); this->next(); - return node; + return sign * node; } UDQASTNode UDQParser::parse_pow() { diff --git a/tests/parser/UDQTests.cpp b/tests/parser/UDQTests.cpp index 129c379c5..331d73a0e 100644 --- a/tests/parser/UDQTests.cpp +++ b/tests/parser/UDQTests.cpp @@ -2293,3 +2293,37 @@ BOOST_AUTO_TEST_CASE(UDQ_DIV_TEST) { } +BOOST_AUTO_TEST_CASE(UDQ_LEADING_SIGN) { + std::string deck_string = R"( +SCHEDULE + +UDQ + DEFINE FU_VAR1 - 100 + 215 / + DEFINE FU_VAR2 (-100 + 200) / 10 / + DEFINE FU_VAR3 -(100 + 200) * -10 / + DEFINE FU_VAR4 2^-1 / + ASSIGN FU_VAR6 2 / + ASSIGN FU_VAR7 3 / + DEFINE FU_VAR5 (-0.00000041232 * (FU_VAR6 ^ 2)) + (0.0010395 * FU_VAR7) + 0.16504 / +/ + +)"; + + auto schedule = make_schedule(deck_string); + UDQState udq_state(0); + SummaryState st(std::chrono::system_clock::now()); + + const auto& udq = schedule.getUDQConfig(0); + udq.eval(0, st, udq_state); + auto fu_var1 = st.get("FU_VAR1"); + auto fu_var2 = st.get("FU_VAR2"); + auto fu_var3 = st.get("FU_VAR3"); + auto fu_var4 = st.get("FU_VAR4"); + auto fu_var5 = st.get("FU_VAR5"); + BOOST_CHECK_EQUAL(fu_var1, 115); + BOOST_CHECK_EQUAL(fu_var2, 10); + BOOST_CHECK_EQUAL(fu_var3, 3000); + BOOST_CHECK_EQUAL(fu_var4, 0.5); + BOOST_CHECK_CLOSE(fu_var5, -0.00000041232 * 4 + 0.0010395 * 3 + 0.16504, 1e-5); +} + From 716b4d3bf18323d1cd67272c5555f823726a7c97 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Sun, 25 Oct 2020 20:55:18 +0100 Subject: [PATCH 3/3] Remove special casing of leading '-' in UDQ parsing --- .../eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp index a5c56b3a1..1b9f17e21 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp @@ -189,16 +189,7 @@ UDQDefine::UDQDefine(const UDQParams& udq_params, } } } - /* - This is hysterical special casing; the parser does not correctly handle a - leading '-' to change sign; we just hack it up by adding a fictious '0' - token in front. - */ - if (string_tokens[0] == "-") - string_tokens.insert( string_tokens.begin(), "0" ); std::vector tokens = make_tokens(string_tokens); - - this->ast = std::make_shared( UDQParser::parse(udq_params, this->m_var_type, this->m_keyword, this->m_location, tokens, parseContext, errors) ); this->string_data = ""; for (std::size_t index = 0; index < deck_data.size(); index++) {