Merge pull request #2769 from joakim-hove/rst-deck-skip

Rst deck skip
This commit is contained in:
Bård Skaflestad 2021-10-20 15:45:30 +02:00 committed by GitHub
commit 9f0185018e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 17 deletions

View File

@ -63,7 +63,7 @@ output the program will update the SOLUTION and SCHEDULE sections. All keywords
from the SOLUTION section will be cleared out(1) and a RESTART keyword will be
inserted. In the SCHEDULE section the program can either remove all keywords up
until the restart date, or alternatively insert SKIPREST immediately following
the SCHEDULE keyword(2).
the SCHEDULE keyword.
When creating the updated restart deck the program can either link to unmodified
include files with INCLUDE statements, create a copy of deck structure in an
@ -77,7 +77,7 @@ Arguments:
1. The data file we are starting with.
2. The basename of the restart file - with an optional path prefix and a :N to
restart from step N(3). A restart step value of 0 is interpreted as a dry run
restart from step N(2). A restart step value of 0 is interpreted as a dry run
- a deck which has not been set up for restart will be written out.
3. Basename of the restart deck we create, can optionally contain a path prefix;
@ -91,7 +91,7 @@ Options:
-s: Manipulate the SCHEDULE section by inserting a SKIPREST keyword immediately
following the SCHEDULE keyword. If the -s option is not used the SCHEDULE
section will be modified by removing all keywords until we reach the restart
date. NB: Currently the -s option is required
date.
-m: [share|inline|copy] The restart deck can reuse the unmodified include files
from the base case, this is mode 'share' and is the default. With mode
@ -102,7 +102,7 @@ Options:
In the case of 'share' and 'copy' the correct path to include files will be
negotiated based on the path given to the output case in the third argument.
If the restart deck is passed to stdout the include files will be resolved
based on output in cwd.
based on output in cwd.
Example:
@ -111,10 +111,7 @@ Example:
1: The program has a compiled list of keywords which will be retained in the
SOLUTION section. The current value of that list is: {}
2: Current version of the program *only* supports the SKIPREST option, and the
-s option is required.
3: The second argument is treated purely as a string and inserted verbatim into
2: The second argument is treated purely as a string and inserted verbatim into
the updated restart deck. In a future version we might interpret the second
argument as a file path and check the content and also do filesystem
manipulations from it.
@ -248,6 +245,8 @@ void update_schedule(const options& opt, Opm::FileDeck& file_deck)
if (opt.skiprest)
file_deck.insert_skiprest();
else
file_deck.skip(opt.restart.second);
}

View File

