Merge pull request #3736 from blattms/backport-of-pr-3712
Better error handling for problems in conditions of ACTIONX
This commit is contained in:
commit
08ac19f242
@ -314,6 +314,14 @@ class KeywordLocation;
|
||||
*/
|
||||
const static std::string ACTIONX_ILLEGAL_KEYWORD;
|
||||
|
||||
/*
|
||||
Error flag marking parser errors ic ACTIONX conditions
|
||||
*/
|
||||
const static std::string ACTIONX_CONDITION_ERROR;
|
||||
/*
|
||||
Error flag marking that an ACTIONX has no condition
|
||||
*/
|
||||
const static std::string ACTIONX_NO_CONDITION;
|
||||
|
||||
/*
|
||||
The RPTSCH, RPTSOL and RPTSCHED keywords have two alternative forms,
|
||||
|
@ -75,7 +75,10 @@ class ActionX {
|
||||
public:
|
||||
ActionX();
|
||||
ActionX(const std::string& name, size_t max_run, double max_wait, std::time_t start_time);
|
||||
ActionX(const DeckKeyword& kw, const Actdims& actimds, std::time_t start_time);
|
||||
ActionX(const std::string& name, size_t max_run, double max_wait,
|
||||
std::time_t start_time,
|
||||
const std::vector<Condition>&& conditions,
|
||||
const std::vector<std::string>&& tokens);
|
||||
ActionX(const DeckRecord& record, std::time_t start_time);
|
||||
explicit ActionX(const RestartIO::RstAction& rst_action);
|
||||
|
||||
@ -131,6 +134,15 @@ private:
|
||||
std::vector<Condition> m_conditions;
|
||||
};
|
||||
|
||||
/// \brief Parse ActionX keyword.
|
||||
/// \param kw The keyword representation of ActionX
|
||||
/// \param actdims Dimensions for ActionX as specified in the deck.
|
||||
/// \param start_time The first time that the ActionX should be evaluated
|
||||
/// \return A tuple of the ActionX created and a vector that contains for each error experienced
|
||||
/// during parsing the string indicating the type of error and the error string itself.
|
||||
std::tuple<ActionX, std::vector<std::pair<std::string, std::string>>>
|
||||
parseActionX(const DeckKeyword& kw, const Actdims& actimds, std::time_t start_time);
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* WELL_HPP_ */
|
||||
|
@ -114,6 +114,8 @@ namespace Opm {
|
||||
this->addKey(SUMMARY_REGION_TOO_LARGE, InputErrorAction::WARN);
|
||||
|
||||
addKey(ACTIONX_ILLEGAL_KEYWORD, InputErrorAction::THROW_EXCEPTION);
|
||||
addKey(ACTIONX_CONDITION_ERROR, InputErrorAction::THROW_EXCEPTION);
|
||||
addKey(ACTIONX_NO_CONDITION, InputErrorAction::WARN);
|
||||
|
||||
addKey(RPT_MIXED_STYLE, InputErrorAction::WARN);
|
||||
addKey(RPT_UNKNOWN_MNEMONIC, InputErrorAction::WARN);
|
||||
@ -369,6 +371,8 @@ namespace Opm {
|
||||
|
||||
const std::string ParseContext::SCHEDULE_INVALID_NAME = "SCHEDULE_INVALID_NAME";
|
||||
const std::string ParseContext::ACTIONX_ILLEGAL_KEYWORD = "ACTIONX_ILLEGAL_KEYWORD";
|
||||
const std::string ParseContext::ACTIONX_CONDITION_ERROR = "ACTIONX_CONDITION_ERROR";
|
||||
const std::string ParseContext::ACTIONX_NO_CONDITION = "ACTIONX_NO_CONDITION";
|
||||
|
||||
const std::string ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED = "SIMULATOR_KEYWORD_NOT_SUPPORTED";
|
||||
const std::string ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED_CRITICAL = "SIMULATOR_KEYWORD_NOT_SUPPORTED_CRITICAL";
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
|
||||
|
||||
#include "ActionParser.hpp"
|
||||
@ -128,7 +130,9 @@ ParseNode Parser::current() const {
|
||||
Action::ASTNode Parser::parse_left() {
|
||||
auto current = this->current();
|
||||
if (current.type != TokenType::ecl_expr)
|
||||
return TokenType::error;
|
||||
throw std::invalid_argument(fmt::format("Expected expression as left hand side "
|
||||
"of comparison, but got {} instead.",
|
||||
current.value));
|
||||
|
||||
std::string func = current.value;
|
||||
FuncType func_type = get_func(current.value);
|
||||
@ -270,15 +274,17 @@ Action::ASTNode Parser::parse(const std::vector<std::string>& tokens) {
|
||||
return ASTNode( start_node.type );
|
||||
|
||||
auto tree = parser.parse_or();
|
||||
|
||||
if (tree.type == TokenType::error)
|
||||
throw std::invalid_argument("Failed to parse ACTIONX condition.");
|
||||
|
||||
auto current = parser.current();
|
||||
if (current.type != TokenType::end) {
|
||||
size_t index = parser.current_pos;
|
||||
throw std::invalid_argument("Extra unhandled data starting with token[" + std::to_string(index) + "] = " + current.value);
|
||||
throw std::invalid_argument("Extra unhandled data starting with token[" + std::to_string(index) + "] = " + current.value+
|
||||
" in ACTIONX condition.");
|
||||
}
|
||||
|
||||
if (tree.type == TokenType::error)
|
||||
throw std::invalid_argument("Failed to parse");
|
||||
|
||||
return tree;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <opm/input/eclipse/Schedule/Action/Actdims.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/W.hpp>
|
||||
#include <opm/io/eclipse/rst/action.hpp>
|
||||
#include <opm/common/utility/OpmInputError.hpp>
|
||||
@ -73,6 +74,50 @@ bool ActionX::valid_keyword(const std::string& keyword) {
|
||||
return (actionx_allowed_list.find(keyword) != actionx_allowed_list.end());
|
||||
}
|
||||
|
||||
std::tuple<ActionX, std::vector<std::pair<std::string, std::string>>>
|
||||
parseActionX(const DeckKeyword& kw, const Actdims& actdims,
|
||||
std::time_t start_time)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> condition_errors;
|
||||
std::vector<std::string> tokens;
|
||||
std::vector<Condition> conditions;
|
||||
auto record = kw.getRecord(0);
|
||||
const std::string name = record.getItem("NAME").getTrimmedString(0);
|
||||
|
||||
for (size_t record_index = 1; record_index < kw.size(); record_index++) {
|
||||
const auto& cond_tokens = RawString::strings( kw.getRecord(record_index)
|
||||
.getItem("CONDITION").getData<RawString>() );
|
||||
|
||||
for (const auto& token : cond_tokens)
|
||||
tokens.push_back(dequote(token, kw.location()));
|
||||
|
||||
conditions.emplace_back(cond_tokens, kw.location());
|
||||
}
|
||||
if (conditions.empty())
|
||||
condition_errors.push_back({ParseContext::ACTIONX_NO_CONDITION,
|
||||
fmt::format("Action {} is missing a condition.", name)});
|
||||
|
||||
if (conditions.size() > actdims.max_conditions())
|
||||
condition_errors.push_back({ ParseContext::ACTIONX_CONDITION_ERROR,
|
||||
fmt::format("Action {} has too many conditions - adjust item "
|
||||
"4 of ACTDIMS to at least {}",
|
||||
name, conditions.size())});
|
||||
|
||||
try
|
||||
{
|
||||
return { ActionX(name,
|
||||
record.getItem("NUM").get<int>(0),
|
||||
record.getItem("MIN_WAIT").getSIDouble(0),
|
||||
start_time, std::move(conditions), std::move(tokens)),
|
||||
condition_errors};
|
||||
}
|
||||
catch(const std::invalid_argument& e)
|
||||
{
|
||||
condition_errors.push_back({ ParseContext::ACTIONX_CONDITION_ERROR,
|
||||
fmt::format("condition of action {} has the following error: {}", name, e.what())});
|
||||
return {ActionX(kw.getRecord(0), start_time), condition_errors};
|
||||
}
|
||||
}
|
||||
|
||||
ActionX::ActionX() :
|
||||
m_start_time(0)
|
||||
@ -119,24 +164,13 @@ ActionX::ActionX(const DeckRecord& record, std::time_t start_time) :
|
||||
|
||||
|
||||
|
||||
ActionX::ActionX(const DeckKeyword& kw, const Actdims& actdims, 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);
|
||||
const auto& cond_tokens = RawString::strings( record.getItem("CONDITION").getData<RawString>() );
|
||||
|
||||
for (const auto& token : cond_tokens)
|
||||
tokens.push_back(dequote(token, kw.location()));
|
||||
|
||||
this->m_conditions.emplace_back(cond_tokens, kw.location());
|
||||
}
|
||||
if (this->m_conditions.size() > actdims.max_conditions())
|
||||
throw OpmInputError(fmt::format("Action {} has too many conditions - adjust item 4 of ACTDIMS to at least {}", this->name(), this->m_conditions.size()), kw.location());
|
||||
|
||||
this->condition = Action::AST(tokens);
|
||||
}
|
||||
ActionX::ActionX(const std::string& name, size_t max_run, double min_wait,
|
||||
std::time_t start_time,
|
||||
const std::vector<Condition>&& conditions,
|
||||
const std::vector<std::string>&& tokens)
|
||||
: m_name(name), m_max_run(max_run), m_min_wait(min_wait),
|
||||
m_start_time(start_time), condition(tokens), m_conditions(conditions)
|
||||
{}
|
||||
|
||||
|
||||
ActionX ActionX::serializationTestObject()
|
||||
|
@ -665,9 +665,15 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
|
||||
logger.location(location);
|
||||
|
||||
if (keyword.is<ParserKeywords::ACTIONX>()) {
|
||||
Action::ActionX action(keyword,
|
||||
this->m_static.m_runspec.actdims(),
|
||||
std::chrono::system_clock::to_time_t(this->snapshots[report_step].start_time()));
|
||||
auto [action, condition_errors] =
|
||||
Action::parseActionX(keyword,
|
||||
this->m_static.m_runspec.actdims(),
|
||||
std::chrono::system_clock::to_time_t(this->snapshots[report_step].start_time()));
|
||||
|
||||
for(const auto& [ marker, msg]: condition_errors) {
|
||||
parseContext.handleError(marker, msg, keyword.location(), errors);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
keyword_index++;
|
||||
if (keyword_index == block.size())
|
||||
|
@ -87,8 +87,27 @@ ACTIONX
|
||||
const auto deck = Parser{}.parseString( action_kw );
|
||||
const auto& kw = deck["ACTIONX"].back();
|
||||
|
||||
Action::ActionX action2(kw, {}, 0);
|
||||
|
||||
const auto& [action2, condition_errors2 ] =
|
||||
Action::parseActionX(kw, {}, 0);
|
||||
BOOST_CHECK_EQUAL(action2.name(), "ACTION");
|
||||
BOOST_CHECK_EQUAL(condition_errors2.size(), 0U);
|
||||
|
||||
// left hand side has to be an expression.
|
||||
// Check whether we add an error to condition_errors
|
||||
// if that is not the case
|
||||
const auto action_kw_num_first = std::string{ R"(
|
||||
ACTIONX
|
||||
'ACTION' /
|
||||
0.75 < WWCT OPX /
|
||||
/
|
||||
)"};
|
||||
|
||||
|
||||
const auto deck1 = Parser{}.parseString( action_kw_num_first);
|
||||
const auto& [action3, condition_errors3] =
|
||||
Action::parseActionX(deck1["ACTIONX"].back(), {}, 0);
|
||||
BOOST_CHECK_EQUAL(condition_errors3.size(), 1U);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user