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);
serializer.vector(snapshots);
serializer(this->m_input_path);
}
private:
template<class Key, class Value> using Map2 = std::map<Key,Value>;
std::shared_ptr<const Python> python_handle;
std::string m_input_path;
ScheduleDeck m_sched_deck;
TimeMap m_timeMap;
WellMap wells_static;
@@ -411,7 +413,10 @@ namespace Opm
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> = {});
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);
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);
@@ -421,9 +426,7 @@ 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 updateUDQ(const DeckKeyword& keyword, std::size_t current_step);
void handleKeyword(std::shared_ptr<const Python> python,
const std::string& input_path,
std::size_t currentStep,
void handleKeyword(std::size_t currentStep,
const ScheduleBlock& block,
const DeckKeyword& keyword,
const ParseContext& parseContext, ErrorGuard& errors,
@@ -507,7 +510,7 @@ namespace Opm
bool handleNormalKeyword(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors);
// 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 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);
@@ -101,6 +101,7 @@ namespace Opm {
std::vector<ScheduleBlock>::const_iterator begin() const;
std::vector<ScheduleBlock>::const_iterator end() const;
std::size_t size() const;
std::size_t restart_offset() const;
const KeywordLocation& location() const;
bool operator==(const ScheduleDeck& other) const;
@@ -58,6 +58,7 @@ namespace Opm {
const PAvg& pavg() const;
void tuning(Tuning tuning);
Tuning& tuning();
const Tuning& tuning() const;
void nupcol(int nupcol);
@@ -1615,15 +1615,14 @@ namespace {
}
void Schedule::handleWSEGITER(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
auto tuning = this->snapshots.back().tuning();
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.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_INCREASE_FACTOR = record.getItem<ParserKeywords::WSEGITER::INCREASING_FACTOR>().get<double>(0);
this->snapshots.back().tuning(tuning);
m_events.addEvent(ScheduleEvents::TUNING_CHANGE, handlerContext.currentStep);
}
@@ -109,6 +109,7 @@ namespace {
const RestartIO::RstState * rst)
try :
python_handle(python),
m_input_path(deck.getInputPath()),
m_sched_deck(deck, restart_info(rst) ),
m_timeMap( deck , restart_info( rst )),
m_events( this->m_timeMap ),
@@ -149,12 +150,28 @@ namespace {
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
Schedule class.
The code in the if (integration_test) { ... } is an enforced
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++) {
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])) {
@@ -285,6 +302,7 @@ namespace {
result.wellgroup_events = {{"test", Events::serializeObject()}};
result.unit_system = UnitSystem::newFIELD();
result.snapshots = { ScheduleState::serializeObject() };
result.m_input_path = "Some/funny/path";
return result;
}
@@ -302,9 +320,7 @@ namespace {
}
void Schedule::handleKeyword(std::shared_ptr<const Python> python,
const std::string& input_path,
std::size_t currentStep,
void Schedule::handleKeyword(std::size_t currentStep,
const ScheduleBlock& block,
const DeckKeyword& keyword,
const ParseContext& parseContext,
@@ -325,7 +341,7 @@ namespace {
rftProperties.push_back( std::make_pair( &keyword , currentStep ));
else if (keyword.name() == "PYACTION")
handlePYACTION(python, input_path, keyword, currentStep);
handlePYACTION(keyword, currentStep);
}
namespace {
@@ -372,8 +388,7 @@ private:
}
void Schedule::iterateScheduleSection(std::shared_ptr<const Opm::Python> python,
const std::string& input_path,
void Schedule::iterateScheduleSection(std::optional<std::size_t> load_offset,
const ParseContext& parseContext ,
ErrorGuard& errors,
const EclipseGrid& grid,
@@ -384,6 +399,78 @@ private:
auto deck_time = [this](double seconds) { return this->unit_system.from_si(UnitSystem::measure::time, seconds); };
std::string current_file;
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
SCHEDULE section even though the SKIPREST keyword is in action. The
@@ -426,6 +513,12 @@ private:
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) {
std::size_t keyword_index = 0;
auto time_type = block.time_type();
@@ -462,6 +555,11 @@ private:
current_file = location.filename;
}
if (load_offset.has_value() && old_style_keywords.count(keyword.name()) == 1) {
keyword_index += 1;
continue;
}
if (keyword.name() == "ACTIONX") {
Action::ActionX action(keyword, this->m_timeMap.getStartTime(currentStep));
while (true) {
@@ -487,9 +585,7 @@ private:
}
logger(fmt::format("Processing keyword {} at line {}", location.keyword, location.lineno));
this->handleKeyword(python,
input_path,
currentStep,
this->handleKeyword(currentStep,
block,
keyword,
parseContext,
@@ -522,8 +618,8 @@ private:
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) {
if (!python->enabled()) {
void Schedule::handlePYACTION(const DeckKeyword& keyword, std::size_t currentStep) {
if (!this->python_handle->enabled()) {
//Must have a real Python instance here - to ensure that IMPORT works
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.");
@@ -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& module_arg = keyword.getRecord(1).getItem<ParserKeywords::PYACTION::FILENAME>().get<std::string>(0);
std::string module;
if (input_path.empty())
if (this->m_input_path.empty())
module = module_arg;
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) );
new_actions->add(pyaction);
this->m_actions.update(currentStep, new_actions);
@@ -1631,6 +1727,7 @@ private:
};
return this->m_timeMap == data.m_timeMap &&
this->m_input_path == data.m_input_path &&
compareMap(this->wells_static, data.wells_static) &&
compareMap(this->groups, data.groups) &&
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) {
const std::unordered_set<std::string> skiprest_include = {"VFPPROD", "VFPINJ", "RPTSCHED", "RPTRST", "TUNING", "MESSAGES"};
std::chrono::system_clock::time_point start_time;
@@ -110,4 +110,8 @@ const Tuning& ScheduleState::tuning() const {
return this->m_tuning;
}
Tuning& ScheduleState::tuning() {
return this->m_tuning;
}
}