@ -39,7 +39,7 @@ class Deck;
class FileDeck {
public:
static const std::unordered_set<std::string> rst_keep_in_solution;
static const std::unordered_set<std::string> rst_keep_in_schedule;
enum class OutputMode {
INLINE = 1,
@ -79,7 +79,7 @@ public:
explicit Block(const std::string& filename);
std::size_t size() const;
void load(const Deck& deck, std::size_t deck_index);
std::optional<std::size_t> find(const std::string& keyword) const;
std::optional<std::size_t> find(const std::string& keyword, std::size_t keyword_index) const;
bool empty() const;
void erase(const FileDeck::Index& index);
void insert(std::size_t keyword_index, const DeckKeyword& keyword);
@ -94,7 +94,9 @@ friend FileDeck;
explicit FileDeck(const Deck& deck);
std::optional<Index> find(const std::string& keyword, const Index& offset) const;
std::optional<Index> find(const std::string& keyword) const;
std::size_t count(const std::string& keyword) const;
void erase(const Index& index);
void erase(const Index& begin, const Index& end);
void insert(const Index& index, const DeckKeyword& keyword);
@ -107,6 +109,7 @@ friend FileDeck;
void rst_solution(const std::string& rst_base, int report_step);
void insert_skiprest();
void skip(int report_step);
private:
std::vector<Block> blocks;

View File

@ -22,8 +22,10 @@
#include <opm/parser/eclipse/Deck/DeckValue.hpp>
#include <opm/parser/eclipse/Deck/DeckOutput.hpp>
#include <opm/parser/eclipse/Deck/FileDeck.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/D.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/R.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/T.hpp>
namespace fs = Opm::filesystem;
@ -158,14 +160,16 @@ std::size_t FileDeck::FileDeck::Block::size() const {
return this->keywords.size();
}
std::optional<std::size_t> FileDeck::Block::find(const std::string& keyword) const {
auto iter = std::find_if(this->keywords.begin(), this->keywords.end(), [&keyword](const DeckKeyword& kw) { return kw.name() == keyword;});
std::optional<std::size_t> FileDeck::Block::find(const std::string& keyword, std::size_t keyword_index) const {
auto iter = std::find_if(this->keywords.begin() + keyword_index, this->keywords.end(), [&keyword](const DeckKeyword& kw) { return kw.name() == keyword;});
if (iter == this->keywords.end())
return {};
return std::distance(this->keywords.begin(), iter);
}
void FileDeck::erase(const FileDeck::Index& index) {
auto& block = this->blocks.at(index.file_index);
this->modified_files.insert(block.fname);
@ -207,24 +211,44 @@ FileDeck::FileDeck::Block::Block(const std::string& filename)
: fname(fs::canonical(filename))
{}
std::optional<FileDeck::Index> FileDeck::find(const std::string& keyword) const {
std::size_t file_index = 0;
std::optional<FileDeck::Index> FileDeck::find(const std::string& keyword, const Index& offset) const {
std::size_t file_index = offset.file_index;
std::size_t keyword_index = offset.keyword_index;
while (true) {
if (file_index >= this->blocks.size())
break;
const auto& file_block = this->blocks[file_index];
const auto& block_index = file_block.find(keyword);
const auto& block_index = file_block.find(keyword, keyword_index);
if (block_index.has_value())
return std::make_optional<FileDeck::Index>(file_index, block_index.value(), this);
file_index++;
keyword_index = 0;
}
return {};
}
std::optional<FileDeck::Index> FileDeck::find(const std::string& keyword) const {
return this->find(keyword, this->start());
}
std::size_t FileDeck::count(const std::string& keyword) const {
std::size_t c = 0;
auto index = this->start();
while (index != this->stop()) {
const auto& deck_kw = this->operator[](index);
if (deck_kw.name() == keyword)
c += 1;
index++;
}
return c;
}
void FileDeck::insert(const Index& index, const DeckKeyword& keyword)
{
auto& block = this->blocks.at(index.file_index);
@ -396,6 +420,62 @@ void FileDeck::insert_skiprest() {
this->insert(++index, skiprest);
}
void FileDeck::skip(int report_step) {
int current_report = 0;
const auto& schedule = this->find("SCHEDULE");
auto deck_pos = schedule.value();
while (true) {
const auto& deck_keyword = this->operator[](deck_pos);
if (deck_keyword.name() == "DATES")
current_report += deck_keyword.size();
else if (deck_keyword.name() == "TSTEP")
current_report += deck_keyword[0].getItem<ParserKeywords::TSTEP::step_list>().data_size();
if (current_report >= report_step)
break;
deck_pos++;
if (deck_pos == this->stop())
throw std::logic_error(fmt::format("Could not find DATES keyword corresponding to report_step {}", report_step));
}
auto index = schedule.value();
auto end_pos = deck_pos;
while (index < end_pos) {
const auto& keyword = this->operator[](index);
if (FileDeck::rst_keep_in_schedule.count(keyword.name()) == 0) {
this->erase(index);
end_pos--;
} else
index++;
}
if (current_report == report_step)
this->erase(end_pos);
else {
auto deck_keyword = this->operator[](end_pos);
this->erase(end_pos);
std::vector<std::vector<DeckValue>> records;
using D = ParserKeywords::DATES;
current_report -= deck_keyword.size();
for (int record_index = 0; record_index < (report_step - current_report); record_index++) {
const auto& record = deck_keyword[record_index];
records.push_back( {DeckValue{record.getItem<D::DAY>().get<int>(0)},
DeckValue{record.getItem<D::MONTH>().get<std::string>(0)},
DeckValue{record.getItem<D::YEAR>().get<int>(0)} });
}
UnitSystem unit_system;
this->insert(end_pos, DeckKeyword{ParserKeywords::DATES{}, records, unit_system, unit_system});
}
}
const std::unordered_set<std::string> FileDeck::rst_keep_in_solution = {"ABC"};
const std::unordered_set<std::string> FileDeck::rst_keep_in_schedule = {"VFPPROD", "VFPINJ", "RPTSCHED", "RPTRST", "TUNING", "MESSAGES"};
}

View File

@ -35,6 +35,7 @@
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Action/State.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/D.hpp>
#include <opm/parser/eclipse/Deck/DeckValue.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
@ -264,13 +265,18 @@ BOOST_AUTO_TEST_CASE(TestFileDeck)
const auto& index1 = fd.find("RADIAL");
BOOST_CHECK( !index1.has_value() );
BOOST_CHECK_EQUAL( fd.count("RADIAL"), 0);
BOOST_CHECK_EQUAL( fd.count("DIMENS"), 1);
BOOST_CHECK_EQUAL( fd.count("DATES"), 5);
const auto& index2 = fd.find("DIMENS");
BOOST_CHECK( index2.has_value());
BOOST_CHECK_EQUAL( index2.value().file_index , 0);
BOOST_CHECK_EQUAL( index2.value().keyword_index, 3);
auto offset = index2.value();
const auto& dimens2 = fd.find("DIMENS", ++offset);
BOOST_CHECK(!dimens2.has_value());
const auto& index3 = fd.find("COORD");
BOOST_CHECK_EQUAL( index3.value().file_index , 1);
@ -298,7 +304,7 @@ BOOST_AUTO_TEST_CASE(RestartTest2)
auto deck = parser.parseFile("UDQ_WCONPROD.DATA");
FileDeck fd(deck);
fd.rst_solution("RESTART", 77);
fd.rst_solution("RESTART", 6);
fd.insert_skiprest();
auto solution_index = fd.find("SOLUTION").value();
@ -313,6 +319,23 @@ BOOST_AUTO_TEST_CASE(RestartTest2)
BOOST_CHECK(schedule_index < skiprest_index);
}
BOOST_AUTO_TEST_CASE(RestartTest23)
{
Parser parser;
auto python = std::make_shared<Python>();
auto deck = parser.parseFile("UDQ_WCONPROD.DATA");
FileDeck fd(deck);
fd.skip(7);
BOOST_CHECK_EQUAL(fd.count("DATES"), 1);
auto dates_index = fd.find("DATES");
BOOST_CHECK(dates_index.has_value());
auto kw = fd[dates_index.value()];
auto rec0 = kw[0];
BOOST_CHECK_EQUAL( rec0.getItem<ParserKeywords::DATES::MONTH>().get<std::string>(0), "MAR");
BOOST_CHECK_EQUAL(kw.size() , 1);
}
BOOST_AUTO_TEST_CASE(RestartTest)
{