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:
Joakim Hove 2020-09-29 22:01:24 +02:00
parent 1ae7026a4b
commit 42f1278db3
5 changed files with 113 additions and 109 deletions

View File

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

View File

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

View File

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

View File

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

View File

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