commit
9f0185018e
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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"};
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user