commit
01abada947
@ -74,6 +74,7 @@ if(ENABLE_ECL_INPUT)
|
||||
src/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp
|
||||
src/opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Runspec.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/ActionAST.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/ActionContext.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/Actions.cpp
|
||||
src/opm/parser/eclipse/EclipseState/Schedule/ActionX.cpp
|
||||
@ -440,6 +441,7 @@ if(ENABLE_ECL_INPUT)
|
||||
opm/parser/eclipse/EclipseState/Aquancon.hpp
|
||||
opm/parser/eclipse/EclipseState/AquiferCT.hpp
|
||||
opm/parser/eclipse/EclipseState/Aquifetp.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/ActionAST.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/ActionContext.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/Actions.hpp
|
||||
opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp
|
||||
|
141
opm/parser/eclipse/EclipseState/Schedule/ActionAST.hpp
Normal file
141
opm/parser/eclipse/EclipseState/Schedule/ActionAST.hpp
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
Copyright 2018 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ActionAST_HPP
|
||||
#define ActionAST_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class ActionContext;
|
||||
|
||||
enum TokenType {
|
||||
number, // 0
|
||||
ecl_expr, // 1
|
||||
open_paren, // 2
|
||||
close_paren, // 3
|
||||
op_gt, // 4
|
||||
op_ge, // 5
|
||||
op_lt, // 6
|
||||
op_le, // 7
|
||||
op_eq, // 8
|
||||
op_ne, // 9
|
||||
op_and, // 10
|
||||
op_or, // 11
|
||||
end, // 12
|
||||
error // 13
|
||||
};
|
||||
|
||||
struct ParseNode {
|
||||
ParseNode(TokenType type, const std::string& value) :
|
||||
type(type),
|
||||
value(value)
|
||||
{}
|
||||
|
||||
|
||||
ParseNode(TokenType type) : ParseNode(type, "")
|
||||
{}
|
||||
|
||||
|
||||
TokenType type;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
|
||||
class ASTNode {
|
||||
public:
|
||||
|
||||
ASTNode() :
|
||||
type(TokenType::error)
|
||||
{}
|
||||
|
||||
|
||||
ASTNode(TokenType type):
|
||||
type(type)
|
||||
{}
|
||||
|
||||
|
||||
ASTNode(double value) :
|
||||
type(TokenType::number),
|
||||
number(value)
|
||||
{}
|
||||
|
||||
|
||||
ASTNode(TokenType type, const std::string& func, const std::vector<std::string>& arg_list):
|
||||
type(type),
|
||||
func(func),
|
||||
arg_list(arg_list)
|
||||
{}
|
||||
|
||||
bool eval(const ActionContext& context) const;
|
||||
double value(const ActionContext& context) const;
|
||||
TokenType type;
|
||||
void add_child(const ASTNode& child);
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::string func;
|
||||
std::vector<std::string> arg_list;
|
||||
double number;
|
||||
|
||||
/*
|
||||
To have a memmber std::vector<ASTNode> inside the ASTNode class is
|
||||
supposedly borderline undefined behaviour; it compiles without warnings
|
||||
and works. Good for enough for me.
|
||||
*/
|
||||
std::vector<ASTNode> children;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ActionParser {
|
||||
public:
|
||||
ActionParser(const std::vector<std::string>& tokens);
|
||||
TokenType get_type(const std::string& arg) const;
|
||||
ParseNode current() const;
|
||||
ParseNode next();
|
||||
size_t pos() const;
|
||||
void print() const;
|
||||
private:
|
||||
const std::vector<std::string>& tokens;
|
||||
ssize_t current_pos = -1;
|
||||
};
|
||||
|
||||
|
||||
class ActionAST{
|
||||
public:
|
||||
ActionAST() = default;
|
||||
explicit ActionAST(const std::vector<std::string>& tokens);
|
||||
ASTNode parse_right(ActionParser& parser);
|
||||
ASTNode parse_left(ActionParser& parser);
|
||||
ASTNode parse_op(ActionParser& parser);
|
||||
ASTNode parse_cmp(ActionParser& parser);
|
||||
ASTNode parse_or(ActionParser& parser);
|
||||
ASTNode parse_and(ActionParser& parser);
|
||||
|
||||
bool eval(const ActionContext& context) const;
|
||||
private:
|
||||
ASTNode tree;
|
||||
};
|
||||
}
|
||||
#endif
|
@ -33,9 +33,14 @@ namespace Opm {
|
||||
|
||||
class ActionContext {
|
||||
public:
|
||||
ActionContext();
|
||||
|
||||
double get(const std::string& func, const std::string& arg) const;
|
||||
void add(const std::string& func, const std::string& arg, double value);
|
||||
|
||||
double get(const std::string& func) const;
|
||||
void add(const std::string& func, double value);
|
||||
|
||||
private:
|
||||
std::map<std::string, double> values;
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <ctime>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionAST.hpp>
|
||||
|
||||
namespace Opm {
|
||||
/*
|
||||
@ -78,6 +79,7 @@ private:
|
||||
std::time_t m_start_time;
|
||||
|
||||
std::vector<DeckKeyword> keywords;
|
||||
ActionAST ast;
|
||||
size_t run_count = 0;
|
||||
std::time_t last_run = 0;
|
||||
};
|
||||
|
337
src/opm/parser/eclipse/EclipseState/Schedule/ActionAST.cpp
Normal file
337
src/opm/parser/eclipse/EclipseState/Schedule/ActionAST.cpp
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
Copyright 2018 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionAST.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionContext.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
ActionParser::ActionParser(const std::vector<std::string>& tokens) :
|
||||
tokens(tokens)
|
||||
{}
|
||||
|
||||
|
||||
TokenType ActionParser::get_type(const std::string& arg) const {
|
||||
std::string lower_arg = arg;
|
||||
std::for_each(lower_arg.begin(),
|
||||
lower_arg.end(),
|
||||
[](char& c) {
|
||||
c = std::tolower(static_cast<unsigned char>(c));
|
||||
});
|
||||
|
||||
if (lower_arg == "and")
|
||||
return TokenType::op_and;
|
||||
|
||||
if (lower_arg == "or")
|
||||
return TokenType::op_or;
|
||||
|
||||
if (lower_arg == "(")
|
||||
return TokenType::open_paren;
|
||||
|
||||
if (lower_arg == ")")
|
||||
return TokenType::close_paren;
|
||||
|
||||
if (lower_arg == ">" || lower_arg == ".gt.")
|
||||
return TokenType::op_gt;
|
||||
|
||||
if (lower_arg == ">=" || lower_arg == ".ge.")
|
||||
return TokenType::op_ge;
|
||||
|
||||
if (lower_arg == "<=" || lower_arg == ".le.")
|
||||
return TokenType::op_le;
|
||||
|
||||
if (lower_arg == "<" || lower_arg == ".lt.")
|
||||
return TokenType::op_lt;
|
||||
|
||||
if (lower_arg == "<=" || lower_arg == ".le.")
|
||||
return TokenType::op_le;
|
||||
|
||||
if (lower_arg == "=" || lower_arg == ".eq.")
|
||||
return TokenType::op_eq;
|
||||
|
||||
if (lower_arg == "!=" || lower_arg == ".ne.")
|
||||
return TokenType::op_ne;
|
||||
|
||||
{
|
||||
char * end_ptr;
|
||||
strtod(lower_arg.c_str(), &end_ptr);
|
||||
if (std::strlen(end_ptr) == 0)
|
||||
return TokenType::number;
|
||||
}
|
||||
|
||||
return TokenType::ecl_expr;
|
||||
}
|
||||
|
||||
ParseNode ActionParser::next() {
|
||||
this->current_pos++;
|
||||
if (static_cast<size_t>(this->current_pos) == this->tokens.size())
|
||||
return TokenType::end;
|
||||
|
||||
std::string arg = this->tokens[this->current_pos];
|
||||
return ParseNode(get_type(arg), arg);
|
||||
}
|
||||
|
||||
|
||||
ParseNode ActionParser::current() const {
|
||||
if (static_cast<size_t>(this->current_pos) == this->tokens.size())
|
||||
return TokenType::end;
|
||||
|
||||
std::string arg = this->tokens[this->current_pos];
|
||||
return ParseNode(get_type(arg), arg);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionParser::pos() const {
|
||||
return this->current_pos;
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
void ASTNode::add_child(const ASTNode& child) {
|
||||
this->children.push_back(child);
|
||||
}
|
||||
|
||||
double ASTNode::value(const ActionContext& context) const {
|
||||
if (this->children.size() != 0)
|
||||
throw std::invalid_argument("value() method should only reach leafnodes");
|
||||
|
||||
if (this->type == TokenType::number)
|
||||
return this->number;
|
||||
|
||||
if (this->arg_list.size() == 0)
|
||||
return context.get(this->func);
|
||||
else {
|
||||
std::string arg_key = this->arg_list[0];
|
||||
for (size_t index = 1; index < this->arg_list.size(); index++)
|
||||
arg_key += ":" + this->arg_list[index];
|
||||
return context.get(this->func, arg_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ASTNode::eval(const ActionContext& context) const {
|
||||
if (this->children.size() == 0)
|
||||
throw std::invalid_argument("bool eval should not reach leafnodes");
|
||||
|
||||
if (this->type == TokenType::op_or || this->type == TokenType::op_and) {
|
||||
bool value = (this->type == TokenType::op_and);
|
||||
for (const auto& child : this->children) {
|
||||
if (this->type == TokenType::op_or)
|
||||
value = value || child.eval(context);
|
||||
else
|
||||
value = value && child.eval(context);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
double v1 = this->children[0].value(context);
|
||||
double v2 = this->children[1].value(context);
|
||||
|
||||
switch (this->type) {
|
||||
|
||||
case TokenType::op_eq:
|
||||
return v1 == v2;
|
||||
|
||||
case TokenType::op_ge:
|
||||
return v1 >= v2;
|
||||
|
||||
case TokenType::op_le:
|
||||
return v1 <= v2;
|
||||
|
||||
case TokenType::op_ne:
|
||||
return v1 != v2;
|
||||
|
||||
case TokenType::op_gt:
|
||||
return v1 > v2;
|
||||
|
||||
case TokenType::op_lt:
|
||||
return v1 < v2;
|
||||
|
||||
default:
|
||||
throw std::invalid_argument("Incorrect operator type - expected comparison");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t ASTNode::size() const {
|
||||
return this->children.size();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
ASTNode ActionAST::parse_left(ActionParser& parser) {
|
||||
auto current = parser.current();
|
||||
if (current.type != TokenType::ecl_expr)
|
||||
return TokenType::error;
|
||||
|
||||
std::string func = current.value;
|
||||
std::vector<std::string> arg_list;
|
||||
current = parser.next();
|
||||
while (current.type == TokenType::ecl_expr || current.type == TokenType::number) {
|
||||
arg_list.push_back(current.value);
|
||||
current = parser.next();
|
||||
}
|
||||
|
||||
return ASTNode(TokenType::ecl_expr, func, arg_list);
|
||||
}
|
||||
|
||||
ASTNode ActionAST::parse_op(ActionParser& parser) {
|
||||
auto current = parser.current();
|
||||
if (current.type == TokenType::op_gt ||
|
||||
current.type == TokenType::op_ge ||
|
||||
current.type == TokenType::op_lt ||
|
||||
current.type == TokenType::op_le ||
|
||||
current.type == TokenType::op_eq ||
|
||||
current.type == TokenType::op_ne) {
|
||||
parser.next();
|
||||
return current.type;
|
||||
}
|
||||
return TokenType::error;
|
||||
}
|
||||
|
||||
|
||||
ASTNode ActionAST::parse_right(ActionParser& parser) {
|
||||
auto current = parser.current();
|
||||
if (current.type == TokenType::number) {
|
||||
parser.next();
|
||||
return ASTNode( strtod(current.value.c_str(), nullptr) );
|
||||
}
|
||||
|
||||
current = parser.current();
|
||||
if (current.type != TokenType::ecl_expr)
|
||||
return TokenType::error;
|
||||
|
||||
std::string func = current.value;
|
||||
std::vector<std::string> arg_list;
|
||||
current = parser.next();
|
||||
while (current.type == TokenType::ecl_expr || current.type == TokenType::number) {
|
||||
arg_list.push_back(current.value);
|
||||
current = parser.next();
|
||||
}
|
||||
return ASTNode(TokenType::ecl_expr, func, arg_list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ASTNode ActionAST::parse_cmp(ActionParser& parser) {
|
||||
auto current = parser.current();
|
||||
|
||||
if (current.type == TokenType::open_paren) {
|
||||
parser.next();
|
||||
auto inner_expr = this->parse_or(parser);
|
||||
|
||||
current = parser.current();
|
||||
if (current.type != TokenType::close_paren)
|
||||
return TokenType::error;
|
||||
|
||||
parser.next();
|
||||
return inner_expr;
|
||||
} else {
|
||||
auto left_node = parse_left(parser);
|
||||
if (left_node.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
auto op_node = parse_op(parser);
|
||||
if (op_node.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
auto right_node = parse_right(parser);
|
||||
if (right_node.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
op_node.add_child(left_node);
|
||||
op_node.add_child(right_node);
|
||||
return op_node;
|
||||
}
|
||||
}
|
||||
|
||||
ASTNode ActionAST::parse_and(ActionParser& parser) {
|
||||
auto left = this->parse_cmp(parser);
|
||||
if (left.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
auto current = parser.current();
|
||||
if (current.type == TokenType::op_and) {
|
||||
ASTNode and_node(TokenType::op_and);
|
||||
and_node.add_child(left);
|
||||
|
||||
while (parser.current().type == TokenType::op_and) {
|
||||
parser.next();
|
||||
auto next_cmp = this->parse_cmp(parser);
|
||||
if (next_cmp.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
and_node.add_child(next_cmp);
|
||||
}
|
||||
return and_node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
ASTNode ActionAST::parse_or(ActionParser& parser) {
|
||||
auto left = this->parse_and(parser);
|
||||
if (left.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
auto current = parser.current();
|
||||
if (current.type == TokenType::op_or) {
|
||||
ASTNode or_node(TokenType::op_or);
|
||||
or_node.add_child(left);
|
||||
|
||||
while (parser.current().type == TokenType::op_or) {
|
||||
parser.next();
|
||||
auto next_cmp = this->parse_or(parser);
|
||||
if (next_cmp.type == TokenType::error)
|
||||
return TokenType::error;
|
||||
|
||||
or_node.add_child(next_cmp);
|
||||
}
|
||||
return or_node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
ActionAST::ActionAST(const std::vector<std::string>& tokens) {
|
||||
ActionParser parser(tokens);
|
||||
auto current = parser.next();
|
||||
this->tree = this->parse_or(parser);
|
||||
current = parser.current();
|
||||
if (current.type != TokenType::end) {
|
||||
size_t index = parser.pos();
|
||||
throw std::invalid_argument("Extra unhandled data starting with token[" + std::to_string(index) + "] = " + current.value);
|
||||
}
|
||||
|
||||
if (this->tree.type == TokenType::error)
|
||||
throw std::invalid_argument("Failed to parse");
|
||||
}
|
||||
|
||||
bool ActionAST::eval(const ActionContext& context) const {
|
||||
return this->tree.eval(context);
|
||||
}
|
||||
|
||||
}
|
@ -18,15 +18,28 @@
|
||||
*/
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionContext.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
ActionContext::ActionContext() {
|
||||
for (const auto& pair : TimeMap::eclipseMonthIndices())
|
||||
this->add(pair.first, pair.second);
|
||||
}
|
||||
|
||||
void ActionContext::add(const std::string& func, const std::string& arg, double value) {
|
||||
this->values[func + ":" + arg] = value;
|
||||
}
|
||||
|
||||
void ActionContext::add(const std::string& func, double value) {
|
||||
this->values[func] = value;
|
||||
}
|
||||
|
||||
double ActionContext::get(const std::string& func, const std::string& arg) const {
|
||||
return this->values.at( func + ":" + arg );
|
||||
}
|
||||
|
||||
double ActionContext::get(const std::string& func) const {
|
||||
return this->values.at( func );
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,15 @@ ActionX::ActionX(const DeckRecord& record, std::time_t start_time) :
|
||||
|
||||
ActionX::ActionX(const DeckKeyword& kw, std::time_t start_time) :
|
||||
ActionX(kw.getRecord(0), start_time)
|
||||
{}
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
for (size_t record_index = 1; record_index < kw.size(); record_index++) {
|
||||
const auto& record = kw.getRecord(record_index);
|
||||
for (const auto& token : record.getItem("CONDITION").getData<std::string>())
|
||||
tokens.push_back(token);
|
||||
}
|
||||
this->ast = ActionAST(tokens);
|
||||
}
|
||||
|
||||
|
||||
void ActionX::addKeyword(const DeckKeyword& kw) {
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionAST.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionContext.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Actions.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp>
|
||||
@ -198,3 +199,251 @@ BOOST_AUTO_TEST_CASE(TestContext) {
|
||||
context.add("FUNC", "ARG", 100);
|
||||
BOOST_CHECK_EQUAL(context.get("FUNC", "ARG"), 100);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Opm::Schedule make_action(const std::string& action_string) {
|
||||
std::string start = std::string{ R"(
|
||||
SCHEDULE
|
||||
)"};
|
||||
std::string end = std::string{ R"(
|
||||
ENDACTIO
|
||||
|
||||
TSTEP
|
||||
10 /
|
||||
)"};
|
||||
|
||||
std::string deck_string = start + action_string + end;
|
||||
Opm::Parser parser;
|
||||
auto deck = parser.parseString(deck_string, Opm::ParseContext());
|
||||
EclipseGrid grid1(10,10,10);
|
||||
TableManager table ( deck );
|
||||
Eclipse3DProperties eclipseProperties ( deck , table, grid1);
|
||||
Runspec runspec(deck);
|
||||
|
||||
return Schedule(deck, grid1, eclipseProperties, runspec, ParseContext());
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TestActionAST_BASIC) {
|
||||
// Missing comparator
|
||||
BOOST_REQUIRE_THROW( ActionAST( {"WWCT", "OPX", "0.75"} ), std::invalid_argument);
|
||||
|
||||
// Left hand side must be function expression
|
||||
BOOST_REQUIRE_THROW( ActionAST({"0.75", "<", "1.0"}), std::invalid_argument);
|
||||
|
||||
//Extra data
|
||||
BOOST_REQUIRE_THROW(ActionAST({"0.75", "<", "1.0", "EXTRA"}), std::invalid_argument);
|
||||
|
||||
ActionAST ast1({"WWCT", "OPX", ">", "0.75"});
|
||||
ActionAST ast2({"WWCT", "OPX", "=", "WWCT", "OPX"});
|
||||
ActionAST ast3({"WWCT", "OPY", ">", "0.75"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("WWCT", "OPX", 100);
|
||||
BOOST_CHECK(ast1.eval(context));
|
||||
|
||||
context.add("WWCT", "OPX", -100);
|
||||
BOOST_CHECK(!ast1.eval(context));
|
||||
|
||||
BOOST_CHECK(ast2.eval(context));
|
||||
BOOST_REQUIRE_THROW(ast3.eval(context), std::out_of_range);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TestActionAST_OR_AND) {
|
||||
ActionAST ast_or({"WWCT", "OPX", ">", "0.75", "OR", "WWCT", "OPY", ">", "0.75"});
|
||||
ActionAST ast_and({"WWCT", "OPX", ">", "0.75", "AND", "WWCT", "OPY", ">", "0.75"});
|
||||
ActionAST par({"WWCT", "OPX", ">", "0.75", "AND", "(", "WWCT", "OPY", ">", "0.75", "OR", "WWCT", "OPZ", ">", "0.75", ")"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("WWCT", "OPX", 100);
|
||||
context.add("WWCT", "OPY", -100);
|
||||
context.add("WWCT", "OPZ", 100);
|
||||
BOOST_CHECK( ast_or.eval(context) );
|
||||
BOOST_CHECK( !ast_and.eval(context) );
|
||||
BOOST_CHECK( par.eval(context));
|
||||
|
||||
|
||||
context.add("WWCT", "OPX", -100);
|
||||
context.add("WWCT", "OPY", 100);
|
||||
context.add("WWCT", "OPZ", 100);
|
||||
BOOST_CHECK( ast_or.eval(context) );
|
||||
BOOST_CHECK( !ast_and.eval(context) );
|
||||
BOOST_CHECK( !par.eval(context));
|
||||
|
||||
|
||||
context.add("WWCT", "OPX", 100);
|
||||
context.add("WWCT", "OPY", 100);
|
||||
context.add("WWCT", "OPZ", -100);
|
||||
BOOST_CHECK( ast_or.eval(context) );
|
||||
BOOST_CHECK( ast_and.eval(context) );
|
||||
BOOST_CHECK( par.eval(context));
|
||||
|
||||
context.add("WWCT", "OPX", -100);
|
||||
context.add("WWCT", "OPY", -100);
|
||||
context.add("WWCT", "OPZ", -100);
|
||||
BOOST_CHECK( !ast_or.eval(context) );
|
||||
BOOST_CHECK( !ast_and.eval(context) );
|
||||
BOOST_CHECK( !par.eval(context));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DATE) {
|
||||
ActionAST ast({"MNTH", ">=", "JUN"});
|
||||
ActionContext context;
|
||||
context.add("MNTH", 6);
|
||||
BOOST_CHECK( ast.eval(context) );
|
||||
|
||||
context.add("MNTH", 8);
|
||||
BOOST_CHECK( ast.eval(context) );
|
||||
|
||||
context.add("MNTH", 5);
|
||||
BOOST_CHECK( !ast.eval(context) );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MANUAL1) {
|
||||
ActionAST ast({"GGPR", "FIELD", ">", "50000", "AND", "WGOR", "PR", ">" ,"GGOR", "FIELD"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("GGPR", "FIELD", 60000 );
|
||||
context.add("WGOR", "PR" , 300 );
|
||||
context.add("GGOR", "FIELD", 200);
|
||||
BOOST_CHECK( ast.eval(context) );
|
||||
|
||||
context.add("GGPR", "FIELD", 0 );
|
||||
context.add("WGOR", "PR" , 300 );
|
||||
context.add("GGOR", "FIELD", 200);
|
||||
BOOST_CHECK( !ast.eval(context) );
|
||||
|
||||
context.add("GGPR", "FIELD", 60000 );
|
||||
context.add("WGOR", "PR" , 100 );
|
||||
context.add("GGOR", "FIELD", 200);
|
||||
BOOST_CHECK( !ast.eval(context) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MANUAL2) {
|
||||
ActionAST ast({"GWCT", "LIST1", ">", "0.70", "AND", "(", "GWPR", "LIST1", ">", "GWPR", "LIST2", "OR", "GWPR", "LIST1", ">", "GWPR", "LIST3", ")"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("GWCT", "LIST1", 1.0);
|
||||
context.add("GWPR", "LIST1", 1 );
|
||||
context.add("GWPR", "LIST2", 2 );
|
||||
context.add("GWPR", "LIST3", 3 );
|
||||
BOOST_CHECK( !ast.eval(context));
|
||||
|
||||
context.add("GWCT", "LIST1", 1.0);
|
||||
context.add("GWPR", "LIST1", 1 );
|
||||
context.add("GWPR", "LIST2", 2 );
|
||||
context.add("GWPR", "LIST3", 0 );
|
||||
BOOST_CHECK( ast.eval(context));
|
||||
|
||||
context.add("GWCT", "LIST1", 1.0);
|
||||
context.add("GWPR", "LIST1", 1 );
|
||||
context.add("GWPR", "LIST2", 0 );
|
||||
context.add("GWPR", "LIST3", 3 );
|
||||
BOOST_CHECK( ast.eval(context));
|
||||
|
||||
context.add("GWCT", "LIST1", 1.0);
|
||||
context.add("GWPR", "LIST1", 1 );
|
||||
context.add("GWPR", "LIST2", 0 );
|
||||
context.add("GWPR", "LIST3", 0 );
|
||||
BOOST_CHECK( ast.eval(context));
|
||||
|
||||
context.add("GWCT", "LIST1", 0.0);
|
||||
context.add("GWPR", "LIST1", 1 );
|
||||
context.add("GWPR", "LIST2", 0 );
|
||||
context.add("GWPR", "LIST3", 3 );
|
||||
BOOST_CHECK( !ast.eval(context));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MANUAL3) {
|
||||
ActionAST ast({"MNTH", ".GE.", "MAR", "AND", "MNTH", ".LE.", "OCT", "AND", "GMWL", "HIGH", ".GE.", "4"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("MNTH", 4);
|
||||
context.add("GMWL", "HIGH", 4);
|
||||
BOOST_CHECK( ast.eval(context));
|
||||
|
||||
context.add("MNTH", 3);
|
||||
context.add("GMWL", "HIGH", 4);
|
||||
BOOST_CHECK( ast.eval(context));
|
||||
|
||||
context.add("MNTH", 11);
|
||||
context.add("GMWL", "HIGH", 4);
|
||||
BOOST_CHECK( !ast.eval(context));
|
||||
|
||||
context.add("MNTH", 3);
|
||||
context.add("GMWL", "HIGH", 3);
|
||||
BOOST_CHECK( !ast.eval(context));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MANUAL4) {
|
||||
ActionAST ast({"GWCT", "FIELD", ">", "0.8", "AND", "DAY", ">", "1", "AND", "MNTH", ">", "JUN", "AND", "YEAR", ">=", "2021"});
|
||||
ActionContext context;
|
||||
|
||||
|
||||
context.add("MNTH", 7);
|
||||
context.add("DAY", 2);
|
||||
context.add("YEAR", 2030);
|
||||
context.add("GWCT", "FIELD", 1.0);
|
||||
BOOST_CHECK( ast.eval(context) );
|
||||
|
||||
context.add("MNTH", 7);
|
||||
context.add("DAY", 2);
|
||||
context.add("YEAR", 2019);
|
||||
context.add("GWCT", "FIELD", 1.0);
|
||||
BOOST_CHECK( !ast.eval(context) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MANUAL5) {
|
||||
ActionAST ast({"WCG2", "PROD1", ">", "WCG5", "PROD2", "AND", "GCG3", "G1", ">", "GCG7", "G2", "OR", "FCG1", ">", "FCG7"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("WCG2", "PROD1", 100);
|
||||
context.add("WCG5", "PROD2", 50);
|
||||
context.add("GCG3", "G1", 200);
|
||||
context.add("GCG7", "G2", 100);
|
||||
context.add("FCG1", 100);
|
||||
context.add("FCG7", 50);
|
||||
BOOST_CHECK(ast.eval(context));
|
||||
|
||||
context.add("WCG2", "PROD1", 100);
|
||||
context.add("WCG5", "PROD2", 50);
|
||||
context.add("GCG3", "G1", 200);
|
||||
context.add("GCG7", "G2", 100);
|
||||
context.add("FCG1", 100);
|
||||
context.add("FCG7", 150);
|
||||
BOOST_CHECK(ast.eval(context));
|
||||
|
||||
context.add("WCG2", "PROD1", 100);
|
||||
context.add("WCG5", "PROD2", 50);
|
||||
context.add("GCG3", "G1", 20);
|
||||
context.add("GCG7", "G2", 100);
|
||||
context.add("FCG1", 100);
|
||||
context.add("FCG7", 150);
|
||||
BOOST_CHECK(!ast.eval(context));
|
||||
|
||||
context.add("WCG2", "PROD1", 100);
|
||||
context.add("WCG5", "PROD2", 50);
|
||||
context.add("GCG3", "G1", 20);
|
||||
context.add("GCG7", "G2", 100);
|
||||
context.add("FCG1", 200);
|
||||
context.add("FCG7", 150);
|
||||
BOOST_CHECK(ast.eval(context));
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LGR) {
|
||||
ActionAST ast({"LWCC" , "OPX", "LOCAL", "1", "2", "3", ">", "100"});
|
||||
ActionContext context;
|
||||
|
||||
context.add("LWCC", "OPX:LOCAL:1:2:3", 200);
|
||||
BOOST_CHECK(ast.eval(context));
|
||||
|
||||
context.add("LWCC", "OPX:LOCAL:1:2:3", 20);
|
||||
BOOST_CHECK(!ast.eval(context));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user