@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user