Abort parser if COMPSEGS is missing for multisegment well.
This might not be 100% perfect but it will detect completely missing COMPSEGS keywords for multisegment wells already during file parsing instead of during the simulation at the report step where the problem occurs (could be rather late). Hence it improves OPM/opm-simulators#4329. We keep track of all the wells that appear in WELSEGS and COMPSEGS and at the end of each report step parsed, we check that there is entry using COMPSEGS for each well that was in WELSEGS. Note that the keyword used for the error is the last one in the report step, which is a bit misleading. Error message looks like: ``` Error: Problem with keyword WCONPROD In /tmp/MSW-3D-03.DATA line 2462 Missing COMPSEGS keyword for well PROD01 between <memory string> line 0 and /tmp/MSW-3D-03.DATA line 2462. Error: Unrecoverable errors while loading input: Problem with keyword WCONPROD In /tmp/MSW-3D-03.DATA line 2462 Missing COMPSEGS keyword for well PROD01 between <memory string> line 0 and /tmp/MSW-3D-03.DATA line 2462. ```
This commit is contained in:
@@ -499,8 +499,11 @@ namespace Opm
|
||||
SimulatorUpdate * sim_update;
|
||||
const std::unordered_map<std::string, double> * target_wellpi;
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor;
|
||||
std::set<std::string> *welsegs_wells, *compsegs_wells;
|
||||
const ScheduleGrid& grid;
|
||||
|
||||
/// \param welsegs_wells All wells with a WELSEGS entry for checks.
|
||||
/// \param compegs_wells All wells with a COMPSEGS entry for checks.
|
||||
HandlerContext(const ScheduleBlock& block_,
|
||||
const DeckKeyword& keyword_,
|
||||
const ScheduleGrid& grid_,
|
||||
@@ -511,7 +514,9 @@ namespace Opm
|
||||
ErrorGuard& errors_,
|
||||
SimulatorUpdate * sim_update_,
|
||||
const std::unordered_map<std::string, double> * target_wellpi_,
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor_)
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor_,
|
||||
std::set<std::string>* welsegs_wells_,
|
||||
std::set<std::string>* compsegs_wells_)
|
||||
: block(block_)
|
||||
, keyword(keyword_)
|
||||
, currentStep(currentStep_)
|
||||
@@ -522,6 +527,8 @@ namespace Opm
|
||||
, sim_update(sim_update_)
|
||||
, target_wellpi(target_wellpi_)
|
||||
, wpimult_global_factor(wpimult_global_factor_)
|
||||
, welsegs_wells(welsegs_wells_)
|
||||
, compsegs_wells(compsegs_wells_)
|
||||
, grid(grid_)
|
||||
{}
|
||||
|
||||
@@ -530,6 +537,20 @@ namespace Opm
|
||||
this->sim_update->affected_wells.insert(well_name);
|
||||
}
|
||||
|
||||
/// \brief Mark that the well occured in a WELSEGS keyword
|
||||
void welsegs_handled(const std::string& well_name)
|
||||
{
|
||||
if (welsegs_wells)
|
||||
welsegs_wells->insert(well_name);
|
||||
}
|
||||
|
||||
/// \brief Mark that the well occured in a COMPSEGS keyword
|
||||
void compsegs_handled(const std::string& well_name)
|
||||
{
|
||||
if (compsegs_wells)
|
||||
compsegs_wells->insert(well_name);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Please update the member functions
|
||||
@@ -586,6 +607,8 @@ namespace Opm
|
||||
void addWell(const std::string& wellName, const DeckRecord& record, std::size_t timeStep, Connection::Order connection_order);
|
||||
void checkIfAllConnectionsIsShut(std::size_t currentStep);
|
||||
void end_report(std::size_t report_step);
|
||||
/// \param welsegs_wells All wells with a WELSEGS entry for checks.
|
||||
/// \param compegs_wells All wells with a COMPSEGS entry for checks.
|
||||
void handleKeyword(std::size_t currentStep,
|
||||
const ScheduleBlock& block,
|
||||
const DeckKeyword& keyword,
|
||||
@@ -596,7 +619,9 @@ namespace Opm
|
||||
bool actionx_mode,
|
||||
SimulatorUpdate* sim_update,
|
||||
const std::unordered_map<std::string, double>* target_wellpi,
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor = nullptr);
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor = nullptr,
|
||||
std::set<std::string>* welsegs_wells = nullptr,
|
||||
std::set<std::string>* compsegs_wells = nullptr);
|
||||
|
||||
void prefetch_cell_properties(const ScheduleGrid& grid, const DeckKeyword& keyword);
|
||||
void store_wgnames(const DeckKeyword& keyword);
|
||||
|
||||
@@ -229,6 +229,8 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
||||
|
||||
if (well.handleCOMPSEGS(handlerContext.keyword, handlerContext.grid, handlerContext.parseContext, handlerContext.errors))
|
||||
this->snapshots.back().wells.update( std::move(well) );
|
||||
|
||||
handlerContext.compsegs_handled(wname);
|
||||
}
|
||||
|
||||
void Schedule::handleDRSDT(HandlerContext& handlerContext) {
|
||||
@@ -1390,6 +1392,7 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
||||
auto well = this->snapshots.back().wells.get(wname);
|
||||
if (well.handleWELSEGS(handlerContext.keyword))
|
||||
this->snapshots.back().wells.update( std::move(well) );
|
||||
handlerContext.welsegs_handled(wname);
|
||||
} else {
|
||||
const auto& location = handlerContext.keyword.location();
|
||||
if (this->action_wgnames.has_well(wname)) {
|
||||
|
||||
@@ -324,7 +324,9 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const std::optional
|
||||
bool actionx_mode,
|
||||
SimulatorUpdate* sim_update,
|
||||
const std::unordered_map<std::string, double>* target_wellpi,
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor)
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor,
|
||||
std::set<std::string>* welsegs_wells,
|
||||
std::set<std::string>* compsegs_wells)
|
||||
{
|
||||
|
||||
static const std::unordered_set<std::string> require_grid = {
|
||||
@@ -333,8 +335,9 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const std::optional
|
||||
};
|
||||
|
||||
|
||||
HandlerContext handlerContext { block, keyword, grid, currentStep, matching_wells, actionx_mode, parseContext, errors, sim_update, target_wellpi,
|
||||
wpimult_global_factor};
|
||||
HandlerContext handlerContext { block, keyword, grid, currentStep, matching_wells, actionx_mode,
|
||||
parseContext, errors, sim_update, target_wellpi,
|
||||
wpimult_global_factor, welsegs_wells, compsegs_wells};
|
||||
/*
|
||||
The grid and fieldProps members create problems for reiterating the
|
||||
Schedule section. We therefor single them out very clearly here.
|
||||
@@ -472,7 +475,43 @@ private:
|
||||
return ScheduleLogger::Stream::Info;
|
||||
}
|
||||
}
|
||||
} // end namespace Opm
|
||||
|
||||
namespace
|
||||
{
|
||||
/// \brief Check whether each MS well has COMPSEGS entry andissue error if not.
|
||||
/// \param welsegs All wells with a WELSEGS entry
|
||||
/// \param compegs All wells with a COMPSEGS entry
|
||||
/// \param block_location location where recent DATES/TSTEP started
|
||||
/// \param last_location Last location red in this block
|
||||
void check_compsegs_consistency(std::set<std::string>& welsegs, std::set<std::string>& compsegs,
|
||||
const Opm::KeywordLocation& block_location,
|
||||
const Opm::KeywordLocation& last_location)
|
||||
{
|
||||
std::vector<std::string> difference;
|
||||
difference.reserve(welsegs.size());
|
||||
std::set_difference(welsegs.begin(), welsegs.end(),
|
||||
compsegs.begin(), compsegs.end(),
|
||||
std::back_inserter(difference));
|
||||
if (difference.size()) {
|
||||
std::string wells = "well";
|
||||
if (difference.size()>1) {
|
||||
wells.append("s");
|
||||
}
|
||||
|
||||
for(const auto& missing_wells: difference) {
|
||||
wells.append(" "+missing_wells);
|
||||
}
|
||||
auto msg = fmt::format("Missing COMPSEGS keyword for {} between {} line {} and {} line {}.", wells,
|
||||
block_location.filename, block_location.lineno,
|
||||
last_location.filename, last_location.lineno);
|
||||
throw Opm::OpmInputError(msg, last_location);
|
||||
}
|
||||
}
|
||||
}// end anonymous namespace
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_end,
|
||||
const ParseContext& parseContext,
|
||||
ErrorGuard& errors,
|
||||
@@ -529,6 +568,8 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
|
||||
location.lineno));
|
||||
}
|
||||
|
||||
std::set<std::string> welsegs_wells, compsegs_wells;
|
||||
|
||||
for (auto report_step = load_start; report_step < load_end; report_step++) {
|
||||
std::size_t keyword_index = 0;
|
||||
auto& block = this->m_sched_deck[report_step];
|
||||
@@ -558,13 +599,16 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
|
||||
this->create_next(block);
|
||||
|
||||
std::unordered_map<std::string, double> wpimult_global_factor;
|
||||
|
||||
auto last_location = block.location();
|
||||
|
||||
while (true) {
|
||||
if (keyword_index == block.size())
|
||||
break;
|
||||
|
||||
const auto& keyword = block[keyword_index];
|
||||
const auto& location = keyword.location();
|
||||
logger.location(keyword.location());
|
||||
logger.location(location);
|
||||
|
||||
if (keyword.is<ParserKeywords::ACTIONX>()) {
|
||||
Action::ActionX action(keyword,
|
||||
@@ -588,6 +632,7 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
|
||||
std::string msg_fmt = fmt::format("The keyword {} is not supported in the ACTIONX block", action_keyword.name());
|
||||
parseContext.handleError( ParseContext::ACTIONX_ILLEGAL_KEYWORD, msg_fmt, action_keyword.location(), errors);
|
||||
}
|
||||
last_location = action_keyword.location();
|
||||
}
|
||||
this->addACTIONX(action);
|
||||
keyword_index++;
|
||||
@@ -605,10 +650,14 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
|
||||
false,
|
||||
nullptr,
|
||||
target_wellpi,
|
||||
&wpimult_global_factor);
|
||||
&wpimult_global_factor,
|
||||
&welsegs_wells,
|
||||
&compsegs_wells);
|
||||
last_location = location;
|
||||
keyword_index++;
|
||||
}
|
||||
|
||||
check_compsegs_consistency(welsegs_wells, compsegs_wells, block.location(), last_location);
|
||||
this->applyGlobalWPIMULT(wpimult_global_factor);
|
||||
this->end_report(report_step);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user