Allow restart date to be at a TSTEP

This commit is contained in:
Joakim Hove 2020-10-21 17:22:18 +02:00
parent cab2e29724
commit 70353f496d
3 changed files with 165 additions and 37 deletions

View File

@ -36,6 +36,8 @@ namespace Opm {
class Deck;
class DeckKeyword;
class DeckRecord;
class KeywordLocation;
class TimeMapContext;
class TimeMap {
public:
@ -108,9 +110,8 @@ namespace Opm {
bool isTimestepInFreqSequence (size_t timestep, size_t start_timestep, size_t frequency, bool years) const;
size_t closest(const std::vector<size_t> & vec, size_t value) const;
void addTStep(int64_t step);
void addTime(std::time_t newTime);
void addFromTSTEPKeyword( const DeckKeyword& TSTEPKeyword );
void addTime(std::time_t newTime, TimeMapContext& context, const KeywordLocation& location);
void addFromTSTEPKeyword( const DeckKeyword& TSTEPKeyword, TimeMapContext& context);
void init_start(std::time_t start_time);
std::vector<std::time_t> m_timeList;

View File

@ -28,6 +28,7 @@
#include <opm/common/utility/TimeService.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/utility/OpmInputError.hpp>
@ -44,6 +45,8 @@ constexpr const std::time_t invalid_time = -1;
namespace Opm {
namespace {
const std::map<std::string, int> month_indices = {{"JAN", 1},
{"FEB", 2},
@ -62,8 +65,21 @@ namespace {
{"DEC", 12},
{"DES", 12}};
}
struct TimeMapContext {
bool rst_skip;
std::time_t last_time;
TimeMapContext(bool skip, std::time_t t) :
rst_skip(skip),
last_time(t)
{}
};
void TimeMap::init_start(std::time_t start_time) {
auto timestamp = TimeStampUTC{start_time};
@ -77,6 +93,7 @@ namespace {
if (time_points.empty())
throw std::invalid_argument("Can not initialize with empty list of time points");
TimeMapContext context(false, time_points[0]);
this->init_start(time_points[0]);
for (std::size_t ti = 1; ti < time_points.size(); ti++) {
if (time_points[ti] == invalid_time) {
@ -84,7 +101,7 @@ namespace {
this->m_restart_offset += 1;
}
else
this->addTime( time_points[ti] );
this->addTime( time_points[ti], context, {} );
}
if (this->m_restart_offset > 0)
this->m_restart_offset += 1;
@ -113,8 +130,7 @@ namespace {
for (std::size_t it = 1; it < this->m_restart_offset; it++)
this->m_timeList.push_back(invalid_time);
bool skip = (this->m_restart_offset > 0);
bool restart_found = false;
TimeMapContext context(this->m_restart_offset > 0, start_time);
for( const auto& keyword : SCHEDULESection(deck)) {
// We're only interested in "TSTEP" and "DATES" keywords,
// so we ignore everything else here...
@ -134,32 +150,11 @@ namespace {
std::throw_with_nested(opm_error);
}
if (nextTime == this->m_restart_time) {
skip = false;
restart_found = true;
}
if (!skip)
this->addTime(nextTime);
this->addTime(nextTime, context, keyword.location());
}
continue;
}
if (skip)
continue;
this->addFromTSTEPKeyword(keyword);
}
/*
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 && !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()));
this->addFromTSTEPKeyword(keyword, context);
}
}
@ -199,7 +194,22 @@ namespace {
this->m_timeList.front());
}
void TimeMap::addTime(std::time_t newTime) {
void TimeMap::addTime(std::time_t newTime, TimeMapContext& context, const KeywordLocation& location) {
context.last_time = newTime;
if (context.rst_skip) {
if (newTime < this->m_restart_time)
return;
if (newTime == this->m_restart_time)
context.rst_skip = false;
if (newTime > this->m_restart_time) {
TimeStampUTC ts(this->m_restart_time);
auto reason = fmt::format("Have scanned past restart data: {:4d}-{:02d}-{:02d}", ts.year(), ts.month(), ts.day());
throw OpmInputError(reason, location);
}
}
const std::time_t lastTime = m_timeList.back();
const size_t step = m_timeList.size();
if (newTime > lastTime) {
@ -223,10 +233,6 @@ namespace {
throw std::invalid_argument("Times added must be in strictly increasing order.");
}
void TimeMap::addTStep(int64_t step) {
this->addTime(forward(m_timeList.back(), step));
}
size_t TimeMap::size() const {
return m_timeList.size();
}
@ -266,7 +272,7 @@ namespace {
}
void TimeMap::addFromTSTEPKeyword(const DeckKeyword &TSTEPKeyword) {
void TimeMap::addFromTSTEPKeyword(const DeckKeyword &TSTEPKeyword, TimeMapContext& context) {
if (TSTEPKeyword.name() != "TSTEP")
throw std::invalid_argument("Method requires TSTEP keyword input.");
{
@ -274,7 +280,8 @@ namespace {
for (size_t itemIndex = 0; itemIndex < item.data_size(); itemIndex++) {
const int64_t seconds = static_cast<int64_t>(item.getSIDouble(itemIndex));
this->addTStep(seconds);
std::time_t next_time = TimeMap::forward(context.last_time, seconds);
this->addTime(next_time, context, TSTEPKeyword.location());
}
}
}

View File

@ -683,7 +683,7 @@ DATES
auto invalid_restart = std::make_pair(Opm::asTimeT(Opm::TimeStampUTC(2005, 1, 2)), 5);
auto valid_restart = std::make_pair(Opm::asTimeT(Opm::TimeStampUTC(2005, 1, 1)), 5);
BOOST_CHECK_THROW( Opm::TimeMap(deck1, invalid_restart) , std::invalid_argument);
BOOST_CHECK_THROW( Opm::TimeMap(deck1, invalid_restart) , std::exception);
Opm::TimeMap tm1(deck1, valid_restart);
BOOST_CHECK_THROW( tm1[1], std::invalid_argument );
BOOST_CHECK_THROW( tm1[4], std::invalid_argument );
@ -696,3 +696,123 @@ DATES
BOOST_CHECK_EQUAL(tm2[6], Opm::asTimeT(Opm::TimeStampUTC(2006,1,1)));
}
BOOST_AUTO_TEST_CASE(RESTART2) {
std::string deck_string1 = R"(
START
1 JAN 2000 /
RESTART
'CASE' 5 /
SCHEDULE
DATES
1 JAN 2001 /
1 JAN 2002 /
1 JAN 2003 /
1 JAN 2004 / -- 4
/
DATES -- Report step 5
1 JAN 2005 /
/
DATES
1 JAN 2006 / -- 6
1 JAN 2007 / -- 7
1 JAN 2008 / -- 8
1 JAN 2009 / -- 9
1 JAN 2010 / -- 10
/
)";
std::string deck_string2 = R"(
START
1 JAN 2000 /
RESTART
'CASE' 5 /
SCHEDULE
DATES
1 JAN 2001 /
1 JAN 2002 /
1 JAN 2004 / -- 3
/
DATES -- Report step 4
1 JAN 2005 /
/
TSTEP
1 / -- <- Restart from here 5
DATES
1 JAN 2006 / -- 6
1 JAN 2007 / -- 7
1 JAN 2008 / -- 8
1 JAN 2009 / -- 9
1 JAN 2010 / -- 10
/
)";
std::string deck_string3 = R"(
START
1 JAN 2000 /
RESTART
'CASE' 5 /
SCHEDULE
DATES
1 JAN 2001 /
1 JAN 2002 /
1 JAN 2004 / -- 3
/
DATES -- Report step 4
1 JAN 2005 /
/
TSTEP
1 / -- <- Restart from here 5
)";
std::string deck_string4 = R"(
START
1 JAN 2000 /
RESTART
'CASE' 5 /
SCHEDULE
DATES
1 JAN 2001 /
1 JAN 2002 /
1 JAN 2004 / -- 3
/
DATES -- Report step 4
1 JAN 2005 /
/
TSTEP
2 / -- <- Restart from here 5
)";
Opm::Parser parser;
const auto deck1 = parser.parseString(deck_string1);
const auto deck2 = parser.parseString(deck_string2);
const auto deck3 = parser.parseString(deck_string3);
const auto deck4 = parser.parseString(deck_string4);
auto restart = std::make_pair(Opm::asTimeT(Opm::TimeStampUTC(2005, 1, 2)), 5);
BOOST_CHECK_THROW( Opm::TimeMap(deck1, restart) , std::exception);
BOOST_CHECK_NO_THROW( Opm::TimeMap(deck2, restart) );
BOOST_CHECK_NO_THROW( Opm::TimeMap(deck3, restart) );
BOOST_CHECK_THROW( Opm::TimeMap(deck4, restart) , std::exception);
}