Pass restart info to TimeMap constructor

This commit is contained in:
Joakim Hove
2020-01-23 09:15:51 +01:00
parent 0ba3a65d16
commit db8ded1f09
3 changed files with 212 additions and 52 deletions

View File

@@ -26,6 +26,7 @@
#include <vector>
#include <ctime>
#include <map>
#include <utility>
#include <stddef.h>
@@ -38,7 +39,7 @@ namespace Opm {
class TimeMap {
public:
TimeMap() = default;
explicit TimeMap(const Deck& deck);
explicit TimeMap(const Deck& deck, const std::pair<std::time_t, std::size_t>& restart = std::make_pair(std::time_t{0}, std::size_t{0}));
explicit TimeMap(const std::vector<std::time_t>& time_points);
size_t size() const;
@@ -83,17 +84,17 @@ namespace Opm {
}
};
std::vector<std::time_t> m_timeList;
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 addFromDATESKeyword( const DeckKeyword& DATESKeyword );
void addFromTSTEPKeyword( const DeckKeyword& TSTEPKeyword );
void init_start(std::time_t start_time);
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
std::size_t restart_offset = 0;
};
}

View File

@@ -22,12 +22,17 @@
#include <opm/common/utility/TimeService.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
constexpr const std::time_t invalid_time = -1;
namespace Opm {
namespace {
@@ -49,52 +54,108 @@ namespace {
{"DES", 12}};
}
void TimeMap::init_start(std::time_t start_time) {
auto timestamp = TimeStampUTC{start_time};
this->m_timeList.push_back(start_time);
this->m_first_timestep_months.push_back({0, timestamp});
this->m_first_timestep_years.push_back({0, timestamp});
}
TimeMap::TimeMap(const std::vector<std::time_t>& time_points) {
if (time_points.empty())
throw std::invalid_argument("Can not initialize with empty list of time points");
this->m_timeList.push_back(time_points[0]);
m_first_timestep_months.push_back({0, TimeStampUTC{time_points[0]}});
m_first_timestep_years.push_back({0, TimeStampUTC{time_points[0]}});
for (std::size_t ti = 1; ti < time_points.size(); ti++)
this->addTime( time_points[ti] );
this->init_start(time_points[0]);
for (std::size_t ti = 1; ti < time_points.size(); ti++) {
if (time_points[ti] == invalid_time) {
this->m_timeList.push_back(invalid_time);
this->restart_offset += 1;
}
else
this->addTime( time_points[ti] );
}
if (this->restart_offset > 0)
this->restart_offset += 1;
}
TimeMap::TimeMap( const Deck& deck) {
std::time_t 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");
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...
time = mkdate(1983, 1, 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;
this->restart_offset = restart.second;
bool skip = false;
for (std::size_t it = 1; it < this->restart_offset; it++)
this->m_timeList.push_back(invalid_time);
if (this->restart_offset > 0) {
if (skiprest)
skip = true;
else {
this->m_timeList.push_back(restart_time);
skip = false;
}
}
m_timeList.push_back(time);
auto timestamp = TimeStampUTC{time};
m_first_timestep_months.push_back({0, timestamp});
m_first_timestep_years.push_back({0, timestamp});
// find all "TSTEP" and "DATES" keywords in the deck and deal
// with them one after another
for( const auto& keyword : deck ) {
// We're only interested in "TSTEP" and "DATES" keywords,
// so we ignore everything else here...
if (keyword.name() != "TSTEP" &&
keyword.name() != "DATES")
{
if (keyword.name() != "TSTEP" && keyword.name() != "DATES")
continue;
if (keyword.name() == "DATES") {
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)
skip = false;
if (!skip)
addTime(nextTime);
}
continue;
}
if (keyword.name() == "TSTEP")
addFromTSTEPKeyword(keyword);
else if (keyword.name() == "DATES")
addFromDATESKeyword(keyword);
if (skip)
continue;
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 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".
*/
if (this->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())
throw std::invalid_argument("Could not find restart date");
}
}
}
@@ -105,7 +166,7 @@ namespace {
std::time_t TimeMap::getStartTime(size_t tStepIdx) const {
return this->operator[]( tStepIdx );
return this->operator[](tStepIdx);
}
std::time_t TimeMap::getEndTime() const {
@@ -189,16 +250,6 @@ namespace {
return date;
}
void TimeMap::addFromDATESKeyword(const DeckKeyword &DATESKeyword) {
if (DATESKeyword.name() != "DATES")
throw std::invalid_argument("Method requires DATES keyword input.");
for (size_t recordIndex = 0; recordIndex < DATESKeyword.size(); recordIndex++) {
const auto &record = DATESKeyword.getRecord(recordIndex);
const std::time_t nextTime = TimeMap::timeFromEclipse(record);
addTime(nextTime);
}
}
void TimeMap::addFromTSTEPKeyword(const DeckKeyword &TSTEPKeyword) {
if (TSTEPKeyword.name() != "TSTEP")
@@ -239,7 +290,8 @@ namespace {
{
return this->m_timeList == data.m_timeList &&
this->m_first_timestep_months == data.m_first_timestep_months &&
this->m_first_timestep_years == data.m_first_timestep_years;
this->m_first_timestep_years == data.m_first_timestep_years &&
this->restart_offset == data.restart_offset;
}
bool TimeMap::isTimestepInFirstOfMonthsYearsSequence(size_t timestep, bool years, size_t start_timestep, size_t frequency) const {
@@ -329,12 +381,14 @@ namespace {
std::time_t TimeMap::operator[] (size_t index) const {
if (index < m_timeList.size()) {
return m_timeList[index];
} else
if (index >= m_timeList.size())
throw std::invalid_argument("Index out of range");
}
if (index > 0 && index < this->restart_offset)
throw std::invalid_argument("Tried to get time information from the base case in restarted run");
return m_timeList[index];
}
std::time_t TimeMap::mkdate(int in_year, int in_month, int in_day) {
return mkdatetime(in_year , in_month , in_day, 0,0,0);

View File

@@ -594,3 +594,108 @@ BOOST_AUTO_TEST_CASE(TimeServiceOperatorPlus) {
}
BOOST_AUTO_TEST_CASE(RESTART) {
std::string deck_string1 = R"(
START
1 JAN 2000 /
RESTART
'CASE' 5 /
SCHEDULE
SKIPREST
DATES
1 JAN 2001 /
1 JAN 2002 /
1 JAN 2003 /
1 JAN 2004 /
/
DATES
1 JAN 2005 /
/
DATES
1 JAN 2006 /
1 JAN 2007 /
1 JAN 2008 /
1 JAN 2009 /
1 JAN 2010 /
/
)";
std::string deck_string2 = R"(
START
1 JAN 2000 /
RESTART
'CASE' 5 /
SCHEDULE
-- The period before the restart dates has been removed - the restart date
-- should still be picked up as report step 5.
--DATES
-- 1 JAN 2001 /
-- 1 JAN 2002 /
-- 1 JAN 2003 /
-- 1 JAN 2004 /
--/
DATES
1 JUL 2005 /
/
DATES
1 JAN 2006 /
1 JAN 2007 /
1 JAN 2008 /
1 JAN 2009 /
1 JAN 2010 /
/
)";
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);
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);
Opm::TimeMap tm1(deck1, valid_restart);
BOOST_CHECK_THROW( tm1[1], std::invalid_argument );
BOOST_CHECK_THROW( tm1[4], std::invalid_argument );
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})));
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})));
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})));
}