Changes in restart TimeMap and Schedule::iterateSection
This commit changes two aspects of restarts where well and group information is assembled from the restart file: o We require the restart date to be present in the Schedule file as a DATES keyword. o SKIPREST behavior is implemented unconditionally for restarts with restart files, even if the SKIPREST keyword is not present.
This commit is contained in:
parent
1ae7026a4b
commit
42f1278db3
@ -51,12 +51,12 @@ namespace Opm {
|
||||
double getTotalTime() const;
|
||||
double seconds(size_t timeStep) const;
|
||||
std::size_t restart_offset() const;
|
||||
std::time_t restart_time() const;
|
||||
|
||||
std::time_t operator[] (size_t index) const;
|
||||
/// Return the date and time where a given time step starts.
|
||||
std::time_t getStartTime(size_t tStepIdx) const;
|
||||
std::time_t getEndTime() const;
|
||||
bool skiprest() const;
|
||||
/// Return the period of time in seconds which passed between the start of the simulation and a given point in time.
|
||||
double getTimePassedUntil(size_t tLevelIdx) const;
|
||||
/// Return the length of a given time step in seconds.
|
||||
@ -83,7 +83,6 @@ namespace Opm {
|
||||
serializer(m_timeList);
|
||||
serializer.vector(m_first_timestep_years);
|
||||
serializer.vector(m_first_timestep_months);
|
||||
serializer(m_skiprest);
|
||||
serializer(m_restart_offset);
|
||||
}
|
||||
|
||||
@ -117,8 +116,8 @@ namespace Opm {
|
||||
std::vector<std::time_t> m_timeList;
|
||||
std::vector<StepData> m_first_timestep_years; // A list of the first timestep of every year
|
||||
std::vector<StepData> m_first_timestep_months; // A list of the first timestep of every month
|
||||
bool m_skiprest = false;
|
||||
std::size_t m_restart_offset = 0;
|
||||
std::time_t m_restart_time;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const TimeMap& tm);
|
||||
|
@ -311,15 +311,60 @@ namespace {
|
||||
all.
|
||||
*/
|
||||
std::unordered_set<std::string> skiprest_whitelist = {"VFPPROD", "VFPINJ", "RPTSCHED", "RPTRST", "TUNING", "MESSAGES"};
|
||||
std::size_t currentStep = 0;
|
||||
const auto restart_offset = this->m_timeMap.restart_offset();
|
||||
|
||||
std::size_t currentStep;
|
||||
if (this->m_timeMap.skiprest())
|
||||
currentStep = 0;
|
||||
else
|
||||
currentStep = this->m_timeMap.restart_offset();
|
||||
/*
|
||||
The behavior of variable restart_skip is more lenient than the
|
||||
SKIPREST keyword. If this is a restarted[1] run the loop iterating
|
||||
over keywords will skip the all keywords[2] until DATES keyword with
|
||||
the restart date is encountered - irrespective of whether the SKIPREST
|
||||
keyword is present in the deck or not.
|
||||
|
||||
[1]: opm/flow can restart in a mode where all the keywords from the
|
||||
historical part of the Schedule section is internalized, and only
|
||||
the solution fields are read from the restart file. In this case
|
||||
we will have TimeMap::restart_offset() == 0.
|
||||
|
||||
[2]: With the exception of the keywords in the skiprest_whitelist;
|
||||
these keywords will be assigned to report step 0.
|
||||
*/
|
||||
|
||||
auto restart_skip = restart_offset > 0;
|
||||
while (true) {
|
||||
if (keywordIdx == section.size())
|
||||
break;
|
||||
|
||||
const auto& keyword = section.getKeyword(keywordIdx);
|
||||
if (keyword.name() == "DATES") {
|
||||
checkIfAllConnectionsIsShut(currentStep);
|
||||
for (const auto& record : keyword) {
|
||||
if (restart_skip) {
|
||||
auto deck_time = TimeMap::timeFromEclipse(record);
|
||||
if (deck_time == this->m_timeMap.restart_time()) {
|
||||
restart_skip = false;
|
||||
currentStep = this->m_timeMap.restart_offset();
|
||||
}
|
||||
} else
|
||||
currentStep += 1;
|
||||
}
|
||||
keywordIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keyword.name() == "TSTEP") {
|
||||
checkIfAllConnectionsIsShut(currentStep);
|
||||
currentStep += keyword.getRecord(0).getItem(0).data_size();
|
||||
keywordIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (restart_skip && skiprest_whitelist.count(keyword.name()) == 0) {
|
||||
OpmLog::info("Skipping keyword: " + keyword.name() + " while loading SCHEDULE section");
|
||||
keywordIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keyword.name() == "ACTIONX") {
|
||||
Action::ActionX action(keyword, this->m_timeMap.getStartTime(currentStep));
|
||||
while (true) {
|
||||
@ -334,39 +379,32 @@ namespace {
|
||||
if (Action::ActionX::valid_keyword(action_keyword.name()))
|
||||
action.addKeyword(action_keyword);
|
||||
else {
|
||||
std::string msg = "The keyword {0} is not supported in a ACTIONX block. file: {1} line: {2}";
|
||||
std::string msg_fmt = "The keyword {keyword} is not supported in the ACTIONX block\n"
|
||||
"In {file} line {line}.";
|
||||
parseContext.handleError( ParseContext::ACTIONX_ILLEGAL_KEYWORD, msg, action_keyword.location(), errors);
|
||||
parseContext.handleError( ParseContext::ACTIONX_ILLEGAL_KEYWORD, msg_fmt, action_keyword.location(), errors);
|
||||
}
|
||||
}
|
||||
this->addACTIONX(action, currentStep);
|
||||
keywordIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (keyword.name() == "DATES") {
|
||||
checkIfAllConnectionsIsShut(currentStep);
|
||||
currentStep += keyword.size();
|
||||
}
|
||||
|
||||
else if (keyword.name() == "TSTEP") {
|
||||
checkIfAllConnectionsIsShut(currentStep);
|
||||
currentStep += keyword.getRecord(0).getItem(0).data_size();
|
||||
}
|
||||
|
||||
else {
|
||||
if (currentStep >= this->m_timeMap.restart_offset() || skiprest_whitelist.count(keyword.name()))
|
||||
this->handleKeyword(python, input_path, currentStep, section, keywordIdx, keyword, parseContext, errors, grid, fp, rftProperties);
|
||||
else
|
||||
OpmLog::info("Skipping keyword: " + keyword.name() + " while loading SCHEDULE section");
|
||||
}
|
||||
|
||||
this->handleKeyword(python,
|
||||
input_path,
|
||||
currentStep,
|
||||
section,
|
||||
keywordIdx,
|
||||
keyword,
|
||||
parseContext,
|
||||
errors,
|
||||
grid,
|
||||
fp,
|
||||
rftProperties);
|
||||
keywordIdx++;
|
||||
if (keywordIdx == section.size())
|
||||
break;
|
||||
}
|
||||
|
||||
checkIfAllConnectionsIsShut(currentStep);
|
||||
|
||||
|
||||
for (auto rftPair = rftProperties.begin(); rftPair != rftProperties.end(); ++rftPair) {
|
||||
const DeckKeyword& keyword = *rftPair->first;
|
||||
std::size_t timeStep = rftPair->second;
|
||||
|
@ -85,41 +85,31 @@ namespace {
|
||||
this->m_restart_offset += 1;
|
||||
}
|
||||
|
||||
TimeMap::TimeMap( const Deck& deck, const std::pair<std::time_t, std::size_t>& restart) {
|
||||
bool skiprest = deck.hasKeyword<ParserKeywords::SKIPREST>();
|
||||
{
|
||||
std::time_t start_time;
|
||||
if (deck.hasKeyword("START")) {
|
||||
// Use the 'START' keyword to find out the start date (if the
|
||||
// keyword was specified)
|
||||
const auto& keyword = deck.getKeyword("START");
|
||||
start_time = timeFromEclipse(keyword.getRecord(0));
|
||||
} else {
|
||||
// The default start date is not specified in the Eclipse
|
||||
// reference manual. We hence just assume it is same as for
|
||||
// the START keyword for Eclipse R100, i.e., January 1st,
|
||||
// 1983...
|
||||
start_time = mkdate(1983, 1, 1);
|
||||
}
|
||||
this->init_start(start_time);
|
||||
}
|
||||
|
||||
auto restart_time = restart.first;
|
||||
TimeMap::TimeMap( const Deck& deck, const std::pair<std::time_t, std::size_t>& restart) {
|
||||
std::time_t start_time;
|
||||
if (deck.hasKeyword("START")) {
|
||||
// Use the 'START' keyword to find out the start date (if the
|
||||
// keyword was specified)
|
||||
const auto& keyword = deck.getKeyword("START");
|
||||
start_time = timeFromEclipse(keyword.getRecord(0));
|
||||
} else {
|
||||
// The default start date is not specified in the Eclipse
|
||||
// reference manual. We hence just assume it is same as for
|
||||
// the START keyword for Eclipse R100, i.e., January 1st,
|
||||
// 1983...
|
||||
start_time = mkdate(1983, 1, 1);
|
||||
}
|
||||
this->init_start(start_time);
|
||||
|
||||
this->m_restart_time = restart.first;
|
||||
this->m_restart_offset = restart.second;
|
||||
bool skip = false;
|
||||
|
||||
for (std::size_t it = 1; it < this->m_restart_offset; it++)
|
||||
this->m_timeList.push_back(invalid_time);
|
||||
|
||||
if (this->m_restart_offset > 0) {
|
||||
if (skiprest)
|
||||
skip = true;
|
||||
else {
|
||||
this->m_timeList.push_back(restart_time);
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool skip = (this->m_restart_offset > 0);
|
||||
bool restart_found = false;
|
||||
for( const auto& keyword : SCHEDULESection(deck)) {
|
||||
// We're only interested in "TSTEP" and "DATES" keywords,
|
||||
// so we ignore everything else here...
|
||||
@ -130,11 +120,13 @@ namespace {
|
||||
for (size_t recordIndex = 0; recordIndex < keyword.size(); recordIndex++) {
|
||||
const auto &record = keyword.getRecord(recordIndex);
|
||||
const std::time_t nextTime = TimeMap::timeFromEclipse(record);
|
||||
if (nextTime == restart_time)
|
||||
if (nextTime == this->m_restart_time) {
|
||||
skip = false;
|
||||
restart_found = true;
|
||||
}
|
||||
|
||||
if (!skip)
|
||||
addTime(nextTime);
|
||||
this->addTime(nextTime);
|
||||
}
|
||||
|
||||
continue;
|
||||
@ -143,36 +135,25 @@ namespace {
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
addFromTSTEPKeyword(keyword);
|
||||
this->addFromTSTEPKeyword(keyword);
|
||||
}
|
||||
|
||||
/*
|
||||
There is a coupling between the presence of the SKIPREST keyword and
|
||||
the restart argument: The restart argument indicates whether this is
|
||||
deck should be parsed as restarted deck. If m_restart_offset == 0 we do
|
||||
not interpret this as restart situation and the presence of SKIPREST
|
||||
is ignored. In the opposite case we verify - post loading - that we
|
||||
have actually located the restart date - otherwise "something is
|
||||
broken".
|
||||
It is a hard requirement that the restart date is found as a DATES
|
||||
keyword, although it is technically possible to create a valid
|
||||
restarted case using TSTEP we do not accept that.
|
||||
*/
|
||||
if (this->m_restart_offset != 0) {
|
||||
if (skiprest) {
|
||||
const auto iter = std::find(this->m_timeList.begin(), this->m_timeList.end(), restart_time);
|
||||
if (iter == this->m_timeList.end()) {
|
||||
TimeStampUTC ts(restart_time);
|
||||
throw std::invalid_argument("Could not find restart date " + std::to_string(ts.year()) + "-" + std::to_string(ts.month()) + "-" + std::to_string(ts.day()));
|
||||
}
|
||||
this->m_skiprest = true;
|
||||
}
|
||||
if (this->m_restart_offset != 0 && !restart_found) {
|
||||
TimeStampUTC ts(this->m_restart_time);
|
||||
throw std::invalid_argument("Could not find restart date " + std::to_string(ts.year()) + "-" + std::to_string(ts.month()) + "-" + std::to_string(ts.day()));
|
||||
}
|
||||
}
|
||||
|
||||
TimeMap TimeMap::serializeObject()
|
||||
{
|
||||
TimeMap result({123});
|
||||
result.m_skiprest = true;
|
||||
result.m_restart_offset = 4;
|
||||
|
||||
result.m_restart_time = 19867234;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -229,7 +210,7 @@ namespace {
|
||||
}
|
||||
|
||||
void TimeMap::addTStep(int64_t step) {
|
||||
addTime(forward(m_timeList.back(), step));
|
||||
this->addTime(forward(m_timeList.back(), step));
|
||||
}
|
||||
|
||||
size_t TimeMap::size() const {
|
||||
@ -279,7 +260,7 @@ namespace {
|
||||
|
||||
for (size_t itemIndex = 0; itemIndex < item.data_size(); itemIndex++) {
|
||||
const int64_t seconds = static_cast<int64_t>(item.getSIDouble(itemIndex));
|
||||
addTStep(seconds);
|
||||
this->addTStep(seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -444,10 +425,11 @@ namespace {
|
||||
return this->m_restart_offset;
|
||||
}
|
||||
|
||||
bool TimeMap::skiprest() const {
|
||||
return this->m_skiprest;
|
||||
std::time_t TimeMap::restart_time() const {
|
||||
return this->m_restart_time;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const TimeMap& tm) {
|
||||
std::stringstream ss;
|
||||
ss << "{";
|
||||
|
@ -449,7 +449,14 @@ TSTEP
|
||||
28 31 30 31 30 31 31 30 31 30 31
|
||||
31 28 31 30 31 30 31 31 30 31 30 31
|
||||
31 28 31 30 31 30 31 31 30 31 30 31
|
||||
31 28 31 30 31 30 31 31 30 31 30 31
|
||||
31 /
|
||||
|
||||
DATES
|
||||
28 'FEB' 2019 /
|
||||
/
|
||||
|
||||
TSTEP
|
||||
31 30 31 30 31 31 30 31 30 31
|
||||
31 28 31 30 31 30 31 31 30 31 30 31
|
||||
31 28 31 30 31 30 31 31 30 31 30 31
|
||||
31 28 31 30 31 30 31 31 30 31 30 31
|
||||
|
@ -223,7 +223,6 @@ BOOST_AUTO_TEST_CASE(TimeStepsCorrect) {
|
||||
|
||||
BOOST_CHECK_EQUAL(tmap.getTimeStepLength(8), 6*24*60*60);
|
||||
BOOST_CHECK_EQUAL(tmap.getTimeStepLength(9), 7*24*60*60);
|
||||
BOOST_CHECK(!tmap.skiprest());
|
||||
}
|
||||
|
||||
|
||||
@ -663,7 +662,7 @@ SCHEDULE
|
||||
--/
|
||||
|
||||
DATES
|
||||
1 JUL 2005 /
|
||||
1 JAN 2005 /
|
||||
/
|
||||
|
||||
DATES
|
||||
@ -675,25 +674,10 @@ DATES
|
||||
/
|
||||
)";
|
||||
|
||||
std::string deck_string3 = R"(
|
||||
START
|
||||
1 JAN 2000 /
|
||||
|
||||
RESTART
|
||||
'CASE' 5 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
-- This test does not have SKIPREST
|
||||
|
||||
TSTEP
|
||||
1 1 1 /
|
||||
)";
|
||||
|
||||
Opm::Parser parser;
|
||||
const auto deck1 = parser.parseString(deck_string1);
|
||||
const auto deck2 = parser.parseString(deck_string2);
|
||||
const auto deck3 = parser.parseString(deck_string3);
|
||||
|
||||
// The date 2005-01-02 is not present as a DATES in the deck; invalid input.
|
||||
auto invalid_restart = std::make_pair(Opm::asTimeT(Opm::TimeStampUTC(2005, 1, 2)), 5);
|
||||
@ -706,15 +690,9 @@ TSTEP
|
||||
auto start = tm1[0];
|
||||
BOOST_CHECK_EQUAL(start , Opm::asTimeT(Opm::TimeStampUTC(2000,1,1)));
|
||||
BOOST_CHECK_EQUAL(tm1[5] , Opm::asTimeT(Opm::TimeStampUTC(2005,1,1)));
|
||||
BOOST_CHECK(tm1.skiprest());
|
||||
|
||||
Opm::TimeMap tm2(deck2, valid_restart);
|
||||
BOOST_CHECK_EQUAL(tm2[5], Opm::asTimeT(Opm::TimeStampUTC(2005,1,1)));
|
||||
BOOST_CHECK_EQUAL(tm2[6], Opm::asTimeT(Opm::TimeStampUTC(2005,7,1)));
|
||||
BOOST_CHECK_EQUAL(tm2[6], Opm::asTimeT(Opm::TimeStampUTC(2006,1,1)));
|
||||
|
||||
Opm::TimeMap tm3(deck3, valid_restart);
|
||||
BOOST_CHECK_EQUAL(tm3[5], Opm::asTimeT(Opm::TimeStampUTC(2005,1,1)));
|
||||
BOOST_CHECK_EQUAL(tm3[6], Opm::asTimeT(Opm::TimeStampUTC(2005,1,2)));
|
||||
BOOST_CHECK_EQUAL(tm3[7], Opm::asTimeT(Opm::TimeStampUTC(2005,1,3)));
|
||||
BOOST_CHECK_EQUAL(tm3[8], Opm::asTimeT(Opm::TimeStampUTC(2005,1,4)));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user