Add Facility for Recording ACTIONX Well Structure Changes
This commit adds a new member, well_structure_change, to the SimulatorUpdate structure. The member defaults to 'false', but will be set to 'true' if an ACTIONX block contains at least one of a select group of keywords that affect the model's well topology. In particular, set this member to 'true' if the ACTIONX block has at least one of the keywords - COMPDAT - WELOPEN - WELSPECS This will enable adding simulator logic to open or create wells in the middle of a report step.
This commit is contained in:
@@ -25,23 +25,27 @@
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*
|
||||
This struct is used to communicate back from the Schdule::applyAction() what
|
||||
needs to be updated in the simulator when execution is returned to the
|
||||
simulator code.
|
||||
*/
|
||||
/// This struct is used to communicate back from the Schedule::applyAction()
|
||||
/// what needs to be updated in the simulator when execution is returned to
|
||||
/// the simulator code.
|
||||
|
||||
|
||||
struct SimulatorUpdate {
|
||||
// These wells have been affected by the ACTIONX and the simulator needs to
|
||||
struct SimulatorUpdate
|
||||
{
|
||||
// Wells affected by ACTIONX and for which the simulator needs to
|
||||
// reapply rates and state from the newly updated Schedule object.
|
||||
std::unordered_set<std::string> affected_wells;
|
||||
|
||||
// If one of the transmissibility multiplier keywords has been invoked as an
|
||||
// ACTIONX keyword the simulator needs to recalculate the transmissibility.
|
||||
// If one of the transmissibility multiplier keywords has been invoked
|
||||
// as an ACTIONX keyword the simulator needs to recalculate the
|
||||
// transmissibility.
|
||||
bool tran_update{false};
|
||||
|
||||
/// Whether or not well structure changed in processing an ACTIONX
|
||||
/// block. Typically because of a keyword like WELSPECS, COMPDAT,
|
||||
/// and/or WELOPEN.
|
||||
bool well_structure_changed{false};
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
||||
#endif // SIMULATOR_UPDATE_HPP
|
||||
|
||||
@@ -514,11 +514,11 @@ namespace Opm
|
||||
const bool actionx_mode;
|
||||
const ParseContext& parseContext;
|
||||
ErrorGuard& errors;
|
||||
SimulatorUpdate * sim_update;
|
||||
const std::unordered_map<std::string, double> * target_wellpi;
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor;
|
||||
WelSegsSet *welsegs_wells;
|
||||
std::set<std::string>*compsegs_wells;
|
||||
SimulatorUpdate* sim_update{nullptr};
|
||||
const std::unordered_map<std::string, double>* target_wellpi{nullptr};
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor{nullptr};
|
||||
WelSegsSet* welsegs_wells{nullptr};
|
||||
std::set<std::string>* compsegs_wells{nullptr};
|
||||
const ScheduleGrid& grid;
|
||||
|
||||
/// \param welsegs_wells All wells with a WELSEGS entry for checks.
|
||||
@@ -531,8 +531,8 @@ namespace Opm
|
||||
bool actionx_mode_,
|
||||
const ParseContext& parseContext_,
|
||||
ErrorGuard& errors_,
|
||||
SimulatorUpdate * sim_update_,
|
||||
const std::unordered_map<std::string, double> * target_wellpi_,
|
||||
SimulatorUpdate* sim_update_,
|
||||
const std::unordered_map<std::string, double>* target_wellpi_,
|
||||
std::unordered_map<std::string, double>* wpimult_global_factor_,
|
||||
WelSegsSet* welsegs_wells_,
|
||||
std::set<std::string>* compsegs_wells_)
|
||||
@@ -552,6 +552,7 @@ namespace Opm
|
||||
{}
|
||||
|
||||
void affected_well(const std::string& well_name);
|
||||
void record_well_structure_change();
|
||||
|
||||
/// \brief Mark that the well occured in a WELSEGS keyword
|
||||
void welsegs_handled(const std::string& well_name)
|
||||
|
||||
@@ -213,6 +213,10 @@ namespace {
|
||||
well.updateRefDepth();
|
||||
this->snapshots.back().wells.update( std::move(well));
|
||||
}
|
||||
|
||||
if (! wells.empty()) {
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
}
|
||||
|
||||
void Schedule::handleWELTRAJ(HandlerContext& handlerContext) {
|
||||
@@ -226,6 +230,7 @@ namespace {
|
||||
connections->loadWELTRAJ(record, handlerContext.grid, name, handlerContext.keyword.location());
|
||||
if (well2.updateConnections(connections, handlerContext.grid)) {
|
||||
this->snapshots.back().wells.update( well2 );
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
this->snapshots.back().wellgroup_events().addEvent( name, ScheduleEvents::COMPLETION_CHANGE);
|
||||
const auto& md = connections->getMD();
|
||||
@@ -279,6 +284,10 @@ namespace {
|
||||
well.updateRefDepth();
|
||||
this->snapshots.back().wells.update( std::move(well));
|
||||
}
|
||||
|
||||
if (! wells.empty()) {
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
}
|
||||
|
||||
void Schedule::handleCOMPLUMP(HandlerContext& handlerContext) {
|
||||
@@ -288,8 +297,11 @@ namespace {
|
||||
|
||||
for (const auto& wname : well_names) {
|
||||
auto well = this->snapshots.back().wells.get(wname);
|
||||
if (well.handleCOMPLUMP(record))
|
||||
if (well.handleCOMPLUMP(record)) {
|
||||
this->snapshots.back().wells.update( std::move(well) );
|
||||
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,7 +342,10 @@ 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.record_well_structure_change();
|
||||
}
|
||||
|
||||
handlerContext.compsegs_handled(wname);
|
||||
}
|
||||
@@ -1411,8 +1426,10 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
||||
const auto did_update_well_status =
|
||||
this->updateWellStatus(wname, currentStep, new_well_status);
|
||||
|
||||
if (handlerContext.sim_update) {
|
||||
handlerContext.sim_update->affected_wells.insert(wname);
|
||||
handlerContext.affected_well(wname);
|
||||
|
||||
if (did_update_well_status) {
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
|
||||
if (did_update_well_status && (new_well_status == open)) {
|
||||
@@ -1451,10 +1468,10 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
||||
this->snapshots[currentStep].wells.update( std::move(well) );
|
||||
}
|
||||
|
||||
auto* sim_update = handlerContext.sim_update;
|
||||
if (sim_update)
|
||||
sim_update->affected_wells.insert(wname);
|
||||
this->snapshots.back().events().addEvent( ScheduleEvents::COMPLETION_CHANGE);
|
||||
handlerContext.affected_well(wname);
|
||||
handlerContext.record_well_structure_change();
|
||||
|
||||
this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1537,8 +1554,10 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
|
||||
const auto& wname = record1.getItem("WELL").getTrimmedString(0);
|
||||
if (this->hasWell(wname, handlerContext.currentStep)) {
|
||||
auto well = this->snapshots.back().wells.get(wname);
|
||||
if (well.handleWELSEGS(handlerContext.keyword))
|
||||
if (well.handleWELSEGS(handlerContext.keyword)) {
|
||||
this->snapshots.back().wells.update( std::move(well) );
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
handlerContext.welsegs_handled(wname);
|
||||
} else {
|
||||
const auto& location = handlerContext.keyword.location();
|
||||
@@ -1645,6 +1664,10 @@ Well{0} entered with 'FIELD' parent group:
|
||||
handlerContext.keyword.location(),
|
||||
handlerContext.errors );
|
||||
}
|
||||
|
||||
if (! handlerContext.keyword.empty()) {
|
||||
handlerContext.record_well_structure_change();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1511,7 +1511,12 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
|
||||
}
|
||||
|
||||
|
||||
SimulatorUpdate Schedule::applyAction(std::size_t reportStep, const Action::ActionX& action, const std::vector<std::string>& matching_wells, const std::unordered_map<std::string, double>& target_wellpi) {
|
||||
SimulatorUpdate
|
||||
Schedule::applyAction(std::size_t reportStep,
|
||||
const Action::ActionX& action,
|
||||
const std::vector<std::string>& matching_wells,
|
||||
const std::unordered_map<std::string, double>& target_wellpi)
|
||||
{
|
||||
const std::string prefix = "| ";
|
||||
ParseContext parseContext;
|
||||
ErrorGuard errors;
|
||||
@@ -1519,14 +1524,21 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
|
||||
ScheduleGrid grid(this->completed_cells);
|
||||
|
||||
OpmLog::debug("/----------------------------------------------------------------------");
|
||||
OpmLog::debug(fmt::format("{0}Action {1} triggered. Will add action keywords and\n{0}rerun Schedule section.\n{0}", prefix, action.name()));
|
||||
OpmLog::debug(fmt::format("{0}Action {1} triggered. Will add action "
|
||||
"keywords and\n{0}rerun Schedule section.\n{0}",
|
||||
prefix, action.name()));
|
||||
|
||||
this->snapshots.resize(reportStep + 1);
|
||||
auto& input_block = this->m_sched_deck[reportStep];
|
||||
|
||||
std::unordered_map<std::string, double> wpimult_global_factor;
|
||||
for (const auto& keyword : action) {
|
||||
input_block.push_back(keyword);
|
||||
|
||||
const auto& location = keyword.location();
|
||||
OpmLog::debug(fmt::format("{}Processing keyword {} from {} line {}", prefix, location.keyword, location.filename, location.lineno));
|
||||
OpmLog::debug(fmt::format("{}Processing keyword {} from {} line {}", prefix,
|
||||
location.keyword, location.filename, location.lineno));
|
||||
|
||||
this->handleKeyword(reportStep,
|
||||
input_block,
|
||||
keyword,
|
||||
@@ -1539,12 +1551,20 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
|
||||
&target_wellpi,
|
||||
&wpimult_global_factor);
|
||||
}
|
||||
|
||||
this->applyGlobalWPIMULT(wpimult_global_factor);
|
||||
|
||||
this->end_report(reportStep);
|
||||
if (!sim_update.affected_wells.empty()) {
|
||||
this->snapshots.back().events().addEvent( ScheduleEvents::ACTIONX_WELL_EVENT );
|
||||
for (const auto& well: sim_update.affected_wells)
|
||||
this->snapshots.back().wellgroup_events().addEvent(well, ScheduleEvents::ACTIONX_WELL_EVENT);
|
||||
|
||||
if (! sim_update.affected_wells.empty()) {
|
||||
this->snapshots.back().events()
|
||||
.addEvent(ScheduleEvents::ACTIONX_WELL_EVENT);
|
||||
|
||||
auto& wgEvents = this->snapshots.back().wellgroup_events();
|
||||
|
||||
for (const auto& well: sim_update.affected_wells) {
|
||||
wgEvents.addEvent(well, ScheduleEvents::ACTIONX_WELL_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (reportStep < this->m_sched_deck.size() - 1) {
|
||||
@@ -1553,6 +1573,7 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
|
||||
parseContext, errors, grid, &target_wellpi,
|
||||
prefix, log_to_debug);
|
||||
}
|
||||
|
||||
OpmLog::debug("\\----------------------------------------------------------------------");
|
||||
|
||||
return sim_update;
|
||||
@@ -2326,4 +2347,11 @@ void Schedule::HandlerContext::affected_well(const std::string& well_name)
|
||||
this->sim_update->affected_wells.insert(well_name);
|
||||
}
|
||||
|
||||
void Schedule::HandlerContext::record_well_structure_change()
|
||||
{
|
||||
if (this->sim_update != nullptr) {
|
||||
this->sim_update->well_structure_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user