Enable rerun of iteration over Schedule keywords

This commit is contained in:
Joakim Hove
2021-01-08 10:03:20 +01:00
parent 248e6a3c8c
commit 77312b1432
7 changed files with 139 additions and 29 deletions
@@ -348,11 +348,13 @@ namespace Opm
} }
unit_system.serializeOp(serializer); unit_system.serializeOp(serializer);
serializer.vector(snapshots); serializer.vector(snapshots);
serializer(this->m_input_path);
} }
private: private:
template<class Key, class Value> using Map2 = std::map<Key,Value>; template<class Key, class Value> using Map2 = std::map<Key,Value>;
std::shared_ptr<const Python> python_handle; std::shared_ptr<const Python> python_handle;
std::string m_input_path;
ScheduleDeck m_sched_deck; ScheduleDeck m_sched_deck;
TimeMap m_timeMap; TimeMap m_timeMap;
WellMap wells_static; WellMap wells_static;
@@ -411,7 +413,10 @@ namespace Opm
void updateUDQActive( std::size_t timeStep, std::shared_ptr<UDQActive> udq ); void updateUDQActive( std::size_t timeStep, std::shared_ptr<UDQActive> udq );
bool updateWellStatus( const std::string& well, std::size_t reportStep, bool runtime, Well::Status status, std::optional<KeywordLocation> = {}); bool updateWellStatus( const std::string& well, std::size_t reportStep, bool runtime, Well::Status status, std::optional<KeywordLocation> = {});
void addWellToGroup( const std::string& group_name, const std::string& well_name , std::size_t timeStep); void addWellToGroup( const std::string& group_name, const std::string& well_name , std::size_t timeStep);
void iterateScheduleSection(std::shared_ptr<const Python> python, const std::string& input_path, const ParseContext& parseContext , ErrorGuard& errors, const EclipseGrid& grid, void iterateScheduleSection(std::optional<std::size_t> load_offset,
const ParseContext& parseContext,
ErrorGuard& errors,
const EclipseGrid& grid,
const FieldPropsManager& fp); const FieldPropsManager& fp);
void addACTIONX(const Action::ActionX& action, std::size_t currentStep); void addACTIONX(const Action::ActionX& action, std::size_t currentStep);
void addGroupToGroup( const std::string& parent_group, const std::string& child_group, std::size_t timeStep); void addGroupToGroup( const std::string& parent_group, const std::string& child_group, std::size_t timeStep);
@@ -421,9 +426,7 @@ namespace Opm
void addWell(const std::string& wellName, const DeckRecord& record, std::size_t timeStep, Connection::Order connection_order); void addWell(const std::string& wellName, const DeckRecord& record, std::size_t timeStep, Connection::Order connection_order);
void checkIfAllConnectionsIsShut(std::size_t currentStep); void checkIfAllConnectionsIsShut(std::size_t currentStep);
void updateUDQ(const DeckKeyword& keyword, std::size_t current_step); void updateUDQ(const DeckKeyword& keyword, std::size_t current_step);
void handleKeyword(std::shared_ptr<const Python> python, void handleKeyword(std::size_t currentStep,
const std::string& input_path,
std::size_t currentStep,
const ScheduleBlock& block, const ScheduleBlock& block,
const DeckKeyword& keyword, const DeckKeyword& keyword,
const ParseContext& parseContext, ErrorGuard& errors, const ParseContext& parseContext, ErrorGuard& errors,
@@ -507,7 +510,7 @@ namespace Opm
bool handleNormalKeyword(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors); bool handleNormalKeyword(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors);
// Keyword Handlers // Keyword Handlers
void handlePYACTION (std::shared_ptr<const Python> python, const std::string& input_path, const DeckKeyword&, std::size_t currentStep); void handlePYACTION(const DeckKeyword&, std::size_t currentStep);
void handleGCONPROD(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors); void handleGCONPROD(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors);
void handleGCONINJE(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors); void handleGCONINJE(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors);
void handleGLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors); void handleGLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors);
@@ -101,6 +101,7 @@ namespace Opm {
std::vector<ScheduleBlock>::const_iterator begin() const; std::vector<ScheduleBlock>::const_iterator begin() const;
std::vector<ScheduleBlock>::const_iterator end() const; std::vector<ScheduleBlock>::const_iterator end() const;
std::size_t size() const; std::size_t size() const;
std::size_t restart_offset() const;
const KeywordLocation& location() const; const KeywordLocation& location() const;
bool operator==(const ScheduleDeck& other) const; bool operator==(const ScheduleDeck& other) const;
@@ -58,6 +58,7 @@ namespace Opm {
const PAvg& pavg() const; const PAvg& pavg() const;
void tuning(Tuning tuning); void tuning(Tuning tuning);
Tuning& tuning();
const Tuning& tuning() const; const Tuning& tuning() const;
void nupcol(int nupcol); void nupcol(int nupcol);
@@ -1615,15 +1615,14 @@ namespace {
} }
void Schedule::handleWSEGITER(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) { void Schedule::handleWSEGITER(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
auto tuning = this->snapshots.back().tuning();
const auto& record = handlerContext.keyword.getRecord(0); const auto& record = handlerContext.keyword.getRecord(0);
auto& tuning = this->snapshots.back().tuning();
tuning.MXWSIT = record.getItem<ParserKeywords::WSEGITER::MAX_WELL_ITERATIONS>().get<int>(0); tuning.MXWSIT = record.getItem<ParserKeywords::WSEGITER::MAX_WELL_ITERATIONS>().get<int>(0);
tuning.WSEG_MAX_RESTART = record.getItem<ParserKeywords::WSEGITER::MAX_TIMES_REDUCED>().get<int>(0); tuning.WSEG_MAX_RESTART = record.getItem<ParserKeywords::WSEGITER::MAX_TIMES_REDUCED>().get<int>(0);
tuning.WSEG_REDUCTION_FACTOR = record.getItem<ParserKeywords::WSEGITER::REDUCTION_FACTOR>().get<double>(0); tuning.WSEG_REDUCTION_FACTOR = record.getItem<ParserKeywords::WSEGITER::REDUCTION_FACTOR>().get<double>(0);
tuning.WSEG_INCREASE_FACTOR = record.getItem<ParserKeywords::WSEGITER::INCREASING_FACTOR>().get<double>(0); tuning.WSEG_INCREASE_FACTOR = record.getItem<ParserKeywords::WSEGITER::INCREASING_FACTOR>().get<double>(0);
this->snapshots.back().tuning(tuning);
m_events.addEvent(ScheduleEvents::TUNING_CHANGE, handlerContext.currentStep); m_events.addEvent(ScheduleEvents::TUNING_CHANGE, handlerContext.currentStep);
} }
@@ -109,6 +109,7 @@ namespace {
const RestartIO::RstState * rst) const RestartIO::RstState * rst)
try : try :
python_handle(python), python_handle(python),
m_input_path(deck.getInputPath()),
m_sched_deck(deck, restart_info(rst) ), m_sched_deck(deck, restart_info(rst) ),
m_timeMap( deck , restart_info( rst )), m_timeMap( deck , restart_info( rst )),
m_events( this->m_timeMap ), m_events( this->m_timeMap ),
@@ -149,12 +150,28 @@ namespace {
applyMESSAGES(keyword, 0); applyMESSAGES(keyword, 0);
} }
this->iterateScheduleSection( python, deck.getInputPath(), parseContext, errors, grid, fp); this->iterateScheduleSection( {}, parseContext, errors, grid, fp);
/* /*
This is temporary "integration test" for the time arguments in the The code in the if (integration_test) { ... } is an enforced
Schedule class. integration test to assert the sanity of the ongoing Schedule
refactoring. At the very latest this should be removed when the
Schedule refactoring is complete.
*/ */
if (this->size() > 0) { const bool integration_test = true;
if (integration_test) {
if (this->size() == 0)
return;
// Verify that we can safely re-iterate over the Schedule section
if (!rst)
this->iterateScheduleSection( 0, parseContext, errors, grid, fp);
else {
auto restart_offset = this->m_sched_deck.restart_offset();
this->iterateScheduleSection( restart_offset, parseContext, errors, grid, fp);
}
// Verify that the time schedule is correct.
for (std::size_t report_step = 0; report_step < this->size() - 1; report_step++) { for (std::size_t report_step = 0; report_step < this->size() - 1; report_step++) {
const auto& this_block = this->m_sched_deck[report_step]; const auto& this_block = this->m_sched_deck[report_step];
if (this_block.start_time() != std::chrono::system_clock::from_time_t(this->m_timeMap[report_step])) { if (this_block.start_time() != std::chrono::system_clock::from_time_t(this->m_timeMap[report_step])) {
@@ -285,6 +302,7 @@ namespace {
result.wellgroup_events = {{"test", Events::serializeObject()}}; result.wellgroup_events = {{"test", Events::serializeObject()}};
result.unit_system = UnitSystem::newFIELD(); result.unit_system = UnitSystem::newFIELD();
result.snapshots = { ScheduleState::serializeObject() }; result.snapshots = { ScheduleState::serializeObject() };
result.m_input_path = "Some/funny/path";
return result; return result;
} }
@@ -302,9 +320,7 @@ namespace {
} }
void Schedule::handleKeyword(std::shared_ptr<const Python> python, void Schedule::handleKeyword(std::size_t currentStep,
const std::string& input_path,
std::size_t currentStep,
const ScheduleBlock& block, const ScheduleBlock& block,
const DeckKeyword& keyword, const DeckKeyword& keyword,
const ParseContext& parseContext, const ParseContext& parseContext,
@@ -325,7 +341,7 @@ namespace {
rftProperties.push_back( std::make_pair( &keyword , currentStep )); rftProperties.push_back( std::make_pair( &keyword , currentStep ));
else if (keyword.name() == "PYACTION") else if (keyword.name() == "PYACTION")
handlePYACTION(python, input_path, keyword, currentStep); handlePYACTION(keyword, currentStep);
} }
namespace { namespace {
@@ -372,18 +388,89 @@ private:
} }
void Schedule::iterateScheduleSection(std::shared_ptr<const Opm::Python> python, void Schedule::iterateScheduleSection(std::optional<std::size_t> load_offset,
const std::string& input_path, const ParseContext& parseContext ,
const ParseContext& parseContext , ErrorGuard& errors,
ErrorGuard& errors, const EclipseGrid& grid,
const EclipseGrid& grid, const FieldPropsManager& fp) {
const FieldPropsManager& fp) {
std::vector<std::pair< const DeckKeyword* , std::size_t> > rftProperties; std::vector<std::pair< const DeckKeyword* , std::size_t> > rftProperties;
std::string time_unit = this->unit_system.name(UnitSystem::measure::time); std::string time_unit = this->unit_system.name(UnitSystem::measure::time);
auto deck_time = [this](double seconds) { return this->unit_system.from_si(UnitSystem::measure::time, seconds); }; auto deck_time = [this](double seconds) { return this->unit_system.from_si(UnitSystem::measure::time, seconds); };
std::string current_file; std::string current_file;
const auto& time_map = this->m_timeMap; const auto& time_map = this->m_timeMap;
/*
The process of transitioning to Schedule model based on ScheduleState
instances is a gradual one. For the keywords which have been converted
to the ScheduleState implementation the iterateScheduleSection()
function can be called repeatedly, whereas for the keywords which have
not yet been converted that is not safe. The old_style_keywords is a
list of keywords which should be ignored when iterateScheduleSection()
is called repeatedly.
*/
std::unordered_set<std::string> old_style_keywords = {
"PYACTION",
"GCONPROD",
"GCONINJE",
"GLIFTOPT",
"WELPI",
"BRANPROP",
"COMPDAT",
"COMPLUMP",
"COMPORD",
"COMPSEGS",
"GCONINJE",
"GCONPROD",
"GCONSALE",
"GCONSUMP",
"GEFAC",
"GLIFTOPT",
"GPMAINT",
"GRUPNET",
"GRUPTREE",
"GUIDERAT",
"LIFTOPT",
"LINCOM",
"MESSAGES",
"MULTFLT",
"MXUNSUPP",
"NODEPROP",
"RPTSCHED",
"UDQ",
"VFPINJ",
"VFPPROD",
"WCONHIST",
"WCONINJE",
"WCONINJH",
"WCONPROD",
"WECON",
"WEFAC",
"WELOPEN",
"WELPI",
"WELSEGS",
"WELSPECS",
"WELTARG",
"WFOAM",
"WGRUPCON",
"WHISTCTL",
"WINJTEMP",
"WLIFTOPT",
"WLIST",
"WPAVEDEP",
"WPIMULT",
"WPMITAB",
"WPOLYMER",
"WSALT",
"WSEGSICD",
"WSEGAICD",
"WSEGVALV",
"WSKPTAB",
"WSOLVENT",
"WTEMP",
"WTEST",
"WTRACER"
};
/* /*
The keywords in the skiprest_whitelist set are loaded from the The keywords in the skiprest_whitelist set are loaded from the
SCHEDULE section even though the SKIPREST keyword is in action. The SCHEDULE section even though the SKIPREST keyword is in action. The
@@ -426,6 +513,12 @@ private:
location.lineno)); location.lineno));
} }
if (load_offset.has_value()) {
if (load_offset.value() < this->m_sched_deck.restart_offset())
throw std::logic_error("BUG: Tried to replay schedule keywords from historical section in restarted run");
this->snapshots.resize( load_offset.value() );
}
for (const auto& block : this->m_sched_deck) { for (const auto& block : this->m_sched_deck) {
std::size_t keyword_index = 0; std::size_t keyword_index = 0;
auto time_type = block.time_type(); auto time_type = block.time_type();
@@ -462,6 +555,11 @@ private:
current_file = location.filename; current_file = location.filename;
} }
if (load_offset.has_value() && old_style_keywords.count(keyword.name()) == 1) {
keyword_index += 1;
continue;
}
if (keyword.name() == "ACTIONX") { if (keyword.name() == "ACTIONX") {
Action::ActionX action(keyword, this->m_timeMap.getStartTime(currentStep)); Action::ActionX action(keyword, this->m_timeMap.getStartTime(currentStep));
while (true) { while (true) {
@@ -487,9 +585,7 @@ private:
} }
logger(fmt::format("Processing keyword {} at line {}", location.keyword, location.lineno)); logger(fmt::format("Processing keyword {} at line {}", location.keyword, location.lineno));
this->handleKeyword(python, this->handleKeyword(currentStep,
input_path,
currentStep,
block, block,
keyword, keyword,
parseContext, parseContext,
@@ -522,8 +618,8 @@ private:
this->m_actions.update(currentStep, new_actions); this->m_actions.update(currentStep, new_actions);
} }
void Schedule::handlePYACTION(std::shared_ptr<const Python> python, const std::string& input_path, const DeckKeyword& keyword, std::size_t currentStep) { void Schedule::handlePYACTION(const DeckKeyword& keyword, std::size_t currentStep) {
if (!python->enabled()) { if (!this->python_handle->enabled()) {
//Must have a real Python instance here - to ensure that IMPORT works //Must have a real Python instance here - to ensure that IMPORT works
const auto& loc = keyword.location(); const auto& loc = keyword.location();
OpmLog::warning("This version of flow is built without support for Python. Keyword PYACTION in file: " + loc.filename + " line: " + std::to_string(loc.lineno) + " is ignored."); OpmLog::warning("This version of flow is built without support for Python. Keyword PYACTION in file: " + loc.filename + " line: " + std::to_string(loc.lineno) + " is ignored.");
@@ -534,12 +630,12 @@ private:
const auto& run_count = Action::PyAction::from_string( keyword.getRecord(0).getItem<ParserKeywords::PYACTION::RUN_COUNT>().get<std::string>(0) ); const auto& run_count = Action::PyAction::from_string( keyword.getRecord(0).getItem<ParserKeywords::PYACTION::RUN_COUNT>().get<std::string>(0) );
const auto& module_arg = keyword.getRecord(1).getItem<ParserKeywords::PYACTION::FILENAME>().get<std::string>(0); const auto& module_arg = keyword.getRecord(1).getItem<ParserKeywords::PYACTION::FILENAME>().get<std::string>(0);
std::string module; std::string module;
if (input_path.empty()) if (this->m_input_path.empty())
module = module_arg; module = module_arg;
else else
module = input_path + "/" + module_arg; module = this->m_input_path + "/" + module_arg;
Action::PyAction pyaction(python, name, run_count, module); Action::PyAction pyaction(this->python_handle, name, run_count, module);
auto new_actions = std::make_shared<Action::Actions>( this->actions(currentStep) ); auto new_actions = std::make_shared<Action::Actions>( this->actions(currentStep) );
new_actions->add(pyaction); new_actions->add(pyaction);
this->m_actions.update(currentStep, new_actions); this->m_actions.update(currentStep, new_actions);
@@ -1631,6 +1727,7 @@ private:
}; };
return this->m_timeMap == data.m_timeMap && return this->m_timeMap == data.m_timeMap &&
this->m_input_path == data.m_input_path &&
compareMap(this->wells_static, data.wells_static) && compareMap(this->wells_static, data.wells_static) &&
compareMap(this->groups, data.groups) && compareMap(this->groups, data.groups) &&
this->m_events == data.m_events && this->m_events == data.m_events &&
@@ -121,6 +121,11 @@ const KeywordLocation& ScheduleDeck::location() const {
} }
std::size_t ScheduleDeck::restart_offset() const {
return this->m_restart_offset;
}
ScheduleDeck::ScheduleDeck(const Deck& deck, const std::pair<std::time_t, std::size_t>& restart) { ScheduleDeck::ScheduleDeck(const Deck& deck, const std::pair<std::time_t, std::size_t>& restart) {
const std::unordered_set<std::string> skiprest_include = {"VFPPROD", "VFPINJ", "RPTSCHED", "RPTRST", "TUNING", "MESSAGES"}; const std::unordered_set<std::string> skiprest_include = {"VFPPROD", "VFPINJ", "RPTSCHED", "RPTRST", "TUNING", "MESSAGES"};
std::chrono::system_clock::time_point start_time; std::chrono::system_clock::time_point start_time;
@@ -110,4 +110,8 @@ const Tuning& ScheduleState::tuning() const {
return this->m_tuning; return this->m_tuning;
} }
Tuning& ScheduleState::tuning() {
return this->m_tuning;
}
} }