From c081a764a7258b23ab06af901395373518be487a Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Sat, 20 Nov 2021 23:49:54 +0100 Subject: [PATCH] Implement schedule dump to deck functionality --- .../EclipseState/Schedule/Schedule.hpp | 4 +- .../EclipseState/Schedule/ScheduleDeck.hpp | 6 ++ .../EclipseState/Schedule/Schedule.cpp | 10 +++ .../EclipseState/Schedule/ScheduleDeck.cpp | 51 ++++++++++++++ tests/parser/ScheduleTests.cpp | 69 +++++++++++++++++++ 5 files changed, 139 insertions(+), 1 deletion(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index ecfec1a2d..3ae1095c3 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -467,7 +468,8 @@ namespace Opm } } - + friend std::ostream& operator<<(std::ostream& os, const Schedule& sched); + void dump_deck(std::ostream& os) const; private: ScheduleStatic m_static; diff --git a/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp b/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp index e8615dd3f..b4444adfd 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ namespace Opm { class Deck; + class DeckOutput; struct ScheduleDeckContext; class Runspec; @@ -76,6 +78,8 @@ namespace Opm { serializer.vector(m_keywords); m_location.serializeOp(serializer); } + + void dump_deck(DeckOutput& output, time_point& current_time) const; private: ScheduleTimeType m_time_type; time_point m_start_time; @@ -143,6 +147,8 @@ namespace Opm { m_location.serializeOp(serializer); } + void dump_deck(std::ostream& os) const; + private: time_point m_restart_time; std::size_t m_restart_offset; diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index d2c9871a1..0385d8955 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -2001,4 +2001,14 @@ void Schedule::create_next(const ScheduleBlock& block) { this->create_next(start_time, end_time); } +void Schedule::dump_deck(std::ostream& os) const { + this->m_sched_deck.dump_deck(os); +} + +std::ostream& operator<<(std::ostream& os, const Schedule& sched) +{ + sched.dump_deck(os); + return os; +} + } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.cpp index ccbcc1f12..f46899bf3 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,46 @@ bool ScheduleBlock::operator==(const ScheduleBlock& other) const { this->m_keywords == other.m_keywords; } +namespace { + +void dump_time(time_point tp, ScheduleTimeType time_type, time_point current_time, DeckOutput& output) { + if (time_type == ScheduleTimeType::START) + return; + + if (time_type == ScheduleTimeType::DATES) { + TimeStampUTC ts(TimeService::to_time_t(tp)); + auto ecl_month = TimeService::eclipseMonthNames().at(ts.month()); + std::string dates_string = fmt::format(R"( +DATES + {} '{}' {} / +/ +)", ts.day(), ecl_month, ts.year()); + output.write_string(dates_string); + } else { + auto seconds = std::chrono::duration_cast(tp - current_time); + double days = seconds.count() / 86400.0; + std::string tstep_string = fmt::format(R"( +TSTEP + {} / +)", days); + output.write_string(tstep_string); + } +} + +} + + +void ScheduleBlock::dump_deck(DeckOutput& output, time_point& current_time) const { + dump_time(this->start_time(), this->m_time_type, current_time, output); + if (!this->end_time().has_value()) + return; + + for (const auto& keyword : this->m_keywords) + keyword.write(output); + + current_time = this->end_time().value(); +} + const KeywordLocation& ScheduleBlock::location() const { return this->m_location; @@ -307,4 +348,14 @@ ScheduleDeck ScheduleDeck::serializeObject() { return deck; } +void ScheduleDeck::dump_deck(std::ostream& os) const { + DeckOutput output(os); + + output.write_string("SCHEDULE\n"); + auto current_time = this->m_blocks[0].start_time(); + for (const auto& block : this->m_blocks) + block.dump_deck(output, current_time); +} + + } diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index 15252abc8..c2cd6902c 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ #include #include +#include "tests/WorkArea.cpp" using namespace Opm; @@ -4950,8 +4952,75 @@ END BOOST_CHECK_MESSAGE(! sched[3].rptonly(), R"("RPTONLY" must NOT be configured on report step 4)"); + + } +BOOST_AUTO_TEST_CASE(DUMP_DECK) { + const std::string part1 = R"( +DIMENS + 10 10 10 / + +START -- 0 +10 MAI 2007 / + +GRID +DXV +10*100.0 / +DYV +10*100.0 / +DZV +10*10.0 / +DEPTHZ +121*2000.0 / + +SUMMARY +RPTONLY +)"; + const std::string schedule_string = R"( +SCHEDULE +WELSPECS + 'W_1' 'OP' 30 37 3.33 'OIL' 7* / +/ +DATES -- 1, 2 + 10 'JUN' 2007 / + 10 JLY 2007 / +/ +WELSPECS + 'WX2' 'OP' 30 37 3.33 'OIL' 7* / + 'W_3' 'OP' 20 51 3.92 'OIL' 7* / +/ +RPTONLYO +DATES -- 3, 4 + 10 AUG 2007 / + 10 SEP 2007 / +/ +END +)"; + + WorkArea wa; + { + std::ofstream stream{"CASE1.DATA"}; + stream << part1 << std::endl << schedule_string; + } + const auto& deck1 = Parser{}.parseFile("CASE1.DATA"); + const auto es1 = EclipseState { deck1 }; + const auto sched1 = Schedule { deck1, es1, std::make_shared() }; + + + { + std::ofstream stream{"CASE2.DATA"}; + stream << part1 << std::endl << sched1; + } + const auto& deck2 = Parser{}.parseFile("CASE2.DATA"); + const auto es2 = EclipseState { deck2 }; + const auto sched2 = Schedule { deck2, es2, std::make_shared() }; + + // Can not do a full sched == sched2 because the Deck member will have embedded + // keyword location information. + for (std::size_t step = 0; step < sched1.size(); step++) + BOOST_CHECK(sched1[step] == sched2[step]); +} BOOST_AUTO_TEST_CASE(TestScheduleGrid) {