From b787a1a259a0660d56a24b6414c75a78366b8bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Atgeirr=20Fl=C3=B8=20Rasmussen?= Date: Fri, 8 Nov 2019 16:14:32 +0100 Subject: [PATCH] Fix TimeMap::isTimestepInFirstOfMonthsYearsSequence() method. --- .../eclipse/EclipseState/Schedule/TimeMap.hpp | 16 +- .../eclipse/EclipseState/Schedule/TimeMap.cpp | 113 +++++++------ tests/parser/RestartConfigTests.cpp | 14 +- tests/parser/TimeMapTest.cpp | 156 +++++++++++++++++- 4 files changed, 231 insertions(+), 68 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp b/opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp index 63c244483..73808ed76 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp @@ -21,6 +21,8 @@ #ifndef TIMEMAP_HPP_ #define TIMEMAP_HPP_ +#include + #include #include #include @@ -58,8 +60,7 @@ namespace Opm { double getTimeStepLength(size_t tStepIdx) const; /// Return true if the given timestep is the first one of a new month or year, or if frequency > 1, - /// return true for every n'th timestep of every first new month or first new year timesteps, - /// starting from start_timestep-1. + /// return true if the step is the first of each n-month or n-month period, starting from start_timestep - 1. bool isTimestepInFirstOfMonthsYearsSequence(size_t timestep, bool years = true, size_t start_timestep = 1, size_t frequency = 1) const; static std::time_t timeFromEclipse(const DeckRecord &dateRecord); @@ -73,13 +74,16 @@ namespace Opm { std::vector m_timeList; - const std::vector& getFirstTimestepMonths() const; - const std::vector& getFirstTimestepYears() const; bool isTimestepInFreqSequence (size_t timestep, size_t start_timestep, size_t frequency, bool years) const; size_t closest(const std::vector & vec, size_t value) const; - std::vector m_first_timestep_years; // A list of the first timestep of every year - std::vector m_first_timestep_months; // A list of the first timestep of every month + struct StepData + { + size_t stepnumber; + TimeStampUTC timestamp; + }; + std::vector m_first_timestep_years; // A list of the first timestep of every year + std::vector m_first_timestep_months; // A list of the first timestep of every month }; } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/TimeMap.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/TimeMap.cpp index dfa6b5295..e4b4aee3a 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/TimeMap.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/TimeMap.cpp @@ -55,20 +55,23 @@ namespace { 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"); - m_timeList.push_back(timeFromEclipse(keyword.getRecord(0))); - + 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... - const std::time_t time = mkdate(1983, 1, 1); - m_timeList.push_back(time); + time = mkdate(1983, 1, 1); } + 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 @@ -128,11 +131,11 @@ namespace { const auto new_year = nw .year(); const auto last_year = last.year(); - if (new_month != last_month) - m_first_timestep_months.push_back(step); + if (new_month != last_month || new_year != last_year) + m_first_timestep_months.push_back({step, nw}); if (new_year != last_year) - m_first_timestep_years.push_back(step); + m_first_timestep_years.push_back({step, nw}); m_timeList.push_back(newTime); } else @@ -221,10 +224,11 @@ namespace { bool TimeMap::isTimestepInFirstOfMonthsYearsSequence(size_t timestep, bool years, size_t start_timestep, size_t frequency) const { bool timestep_first_of_month_year = false; - const std::vector& timesteps = (years) ? getFirstTimestepYears() : getFirstTimestepMonths(); + const auto& timesteps = (years) ? m_first_timestep_years : m_first_timestep_months; - std::vector::const_iterator ci_timestep = std::find(timesteps.begin(), timesteps.end(), timestep); - if (ci_timestep != timesteps.end()) { + auto same_step = [timestep](const StepData& sd) { return sd.stepnumber == timestep; }; + auto ci_timestep = std::find_if(timesteps.begin(), timesteps.end(), same_step); + if (ci_timestep != timesteps.end() && ci_timestep != timesteps.begin()) { if (1 >= frequency) { timestep_first_of_month_year = true; } else { //Frequency given @@ -235,56 +239,63 @@ namespace { } - // This method returns true for every n'th timestep in the vector of timesteps m_first_timestep_years or m_first_timestep_months, - // starting from one before the position of start_timestep. If the given start_timestep is not a value in the month or year vector, - // set the first timestep that are both within the vector and higher than the initial start_timestep as new start_timestep. - + // Return true if the step is the first of each n-month or n-month + // period, starting from start_timestep - 1, with n = frequency. bool TimeMap::isTimestepInFreqSequence (size_t timestep, size_t start_timestep, size_t frequency, bool years) const { - bool timestep_right_frequency = false; - const std::vector& timesteps = (years) ? getFirstTimestepYears() : getFirstTimestepMonths(); + // Find iterator to data for 'start_timestep' or first + // in-sequence step following it, set start_year and + // start_month. + const auto& timesteps = (years) ? m_first_timestep_years : m_first_timestep_months; + auto compare_stepnumber = [](const StepData& sd, size_t value) { return sd.stepnumber < value; }; + auto ci_start_timestep = std::lower_bound(timesteps.begin(), timesteps.end(), start_timestep - 1, compare_stepnumber); + if (ci_start_timestep == timesteps.end()) { + // We are after the end of the sequence. + return false; + } + const int start_year = ci_start_timestep->timestamp.year(); + const int start_month = ci_start_timestep->timestamp.month() - 1; // For 0-indexing. - std::vector::const_iterator ci_timestep = std::find(timesteps.begin(), timesteps.end(), timestep); - std::vector::const_iterator ci_start_timestep = std::find(timesteps.begin(), timesteps.end(), start_timestep); - - //Find new start_timestep if the given one is not a value in the timesteps vector - bool start_ts_in_timesteps = false; - if (ci_start_timestep != timesteps.end()) { - start_ts_in_timesteps = true; - } else if (ci_start_timestep == timesteps.end()) { - size_t new_start = closest(timesteps, start_timestep); - if (0 != new_start) { - ci_start_timestep = std::find(timesteps.begin(), timesteps.end(), new_start); - start_ts_in_timesteps = true; - } + // Find iterator to data for 'timestep'. + auto same_step = [timestep](const StepData& sd) { return sd.stepnumber == timestep; }; + auto ci_timestep = std::find_if(timesteps.begin(), timesteps.end(), same_step); + // The ci_timestep can be assumed to be different from + // timesteps.end(), or we would not be in this function. + // If, however, it is at or before the first timestep we should + // always return false. + if (ci_timestep <= ci_start_timestep) { + return false; } - - if (start_ts_in_timesteps) { - //Pick every n'th element, starting on start_timestep + (n-1), that is, every n'th element from ci_start_timestep - 1 for freq n > 1 - if (ci_timestep >= ci_start_timestep) { - int dist = std::distance( ci_start_timestep, ci_timestep ) + 1; - if ((dist % frequency) == 0) { - timestep_right_frequency = true; - } + if (years) { + // Year logic. + const int my_year = ci_timestep->timestamp.year(); + if ((my_year - start_year) % frequency == 0) { + return true; + } else { + // Check if we are in a new (frequency-year) period. + const auto prev_it = ci_timestep - 1; + const int prev_year = prev_it->timestamp.year(); + return (my_year - start_year)/frequency > (prev_year - start_year)/frequency; + } + } else { + // Month logic. + const int my_year = ci_timestep->timestamp.year(); + const int my_month = (my_year - start_year) * 12 + ci_timestep->timestamp.month() - 1; + // my_month is now the count of months since start_month. + assert(my_month > start_month); + if ((my_month - start_month) % frequency == 0) { + return true; + } else { + // Check if we are in a new (frequency-month) period. + const auto prev_it = ci_timestep - 1; + const int prev_year = prev_it->timestamp.year(); + const int prev_month = (prev_year - start_year) * 12 + prev_it->timestamp.month() - 1; + return (my_month - start_month)/frequency > (prev_month - start_month)/frequency; } } - - return timestep_right_frequency; } - - - - const std::vector& TimeMap::getFirstTimestepMonths() const { - return m_first_timestep_months; - } - - - const std::vector& TimeMap::getFirstTimestepYears() const { - return m_first_timestep_years; - } - // vec is assumed to be sorted size_t TimeMap::closest(const std::vector & vec, size_t value) const { diff --git a/tests/parser/RestartConfigTests.cpp b/tests/parser/RestartConfigTests.cpp index a71334293..59057660b 100644 --- a/tests/parser/RestartConfigTests.cpp +++ b/tests/parser/RestartConfigTests.cpp @@ -876,12 +876,12 @@ BOOST_AUTO_TEST_CASE(BASIC_EQ_5) { " 24 MAY 1981 /\n" " 1 JUN 1981 /\n" " 1 JUL 1981 /\n" // write - " 1 JAN 1982 /\n" + " 1 JAN 1982 /\n" // write " 2 JAN 1982 /\n" - " 1 FEB 1982 /\n" // write - " 1 MAR 1982 /\n" - " 1 APR 1983 /\n" //write - " 2 JUN 1983 /\n" + " 1 FEB 1982 /\n" + " 1 MAR 1982 /\n" // write + " 1 APR 1983 /\n" // write + " 2 JUN 1983 /\n" // write "/\n"; auto deck = Parser().parseString( data); @@ -889,10 +889,10 @@ BOOST_AUTO_TEST_CASE(BASIC_EQ_5) { /* BASIC=5, restart file is written at the first report step of each month. */ - for( size_t ts : { 1, 2, 3, 4, 6, 7, 9, 11 } ) + for( size_t ts : { 1, 2, 3, 4, 7, 8 } ) BOOST_CHECK( !ioConfig.getWriteRestartFile( ts ) ); - for( size_t ts : { 5, 8, 10 } ) + for( size_t ts : { 5, 6, 9, 10, 11 } ) BOOST_CHECK( ioConfig.getWriteRestartFile( ts ) ); } diff --git a/tests/parser/TimeMapTest.cpp b/tests/parser/TimeMapTest.cpp index a9abcbf4d..466f99eb3 100644 --- a/tests/parser/TimeMapTest.cpp +++ b/tests/parser/TimeMapTest.cpp @@ -313,17 +313,165 @@ BOOST_AUTO_TEST_CASE(initTimestepsYearsAndMonths) { for (size_t timestep = 0; timestep <= 17; ++timestep) { if ((5 == timestep) || (6 == timestep) || (8 == timestep) || (9 == timestep) || (10 == timestep) || (11 == timestep) || (12 == timestep) || (13 == timestep)) { - BOOST_CHECK_EQUAL(true, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, false, true)); + BOOST_CHECK_EQUAL(true, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, false)); } else { - BOOST_CHECK_EQUAL(false, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, false, true)); + BOOST_CHECK_EQUAL(false, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, false)); } } for (size_t timestep = 0; timestep <= 17; ++timestep) { if (13 == timestep) { - BOOST_CHECK_EQUAL(true, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, true, false)); + BOOST_CHECK_EQUAL(true, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, true)); } else { - BOOST_CHECK_EQUAL(false, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, true, false)); + BOOST_CHECK_EQUAL(false, tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, true)); + } + } +} + +BOOST_AUTO_TEST_CASE(initTimestepsYearsAndMonthsSkippingMonthsFrequency) { + const char *deckData = + "START\n" + " 21 MAY 1981 /\n" + "\n" + "DATES\n" + " 5 JUL 1981 /\n" + " 6 JUL 1981 /\n" + " 5 AUG 1981 /\n" + " 5 SEP 1981 /\n" + " 1 OCT 1981 /\n" + " 1 NOV 1981 /\n" + " 1 DEC 1981 /\n" + " 1 JAN 1982 /\n" + " 1 JAN 1982 13:55:44 /\n" + " 3 JAN 1982 14:56:45.123 /\n" + " 1 JAN 1983 /\n" + " 1 JAN 1984 /\n" + " 1 JAN 1985 /\n" + " 1 JAN 1988 /\n" + "/\n"; + + Opm::Parser parser; + auto deck = parser.parseString(deckData); + const Opm::TimeMap tmap(deck); + + /*deckData timesteps: + 0 21 may 1981 START + 1 5 jul 1981 + 2 6 jul 1981 + 3 5 aug 1981 + 4 5 sep 1981 + 5 1 oct 1981 + 6 1 nov 1981 + 7 1 dec 1981 + 8 1 jan 1982 + 9 1 jan 1982 + 10 3 jan 1982 + 11 1 jan 1983 + 12 1 jan 1984 + 13 1 jan 1985 + 14 1 jan 1988*/ + + // Month, not set frequency. + { + std::vector expected = { + false, // 0 21 may 1981 START + true, // 1 5 jul 1981 + false, // 2 6 jul 1981 + true, // 3 5 aug 1981 + true, // 4 5 sep 1981 + true, // 5 1 oct 1981 + true, // 6 1 nov 1981 + true, // 7 1 dec 1981 + true, // 8 1 jan 1982 + false, // 9 1 jan 1982 + false, // 10 3 jan 1982 + true, // 11 1 jan 1983 + true, // 12 1 jan 1984 + true, // 13 1 jan 1985 + true // 14 1 jan 1988 + }; + + for (size_t timestep = 0; timestep < expected.size(); ++timestep) { + const bool ok = tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, false) == expected[timestep]; + BOOST_CHECK_MESSAGE(ok, "failing for timestep " << timestep); + } + } + + // Month, frequency 2. + { + std::vector expected = { + false, // 0 21 may 1981 START + true, // 1 5 jul 1981 + false, // 2 6 jul 1981 + false, // 3 5 aug 1981 + true, // 4 5 sep 1981 + false, // 5 1 oct 1981 + true, // 6 1 nov 1981 + false, // 7 1 dec 1981 + true, // 8 1 jan 1982 + false, // 9 1 jan 1982 + false, // 10 3 jan 1982 + true, // 11 1 jan 1983 + true, // 12 1 jan 1984 + true, // 13 1 jan 1985 + true // 14 1 jan 1988 + }; + + for (size_t timestep = 0; timestep < expected.size(); ++timestep) { + const bool ok = tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, false, 1, 2) == expected[timestep]; + BOOST_CHECK_MESSAGE(ok, "failing for timestep " << timestep); + } + } + + // Year, not set frequency. + { + std::vector expected = { + false, // 0 21 may 1981 START + false, // 1 5 jul 1981 + false, // 2 6 jul 1981 + false, // 3 5 aug 1981 + false, // 4 5 sep 1981 + false, // 5 1 oct 1981 + false, // 6 1 nov 1981 + false, // 7 1 dec 1981 + true, // 8 1 jan 1982 + false, // 9 1 jan 1982 + false, // 10 3 jan 1982 + true, // 11 1 jan 1983 + true, // 12 1 jan 1984 + true, // 13 1 jan 1985 + true // 14 1 jan 1988 + }; + + for (size_t timestep = 0; timestep < expected.size(); ++timestep) { + const bool ok = tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, true) == expected[timestep]; + BOOST_CHECK_MESSAGE(ok, "failing for timestep " << timestep); + } + } + + // Year, frequency 2. + { + std::vector expected = { + false, // 0 21 may 1981 START + false, // 1 5 jul 1981 + false, // 2 6 jul 1981 + false, // 3 5 aug 1981 + false, // 4 5 sep 1981 + false, // 5 1 oct 1981 + false, // 6 1 nov 1981 + false, // 7 1 dec 1981 + false, // 8 1 jan 1982 + false, // 9 1 jan 1982 + false, // 10 3 jan 1982 + true, // 11 1 jan 1983 + false, // 12 1 jan 1984 + true, // 13 1 jan 1985 + true // 14 1 jan 1988 + }; + + for (size_t timestep = 0; timestep < expected.size(); ++timestep) { + const bool ok = tmap.isTimestepInFirstOfMonthsYearsSequence(timestep, true, 1, 2) == expected[timestep]; + BOOST_CHECK_MESSAGE(ok, "failing for timestep " << timestep); } } }