Merge pull request #2193 from joakim-hove/sched-rerun

Sched rerun
This commit is contained in:
Joakim Hove
2021-01-08 15:15:38 +01:00
committed by GitHub
7 changed files with 168 additions and 40 deletions

View File

@@ -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,
@@ -471,19 +474,17 @@ namespace Opm
const ScheduleBlock& block;
const DeckKeyword& keyword;
const std::size_t currentStep;
const EclipseGrid& grid;
const FieldPropsManager& fieldPropsManager;
const EclipseGrid* grid_ptr;
const FieldPropsManager* fp_ptr;
HandlerContext(const ScheduleBlock& block_,
const DeckKeyword& keyword_,
const std::size_t currentStep_,
const EclipseGrid& grid_,
const FieldPropsManager& fieldPropsManager_) :
const std::size_t currentStep_):
block(block_),
keyword(keyword_),
currentStep(currentStep_),
grid(grid_),
fieldPropsManager(fieldPropsManager_)
grid_ptr(nullptr),
fp_ptr(nullptr)
{}
@@ -507,7 +508,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);

View File

@@ -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;

View File

@@ -58,6 +58,7 @@ namespace Opm {
const PAvg& pavg() const;
void tuning(Tuning tuning);
Tuning& tuning();
const Tuning& tuning() const;
void nupcol(int nupcol);

View File

@@ -143,6 +143,9 @@ namespace {
}
void Schedule::handleCOMPDAT(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
if (!handlerContext.grid_ptr)
throw std::logic_error("BUG: Schedule::handleCOMPDAT() has been called with an invalid grid pointer");
std::unordered_set<std::string> wells;
for (const auto& record : handlerContext.keyword) {
const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0);
@@ -153,8 +156,8 @@ namespace {
for (const auto& name : wellnames) {
auto well2 = std::shared_ptr<Well>(new Well( this->getWell(name, handlerContext.currentStep)));
auto connections = std::shared_ptr<WellConnections>( new WellConnections( well2->getConnections()));
connections->loadCOMPDAT(record, handlerContext.grid, handlerContext.fieldPropsManager, name, handlerContext.keyword.location());
if (well2->updateConnections(connections, handlerContext.currentStep, handlerContext.grid, handlerContext.fieldPropsManager.get_int("PVTNUM"))) {
connections->loadCOMPDAT(record, *handlerContext.grid_ptr, *handlerContext.fp_ptr, name, handlerContext.keyword.location());
if (well2->updateConnections(connections, handlerContext.currentStep, *handlerContext.grid_ptr, handlerContext.fp_ptr->get_int("PVTNUM"))) {
this->updateWell(std::move(well2), handlerContext.currentStep);
wells.insert( name );
}
@@ -213,6 +216,9 @@ namespace {
}
void Schedule::handleCOMPSEGS(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
if (!handlerContext.grid_ptr)
throw std::logic_error("BUG: Schedule::handleCOMPDAT() has been called with an invalid grid pointer");
const auto& record1 = handlerContext.keyword.getRecord(0);
const std::string& well_name = record1.getItem("WELL").getTrimmedString(0);
@@ -228,7 +234,7 @@ namespace {
return;
}
if (well_ptr->handleCOMPSEGS(handlerContext.keyword, handlerContext.currentStep, handlerContext.grid, parseContext, errors))
if (well_ptr->handleCOMPSEGS(handlerContext.keyword, handlerContext.currentStep, *handlerContext.grid_ptr, parseContext, errors))
this->updateWell(std::move(well_ptr), handlerContext.currentStep);
}
@@ -1615,15 +1621,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);
}

View File

@@ -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 = false;
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,
@@ -313,8 +329,22 @@ namespace {
const FieldPropsManager& fp,
std::vector<std::pair<const DeckKeyword*, std::size_t > >& rftProperties) {
HandlerContext handlerContext { block, keyword, currentStep, grid, fp };
static const std::unordered_set<std::string> require_grid = {
"COMPDAT",
"COMPSEGS"
};
HandlerContext handlerContext { block, keyword, currentStep };
/*
The grid and fieldProps members create problems for reiterating the
Schedule section. We therefor single them out very clearly here.
*/
if (require_grid.count(keyword.name()) > 0) {
handlerContext.grid_ptr = &grid;
handlerContext.fp_ptr = &fp;
}
if (handleNormalKeyword(handlerContext, parseContext, errors))
return;
@@ -325,7 +355,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,18 +402,89 @@ private:
}
void Schedule::iterateScheduleSection(std::shared_ptr<const Opm::Python> python,
const std::string& input_path,
const ParseContext& parseContext ,
ErrorGuard& errors,
const EclipseGrid& grid,
const FieldPropsManager& fp) {
void Schedule::iterateScheduleSection(std::optional<std::size_t> load_offset,
const ParseContext& parseContext ,
ErrorGuard& errors,
const EclipseGrid& grid,
const FieldPropsManager& fp) {
std::vector<std::pair< const DeckKeyword* , std::size_t> > rftProperties;
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); };
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 +527,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 +569,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 +599,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 +632,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 +644,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 +1741,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 &&

View File

@@ -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;

View File

@@ -110,4 +110,8 @@ const Tuning& ScheduleState::tuning() const {
return this->m_tuning;
}
Tuning& ScheduleState::tuning() {
return this->m_tuning;
}
}