Merge pull request #2039 from joakim-hove/rst-tstep
Allow restart date to be at a TSTEP
This commit is contained in:
commit
2a41058eda
@ -36,6 +36,8 @@ namespace Opm {
|
|||||||
class Deck;
|
class Deck;
|
||||||
class DeckKeyword;
|
class DeckKeyword;
|
||||||
class DeckRecord;
|
class DeckRecord;
|
||||||
|
class KeywordLocation;
|
||||||
|
class TimeMapContext;
|
||||||
|
|
||||||
class TimeMap {
|
class TimeMap {
|
||||||
public:
|
public:
|
||||||
@ -108,9 +110,8 @@ namespace Opm {
|
|||||||
|
|
||||||
bool isTimestepInFreqSequence (size_t timestep, size_t start_timestep, size_t frequency, bool years) const;
|
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;
|
size_t closest(const std::vector<size_t> & vec, size_t value) const;
|
||||||
void addTStep(int64_t step);
|
void addTime(std::time_t newTime, TimeMapContext& context, const KeywordLocation& location);
|
||||||
void addTime(std::time_t newTime);
|
void addFromTSTEPKeyword( const DeckKeyword& TSTEPKeyword, TimeMapContext& context);
|
||||||
void addFromTSTEPKeyword( const DeckKeyword& TSTEPKeyword );
|
|
||||||
void init_start(std::time_t start_time);
|
void init_start(std::time_t start_time);
|
||||||
|
|
||||||
std::vector<std::time_t> m_timeList;
|
std::vector<std::time_t> m_timeList;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <opm/common/utility/TimeService.hpp>
|
#include <opm/common/utility/TimeService.hpp>
|
||||||
|
|
||||||
#include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
|
#include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
|
||||||
|
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||||
|
|
||||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||||
#include <opm/common/utility/OpmInputError.hpp>
|
#include <opm/common/utility/OpmInputError.hpp>
|
||||||
@ -44,6 +45,8 @@ constexpr const std::time_t invalid_time = -1;
|
|||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const std::map<std::string, int> month_indices = {{"JAN", 1},
|
const std::map<std::string, int> month_indices = {{"JAN", 1},
|
||||||
{"FEB", 2},
|
{"FEB", 2},
|
||||||
@ -62,8 +65,21 @@ namespace {
|
|||||||
{"DEC", 12},
|
{"DEC", 12},
|
||||||
{"DES", 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) {
|
void TimeMap::init_start(std::time_t start_time) {
|
||||||
auto timestamp = TimeStampUTC{start_time};
|
auto timestamp = TimeStampUTC{start_time};
|
||||||
|
|
||||||
@ -77,6 +93,7 @@ namespace {
|
|||||||
if (time_points.empty())
|
if (time_points.empty())
|
||||||
throw std::invalid_argument("Can not initialize with empty list of time points");
|
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]);
|
this->init_start(time_points[0]);
|
||||||
for (std::size_t ti = 1; ti < time_points.size(); ti++) {
|
for (std::size_t ti = 1; ti < time_points.size(); ti++) {
|
||||||
if (time_points[ti] == invalid_time) {
|
if (time_points[ti] == invalid_time) {
|
||||||
@ -84,7 +101,7 @@ namespace {
|
|||||||
this->m_restart_offset += 1;
|
this->m_restart_offset += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this->addTime( time_points[ti] );
|
this->addTime( time_points[ti], context, {} );
|
||||||
}
|
}
|
||||||
if (this->m_restart_offset > 0)
|
if (this->m_restart_offset > 0)
|
||||||
this->m_restart_offset += 1;
|
this->m_restart_offset += 1;
|
||||||
@ -113,8 +130,7 @@ namespace {
|
|||||||
for (std::size_t it = 1; it < this->m_restart_offset; it++)
|
for (std::size_t it = 1; it < this->m_restart_offset; it++)
|
||||||
this->m_timeList.push_back(invalid_time);
|
this->m_timeList.push_back(invalid_time);
|
||||||
|
|
||||||
bool skip = (this->m_restart_offset > 0);
|
TimeMapContext context(this->m_restart_offset > 0, start_time);
|
||||||
bool restart_found = false;
|
|
||||||
for( const auto& keyword : SCHEDULESection(deck)) {
|
for( const auto& keyword : SCHEDULESection(deck)) {
|
||||||
// We're only interested in "TSTEP" and "DATES" keywords,
|
// We're only interested in "TSTEP" and "DATES" keywords,
|
||||||
// so we ignore everything else here...
|
// so we ignore everything else here...
|
||||||
@ -134,32 +150,11 @@ namespace {
|
|||||||
std::throw_with_nested(opm_error);
|
std::throw_with_nested(opm_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextTime == this->m_restart_time) {
|
this->addTime(nextTime, context, keyword.location());
|
||||||
skip = false;
|
|
||||||
restart_found = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip)
|
|
||||||
this->addTime(nextTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
this->addFromTSTEPKeyword(keyword, context);
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +194,22 @@ namespace {
|
|||||||
this->m_timeList.front());
|
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 std::time_t lastTime = m_timeList.back();
|
||||||
const size_t step = m_timeList.size();
|
const size_t step = m_timeList.size();
|
||||||
if (newTime > lastTime) {
|
if (newTime > lastTime) {
|
||||||
@ -223,10 +233,6 @@ namespace {
|
|||||||
throw std::invalid_argument("Times added must be in strictly increasing order.");
|
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 {
|
size_t TimeMap::size() const {
|
||||||
return m_timeList.size();
|
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")
|
if (TSTEPKeyword.name() != "TSTEP")
|
||||||
throw std::invalid_argument("Method requires TSTEP keyword input.");
|
throw std::invalid_argument("Method requires TSTEP keyword input.");
|
||||||
{
|
{
|
||||||
@ -274,7 +280,8 @@ namespace {
|
|||||||
|
|
||||||
for (size_t itemIndex = 0; itemIndex < item.data_size(); itemIndex++) {
|
for (size_t itemIndex = 0; itemIndex < item.data_size(); itemIndex++) {
|
||||||
const int64_t seconds = static_cast<int64_t>(item.getSIDouble(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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -683,7 +683,7 @@ DATES
|
|||||||
auto invalid_restart = std::make_pair(Opm::asTimeT(Opm::TimeStampUTC(2005, 1, 2)), 5);
|
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);
|
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);
|
Opm::TimeMap tm1(deck1, valid_restart);
|
||||||
BOOST_CHECK_THROW( tm1[1], std::invalid_argument );
|
BOOST_CHECK_THROW( tm1[1], std::invalid_argument );
|
||||||
BOOST_CHECK_THROW( tm1[4], 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_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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user