Add KeywordLocation argument to ParseContext::handleError()

This commit is contained in:
Joakim Hove 2020-09-27 22:13:30 +02:00
parent 94b4c509b1
commit e01400fa18
20 changed files with 337 additions and 260 deletions

View File

@ -420,8 +420,6 @@ list (APPEND TEST_DATA_FILES
)
if(ENABLE_ECL_OUTPUT)
list (APPEND TEST_DATA_FILES
tests/expect-wdims.chldg.err.out
tests/expect-wdims.err.out
tests/BASE_SIM.DATA
tests/BASE_SIM_THPRES.DATA
tests/RESTART_SIM.DATA

View File

@ -21,9 +21,10 @@
#ifndef OPM_PARSE_CONTEXT_HPP
#define OPM_PARSE_CONTEXT_HPP
#include <string>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <opm/common/OpmLog/OpmLog.hpp>
@ -33,6 +34,9 @@
namespace Opm {
class KeywordLocation;
/*
The ParseContext class is meant to control the behavior of the
parsing and EclipseState construction phase when
@ -87,8 +91,8 @@ namespace Opm {
explicit ParseContext(InputError::Action default_action);
explicit ParseContext(const std::vector<std::pair<std::string , InputError::Action>>& initial);
void handleError( const std::string& errorKey, const std::string& msg, ErrorGuard& errors ) const;
void handleUnknownKeyword(const std::string& keyword, ErrorGuard& errors) const;
void handleError( const std::string& errorKey, const std::string& msg, const std::optional<KeywordLocation>& location, ErrorGuard& errors) const;
void handleUnknownKeyword(const std::string& keyword, const std::optional<KeywordLocation>& location, ErrorGuard& errors) const;
bool hasKey(const std::string& key) const;
ParseContext withKey(const std::string& key, InputError::Action action = InputError::WARN) const;
ParseContext& withKey(const std::string& key, InputError::Action action = InputError::WARN);

View File

@ -24,6 +24,7 @@
#include <iomanip>
#include <sstream>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/parser/eclipse/Utility/Functional.hpp>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
@ -332,17 +333,16 @@ inline std::map< std::string, int > RPT( const DeckKeyword& keyword,
if (ints && strs) {
const auto& location = keyword.location();
std::string msg = "Mixed style input is not allowed for keyword: " + keyword.name() + " at " + location.filename + "(" + std::to_string( location.lineno ) + ")";
parseContext.handleError(ParseContext::RPT_MIXED_STYLE, msg, errors);
std::string msg = "Error in keyword {keyword}, mixing mnemonics and integers is not allowed\n"
"In {file} line {line}.";
parseContext.handleError(ParseContext::RPT_MIXED_STYLE, msg, location, errors);
std::vector<std::string> stack;
for (size_t index=0; index < deck_items.size(); index++) {
if (is_int(deck_items[index])) {
if (stack.size() < 2) {
std::string errmsg = "Can not interpret " + keyword.name() + " at " + location.filename + "(" + std::to_string( location.lineno ) + ")";
throw std::invalid_argument(errmsg);
}
if (stack.size() < 2)
throw OpmInputError("Problem processing {keyword}\nIn {file} line {line}.", location);
if (stack.back() == "=") {
stack.pop_back();
@ -352,10 +352,8 @@ inline std::map< std::string, int > RPT( const DeckKeyword& keyword,
items.insert(items.begin(), stack.begin(), stack.end());
stack.clear();
items.push_back( mnemonic + "=" + deck_items[index]);
} else {
std::string errmsg = "Can not interpret " + keyword.name() + " at " + location.filename + "(" + std::to_string( location.lineno ) + ")";
throw std::invalid_argument(errmsg);
}
} else
throw OpmInputError("Problem processing {keyword}\nIn {file} line {line}.", location);
} else
stack.push_back(deck_items[index]);
@ -370,7 +368,8 @@ inline std::map< std::string, int > RPT( const DeckKeyword& keyword,
std::string base = mnemonic.substr( 0, sep_pos );
if( !is_mnemonic( base ) ) {
parseContext.handleError(ParseContext::RPT_UNKNOWN_MNEMONIC, "The mnemonic: " + base + " is not recognized.", errors);
std::string msg_fmt = fmt::format("Error in keyword {{keyword}}, unrecognized mnemonic {}\nIn {{file}} line {{line}}.", base);
parseContext.handleError(ParseContext::RPT_UNKNOWN_MNEMONIC, msg_fmt, keyword.location(), errors);
continue;
}

View File

@ -21,6 +21,9 @@
#include <iterator>
#include <sstream>
#include <fmt/format.h>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
@ -43,13 +46,20 @@ namespace {
if (nWells > std::size_t(wdims.maxWellsInField()))
{
std::ostringstream os;
os << "Run uses " << nWells << " wells, but allocates at "
<< "most " << wdims.maxWellsInField() << " in RUNSPEC "
<< "section. Increase item 1 of WELLDIMS accordingly.";
const auto& location = wdims.location();
if (location) {
std::string fmt_message = fmt::format("Problem with keyword {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The case has {0} wells - but only {1} are specified in WELLDIMS.\n"
"Please increase item 1 in WELLDIMS to at least {1}", nWells, wdims.maxWellsInField());
ctxt.handleError(Opm::ParseContext::RUNSPEC_NUMWELLS_TOO_LARGE,
os.str(), guard);
ctxt.handleError(Opm::ParseContext::RUNSPEC_NUMWELLS_TOO_LARGE,
fmt_message, *location, guard);
} else {
std::string msg = fmt::format("The case does not have a WELLDIMS keyword.\n"
"Please add a WELLDIMS keyword in the RUNSPEC section specifying at least {} wells in item 1.", nWells);
ctxt.handleError(Opm::ParseContext::RUNSPEC_NUMWELLS_TOO_LARGE, msg, {}, guard);
}
}
}
@ -66,14 +76,20 @@ namespace {
if (nconn > static_cast<decltype(nconn)>(wdims.maxConnPerWell()))
{
std::ostringstream os;
os << "Run has well with " << nconn << " reservoir connections, "
<< "but allocates at most " << wdims.maxConnPerWell()
<< " connections per well in RUNSPEC section. Increase item "
<< "2 of WELLDIMS accordingly.";
const auto& location = wdims.location();
if (location) {
std::string fmt_message = fmt::format("Problem with keyword {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The case has a well with {0} connections, but {1} is specified as maxmimum in WELLDIMS.\n"
"Please increase item 2 in WELLDIMS to at least {0}", nconn, wdims.maxConnPerWell());
ctxt.handleError(Opm::ParseContext::RUNSPEC_CONNS_PER_WELL_TOO_LARGE,
os.str(), guard);
ctxt.handleError(Opm::ParseContext::RUNSPEC_CONNS_PER_WELL_TOO_LARGE,
fmt_message, *location, guard);
} else {
std::string msg = fmt::format("The case does not have a WELLDIMS keyword.\n"
"Please add a WELLDIMS keyword in the RUNSPEC section specifying at least {} connections in item 2.", nconn);
ctxt.handleError(Opm::ParseContext::RUNSPEC_CONNS_PER_WELL_TOO_LARGE, msg, {}, guard);
}
}
}
@ -88,14 +104,21 @@ namespace {
// but excluded from WELLDIMS(3).
if (nGroups > 1U + wdims.maxGroupsInField())
{
std::ostringstream os;
os << "Run uses " << (nGroups - 1) << " non-FIELD groups, but "
<< "allocates at most " << wdims.maxGroupsInField()
<< " in RUNSPEC section. Increase item 3 of WELLDIMS "
<< "accordingly.";
const auto& location = wdims.location();
if (location) {
std::string fmt_message = fmt::format("Problem with keyword {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The case has {0} non-FIELD groups, the WELLDIMS keyword specifies {1}\n."
"Please increase item 3 in WELLDIMS to at least {0}", nGroups - 1, wdims.maxGroupsInField());
ctxt.handleError(Opm::ParseContext::RUNSPEC_NUMGROUPS_TOO_LARGE,
os.str(), guard);
ctxt.handleError(Opm::ParseContext::RUNSPEC_NUMGROUPS_TOO_LARGE,
fmt_message, *location, guard);
} else {
std::string msg = fmt::format("The case does not have a WELLDIMS keyword.\n"
"Please add a WELLDIMS keyword in the RUNSPEC section specifying at least {} groups in item 3.", nGroups - 1);
ctxt.handleError(Opm::ParseContext::RUNSPEC_NUMGROUPS_TOO_LARGE,
msg , {}, guard);
}
}
}
@ -115,14 +138,21 @@ namespace {
if (size > static_cast<decltype(size)>(wdims.maxWellsPerGroup()))
{
std::ostringstream os;
os << "Run uses maximum group size of " << size << ", but "
<< "allocates at most " << wdims.maxWellsPerGroup()
<< " in RUNSPEC section. Increase item 4 of WELLDIMS "
<< "accordingly.";
const auto& location = wdims.location();
if (location) {
std::string fmt_message = fmt::format("Problem with keyword {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The case has a maximum group size of {0} wells, the WELLDIMS keyword specifies {1}\n."
"Please increase item 4 in WELLDIMS to at least {0}", size, wdims.maxGroupsInField());
ctxt.handleError(Opm::ParseContext::RUNSPEC_GROUPSIZE_TOO_LARGE,
os.str(), guard);
ctxt.handleError(Opm::ParseContext::RUNSPEC_GROUPSIZE_TOO_LARGE,
fmt_message, *location, guard);
} else {
std::string msg = fmt::format("The case does not have a WELLDIMS keyword.\n"
"Please add a WELLDIMS keyword in the RUNSPEC section specifying at least {} as max groupsize in item 4.", size);
ctxt.handleError(Opm::ParseContext::RUNSPEC_GROUPSIZE_TOO_LARGE,
msg, Opm::KeywordLocation{}, guard);
}
}
}
} // WellDims

View File

@ -26,6 +26,8 @@
#include <unordered_set>
#include <vector>
#include <fmt/format.h>
#include <opm/common/OpmLog/LogUtil.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/common/utility/numeric/cmp.hpp>
@ -95,13 +97,14 @@ namespace {
means that we do not inform the user about "our fix", but it is *not* possible
to configure the parser to leave the spaces intact.
*/
std::string trim_wgname(const DeckKeyword& keyword, const std::string& wgname_arg, const ParseContext& parseContext, ErrorGuard errors) {
std::string wgname = trim_copy(wgname_arg);
if (wgname != wgname_arg) {
const auto& location = keyword.location();
std::string msg = "Illegal space: \"" + wgname_arg + "\" found when defining WELL/GROUP in keyword: " + keyword.name() + " at " + location.filename + ":" + std::to_string(location.lineno);
parseContext.handleError(ParseContext::PARSE_WGNAME_SPACE, msg, errors);
std::string msg_fmt = fmt::format("Problem with keyword {{keyword}}\n"
"In {{file}} line {{line}}\n"
"Illegal space in {} when defining WELL/GROUP.", wgname_arg);
parseContext.handleError(ParseContext::PARSE_WGNAME_SPACE, msg_fmt, location, errors);
}
return wgname;
}
@ -178,9 +181,10 @@ namespace {
for (const auto& record : handlerContext.keyword) {
const auto& methodItem = record.getItem<ParserKeywords::COMPORD::ORDER_TYPE>();
if ((methodItem.get< std::string >(0) != "TRACK") && (methodItem.get< std::string >(0) != "INPUT")) {
std::string msg = "The COMPORD keyword only handles 'TRACK' or 'INPUT' order.";
OpmLog::error(msg);
parseContext.handleError( ParseContext::UNSUPPORTED_COMPORD_TYPE , msg, errors );
std::string msg_fmt = "Problem with {keyword}\n"
"In {file} line {line}\n"
"Only 'TRACK' and 'INPUT' order are supported";
parseContext.handleError( ParseContext::UNSUPPORTED_COMPORD_TYPE ,msg_fmt , handlerContext.keyword.location(), errors );
}
}
}
@ -350,8 +354,10 @@ namespace {
if ((guide_rate_def == Group::GuideRateTarget::INJV ||
guide_rate_def == Group::GuideRateTarget::POTN ||
guide_rate_def == Group::GuideRateTarget::FORM)) {
std::string msg = "The supplied guide_rate value will be ignored";
parseContext.handleError(ParseContext::SCHEDULE_IGNORED_GUIDE_RATE, msg, errors);
std::string msg_fmt = "Problem with {keyword}\n"
"In {file} line {line}\n"
"The supplied guide rate will be ignored";
parseContext.handleError(ParseContext::SCHEDULE_IGNORED_GUIDE_RATE, msg_fmt, handlerContext.keyword.location(), errors);
} else {
guide_rate = record.getItem("GUIDE_RATE").get<double>(0);
if (guide_rate == 0)
@ -628,8 +634,10 @@ namespace {
}
void Schedule::handleMXUNSUPP(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
std::string msg = "OPM does not support grid property modifier " + handlerContext.keyword.name() + " in the Schedule section. Error at report: " + std::to_string(handlerContext.currentStep);
parseContext.handleError( ParseContext::UNSUPPORTED_SCHEDULE_GEO_MODIFIER , msg, errors );
std::string msg_fmt = fmt::format("Problem with keyword {{keyword}} at report step {}\n"
"In {{file}} line {{line}}\n"
"OPM does not support grid property modifier {} in the Schedule section", handlerContext.currentStep, handlerContext.keyword.name());
parseContext.handleError( ParseContext::UNSUPPORTED_SCHEDULE_GEO_MODIFIER , msg_fmt, handlerContext.keyword.location(), errors );
}
void Schedule::handleNODEPROP(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
@ -765,7 +773,7 @@ namespace {
const auto& current = *this->udq_config.get(handlerContext.currentStep);
std::shared_ptr<UDQConfig> new_udq = std::make_shared<UDQConfig>(current);
for (const auto& record : handlerContext.keyword)
new_udq->add_record(record, handlerContext.currentStep);
new_udq->add_record(record, handlerContext.keyword.location(), handlerContext.currentStep);
this->udq_config.update(handlerContext.currentStep, new_udq);
}
@ -1267,9 +1275,10 @@ namespace {
const std::string bhp_terminate = record.getItem("BPH_TERMINATE").getTrimmedString(0);
if (bhp_terminate == "YES") {
std::string msg = "The WHISTCTL handlerContext.keyword does not handle 'YES'. i.e. to terminate the run";
OpmLog::error(msg);
parseContext.handleError( ParseContext::UNSUPPORTED_TERMINATE_IF_BHP , msg, errors );
std::string msg_fmt = "Problem with {keyword}\n"
"In {file} line {line}\n"
"Setting item 2 in {keyword} to 'YES' to stop the run is not supported";
parseContext.handleError( ParseContext::UNSUPPORTED_TERMINATE_IF_BHP , msg_fmt, handlerContext.keyword.location(), errors );
}
for (auto& well_pair : this->wells_static) {

View File

@ -21,6 +21,8 @@
#include <iostream>
#include <sstream>
#include <fmt/format.h>
#include <opm/parser/eclipse/Parser/ParserKeywords/C.hpp>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
@ -185,6 +187,7 @@ namespace {
ErrorGuard& errors) {
std::vector< Record > compsegs;
const auto& location = compsegsKeyword.location();
// The first record in the keyword only contains the well name
// looping from the second record in the keyword
@ -208,38 +211,38 @@ namespace {
// TODO: the end of the previous connection or range
// 'previous' should be in term of the input order
// since basically no specific order for the connections
const std::string msg = "This way to obtain DISTANCE_START in keyword COMPSEGS "
"is not implemented yet for well " + well_name;
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg, errors);
const std::string msg_fmt = "Must specify start of segment in item 5 in {keyword}\nIn {file} line {line}";
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg_fmt, location, errors);
}
if (record.getItem<ParserKeywords::COMPSEGS::DISTANCE_END>().hasValue(0)) {
distance_end = record.getItem<ParserKeywords::COMPSEGS::DISTANCE_END>().getSIDouble(0);
} else {
// TODO: the distance_start plus the thickness of the grid block
const std::string msg = "This way to obtain DISTANCE_END in keyword COMPSEGS "
"is not implemented yet for well " + well_name;
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg, errors);
const std::string msg_fmt = "Must specify end of segment in item 6 in {keyword}\nIn {file} line {line}";
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg_fmt, location, errors);
}
if (distance_end <= distance_start) {
std::ostringstream sstr;
sstr << " The end of the perforations need be to further down than the start of the perforations\n "
<< " well " << well_name << " " << I + 1 << " " << J + 1 << " " << K + 1 << " in keyword COMPSEGS\n";
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_INVALID, sstr.str(), errors);
std::string msg_fmt = fmt::format("Problems with {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The end of the perforation must be below the start for well {} connection({},{},{})", well_name, I+1, J+1, K+1);
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_INVALID, msg_fmt, location, errors);
}
if( !record.getItem< ParserKeywords::COMPSEGS::DIRECTION >().hasValue( 0 ) &&
!record.getItem< ParserKeywords::COMPSEGS::DISTANCE_END >().hasValue( 0 ) ) {
const std::string msg = "The direction has to be specified when DISTANCE_END "
"is not specified in keyword COMPSEGS for well " + well_name;
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_INVALID, msg, errors);
std::string msg_fmt = fmt::format("Problems with {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The direction must be specified when DISTANCE_END is defaulted. Well: {}", well_name);
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_INVALID, msg_fmt, location, errors);
}
if( record.getItem< ParserKeywords::COMPSEGS::END_IJK >().hasValue( 0 ) &&
!record.getItem< ParserKeywords::COMPSEGS::DIRECTION >().hasValue( 0 ) ) {
const std::string msg = "The direction has to be specified when END_IJK "
"is specified in keyword COMPSEGS for well " + well_name;
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_INVALID, msg, errors);
std::string msg_fmt = fmt::format("Problems with {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The direction must be specified when END_IJK is specified. Well: {}", well_name);
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_INVALID, msg_fmt, location, errors);
}
/*
@ -262,9 +265,10 @@ namespace {
if (center_depth < 0.) {
//TODO: get the depth from COMPDAT data.
const std::string msg = "This way to obtain CENTER_DISTANCE in keyword COMPSEGS "
"is not implemented yet for well " + well_name;
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg, errors);
std::string msg_fmt = fmt::format("Problems with {{keyword}}\n"
"In {{file}} line {{line}}\n"
"The use of negative center depth in item 9 is not supported. Well: {}", well_name);
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg_fmt, location, errors);
}
int segment_number;
@ -287,10 +291,11 @@ namespace {
seqIndex);
}
} else { // a range is defined. genrate a range of Record
std::ostringstream sstr;
sstr << "COMPSEGS entries can only be input for single connection, not supporting COMPSEGS entries specified with a range yet.\n"
<< " well " << well_name << " " << I + 1 << " " << J + 1 << " " << K + 1 << " in keyword COMPSEGS\n";
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, sstr.str(), errors);
std::string msg_fmt = fmt::format("Problems with {{keyword}}\n"
"In {{file}} line {{line}}\n"
"Entering COMPEGS with a range of connections is not yet supported\n"
"Well: {} Connection: ({},{},{})", well_name, I+1, J+1 , K+1);
parseContext.handleError(ParseContext::SCHEDULE_COMPSEGS_NOT_SUPPORTED, msg_fmt, location, errors);
}
}

View File

@ -331,11 +331,13 @@ namespace {
if (action_keyword.name() == "ENDACTIO")
break;
if (Action::ActionX::valid_keyword(action_keyword.name())) {
if (Action::ActionX::valid_keyword(action_keyword.name()))
action.addKeyword(action_keyword);
} else {
std::string msg = "The keyword " + action_keyword.name() + " is not supported in a ACTIONX block.";
parseContext.handleError( ParseContext::ACTIONX_ILLEGAL_KEYWORD, msg, errors);
else {
std::string msg = "The keyword {0} is not supported in a ACTIONX block. file: {1} line: {2}";
std::string msg_fmt = "The keyword {keyword} is not supported in the ACTIONX block\n"
"In {file} line {line}.";
parseContext.handleError( ParseContext::ACTIONX_ILLEGAL_KEYWORD, msg, action_keyword.location(), errors);
}
}
this->addACTIONX(action, currentStep);
@ -599,8 +601,11 @@ namespace {
}
void Schedule::invalidNamePattern( const std::string& namePattern, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword ) const {
std::string msg = "Error when handling " + keyword.name() + " at step: " + std::to_string(report_step) + ". No names match " + namePattern;
parseContext.handleError( ParseContext::SCHEDULE_INVALID_NAME, msg, errors );
std::string msg_fmt = fmt::format("Invalid wellname pattern in {{keyword}}\n"
"In {{file}} line {{line}}\n"
"No wells/groups match the pattern: '{}'", namePattern);
parseContext.handleError( ParseContext::SCHEDULE_INVALID_NAME, msg_fmt, keyword.location(), errors );
}
const TimeMap& Schedule::getTimeMap() const {

View File

@ -21,6 +21,8 @@
#include <cstring>
#include <cassert>
#include <fmt/format.h>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
@ -250,16 +252,8 @@ UDQASTNode UDQParser::parse_set() {
namespace {
void dump_tokens(const std::string& target_var, const std::vector<UDQToken>& tokens) {
std::cout << target_var << " = ";
for (const auto& token : tokens) {
const auto& value = token.value();
if (std::holds_alternative<double>(value))
std::cout << std::get<double>(token.value()) << " ";
else {
std::cout << std::get<std::string>(token.value()) << " ";
for (const auto& s : token.selector())
std::cout << s << " ";
}
}
for (const auto& token : tokens)
std::cout << token.str();
std::cout << std::endl;
}
@ -294,20 +288,32 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
if (!parser.empty()) {
size_t index = parser.current_pos;
auto current = parser.current();
std::string msg = "Extra unhandled data starting with token[" + std::to_string(index) + "] = '" + current.string() + "'";
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg, errors);
std::string msg_fmt = fmt::format("Problem parsing UDQ expression \n"
"In {{file}} line {{line}}.\n"
"Extra unhandled data starting with item {}.", current.string());
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
return UDQASTNode( udq_params.undefinedValue() );
}
if (!tree.valid()) {
std::string msg = "ERROR: Failed to parse UDQ expression";
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg, errors);
std::string token_string;
for (const auto& token : tokens)
token_string += token.str() + " ";
std::string msg_fmt = fmt::format("Failed to parse UDQ expression\n"
"In {{file}} line {{line}}.\n"
"This can be a bug in flow or a bug in the UDQ input string.\n"
"UDQ input: '{}'", token_string);
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
return UDQASTNode( udq_params.undefinedValue() );
}
if (!static_type_check(target_type, tree.var_type)) {
std::string msg = "Invalid compile-time type conversion detected in UDQ expression target type: " + UDQ::typeName(target_type) + " expr type: " + UDQ::typeName(tree.var_type);
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg, errors);
std::string msg_fmt = fmt::format("Failed to parse UDQ expression\n"
"In {{file}} line {{line}}.\n"
"Invalid type conversion detected in UDQ expression expected: {} got: {}", 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)
dump_tokens(target_var, tokens);
@ -315,8 +321,10 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
}
if (tree.var_type == UDQVarType::NONE) {
std::string msg = "Parse error when evaluating UDQ define expression - could not determine expression type";
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg, errors);
std::string msg_fmt = fmt::format("Failed to parse UDQ expression\n"
"In {{file}} line {{line}}.\n"
"Could not determine expression type.");
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
dump_tokens(target_var, tokens);

View File

@ -16,7 +16,7 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <numeric>
#include "UDQToken.hpp"
@ -51,4 +51,13 @@ UDQTokenType UDQToken::type() const {
return this->token_type;
}
std::string UDQToken::str() const {
if (std::holds_alternative<std::string>(this->m_value))
return std::get<std::string>(this->m_value) + std::string{" "} + std::accumulate(this->m_selector.begin(), this->m_selector.end(), std::string{},
[](const std::string& s1, const std::string& s2) { return s1 + " " + s2; });
else
return std::to_string(std::get<double>(this->m_value));
}
}

View File

@ -36,6 +36,7 @@ public:
const std::vector<std::string>& selector() const;
const std::variant<std::string, double>& value() const;
UDQTokenType type() const;
std::string str() const;
private:
UDQTokenType token_type;
std::variant<std::string,double> m_value;

View File

@ -27,6 +27,8 @@
#include <unordered_set>
#include <vector>
#include <fmt/format.h>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/common/utility/OpmInputError.hpp>
@ -326,30 +328,24 @@ namespace {
return SummaryConfigNode::Type::Undefined;
}
void handleMissingWell( const ParseContext& parseContext, ErrorGuard& errors, const std::string& keyword, const std::string& well) {
std::string msg = std::string("Error in keyword:") + keyword + std::string(" No such well: ") + well;
if (parseContext.get( ParseContext::SUMMARY_UNKNOWN_WELL) == InputError::WARN)
std::cerr << "ERROR: " << msg << std::endl;
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_WELL , msg, errors );
void handleMissingWell( const ParseContext& parseContext, ErrorGuard& errors, const KeywordLocation& location, const std::string& well) {
std::string msg_fmt = fmt::format("Request for missing well {} in {{keyword}}\n"
"In {{file}} line {{line}}", well);
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_WELL , msg_fmt, location, errors );
}
void handleMissingGroup( const ParseContext& parseContext , ErrorGuard& errors, const std::string& keyword, const std::string& group) {
std::string msg = std::string("Error in keyword:") + keyword + std::string(" No such group: ") + group;
if (parseContext.get( ParseContext::SUMMARY_UNKNOWN_GROUP) == InputError::WARN)
std::cerr << "ERROR: " << msg << std::endl;
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_GROUP , msg, errors );
void handleMissingGroup( const ParseContext& parseContext , ErrorGuard& errors, const KeywordLocation& location, const std::string& group) {
std::string msg_fmt = fmt::format("Request for missing group {} in {{keyword}}\n"
"In {{file}} line {{line}}", group);
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_GROUP , msg_fmt, location, errors );
}
void handleMissingNode( const ParseContext& parseContext, ErrorGuard& errors, const std::string& keyword, const std::string& node_name )
void handleMissingNode( const ParseContext& parseContext, ErrorGuard& errors, const KeywordLocation& location, const std::string& node_name )
{
const auto msg = std::string("Error in keyword \"") + keyword + std::string("\": No such network node: ") + node_name;
if (parseContext.get( ParseContext::SUMMARY_UNKNOWN_NODE) == InputError::WARN)
std::cerr << "ERROR: " << msg << std::endl;
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_NODE, msg, errors );
std::string msg_fmt = fmt::format("Request for missing network node {} in {{keyword}}\n"
"In {{file}} line {{line}}", node_name);
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_NODE, msg_fmt, location, errors );
}
inline void keywordW( SummaryConfig::keyword_list& list,
@ -391,8 +387,9 @@ inline void keywordW( SummaryConfig::keyword_list& list,
if (keyword.name().back() == 'L') {
if (! (is_control_mode(keyword.name()) || is_udq(keyword.name()))) {
const auto& location = keyword.location();
std::string msg = std::string("The completion keywords like: " + keyword.name() + " are not supported at: " + location.filename + ", line " + std::to_string(location.lineno));
parseContext.handleError( ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, errors);
std::string msg = "Unsupported summary output keyword {}\n"
"In {file} line {line}";
parseContext.handleError( ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, location, errors);
return;
}
}
@ -408,7 +405,7 @@ inline void keywordW( SummaryConfig::keyword_list& list,
auto well_names = schedule.wellNames( pattern, schedule.size() - 1 );
if( well_names.empty() )
handleMissingWell( parseContext, errors, keyword.name(), pattern );
handleMissingWell( parseContext, errors, keyword.location(), pattern );
keywordW( list, well_names, param );
}
@ -463,7 +460,7 @@ inline void keywordG( SummaryConfig::keyword_list& list,
if( schedule.hasGroup( group ) )
list.push_back( param.namedEntity(group) );
else
handleMissingGroup( parseContext, errors, keyword.name(), group );
handleMissingGroup( parseContext, errors, keyword.location(), group );
}
}
@ -507,7 +504,7 @@ void keyword_node( SummaryConfig::keyword_list& list,
if (pos != node_names.end())
list.push_back( param.namedEntity(node_name) );
else
handleMissingNode( parseContext, errors, keyword.name(), node_name );
handleMissingNode( parseContext, errors, keyword.location(), node_name );
}
}
@ -565,8 +562,9 @@ inline void keywordR2R( SummaryConfig::keyword_list& /* list */,
const DeckKeyword& keyword)
{
const auto& location = keyword.location();
std::string msg = "Region to region summary keyword: " + keyword.name() + " at " + location.filename + ", line " + std::to_string(location.lineno) + " is ignored";
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, errors);
std::string msg_fmt = "Region to region summary keyword {keyword} is ignored\n";
"In {file} line {line}";
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg_fmt, location, errors);
}
@ -648,7 +646,7 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
const auto ijk_defaulted = record.getItem( 1 ).defaultApplied( 0 );
if( well_names.empty() )
handleMissingWell( parseContext, errors, keyword.name(), wellitem.getTrimmedString( 0 ) );
handleMissingWell( parseContext, errors, keyword.location(), wellitem.getTrimmedString( 0 ) );
for(const auto& name : well_names) {
param.namedEntity(name);
@ -777,7 +775,7 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
: schedule.wellNames(wellitem.getTrimmedString(0));
if (well_names.empty())
handleMissingWell(parseContext, errors, keyword.name(),
handleMissingWell(parseContext, errors, keyword.location(),
wellitem.getTrimmedString(0));
// Negative 1 (< 0) if segment ID defaulted. Defaulted
@ -852,25 +850,29 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
};
}
void check_udq( const std::string& name,
void check_udq( const KeywordLocation& location,
const Schedule& schedule,
const ParseContext& parseContext,
ErrorGuard& errors ) {
if (! is_udq(name))
if (! is_udq(location.keyword))
// Nothing to do
return;
const auto& udq = schedule.getUDQConfig(schedule.size() - 1);
if (!udq.has_keyword(name)) {
std::string msg{"Summary output has been requested for UDQ keyword: " + name + " but it has not been configured"};
parseContext.handleError(ParseContext::SUMMARY_UNDEFINED_UDQ, msg, errors);
if (!udq.has_keyword(location.keyword)) {
std::string msg = "Summary output requested for UDQ {keyword}\n"
"In {file} line {line}\n"
"No defintion for this UDQ found in the SCHEDULE section";
parseContext.handleError(ParseContext::SUMMARY_UNDEFINED_UDQ, msg, location, errors);
return;
}
if (!udq.has_unit(name)) {
std::string msg{"Summary output has been requested for UDQ keyword: " + name + " but no unit has not been configured"};
parseContext.handleError(ParseContext::SUMMARY_UDQ_MISSING_UNIT, msg, errors);
if (!udq.has_unit(location.keyword)) {
std::string msg = "Summary output requested for UDQ {keyword}\n"
"In {file} line {line}\n"
"No unit define in the SCHEDULE section";
parseContext.handleError(ParseContext::SUMMARY_UDQ_MISSING_UNIT, msg, location, errors);
}
}
@ -885,7 +887,7 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
using Cat = SummaryConfigNode::Category;
const auto& name = keyword.name();
check_udq( name, schedule, parseContext, errors );
check_udq( keyword.location(), schedule, parseContext, errors );
const auto cat = parseKeywordCategory( name );
switch( cat ) {
@ -900,8 +902,9 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
case Cat::Miscellaneous: return keywordMISC( list, keyword );
default:
std::string msg = "Summary keywords of type: " + to_string( cat ) + " is not supported. Keyword: " + name + " is ignored";
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, errors);
std::string msg_fmt = fmt::format("Summary output keyword {{keyword}} of type {} is not supported\n"
"In {{file}} line {{line}}", to_string(cat));
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg_fmt, keyword.location(), errors);
return;
}
}
@ -909,7 +912,7 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
inline void handleKW( SummaryConfig::keyword_list& list,
const std::string& keyword,
KeywordLocation loc,
const KeywordLocation& location,
const Schedule& schedule,
const ParseContext& parseContext,
ErrorGuard& errors) {
@ -918,9 +921,10 @@ inline void handleKW( SummaryConfig::keyword_list& list,
if (is_udq(keyword))
throw std::logic_error("UDQ keywords not handleded when expanding alias list");
if (is_aquifer( keyword )) {
std::string msg = "Summary keywords of type: Aquifer is not supported. Keyword: " + keyword + " is ignored";
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, errors);
if (is_aquifer(keyword)) {
std::string msg = "Summary output keyword {keyword} of type AQUIFER is not supported\n"
"In {{file}} line {{line}}";
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, location, errors);
return;
}
@ -928,10 +932,10 @@ inline void handleKW( SummaryConfig::keyword_list& list,
const auto cat = parseKeywordCategory( keyword );
switch( cat ) {
case Cat::Well: return keywordW( list, keyword, std::move(loc), schedule );
case Cat::Group: return keywordG( list, keyword, std::move(loc), schedule );
case Cat::Field: return keywordF( list, keyword, std::move(loc) );
case Cat::Miscellaneous: return keywordMISC( list, keyword, std::move(loc));
case Cat::Well: return keywordW( list, keyword, location, schedule );
case Cat::Group: return keywordG( list, keyword, location, schedule );
case Cat::Field: return keywordF( list, keyword, location );
case Cat::Miscellaneous: return keywordMISC( list, keyword, location);
default:
throw std::logic_error("Keyword type: " + to_string( cat ) + " is not supported in alias lists. Internal error handling: " + keyword);

View File

@ -57,12 +57,9 @@ bool checkDeck( const Deck& deck, const Parser& parser, const ParseContext& pars
const std::string& fileUnitSystem = uppercase(keyword->getRecord(0).getItem("FILE_UNIT_SYSTEM").getTrimmedString(0));
if (fileUnitSystem != deckUnitSystem) {
const auto& location = keyword->location();
std::string msg =
"Unit system " + fileUnitSystem + " specified via the FILEUNIT keyword at "
+ location.filename + ":" + std::to_string(location.lineno)
+ " does not correspond to the unit system used by the deck ("
+ deckUnitSystem + ")";
parseContext.handleError(ParseContext::UNIT_SYSTEM_MISMATCH, msg, errorGuard);
std::string msg_fmt = "Unit system mismatch\n"
"In {file} line {line}";
parseContext.handleError(ParseContext::UNIT_SYSTEM_MISMATCH, msg_fmt, location, errorGuard);
deckValid = false;
}
}

View File

@ -25,6 +25,7 @@
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/parser/eclipse/Parser/InputErrorAction.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/common/utility/String.hpp>
namespace Opm {
@ -137,6 +138,7 @@ namespace Opm {
void ParseContext::handleError(
const std::string& errorKey,
const std::string& msg,
const std::optional<KeywordLocation>& location,
ErrorGuard& errors) const {
InputError::Action action = get( errorKey );
@ -175,10 +177,10 @@ namespace Opm {
}
}
void ParseContext::handleUnknownKeyword(const std::string& keyword, ErrorGuard& errors) const {
void ParseContext::handleUnknownKeyword(const std::string& keyword, const std::optional<KeywordLocation>& location, ErrorGuard& errors) const {
if (this->ignore_keywords.find(keyword) == this->ignore_keywords.end()) {
std::string msg = "Unknown keyword: " + keyword;
this->handleError(ParseContext::PARSE_UNKNOWN_KEYWORD, msg, errors);
this->handleError(ParseContext::PARSE_UNKNOWN_KEYWORD, msg, location, errors);
}
}

View File

@ -27,6 +27,8 @@
#include <utility>
#include <vector>
#include <fmt/format.h>
#include <opm/common/utility/FileSystem.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
@ -470,7 +472,7 @@ void ParserState::loadFile(const Opm::filesystem::path& inputFile) {
inputFileCanonical = Opm::filesystem::canonical(inputFile);
} catch (const Opm::filesystem::filesystem_error& fs_error) {
std::string msg = "Could not open file: " + inputFile.string();
parseContext.handleError( ParseContext::PARSE_MISSING_INCLUDE , msg, errors);
parseContext.handleError( ParseContext::PARSE_MISSING_INCLUDE , msg, {}, errors);
return;
}
@ -483,8 +485,7 @@ void ParserState::loadFile(const Opm::filesystem::path& inputFile) {
// make sure the file we'd like to parse is readable
if( !ufp ) {
std::string msg = "Could not read from file: " + inputFile.string();
parseContext.handleError( ParseContext::PARSE_MISSING_INCLUDE , msg, errors);
parseContext.handleError( ParseContext::PARSE_MISSING_INCLUDE , msg, {}, errors);
return;
}
@ -516,37 +517,28 @@ void ParserState::loadFile(const Opm::filesystem::path& inputFile) {
void ParserState::handleRandomText(const std::string_view& keywordString ) const {
std::string errorKey;
std::stringstream msg;
std::string trimmedCopy = std::string( keywordString );
std::string msg;
KeywordLocation location{lastKeyWord, this->current_path(), this->line()};
if (trimmedCopy == "/") {
errorKey = ParseContext::PARSE_RANDOM_SLASH;
msg << "Extra '/' detected at: "
<< this->current_path()
<< ":" << this->line();
msg = "Extra '/' detected in {file} line {line}";
}
else if (lastSizeType == OTHER_KEYWORD_IN_DECK) {
errorKey = ParseContext::PARSE_EXTRA_RECORDS;
msg << "String: \'"
<< keywordString
<< "\' invalid."
<< "Too many records in keyword: "
<< lastKeyWord
<< " at: "
<< this->line()
<< ".\n";
msg = "Too many records in keyword {keyword}\n"
"In {} line {}";
}
else {
errorKey = ParseContext::PARSE_RANDOM_TEXT;
msg << "String \'" << keywordString
<< "\' not formatted/recognized as valid keyword at: "
<< this->current_path()
<< ":" << this->line();
msg = fmt::format("String {} not formatted as valid keyword\n"
"In {{file}} line {{line}}.", keywordString);
}
parseContext.handleError( errorKey , msg.str(), errors );
parseContext.handleError( errorKey , msg, location, errors );
}
void ParserState::openRootFile( const Opm::filesystem::path& inputFile) {
this->loadFile( inputFile );
this->deck.setDataFile( inputFile.string() );
@ -643,9 +635,13 @@ RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string
targetSize);
}
std::string msg = "Expected the kewyord: " +keyword_size.keyword
+ " to infer the number of records in: " + keywordString;
parserState.parseContext.handleError(ParseContext::PARSE_MISSING_DIMS_KEYWORD , msg, parserState.errors );
std::string msg_fmt = fmt::format("Problem with {{keyword}} - missing {0}\n"
"In {{file}} line {{line}}\n"
"For the keyword {{keyword}} we expect to read the number of records from keyword {0}, {0} was not found", keyword_size.keyword);
parserState.parseContext.handleError(ParseContext::PARSE_MISSING_DIMS_KEYWORD ,
msg_fmt,
KeywordLocation{keywordString, parserState.current_path().string(), parserState.line()},
parserState.errors );
const auto& keyword = parser.getKeyword( keyword_size.keyword );
const auto& record = keyword.getRecord(0);
@ -665,14 +661,18 @@ RawKeyword * newRawKeyword( const std::string& deck_name, ParserState& parserSta
if (deck_name.size() > RawConsts::maxKeywordLength) {
const std::string keyword8 = deck_name.substr(0, RawConsts::maxKeywordLength);
if (parser.isRecognizedKeyword(keyword8)) {
std::string msg = "Keyword: " + deck_name + " too long - only first eight characters recognized";
parserState.parseContext.handleError(ParseContext::PARSE_LONG_KEYWORD, msg, parserState.errors);
std::string msg = "Keyword {keyword} to long - only eight first characters recognized\n"
"In {file} line {line}\n";
parserState.parseContext.handleError(ParseContext::PARSE_LONG_KEYWORD,
msg,
KeywordLocation{deck_name, parserState.current_path().string(), parserState.line()},
parserState.errors);
parserState.unknown_keyword = false;
const auto& parserKeyword = parser.getParserKeywordFromDeckName( keyword8 );
return newRawKeyword(parserKeyword, keyword8, parserState, parser);
} else {
parserState.parseContext.handleUnknownKeyword( deck_name, parserState.errors );
parserState.parseContext.handleUnknownKeyword( deck_name, KeywordLocation{}, parserState.errors );
parserState.unknown_keyword = true;
return nullptr;
}
@ -685,7 +685,7 @@ RawKeyword * newRawKeyword( const std::string& deck_name, ParserState& parserSta
}
if( ParserKeyword::validDeckName(deck_name) ) {
parserState.parseContext.handleUnknownKeyword( deck_name, parserState.errors );
parserState.parseContext.handleUnknownKeyword( deck_name, KeywordLocation{}, parserState.errors );
parserState.unknown_keyword = true;
return nullptr;
}

View File

@ -17,6 +17,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
@ -119,7 +121,6 @@ namespace {
return *itr;
}
DeckRecord ParserRecord::parse(const ParseContext& parseContext , ErrorGuard& errors , RawRecord& rawRecord, UnitSystem& active_unitsystem, UnitSystem& default_unitsystem, const KeywordLocation& location) const {
std::vector< DeckItem > items;
items.reserve( this->size() + 20 );
@ -127,10 +128,10 @@ namespace {
items.emplace_back( parserItem.scan( rawRecord, active_unitsystem, default_unitsystem ) );
if (rawRecord.size() > 0) {
std::string msg = "The RawRecord for keyword \"" + location.keyword + "\" in file\"" + location.filename + "\" contained " +
std::to_string(rawRecord.size()) +
" too many items according to the spec. RawRecord was: " + rawRecord.getRecordString();
parseContext.handleError(ParseContext::PARSE_EXTRA_DATA , msg, errors);
std::string msg_format = fmt::format("Record contains too many items in keyword {{0}}. Expected {} items, found {}.\n", this->size(), rawRecord.max_size()) +
"In file {1} at line {2}.\n" +
fmt::format("Record is \"{}\".", rawRecord.getRecordString());
parseContext.handleError(ParseContext::PARSE_EXTRA_DATA , msg_format, location, errors);
}
return { std::move( items ) };

View File

@ -1,6 +0,0 @@
Errors:
RUNSPEC_GROUPSIZE_TOO_LARGE: Run uses maximum group size of 6, but allocates at most 4 in RUNSPEC section. Increase item 4 of WELLDIMS accordingly.

View File

@ -1,8 +0,0 @@
Errors:
RUNSPEC_NUMWELLS_TOO_LARGE : Run uses 12 wells, but allocates at most 0 in RUNSPEC section. Increase item 1 of WELLDIMS accordingly.
RUNSPEC_CONNS_PER_WELL_TOO_LARGE: Run has well with 15 reservoir connections, but allocates at most 0 connections per well in RUNSPEC section. Increase item 2 of WELLDIMS accordingly.
RUNSPEC_NUMGROUPS_TOO_LARGE : Run uses 11 non-FIELD groups, but allocates at most 0 in RUNSPEC section. Increase item 3 of WELLDIMS accordingly.
RUNSPEC_GROUPSIZE_TOO_LARGE : Run uses maximum group size of 10, but allocates at most 0 in RUNSPEC section. Increase item 4 of WELLDIMS accordingly.

View File

@ -30,6 +30,7 @@
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
#include <opm/parser/eclipse/Utility/Functional.hpp>
#include <opm/common/utility/OpmInputError.hpp>
inline std::string fst( const std::pair< std::string, int >& p ) {
return p.first;
@ -620,7 +621,7 @@ BOOST_AUTO_TEST_CASE(RPTRST_FORMAT_ERROR) {
// The case "BASIC 1" - i.e. without '=' can not be salvaged; this should
// give an exception whatever is the value of ParseContext::RPT_MIXED_STYLE:
BOOST_CHECK_THROW(RestartConfig(TimeMap(deck0), deck0, ctx, errors), std::invalid_argument);
BOOST_CHECK_THROW(RestartConfig(TimeMap(deck0), deck0, ctx, errors), OpmInputError);
// Observe that this is true due to some undocumented guessing that

View File

@ -74,9 +74,10 @@ BOOST_AUTO_TEST_CASE(TYPE_COERCION) {
BOOST_AUTO_TEST_CASE(GROUP_VARIABLES)
{
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft;
UDQDefine def_group(udqp, "GUOPRL",{"(", "5000", "-", "GOPR", "LOWER", "*", "0.13", "-", "GOPR", "UPPER", "*", "0.15", ")" , "*", "0.89"});
UDQDefine def_group(udqp, "GUOPRL", location, {"(", "5000", "-", "GOPR", "LOWER", "*", "0.13", "-", "GOPR", "UPPER", "*", "0.15", ")" , "*", "0.89"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -95,10 +96,11 @@ BOOST_AUTO_TEST_CASE(GROUP_VARIABLES)
BOOST_AUTO_TEST_CASE(SUBTRACT)
{
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft;
UDQDefine def(udqp, "WU", {"16", "-", "8", "-", "4", "-", "2", "-", "1"});
UDQDefine scalar(udqp, "WU", {"16"});
UDQDefine def(udqp, "WU", location, {"16", "-", "8", "-", "4", "-", "2", "-", "1"});
UDQDefine scalar(udqp, "WU", location, {"16"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
@ -114,12 +116,13 @@ BOOST_AUTO_TEST_CASE(SUBTRACT)
BOOST_AUTO_TEST_CASE(TEST)
{
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft;
UDQDefine def1(udqp, "WUWI3", {"GOPR" , "MAU", "*", "2.0", "*", "0.25", "*", "10"});
UDQDefine def2(udqp, "WUWI3", {"2.0", "*", "0.25", "*", "3"});
UDQDefine def3(udqp, "WUWI3", {"GOPR" , "FIELD", "-", "2.0", "*", "3"});
UDQDefine def4(udqp, "WUWI3", {"FOPR" , "/", "2"});
UDQDefine def1(udqp, "WUWI3", location, {"GOPR" , "MAU", "*", "2.0", "*", "0.25", "*", "10"});
UDQDefine def2(udqp, "WUWI3", location, {"2.0", "*", "0.25", "*", "3"});
UDQDefine def3(udqp, "WUWI3", location, {"GOPR" , "FIELD", "-", "2.0", "*", "3"});
UDQDefine def4(udqp, "WUWI3", location, {"FOPR" , "/", "2"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
@ -152,19 +155,20 @@ BOOST_AUTO_TEST_CASE(TEST)
This expression has a well set as target type, and involves group with
wildcard that is not supported by flow.
*/
BOOST_CHECK_THROW( UDQDefine(udqp, "WUWI2", {"GOPR", "G*", "*", "2.0"}), std::logic_error);
BOOST_CHECK_THROW( UDQDefine(udqp, "WUWI2", location, {"GOPR", "G*", "*", "2.0"}), std::logic_error);
/*
UDQVarType == BLOCK is not yet supported.
*/
BOOST_CHECK_THROW( UDQDefine(udqp, "WUWI2", {"BPR", "1","1", "1", "*", "2.0"}), std::logic_error);
BOOST_CHECK_THROW( UDQDefine(udqp, "WUWI2", location, {"BPR", "1","1", "1", "*", "2.0"}), std::logic_error);
}
BOOST_AUTO_TEST_CASE(MIX_SCALAR) {
UDQFunctionTable udqft;
UDQParams udqp;
UDQDefine def_add(udqp, "WU", {"WOPR", "+", "1"});
KeywordLocation location;
UDQDefine def_add(udqp, "WU", location, {"WOPR", "+", "1"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -178,13 +182,15 @@ BOOST_AUTO_TEST_CASE(MIX_SCALAR) {
BOOST_AUTO_TEST_CASE(UDQ_TABLE_EXCEPTION) {
UDQParams udqp;
BOOST_CHECK_THROW(UDQDefine(udqp, "WU", {"TUPRICE[WOPR]"}), std::invalid_argument);
KeywordLocation location;
BOOST_CHECK_THROW(UDQDefine(udqp, "WU", location, {"TUPRICE[WOPR]"}), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(UDQFieldSetTest) {
std::vector<std::string> wells = {"P1", "P2", "P3", "P4"};
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft(udqp);
SummaryState st(std::chrono::system_clock::now());
@ -205,7 +211,7 @@ BOOST_AUTO_TEST_CASE(UDQFieldSetTest) {
*/
{
UDQDefine def_fopr(udqp, "FUOPR", {"SUM", "(", "WOPR", ")"});
UDQDefine def_fopr(udqp, "FUOPR", location, {"SUM", "(", "WOPR", ")"});
auto fopr_res = def_fopr.eval(context);
BOOST_CHECK_EQUAL( fopr_res[0].get(), 10.0 );
}
@ -286,9 +292,10 @@ BOOST_AUTO_TEST_CASE(UDQ_GROUP_TEST) {
const auto& value = gs["G1"];
BOOST_CHECK_EQUAL(value.get(), 1.0);
{
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft(udqp);
UDQDefine def_fopr(udqp, "FUOPR", {"SUM", "(", "GOPR", ")"});
UDQDefine def_fopr(udqp, "FUOPR", location, {"SUM", "(", "GOPR", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -309,8 +316,9 @@ BOOST_AUTO_TEST_CASE(UDQ_GROUP_TEST) {
BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
UDQParams udqp;
UDQFunctionTable udqft(udqp);
KeywordLocation location;
{
UDQDefine def(udqp, "WUBHP", {"WBHP"});
UDQDefine def(udqp, "WUBHP", location, {"WBHP"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -325,7 +333,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
BOOST_CHECK_EQUAL( res["W3"].get(), 3 );
}
{
UDQDefine def(udqp, "WUBHP", {"WBHP" , "'P*'"});
UDQDefine def(udqp, "WUBHP", location, {"WBHP" , "'P*'"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -343,7 +351,7 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) {
BOOST_CHECK_EQUAL( res["I1"].defined(), false);
}
{
UDQDefine def(udqp, "WUBHP", {"NINT" , "(", "WBHP", ")"});
UDQDefine def(udqp, "WUBHP", location, {"NINT" , "(", "WBHP", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -966,10 +974,11 @@ BOOST_AUTO_TEST_CASE(UDQASSIGN_TEST) {
}
BOOST_AUTO_TEST_CASE(UDQ_POW_TEST) {
KeywordLocation location;
UDQFunctionTable udqft;
UDQParams udqp;
UDQDefine def_pow1(udqp, "WU", {"WOPR", "+", "WWPR", "*", "WGOR", "^", "WWIR"});
UDQDefine def_pow2(udqp, "WU", {"(", "WOPR", "+", "WWPR", ")", "^", "(", "WOPR", "+" , "WGOR", "*", "WWIR", "-", "WOPT", ")"});
UDQDefine def_pow1(udqp, "WU", location, {"WOPR", "+", "WWPR", "*", "WGOR", "^", "WWIR"});
UDQDefine def_pow2(udqp, "WU", location, {"(", "WOPR", "+", "WWPR", ")", "^", "(", "WOPR", "+" , "WGOR", "*", "WWIR", "-", "WOPT", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -987,9 +996,10 @@ BOOST_AUTO_TEST_CASE(UDQ_POW_TEST) {
}
BOOST_AUTO_TEST_CASE(UDQ_CMP_TEST) {
KeywordLocation location;
UDQFunctionTable udqft;
UDQParams udqp;
UDQDefine def_cmp(udqp, "WU", {"WOPR", ">", "WWPR", "+", "WGOR", "*", "WWIR"});
UDQDefine def_cmp(udqp, "WU", location, {"WOPR", ">", "WWPR", "+", "WGOR", "*", "WWIR"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -1016,6 +1026,7 @@ BOOST_AUTO_TEST_CASE(UDQ_CMP_TEST) {
*/
BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft;
SummaryState st(std::chrono::system_clock::now());
@ -1033,7 +1044,7 @@ BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
st.update_well_var("P4", "WWPR", 4);
{
UDQDefine def(udqp, "WUOPR", {"WOPR", "'*1'"});
UDQDefine def(udqp, "WUOPR", location, {"WOPR", "'*1'"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4, res.size());
auto well1 = res["P1"];
@ -1047,7 +1058,7 @@ BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
BOOST_CHECK( !well4.defined() );
}
{
UDQDefine def(udqp, "WUOPR", {"1"});
UDQDefine def(udqp, "WUOPR", location, {"1"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4, res.size());
auto well1 = res["P1"];
@ -1063,7 +1074,7 @@ BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
BOOST_CHECK_EQUAL(well4.get() , 1);
}
{
UDQDefine def(udqp, "WUOPR", {"WOPR", "'P1'"});
UDQDefine def(udqp, "WUOPR", location, {"WOPR", "'P1'"});
auto res = def.eval(context);
BOOST_CHECK_EQUAL(4, res.size());
auto well1 = res["P1"];
@ -1085,8 +1096,9 @@ BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) {
BOOST_AUTO_TEST_CASE(UDQ_SORTD_NAN) {
UDQParams udqp;
UDQFunctionTable udqft;
UDQDefine def(udqp, "WUPR1" , {"1", "/", "(", "WWIR", "'OP*'" , ")"});
UDQDefine def_sort(udqp , "WUPR3", {"SORTD", "(", "WUPR1", ")" });
KeywordLocation location;
UDQDefine def(udqp, "WUPR1" , location, {"1", "/", "(", "WWIR", "'OP*'" , ")"});
UDQDefine def_sort(udqp , "WUPR3", location, {"SORTD", "(", "WUPR1", ")" });
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -1126,10 +1138,11 @@ BOOST_AUTO_TEST_CASE(UDQ_SORTD_NAN) {
BOOST_AUTO_TEST_CASE(UDQ_SORTA) {
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft;
UDQDefine def1(udqp, "WUPR1" , {"1", "/", "(", "WWCT", "'OP*'", "+", "0.00001", ")"});
UDQDefine def_sort(udqp , "WUPR3", {"SORTA", "(", "WUPR1", ")" });
UDQDefine def1(udqp, "WUPR1" , location, {"1", "/", "(", "WWCT", "'OP*'", "+", "0.00001", ")"});
UDQDefine def_sort(udqp , "WUPR3", location, {"SORTA", "(", "WUPR1", ")" });
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -1156,12 +1169,13 @@ BOOST_AUTO_TEST_CASE(UDQ_SORTA) {
BOOST_AUTO_TEST_CASE(UDQ_BASIC_MATH_TEST) {
UDQParams udqp;
UDQFunctionTable udqft;
UDQDefine def_add(udqp, "WU2OPR", {"WOPR", "+", "WOPR"});
UDQDefine def_sub(udqp, "WU2OPR", {"WOPR", "-", "WOPR"});
UDQDefine def_mul(udqp, "WU2OPR", {"WOPR", "*", "WOPR"});
UDQDefine def_div(udqp, "WU2OPR", {"WOPR", "/", "WOPR"});
UDQDefine def_muladd(udqp , "WUX", {"WOPR", "+", "WOPR", "*", "WOPR"});
UDQDefine def_wuwct(udqp , "WUWCT", {"WWPR", "/", "(", "WOPR", "+", "WWPR", ")"});
KeywordLocation location;
UDQDefine def_add(udqp, "WU2OPR", location, {"WOPR", "+", "WOPR"});
UDQDefine def_sub(udqp, "WU2OPR", location, {"WOPR", "-", "WOPR"});
UDQDefine def_mul(udqp, "WU2OPR", location, {"WOPR", "*", "WOPR"});
UDQDefine def_div(udqp, "WU2OPR", location, {"WOPR", "/", "WOPR"});
UDQDefine def_muladd(udqp, "WUX", location, {"WOPR", "+", "WOPR", "*", "WOPR"});
UDQDefine def_wuwct(udqp , "WUWCT", location, {"WWPR", "/", "(", "WOPR", "+", "WWPR", ")"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -1220,9 +1234,10 @@ BOOST_AUTO_TEST_CASE(UDQ_BASIC_MATH_TEST) {
}
BOOST_AUTO_TEST_CASE(DECK_TEST) {
KeywordLocation location;
UDQParams udqp;
UDQFunctionTable udqft(udqp);
UDQDefine def(udqp, "WUOPRL", {"(", "WOPR", "OP1", "-", "150", ")", "*", "0.90"});
UDQDefine def(udqp, "WUOPRL", location, {"(", "WOPR", "OP1", "-", "150", ")", "*", "0.90"});
SummaryState st(std::chrono::system_clock::now());
UDQState udq_state(udqp.undefinedValue());
UDQContext context(udqft, st, udq_state);
@ -1239,11 +1254,12 @@ BOOST_AUTO_TEST_CASE(DECK_TEST) {
BOOST_AUTO_TEST_CASE(UDQPARSE_TEST1) {
KeywordLocation location;
UDQParams udqp;
UDQDefine def1(udqp, "WUBHP", {"1/(WWCT", "'W1*')"});
UDQDefine def1(udqp, "WUBHP", location, {"1/(WWCT", "'W1*')"});
BOOST_CHECK_EQUAL( def1.input_string() , "1/(WWCT 'W1*')");
UDQDefine def2(udqp, "WUBHP", {"2*(1", "+" , "WBHP)"});
UDQDefine def2(udqp, "WUBHP", location, {"2*(1", "+" , "WBHP)"});
BOOST_CHECK_EQUAL( def2.input_string() , "2*(1 + WBHP)");
}
@ -1253,9 +1269,10 @@ BOOST_AUTO_TEST_CASE(UDQ_PARSE_ERROR) {
ParseContext parseContext;
ErrorGuard errors;
std::vector<std::string> tokens = {"WBHP", "+"};
KeywordLocation location;
parseContext.update(ParseContext::UDQ_PARSE_ERROR, InputError::IGNORE);
{
UDQDefine def1(udqp, "WUBHP", tokens, parseContext, errors);
UDQDefine def1(udqp, "WUBHP", location, tokens, parseContext, errors);
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
UDQState udq_state(udqp.undefinedValue());
@ -1267,7 +1284,7 @@ BOOST_AUTO_TEST_CASE(UDQ_PARSE_ERROR) {
}
parseContext.update(ParseContext::UDQ_PARSE_ERROR, InputError::THROW_EXCEPTION);
BOOST_CHECK_THROW( UDQDefine(udqp, "WUBHP", tokens, parseContext, errors), std::invalid_argument);
BOOST_CHECK_THROW( UDQDefine(udqp, "WUBHP", location, tokens, parseContext, errors), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
@ -1276,10 +1293,11 @@ BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
ErrorGuard errors;
std::vector<std::string> tokens1 = {"WBHP", "+", "1"};
std::vector<std::string> tokens2 = {"SUM", "(", "WBHP", ")"};
KeywordLocation location;
parseContext.update(ParseContext::UDQ_TYPE_ERROR, InputError::IGNORE);
{
UDQDefine def1(udqp, "FUBHP", tokens1, parseContext, errors);
UDQDefine def2(udqp, "WUBHP", tokens2, parseContext, errors);
UDQDefine def1(udqp, "FUBHP", location, tokens1, parseContext, errors);
UDQDefine def2(udqp, "WUBHP", location, tokens2, parseContext, errors);
SummaryState st(std::chrono::system_clock::now());
UDQFunctionTable udqft(udqp);
@ -1300,7 +1318,7 @@ BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) {
parseContext.update(ParseContext::UDQ_TYPE_ERROR, InputError::THROW_EXCEPTION);
// This fails because the well expression (WBHP + 1) is assigned to the field variable FUBHP
BOOST_CHECK_THROW( UDQDefine(udqp, "FUBHP", tokens1, parseContext, errors), std::invalid_argument);
BOOST_CHECK_THROW( UDQDefine(udqp, "FUBHP", location, tokens1, parseContext, errors), std::invalid_argument);
}

View File

@ -21,12 +21,6 @@
#include <boost/test/unit_test.hpp>
#include <boost/version.hpp>
#if BOOST_VERSION / 100000 == 1 && BOOST_VERSION / 100 % 1000 < 71
#include <boost/test/output_test_stream.hpp>
#else
#include <boost/test/tools/output_test_stream.hpp>
#endif
#include <opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp>
#include <opm/parser/eclipse/Python/Python.hpp>
@ -445,14 +439,18 @@ BOOST_AUTO_TEST_CASE(WellDims)
// There *should* be errors from dimension checking
BOOST_CHECK(cse.guard);
// Verify that we get expected output from ErrorGuard::dump()
boost::test_tools::output_test_stream output{"expect-wdims.err.out", true};
{
RedirectCERR stream(output.rdbuf());
std::stringstream estream;
RedirectCERR stream(estream.rdbuf());
cse.guard.dump();
const auto error_msg = estream.str();
BOOST_CHECK(output.match_pattern());
for (const auto& s : {"RUNSPEC_NUMWELLS_TOO_LARGE", "item 1",
"RUNSPEC_CONNS_PER_WELL_TOO_LARGE", "item 2",
"RUNSPEC_NUMGROUPS_TOO_LARGE", "item 3",
"RUNSPEC_GROUPSIZE_TOO_LARGE", "item 4"})
BOOST_CHECK( error_msg.find(s) != std::string::npos );
}
}
@ -479,13 +477,15 @@ BOOST_AUTO_TEST_CASE(WellDims_ManyChildGroups)
BOOST_CHECK(cse.guard);
// Verify that we get expected output from ErrorGuard::dump()
boost::test_tools::output_test_stream output{"expect-wdims.chldg.err.out", true};
{
RedirectCERR stream(output.rdbuf());
std::stringstream estream;
RedirectCERR stream(estream.rdbuf());
cse.guard.dump();
const auto error_msg = estream.str();
BOOST_CHECK(output.match_pattern());
for (const auto& s : {"RUNSPEC_GROUPSIZE_TOO_LARGE", "item 4"})
BOOST_CHECK( error_msg.find(s) != std::string::npos );
}
}