Merge pull request #2347 from joakim-hove/ched-state-rst-config2
Internalize restart configuration in new schedule structure
This commit is contained in:
commit
c7200aa1af
@ -89,7 +89,6 @@ if(ENABLE_ECL_INPUT)
|
|||||||
src/opm/parser/eclipse/EclipseState/InitConfig/FoamConfig.cpp
|
src/opm/parser/eclipse/EclipseState/InitConfig/FoamConfig.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/InitConfig/InitConfig.cpp
|
src/opm/parser/eclipse/EclipseState/InitConfig/InitConfig.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp
|
src/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.cpp
|
|
||||||
src/opm/parser/eclipse/EclipseState/Runspec.cpp
|
src/opm/parser/eclipse/EclipseState/Runspec.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/TracerConfig.cpp
|
src/opm/parser/eclipse/EclipseState/TracerConfig.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionAST.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionAST.cpp
|
||||||
@ -130,6 +129,7 @@ if(ENABLE_ECL_INPUT)
|
|||||||
src/opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/RFTConfig.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/RFTConfig.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/RPTConfig.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/RPTConfig.cpp
|
||||||
|
src/opm/parser/eclipse/EclipseState/Schedule/RSTConfig.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.cpp
|
||||||
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleState.cpp
|
src/opm/parser/eclipse/EclipseState/Schedule/ScheduleState.cpp
|
||||||
@ -341,7 +341,6 @@ if(ENABLE_ECL_INPUT)
|
|||||||
tests/parser/CopyRegTests.cpp
|
tests/parser/CopyRegTests.cpp
|
||||||
tests/parser/DeckValueTests.cpp
|
tests/parser/DeckValueTests.cpp
|
||||||
tests/parser/DeckTests.cpp
|
tests/parser/DeckTests.cpp
|
||||||
tests/parser/DynamicStateTests.cpp
|
|
||||||
tests/parser/EclipseGridTests.cpp
|
tests/parser/EclipseGridTests.cpp
|
||||||
tests/parser/EmbeddedPython.cpp
|
tests/parser/EmbeddedPython.cpp
|
||||||
tests/parser/EqualRegTests.cpp
|
tests/parser/EqualRegTests.cpp
|
||||||
@ -758,6 +757,7 @@ if(ENABLE_ECL_INPUT)
|
|||||||
opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp
|
opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/RFTConfig.hpp
|
opm/parser/eclipse/EclipseState/Schedule/RFTConfig.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/RPTConfig.hpp
|
opm/parser/eclipse/EclipseState/Schedule/RPTConfig.hpp
|
||||||
|
opm/parser/eclipse/EclipseState/Schedule/RSTConfig.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp
|
opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/ScheduleState.hpp
|
opm/parser/eclipse/EclipseState/Schedule/ScheduleState.hpp
|
||||||
@ -774,7 +774,6 @@ if(ENABLE_ECL_INPUT)
|
|||||||
opm/parser/eclipse/EclipseState/Schedule/MessageLimits.hpp
|
opm/parser/eclipse/EclipseState/Schedule/MessageLimits.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/Events.hpp
|
opm/parser/eclipse/EclipseState/Schedule/Events.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp
|
opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp
|
|
||||||
opm/parser/eclipse/EclipseState/Schedule/MSW/icd.hpp
|
opm/parser/eclipse/EclipseState/Schedule/MSW/icd.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
|
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
|
opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp
|
||||||
@ -786,7 +785,6 @@ if(ENABLE_ECL_INPUT)
|
|||||||
opm/parser/eclipse/EclipseState/SimulationConfig/RockConfig.hpp
|
opm/parser/eclipse/EclipseState/SimulationConfig/RockConfig.hpp
|
||||||
opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp
|
opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp
|
||||||
opm/parser/eclipse/EclipseState/Schedule/MSW/Valve.hpp
|
opm/parser/eclipse/EclipseState/Schedule/MSW/Valve.hpp
|
||||||
opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp
|
|
||||||
opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp
|
opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp
|
||||||
opm/parser/eclipse/EclipseState/checkDeck.hpp
|
opm/parser/eclipse/EclipseState/checkDeck.hpp
|
||||||
opm/parser/eclipse/EclipseState/Runspec.hpp
|
opm/parser/eclipse/EclipseState/Runspec.hpp
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||||
|
@ -1,390 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Statoil ASA.
|
|
||||||
|
|
||||||
This file is part of the Open Porous Media project (OPM).
|
|
||||||
|
|
||||||
OPM is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OPM is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPM_RESTART_CONFIG_HPP
|
|
||||||
#define OPM_RESTART_CONFIG_HPP
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
|
||||||
|
|
||||||
/*
|
|
||||||
The RestartConfig class internalizes information of when (at which
|
|
||||||
report steps) we should save restart files, and which properties
|
|
||||||
should be included in the restart files. The configuration of this
|
|
||||||
immensely complex, and this code is unfortunately also way too
|
|
||||||
complex.
|
|
||||||
|
|
||||||
The most basic question to disentangle is the "When to write restart
|
|
||||||
files" versus "What data to store write in the restart file". As
|
|
||||||
expressed in the deck keywords this completely entangled, in this
|
|
||||||
implementation we have tried to disentangle it:
|
|
||||||
|
|
||||||
Keywords involved
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
RPTRST: This is the main keyword for configuring restart output; it
|
|
||||||
can be used to configure bothe when to write the files and which
|
|
||||||
properties should be included in the restart files.
|
|
||||||
|
|
||||||
|
|
||||||
RPTSCHED: The main purpose of the RPTSCHED keyword is to configure
|
|
||||||
output from the SCHEDULE section to the PRINT file. However the
|
|
||||||
mneomnic RESTART=n can be used to turn writing of restart files
|
|
||||||
on, and also for values > 2 to some configuration of what is
|
|
||||||
written to the restart file:
|
|
||||||
|
|
||||||
RESTART=1 : As RPTRST,BASIC=1
|
|
||||||
RESTART>1 : As RPTRST,BASIC=2
|
|
||||||
RESTART>2 : Flow is added to restart file
|
|
||||||
RESTART>3 : Fluid in place is added to restart file
|
|
||||||
RESTART=6 : Restart file for every timestep.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RPTSOL: The RPTSOL keyword is very similar to the RPTCHED keyword,
|
|
||||||
it configures output from the SOLUTION section to the PRINT file,
|
|
||||||
but just as the RPTSCHED keyword it accepts a RESTART=n mnenonic
|
|
||||||
which can be used similarly to the BASIC=n mnenonic of the RPTRST
|
|
||||||
keyword. In particular the writing of an initial restart files
|
|
||||||
with initial equilibrium solution is controlled by the RPTSOL
|
|
||||||
keyword. If the restart mneonic is greater than 2 that can be
|
|
||||||
used to configure FLOWS and FIP keywords in the restart file.
|
|
||||||
|
|
||||||
RESTART=1 : As RPTRST,BASIC=1
|
|
||||||
RESTART>1 : As RPTRST,BASIC=2
|
|
||||||
RESTART>2 : Flow is added to restart file
|
|
||||||
RESTART>3 : Fluid in place is added to restart file
|
|
||||||
|
|
||||||
|
|
||||||
The basic rule in ECLIPSE is generally that the 'last keyword wins',
|
|
||||||
but for the RPTRST RPTSHCED combination a BASIC setting with n >= 3
|
|
||||||
will override consecutive RESTART=n settings from RPTSCHED.
|
|
||||||
|
|
||||||
|
|
||||||
When to write restart files:
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
When to write the restart file is governed by the BASIC=n setting in
|
|
||||||
the RPTRST keyword and the RESTART=n settings in the RPTSOL and
|
|
||||||
RPTSCHED keywords. The most common setting is 'ON' - i.e. BASIC=2
|
|
||||||
which means write a restart file for every report step, that can be
|
|
||||||
turned off again with BASIC=0. For BASIC>2 there are varietes of
|
|
||||||
every n'th report step, and the first report step in every month and
|
|
||||||
every year.
|
|
||||||
|
|
||||||
|
|
||||||
Old style / new style
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
All of the relevant keywords can be specified using a new style
|
|
||||||
based on string mneomnics and alternatively an old style represented
|
|
||||||
with a *strictly ordered* list of integers. For instance both of
|
|
||||||
these keywords request restart files written for every report step;
|
|
||||||
in addition to the fields required to actually restart the files
|
|
||||||
should contain the relative permeabilities KRO, KRW, KRG:
|
|
||||||
|
|
||||||
RPTRST
|
|
||||||
BASIC=2 KRG KRW KRO /
|
|
||||||
|
|
||||||
|
|
||||||
RPTRST
|
|
||||||
2 9*0 3*1 17*0
|
|
||||||
|
|
||||||
Integer controls and string mneomnics can not be mixed in the same
|
|
||||||
keyword, but they can be mixed in the same deck - and that is
|
|
||||||
actually quite common.
|
|
||||||
|
|
||||||
|
|
||||||
What is written to the restart file
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
The BASIC=n mneonics request the writing of a restart file which
|
|
||||||
should contain 'all properties required to restart', in addition you
|
|
||||||
can configure extra keywords to be added to the restart file. This
|
|
||||||
is configured by just adding a list as:
|
|
||||||
|
|
||||||
RPTRST
|
|
||||||
BASIC=2 KRG KRW KRO /
|
|
||||||
|
|
||||||
It is really *not clear* what is the correct persistence semantics
|
|
||||||
for these keywords, consider for insance the following series of keywords:
|
|
||||||
|
|
||||||
-- Request restart file at every report step, the restart files
|
|
||||||
-- should contain additional properties KRO, KRG and KRW.
|
|
||||||
RPTRST
|
|
||||||
BASIC=2 KRG KRW KRO /
|
|
||||||
|
|
||||||
-- Advance the simulator forward with TSTEP / DATES
|
|
||||||
TSTEP / DATES / WCONxxx
|
|
||||||
|
|
||||||
-- Turn writing of restart files OFF using integer controls.
|
|
||||||
RPTRST
|
|
||||||
0 /
|
|
||||||
|
|
||||||
-- Advance the simulator forward with TSTEP / DATES
|
|
||||||
TSTEP / DATES / WCONxxx
|
|
||||||
|
|
||||||
-- Turn writing of restart files ON using integer controls.
|
|
||||||
RPTRST
|
|
||||||
2 /
|
|
||||||
|
|
||||||
When writing of restart files is turned on again with the last
|
|
||||||
RPTRST keyword, should still the relative permeabilites KRO, KRW and
|
|
||||||
KRG be added to the restart files? The model we have implemented is:
|
|
||||||
|
|
||||||
- The list of keywords written to the restart file is persisted
|
|
||||||
independtly of the BASIC=n setting.
|
|
||||||
|
|
||||||
- Using string based mnonics you can *only add* kewyords to be
|
|
||||||
written to the files. To stop writing a keyword you must use an
|
|
||||||
integer control with value 0.
|
|
||||||
|
|
||||||
Based on this best guess heuristic the final restart files will
|
|
||||||
still contain KRO, KRW and KRG.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
What is required to restart?
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
A restart capable files is requested with the 'BASIC' mneomnic, but
|
|
||||||
exactly which properties the 'BASIC' keyword is expanded to is the
|
|
||||||
responsability of the simulator; i.e. for a black oil simulation you
|
|
||||||
will at the very least need the expansion:
|
|
||||||
|
|
||||||
BASIC -> PRESSURE, SWAT, SGAS, RS, RV
|
|
||||||
|
|
||||||
But this class just carries the boolean information: Yes - restart
|
|
||||||
is requested - expanding as illustrated is the responsability of the
|
|
||||||
simulator.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
What is not supported?
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
The SAVE keyword is not supported in OPM at all, this implies that
|
|
||||||
the SAVE and SFREQ mneomics are not supported.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Opm {
|
|
||||||
|
|
||||||
template< typename > class DynamicState;
|
|
||||||
|
|
||||||
class Deck;
|
|
||||||
class DeckKeyword;
|
|
||||||
class RUNSPECSection;
|
|
||||||
class SCHEDULESection;
|
|
||||||
class SOLUTIONSection;
|
|
||||||
class Schedule;
|
|
||||||
class ParseContext;
|
|
||||||
class ErrorGuard;
|
|
||||||
|
|
||||||
/*The IOConfig class holds data about input / ouput configurations
|
|
||||||
|
|
||||||
Amongst these configuration settings, a IOConfig object knows if
|
|
||||||
a restart file should be written for a specific report step
|
|
||||||
|
|
||||||
The write of restart files is governed by several eclipse keywords.
|
|
||||||
These keywords are all described in the eclipse manual, but some
|
|
||||||
of them are rather porly described there.
|
|
||||||
To have equal sets of restart files written from Eclipse and Flow for various
|
|
||||||
configurations, we have made a qualified guess on the behaviour
|
|
||||||
for some of the keywords (by running eclipse for different configurations,
|
|
||||||
and looked at which restart files that have been written).
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTSOL RESTART (solution section) ------
|
|
||||||
If RPTSOL RESTART > 1 initial restart file is written.
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTRST (solution section) ------
|
|
||||||
Eclipse manual states that the initial restart file is to be written
|
|
||||||
if RPTSOL RESTART > 1. But - due to that the initial restart file
|
|
||||||
is written from Eclipse for data where RPTSOL RESTART is not set, - we
|
|
||||||
have made a guess that when RPTRST is set in SOLUTION (no basic though...),
|
|
||||||
it means that the initial restart file should be written.
|
|
||||||
Running of eclipse with different settings have proven this to be a qualified guess.
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTRST BASIC=0 (solution or schedule section) ------
|
|
||||||
No restart files are written
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTRST BASIC=1 or RPTRST BASIC=2 (solution or schedule section) ------
|
|
||||||
Restart files are written for every timestep, from timestep 1 to number of timesteps.
|
|
||||||
(Write of inital timestep is governed by a separate setting)
|
|
||||||
|
|
||||||
Notice! Eclipse simulator RPTRST BASIC=1 writes restart files for every
|
|
||||||
report step, but only keeps the last one written. This functionality is
|
|
||||||
not supported in Flow; so to compare Eclipse results with Flow results
|
|
||||||
for every report step, set RPTRST BASIC=2 for the eclipse run
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTRST BASIC=3 FREQ=n (solution or schedule section) ------
|
|
||||||
Restart files are created every nth report time. Default frequency is 1 (every report step)
|
|
||||||
|
|
||||||
If a frequency higher than 1 is given:
|
|
||||||
start_rs = report step the setting was given.
|
|
||||||
write report step rstep if (rstep >= start_rs) && ((rstep % frequency) == 0).
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTRST BASIC=4 FREQ=n or RPTRST BASIC=5 FREQ=n (solution or schedule section) ------
|
|
||||||
For the settings BASIC 4 or BASIC 5, - first report step of every new year(4) or new month(5),
|
|
||||||
the first report step is compared with report step 0 (start), and then every report step is
|
|
||||||
compared with the previous one to see if year/month has changed.
|
|
||||||
|
|
||||||
This leaves us with a set of timesteps.
|
|
||||||
All timesteps in the set that are higher or equal to the timestep the RPTRST keyword was set on is written.
|
|
||||||
|
|
||||||
If in addition FREQUENCY is given (higher than 1), every n'the value of this set are to be written.
|
|
||||||
|
|
||||||
If the setting BASIC=4 or BASIC=5 is set on a timestep that is a member of the set "first timestep of
|
|
||||||
each year" / "First timestep of each month", then the timestep that is freq-1 timesteps (within the set) from
|
|
||||||
this start timestep will be written, and then every n'the timestep (within the set) from this one will be written.
|
|
||||||
|
|
||||||
If the setting BASIC=4 or BASIC=5 is set on a timestep that is not a member of the list "first timestep of
|
|
||||||
each year" / "First timestep of each month", then the list is searched for the closest timestep that are
|
|
||||||
larger than the timestep that introduced the setting, and then; same as above - the timestep that is freq-1
|
|
||||||
timesteps from this one (within the set) will be written, and then every n'the timestep (within the set) from
|
|
||||||
this one will be written.
|
|
||||||
|
|
||||||
|
|
||||||
------ RPTRST BASIC=6 (solution or schedule section) ------
|
|
||||||
Not supported in Flow
|
|
||||||
|
|
||||||
|
|
||||||
------ Default ------
|
|
||||||
If no keywords for config of writing restart files have been handled; no restart files are written.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
//namespace {
|
|
||||||
|
|
||||||
class RestartSchedule {
|
|
||||||
/*
|
|
||||||
The content of this struct is logically divided in two; either the
|
|
||||||
restart behaviour is governed by { timestep , basic , frequency }, or
|
|
||||||
alternatively by { rptshec_restart_set , rptsched_restart }.
|
|
||||||
|
|
||||||
The former triplet is mainly governed by the RPTRST keyword and the
|
|
||||||
latter pair by the RPTSCHED keyword.
|
|
||||||
*/
|
|
||||||
public:
|
|
||||||
|
|
||||||
RestartSchedule() = default;
|
|
||||||
explicit RestartSchedule( size_t sched_restart);
|
|
||||||
RestartSchedule( size_t step, size_t b, size_t freq);
|
|
||||||
|
|
||||||
static RestartSchedule serializeObject();
|
|
||||||
|
|
||||||
bool writeRestartFile( size_t timestep , const TimeMap& timemap) const;
|
|
||||||
bool operator!=(const RestartSchedule& rhs) const;
|
|
||||||
bool operator==( const RestartSchedule& rhs ) const;
|
|
||||||
|
|
||||||
template<class Serializer>
|
|
||||||
void serializeOp(Serializer& serializer)
|
|
||||||
{
|
|
||||||
serializer(timestep);
|
|
||||||
serializer(basic);
|
|
||||||
serializer(frequency);
|
|
||||||
serializer(rptsched_restart_set);
|
|
||||||
serializer(rptsched_restart);
|
|
||||||
}
|
|
||||||
|
|
||||||
//private:
|
|
||||||
size_t timestep = 0;
|
|
||||||
size_t basic = 0;
|
|
||||||
size_t frequency = 0;
|
|
||||||
bool rptsched_restart_set = false;
|
|
||||||
size_t rptsched_restart = 0;
|
|
||||||
};
|
|
||||||
// }
|
|
||||||
class RestartConfig {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
RestartConfig() = default;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
RestartConfig( const Deck&, const std::pair<std::time_t, std::size_t>& restart, const std::optional<int>& output_interval, const ParseContext& parseContext, T&& errors );
|
|
||||||
RestartConfig( const Deck&, const std::pair<std::time_t, std::size_t>& restart, const std::optional<int>& output_interval, const ParseContext& parseContext, ErrorGuard& errors );
|
|
||||||
RestartConfig( const Deck&, const std::pair<std::time_t, std::size_t>& restart, const std::optional<int>& output_interval);
|
|
||||||
|
|
||||||
static RestartConfig serializeObject();
|
|
||||||
|
|
||||||
int getFirstRestartStep() const;
|
|
||||||
bool getWriteRestartFile(size_t timestep, bool log=true) const;
|
|
||||||
const std::map< std::string, int >& getRestartKeywords( size_t timestep ) const;
|
|
||||||
|
|
||||||
void handleSolutionSection(const SOLUTIONSection& solutionSection, const ParseContext& parseContext, ErrorGuard& errors);
|
|
||||||
void setWriteInitialRestartFile(bool writeInitialRestartFile);
|
|
||||||
|
|
||||||
bool operator==(const RestartConfig& data) const;
|
|
||||||
|
|
||||||
template<class Serializer>
|
|
||||||
void serializeOp(Serializer& serializer)
|
|
||||||
{
|
|
||||||
m_timemap.serializeOp(serializer);
|
|
||||||
serializer(m_first_restart_step);
|
|
||||||
serializer(m_write_initial_RST_file);
|
|
||||||
restart_schedule.serializeOp(serializer);
|
|
||||||
restart_keywords.serializeOp<Serializer, false>(serializer);
|
|
||||||
serializer(save_keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// This method will internalize variables with information of
|
|
||||||
/// the first report step with restart and rft output
|
|
||||||
/// respectively. This information is important because right
|
|
||||||
/// at the first output step we must reset the files to size
|
|
||||||
/// zero, for subsequent output steps we should append.
|
|
||||||
void initFirstOutput( );
|
|
||||||
RestartSchedule getNode( size_t timestep ) const;
|
|
||||||
void overrideRestartWriteInterval(size_t interval);
|
|
||||||
|
|
||||||
bool getWriteRestartFileFrequency(size_t timestep,
|
|
||||||
size_t start_timestep,
|
|
||||||
size_t frequency,
|
|
||||||
bool years = false,
|
|
||||||
bool months = false) const;
|
|
||||||
void handleRPTSOL( const DeckKeyword& keyword);
|
|
||||||
void handleScheduleSection( const SCHEDULESection& schedule, const ParseContext& parseContext, ErrorGuard& errors);
|
|
||||||
void update( size_t step, const RestartSchedule& rs);
|
|
||||||
static RestartSchedule rptsched( const DeckKeyword& );
|
|
||||||
|
|
||||||
TimeMap m_timemap;
|
|
||||||
int m_first_restart_step = 1;
|
|
||||||
bool m_write_initial_RST_file = false;
|
|
||||||
|
|
||||||
DynamicState< RestartSchedule > restart_schedule;
|
|
||||||
DynamicState< std::map< std::string, int > > restart_keywords;
|
|
||||||
std::vector< bool > save_keywords;
|
|
||||||
};
|
|
||||||
} //namespace Opm
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,162 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013 Statoil ASA.
|
|
||||||
|
|
||||||
This file is part of the Open Porous Media project (OPM).
|
|
||||||
|
|
||||||
OPM is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OPM is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DYNAMICSTATE_HPP_
|
|
||||||
#define DYNAMICSTATE_HPP_
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <optional>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Opm {
|
|
||||||
|
|
||||||
/**
|
|
||||||
The DynamicState<T> class is designed to hold information about
|
|
||||||
properties with the following semantics:
|
|
||||||
|
|
||||||
1. The property can be updated repeatedly at different
|
|
||||||
timesteps; observe that the class does not support
|
|
||||||
operator[] - only updates with weakly increasing timesteps
|
|
||||||
are supported.
|
|
||||||
|
|
||||||
2. At any point in the time the previous last set value
|
|
||||||
applies.
|
|
||||||
|
|
||||||
The class is very much tailored to support the Schedule file of
|
|
||||||
Eclipse where a control applied at time T will apply
|
|
||||||
indefinitely, or until explicitly set to a different value.
|
|
||||||
|
|
||||||
The update() method returns true if the updated value is
|
|
||||||
different from the current value, this implies that the
|
|
||||||
class<T> must support operator!=
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template< class T >
|
|
||||||
class DynamicState {
|
|
||||||
public:
|
|
||||||
typedef typename std::vector< T >::iterator iterator;
|
|
||||||
|
|
||||||
DynamicState() = default;
|
|
||||||
|
|
||||||
DynamicState( const TimeMap& timeMap, T initial ) :
|
|
||||||
m_data( timeMap.size(), initial ),
|
|
||||||
initial_range( timeMap.size() )
|
|
||||||
{}
|
|
||||||
|
|
||||||
DynamicState(const std::vector<T>& data,
|
|
||||||
size_t init_range) :
|
|
||||||
m_data(data), initial_range(init_range)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void globalReset( T value ) {
|
|
||||||
this->m_data.assign( this->m_data.size(), value );
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& back() const {
|
|
||||||
return m_data.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& get(size_t index) const {
|
|
||||||
return this->m_data.at( index );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
If the current value has been changed the method will
|
|
||||||
return true, otherwise it will return false.
|
|
||||||
*/
|
|
||||||
bool update( size_t index, T value ) {
|
|
||||||
if( this->initial_range == this->m_data.size() )
|
|
||||||
this->initial_range = index;
|
|
||||||
|
|
||||||
const bool change = (value != this->m_data.at( index ));
|
|
||||||
|
|
||||||
if( !change ) return false;
|
|
||||||
|
|
||||||
std::fill( this->m_data.begin() + index,
|
|
||||||
this->m_data.end(),
|
|
||||||
value );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool operator==(const DynamicState<T>& data) const {
|
|
||||||
return m_data == data.m_data &&
|
|
||||||
initial_range == data.initial_range;
|
|
||||||
}
|
|
||||||
|
|
||||||
// complexType=true if contained type has a serializeOp
|
|
||||||
template<class Serializer, bool complexType = true>
|
|
||||||
void serializeOp(Serializer& serializer)
|
|
||||||
{
|
|
||||||
std::vector<T> unique;
|
|
||||||
auto indices = split(unique);
|
|
||||||
serializer.template vector<T,complexType>(unique);
|
|
||||||
serializer(indices);
|
|
||||||
if (!serializer.isSerializing())
|
|
||||||
reconstruct(unique, indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector< T > m_data;
|
|
||||||
size_t initial_range;
|
|
||||||
|
|
||||||
std::vector<size_t> split(std::vector<T>& unique) const {
|
|
||||||
std::vector<size_t> idxVec;
|
|
||||||
idxVec.reserve(m_data.size() + 1);
|
|
||||||
for (const auto& w : m_data) {
|
|
||||||
auto candidate = std::find(unique.begin(), unique.end(), w);
|
|
||||||
size_t idx = candidate - unique.begin();
|
|
||||||
if (candidate == unique.end()) {
|
|
||||||
unique.push_back(w);
|
|
||||||
idx = unique.size() - 1;
|
|
||||||
}
|
|
||||||
idxVec.push_back(idx);
|
|
||||||
}
|
|
||||||
idxVec.push_back(initial_range);
|
|
||||||
|
|
||||||
return idxVec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reconstruct(const std::vector<T>& unique,
|
|
||||||
const std::vector<size_t>& idxVec) {
|
|
||||||
m_data.clear();
|
|
||||||
m_data.reserve(idxVec.size() - 1);
|
|
||||||
for (size_t i = 0; i < idxVec.size() - 1; ++i)
|
|
||||||
m_data.push_back(unique[idxVec[i]]);
|
|
||||||
|
|
||||||
initial_range = idxVec.back();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
235
opm/parser/eclipse/EclipseState/Schedule/RSTConfig.hpp
Normal file
235
opm/parser/eclipse/EclipseState/Schedule/RSTConfig.hpp
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 Equinor ASA.
|
||||||
|
|
||||||
|
This file is part of the Open Porous Media project (OPM).
|
||||||
|
|
||||||
|
OPM is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OPM is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPM_RST_CONFIG_HPP
|
||||||
|
#define OPM_RST_CONFIG_HPP
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The RestartConfig class internalizes information of when (at which
|
||||||
|
report steps) we should save restart files, and which properties
|
||||||
|
should be included in the restart files. The configuration of this
|
||||||
|
immensely complex, and this code is unfortunately also way too
|
||||||
|
complex.
|
||||||
|
|
||||||
|
The most basic question to disentangle is the "When to write restart
|
||||||
|
files" versus "What data to store write in the restart file". As
|
||||||
|
expressed in the deck keywords this completely entangled, in this
|
||||||
|
implementation we have tried to disentangle it:
|
||||||
|
|
||||||
|
Keywords involved
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
RPTRST: This is the main keyword for configuring restart output; it
|
||||||
|
can be used to configure bothe when to write the files and which
|
||||||
|
properties should be included in the restart files.
|
||||||
|
|
||||||
|
|
||||||
|
RPTSCHED: The main purpose of the RPTSCHED keyword is to configure
|
||||||
|
output from the SCHEDULE section to the PRINT file. However the
|
||||||
|
mneomnic RESTART=n can be used to turn writing of restart files
|
||||||
|
on, and also for values > 2 to some configuration of what is
|
||||||
|
written to the restart file:
|
||||||
|
|
||||||
|
RESTART=1 : As RPTRST,BASIC=1
|
||||||
|
RESTART>1 : As RPTRST,BASIC=2
|
||||||
|
RESTART>2 : Flow is added to restart file
|
||||||
|
RESTART>3 : Fluid in place is added to restart file
|
||||||
|
RESTART=6 : Restart file for every timestep.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RPTSOL: The RPTSOL keyword is very similar to the RPTCHED keyword,
|
||||||
|
it configures output from the SOLUTION section to the PRINT file,
|
||||||
|
but just as the RPTSCHED keyword it accepts a RESTART=n mnenonic
|
||||||
|
which can be used similarly to the BASIC=n mnenonic of the RPTRST
|
||||||
|
keyword. In particular the writing of an initial restart files
|
||||||
|
with initial equilibrium solution is controlled by the RPTSOL
|
||||||
|
keyword. If the restart mneonic is greater than 2 that can be
|
||||||
|
used to configure FLOWS and FIP keywords in the restart file.
|
||||||
|
|
||||||
|
RESTART=1 : As RPTRST,BASIC=1
|
||||||
|
RESTART>1 : As RPTRST,BASIC=2
|
||||||
|
RESTART>2 : Flow is added to restart file
|
||||||
|
RESTART>3 : Fluid in place is added to restart file
|
||||||
|
|
||||||
|
|
||||||
|
The basic rule in ECLIPSE is generally that the 'last keyword wins',
|
||||||
|
but for the RPTRST RPTSHCED combination a BASIC setting with n >= 3
|
||||||
|
will override consecutive RESTART=n settings from RPTSCHED.
|
||||||
|
|
||||||
|
|
||||||
|
When to write restart files:
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
When to write the restart file is governed by the BASIC=n setting in
|
||||||
|
the RPTRST keyword and the RESTART=n settings in the RPTSOL and
|
||||||
|
RPTSCHED keywords. The most common setting is 'ON' - i.e. BASIC=2
|
||||||
|
which means write a restart file for every report step, that can be
|
||||||
|
turned off again with BASIC=0. For BASIC>2 there are varietes of
|
||||||
|
every n'th report step, and the first report step in every month and
|
||||||
|
every year.
|
||||||
|
|
||||||
|
|
||||||
|
Old style / new style
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
All of the relevant keywords can be specified using a new style
|
||||||
|
based on string mneomnics and alternatively an old style represented
|
||||||
|
with a *strictly ordered* list of integers. For instance both of
|
||||||
|
these keywords request restart files written for every report step;
|
||||||
|
in addition to the fields required to actually restart the files
|
||||||
|
should contain the relative permeabilities KRO, KRW, KRG:
|
||||||
|
|
||||||
|
RPTRST
|
||||||
|
BASIC=2 KRG KRW KRO /
|
||||||
|
|
||||||
|
|
||||||
|
RPTRST
|
||||||
|
2 9*0 3*1 17*0
|
||||||
|
|
||||||
|
Integer controls and string mneomnics can not be mixed in the same
|
||||||
|
keyword, but they can be mixed in the same deck - and that is
|
||||||
|
actually quite common.
|
||||||
|
|
||||||
|
|
||||||
|
What is written to the restart file
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
The BASIC=n mneonics request the writing of a restart file which
|
||||||
|
should contain 'all properties required to restart', in addition you
|
||||||
|
can configure extra keywords to be added to the restart file. This
|
||||||
|
is configured by just adding a list as:
|
||||||
|
|
||||||
|
RPTRST
|
||||||
|
BASIC=2 KRG KRW KRO /
|
||||||
|
|
||||||
|
It is really *not clear* what is the correct persistence semantics
|
||||||
|
for these keywords, consider for insance the following series of keywords:
|
||||||
|
|
||||||
|
-- Request restart file at every report step, the restart files
|
||||||
|
-- should contain additional properties KRO, KRG and KRW.
|
||||||
|
RPTRST
|
||||||
|
BASIC=2 KRG KRW KRO /
|
||||||
|
|
||||||
|
-- Advance the simulator forward with TSTEP / DATES
|
||||||
|
TSTEP / DATES / WCONxxx
|
||||||
|
|
||||||
|
-- Turn writing of restart files OFF using integer controls.
|
||||||
|
RPTRST
|
||||||
|
0 /
|
||||||
|
|
||||||
|
-- Advance the simulator forward with TSTEP / DATES
|
||||||
|
TSTEP / DATES / WCONxxx
|
||||||
|
|
||||||
|
-- Turn writing of restart files ON using integer controls.
|
||||||
|
RPTRST
|
||||||
|
2 /
|
||||||
|
|
||||||
|
When writing of restart files is turned on again with the last
|
||||||
|
RPTRST keyword, should still the relative permeabilites KRO, KRW and
|
||||||
|
KRG be added to the restart files? The model we have implemented is:
|
||||||
|
|
||||||
|
- The list of keywords written to the restart file is persisted
|
||||||
|
independtly of the BASIC=n setting.
|
||||||
|
|
||||||
|
- Using string based mnonics you can *only add* kewyords to be
|
||||||
|
written to the files. To stop writing a keyword you must use an
|
||||||
|
integer control with value 0.
|
||||||
|
|
||||||
|
Based on this best guess heuristic the final restart files will
|
||||||
|
still contain KRO, KRW and KRG.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What is required to restart?
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
A restart capable files is requested with the 'BASIC' mneomnic, but
|
||||||
|
exactly which properties the 'BASIC' keyword is expanded to is the
|
||||||
|
responsability of the simulator; i.e. for a black oil simulation you
|
||||||
|
will at the very least need the expansion:
|
||||||
|
|
||||||
|
BASIC -> PRESSURE, SWAT, SGAS, RS, RV
|
||||||
|
|
||||||
|
But this class just carries the boolean information: Yes - restart
|
||||||
|
is requested - expanding as illustrated is the responsability of the
|
||||||
|
simulator.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What is not supported?
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The SAVE keyword is not supported in OPM at all, this implies that
|
||||||
|
the SAVE and SFREQ mneomics are not supported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <opm/parser/eclipse/Deck/DeckSection.hpp>
|
||||||
|
|
||||||
|
namespace Opm {
|
||||||
|
|
||||||
|
class ParseContext;
|
||||||
|
class ErrorGuard;
|
||||||
|
|
||||||
|
class RSTConfig {
|
||||||
|
public:
|
||||||
|
RSTConfig() = default;
|
||||||
|
RSTConfig(const SOLUTIONSection& solution_section, const ParseContext& parseContext, ErrorGuard& errors);
|
||||||
|
void update(const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors);
|
||||||
|
void init_next();
|
||||||
|
static RSTConfig first(const RSTConfig& src);
|
||||||
|
static RSTConfig serializeObject();
|
||||||
|
|
||||||
|
template<class Serializer>
|
||||||
|
void serializeOp(Serializer& serializer) {
|
||||||
|
serializer(write_rst_file);
|
||||||
|
serializer.template map<std::map<std::string, int>, false>(keywords);
|
||||||
|
serializer(basic);
|
||||||
|
serializer(freq);
|
||||||
|
serializer(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const RSTConfig& other) const;
|
||||||
|
|
||||||
|
std::optional<bool> write_rst_file;
|
||||||
|
std::map<std::string, int> keywords;
|
||||||
|
std::optional<int> basic;
|
||||||
|
std::optional<int> freq;
|
||||||
|
bool save = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleRPTSOL(const DeckKeyword& keyword);
|
||||||
|
void handleRPTRST(const DeckKeyword& keyword, const ParseContext& parse_context, ErrorGuard& errors);
|
||||||
|
void handleRPTSCHED(const DeckKeyword& keyword, const ParseContext& parse_context, ErrorGuard& errors);
|
||||||
|
void update_schedule(const std::pair<std::optional<int>, std::optional<int>>& basic_freq);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} //namespace Opm
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -24,9 +24,9 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include <opm/parser/eclipse/Deck/DeckSection.hpp>
|
||||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||||
#include <opm/parser/eclipse/Python/Python.hpp>
|
#include <opm/parser/eclipse/Python/Python.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp>
|
||||||
@ -71,6 +71,8 @@ namespace Opm
|
|||||||
MessageLimits m_deck_message_limits;
|
MessageLimits m_deck_message_limits;
|
||||||
UnitSystem m_unit_system;
|
UnitSystem m_unit_system;
|
||||||
Runspec m_runspec;
|
Runspec m_runspec;
|
||||||
|
RSTConfig rst_config;
|
||||||
|
std::optional<int> output_interval;
|
||||||
|
|
||||||
ScheduleStatic() = default;
|
ScheduleStatic() = default;
|
||||||
|
|
||||||
@ -80,13 +82,19 @@ namespace Opm
|
|||||||
|
|
||||||
ScheduleStatic(std::shared_ptr<const Python> python_handle,
|
ScheduleStatic(std::shared_ptr<const Python> python_handle,
|
||||||
const Deck& deck,
|
const Deck& deck,
|
||||||
const Runspec& runspec) :
|
const Runspec& runspec,
|
||||||
|
const std::optional<int>& output_interval_,
|
||||||
|
const ParseContext& parseContext,
|
||||||
|
ErrorGuard& errors):
|
||||||
m_python_handle(python_handle),
|
m_python_handle(python_handle),
|
||||||
m_input_path(deck.getInputPath()),
|
m_input_path(deck.getInputPath()),
|
||||||
m_deck_message_limits( deck ),
|
m_deck_message_limits( deck ),
|
||||||
m_unit_system( deck.getActiveUnitSystem() ),
|
m_unit_system( deck.getActiveUnitSystem() ),
|
||||||
m_runspec( runspec )
|
m_runspec( runspec ),
|
||||||
{}
|
rst_config( SOLUTIONSection(deck), parseContext, errors ),
|
||||||
|
output_interval(output_interval_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
@ -95,6 +103,8 @@ namespace Opm
|
|||||||
m_runspec.serializeOp(serializer);
|
m_runspec.serializeOp(serializer);
|
||||||
m_unit_system.serializeOp(serializer);
|
m_unit_system.serializeOp(serializer);
|
||||||
serializer(this->m_input_path);
|
serializer(this->m_input_path);
|
||||||
|
rst_config.serializeOp(serializer);
|
||||||
|
serializer(this->output_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -105,6 +115,7 @@ namespace Opm
|
|||||||
st.m_runspec = Runspec::serializeObject();
|
st.m_runspec = Runspec::serializeObject();
|
||||||
st.m_unit_system = UnitSystem::newFIELD();
|
st.m_unit_system = UnitSystem::newFIELD();
|
||||||
st.m_input_path = "Some/funny/path";
|
st.m_input_path = "Some/funny/path";
|
||||||
|
st.rst_config = RSTConfig::serializeObject();
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +123,7 @@ namespace Opm
|
|||||||
return this->m_input_path == other.m_input_path &&
|
return this->m_input_path == other.m_input_path &&
|
||||||
this->m_deck_message_limits == other.m_deck_message_limits &&
|
this->m_deck_message_limits == other.m_deck_message_limits &&
|
||||||
this->m_unit_system == other.m_unit_system &&
|
this->m_unit_system == other.m_unit_system &&
|
||||||
|
this->rst_config == other.rst_config &&
|
||||||
this->m_runspec == other.m_runspec;
|
this->m_runspec == other.m_runspec;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -287,7 +299,6 @@ namespace Opm
|
|||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
m_sched_deck.serializeOp(serializer);
|
m_sched_deck.serializeOp(serializer);
|
||||||
restart_config.serializeOp(serializer);
|
|
||||||
serializer.vector(snapshots);
|
serializer.vector(snapshots);
|
||||||
m_static.serializeOp(serializer);
|
m_static.serializeOp(serializer);
|
||||||
serializer(m_restart_info);
|
serializer(m_restart_info);
|
||||||
@ -307,6 +318,7 @@ namespace Opm
|
|||||||
pack_unpack<GuideRateConfig, Serializer>(serializer);
|
pack_unpack<GuideRateConfig, Serializer>(serializer);
|
||||||
pack_unpack<GasLiftOpt, Serializer>(serializer);
|
pack_unpack<GasLiftOpt, Serializer>(serializer);
|
||||||
pack_unpack<RFTConfig, Serializer>(serializer);
|
pack_unpack<RFTConfig, Serializer>(serializer);
|
||||||
|
pack_unpack<RSTConfig, Serializer>(serializer);
|
||||||
|
|
||||||
pack_unpack_map<int, VFPProdTable, Serializer>(serializer);
|
pack_unpack_map<int, VFPProdTable, Serializer>(serializer);
|
||||||
pack_unpack_map<int, VFPInjTable, Serializer>(serializer);
|
pack_unpack_map<int, VFPInjTable, Serializer>(serializer);
|
||||||
@ -451,13 +463,9 @@ namespace Opm
|
|||||||
ScheduleStatic m_static;
|
ScheduleStatic m_static;
|
||||||
std::pair<std::time_t, std::size_t> m_restart_info;
|
std::pair<std::time_t, std::size_t> m_restart_info;
|
||||||
ScheduleDeck m_sched_deck;
|
ScheduleDeck m_sched_deck;
|
||||||
RestartConfig restart_config;
|
|
||||||
std::optional<int> exit_status;
|
std::optional<int> exit_status;
|
||||||
std::vector<ScheduleState> snapshots;
|
std::vector<ScheduleState> snapshots;
|
||||||
|
|
||||||
RestartConfig& restart();
|
|
||||||
const RestartConfig& restart() const;
|
|
||||||
|
|
||||||
void load_rst(const RestartIO::RstState& rst,
|
void load_rst(const RestartIO::RstState& rst,
|
||||||
const EclipseGrid& grid,
|
const EclipseGrid& grid,
|
||||||
const FieldPropsManager& fp);
|
const FieldPropsManager& fp);
|
||||||
@ -599,8 +607,10 @@ namespace Opm
|
|||||||
void handleMXUNSUPP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleMXUNSUPP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleNODEPROP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleNODEPROP (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleNUPCOL (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleNUPCOL (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
|
void handleRPTRST (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleRPTSCHED (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleRPTSCHED (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleTUNING (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleTUNING (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
|
void handleSAVE (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleUDQ (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleUDQ (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleVAPPARS (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleVAPPARS (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
void handleVFPINJ (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
void handleVFPINJ (const HandlerContext&, const ParseContext&, ErrorGuard&);
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/RFTConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/RFTConfig.hpp>
|
||||||
|
#include <opm/parser/eclipse/EclipseState/Schedule/RSTConfig.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -316,6 +317,10 @@ namespace Opm {
|
|||||||
Well::ProducerCMode whistctl() const;
|
Well::ProducerCMode whistctl() const;
|
||||||
void update_whistctl(Well::ProducerCMode whistctl);
|
void update_whistctl(Well::ProducerCMode whistctl);
|
||||||
|
|
||||||
|
bool rst_file(const RSTConfig& rst_config) const;
|
||||||
|
void update_date(const time_point& prev_time);
|
||||||
|
void handleSAVE();
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
|
||||||
ptr_member<PAvg> pavg;
|
ptr_member<PAvg> pavg;
|
||||||
@ -333,6 +338,7 @@ namespace Opm {
|
|||||||
ptr_member<GasLiftOpt> glo;
|
ptr_member<GasLiftOpt> glo;
|
||||||
ptr_member<GuideRateConfig> guide_rate;
|
ptr_member<GuideRateConfig> guide_rate;
|
||||||
ptr_member<RFTConfig> rft_config;
|
ptr_member<RFTConfig> rft_config;
|
||||||
|
ptr_member<RSTConfig> rst_config;
|
||||||
|
|
||||||
template <typename T> struct always_false1 : std::false_type {};
|
template <typename T> struct always_false1 : std::false_type {};
|
||||||
|
|
||||||
@ -368,6 +374,8 @@ namespace Opm {
|
|||||||
return this->guide_rate;
|
return this->guide_rate;
|
||||||
else if constexpr ( std::is_same_v<T, RFTConfig> )
|
else if constexpr ( std::is_same_v<T, RFTConfig> )
|
||||||
return this->rft_config;
|
return this->rft_config;
|
||||||
|
else if constexpr ( std::is_same_v<T, RSTConfig> )
|
||||||
|
return this->rst_config;
|
||||||
else
|
else
|
||||||
static_assert(always_false1<T>::value, "Template type <T> not supported in get()");
|
static_assert(always_false1<T>::value, "Template type <T> not supported in get()");
|
||||||
}
|
}
|
||||||
@ -404,6 +412,8 @@ namespace Opm {
|
|||||||
return this->guide_rate;
|
return this->guide_rate;
|
||||||
else if constexpr ( std::is_same_v<T, RFTConfig> )
|
else if constexpr ( std::is_same_v<T, RFTConfig> )
|
||||||
return this->rft_config;
|
return this->rft_config;
|
||||||
|
else if constexpr ( std::is_same_v<T, RSTConfig> )
|
||||||
|
return this->rst_config;
|
||||||
else
|
else
|
||||||
static_assert(always_false1<T>::value, "Template type <T> not supported in get()");
|
static_assert(always_false1<T>::value, "Template type <T> not supported in get()");
|
||||||
}
|
}
|
||||||
@ -441,6 +451,7 @@ namespace Opm {
|
|||||||
serializer(m_year_num);
|
serializer(m_year_num);
|
||||||
serializer(m_first_in_year);
|
serializer(m_first_in_year);
|
||||||
serializer(m_first_in_month);
|
serializer(m_first_in_month);
|
||||||
|
serializer(m_save_step);
|
||||||
m_tuning.serializeOp(serializer);
|
m_tuning.serializeOp(serializer);
|
||||||
serializer(m_nupcol);
|
serializer(m_nupcol);
|
||||||
m_oilvap.serializeOp(serializer);
|
m_oilvap.serializeOp(serializer);
|
||||||
@ -460,8 +471,10 @@ namespace Opm {
|
|||||||
std::size_t m_sim_step = 0;
|
std::size_t m_sim_step = 0;
|
||||||
std::size_t m_month_num = 0;
|
std::size_t m_month_num = 0;
|
||||||
std::size_t m_year_num = 0;
|
std::size_t m_year_num = 0;
|
||||||
bool m_first_in_month = true;
|
bool m_first_in_month;
|
||||||
bool m_first_in_year = true;
|
bool m_first_in_year;
|
||||||
|
std::optional<int> m_save_step;
|
||||||
|
|
||||||
Tuning m_tuning;
|
Tuning m_tuning;
|
||||||
int m_nupcol;
|
int m_nupcol;
|
||||||
OilVaporizationProperties m_oilvap;
|
OilVaporizationProperties m_oilvap;
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include <opm/parser/eclipse/EclipseState/EclipseConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/EclipseConfig.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/InitConfig/InitConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/InitConfig/InitConfig.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
|
@ -790,8 +790,27 @@ namespace {
|
|||||||
this->snapshots.back().update_nupcol(nupcol);
|
this->snapshots.back().update_nupcol(nupcol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Schedule::handleRPTSCHED(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
|
void Schedule::handleRPTSCHED(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
this->snapshots.back().rpt_config.update( RPTConfig(handlerContext.keyword ));
|
this->snapshots.back().rpt_config.update( RPTConfig(handlerContext.keyword ));
|
||||||
|
auto rst_config = this->snapshots.back().rst_config();
|
||||||
|
rst_config.update(handlerContext.keyword, parseContext, errors);
|
||||||
|
this->snapshots.back().rst_config.update(std::move(rst_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schedule::handleRPTRST(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
|
auto rst_config = this->snapshots.back().rst_config();
|
||||||
|
rst_config.update(handlerContext.keyword, parseContext, errors);
|
||||||
|
this->snapshots.back().rst_config.update(std::move(rst_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
We do not really handle the SAVE keyword, we just interpret it as: Write a
|
||||||
|
normal restart file at this report step.
|
||||||
|
*/
|
||||||
|
void Schedule::handleSAVE(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
|
||||||
|
auto rst_config = this->snapshots.back().rst_config();
|
||||||
|
rst_config.save = true;
|
||||||
|
this->snapshots.back().rst_config.update(std::move(rst_config));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Schedule::handleTUNING(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
|
void Schedule::handleTUNING(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) {
|
||||||
@ -1972,7 +1991,9 @@ namespace {
|
|||||||
{ "MULTZ-" , &Schedule::handleMXUNSUPP },
|
{ "MULTZ-" , &Schedule::handleMXUNSUPP },
|
||||||
{ "NODEPROP", &Schedule::handleNODEPROP },
|
{ "NODEPROP", &Schedule::handleNODEPROP },
|
||||||
{ "NUPCOL" , &Schedule::handleNUPCOL },
|
{ "NUPCOL" , &Schedule::handleNUPCOL },
|
||||||
|
{ "RPTRST" , &Schedule::handleRPTRST },
|
||||||
{ "RPTSCHED", &Schedule::handleRPTSCHED },
|
{ "RPTSCHED", &Schedule::handleRPTSCHED },
|
||||||
|
{ "SAVE" , &Schedule::handleSAVE },
|
||||||
{ "TUNING" , &Schedule::handleTUNING },
|
{ "TUNING" , &Schedule::handleTUNING },
|
||||||
{ "UDQ" , &Schedule::handleUDQ },
|
{ "UDQ" , &Schedule::handleUDQ },
|
||||||
{ "VAPPARS" , &Schedule::handleVAPPARS },
|
{ "VAPPARS" , &Schedule::handleVAPPARS },
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2015 Statoil ASA.
|
Copyright 2021 Equinor ASA.
|
||||||
|
|
||||||
This file is part of the Open Porous Media project (OPM).
|
This file is part of the Open Porous Media project (OPM).
|
||||||
|
|
||||||
@ -15,33 +15,16 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include <optional>
|
||||||
#include <algorithm>
|
|
||||||
#include <climits>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iterator>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <opm/common/utility/OpmInputError.hpp>
|
|
||||||
#include <opm/parser/eclipse/Utility/Functional.hpp>
|
|
||||||
|
|
||||||
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
|
|
||||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
|
||||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
|
||||||
#include <opm/parser/eclipse/Deck/DeckSection.hpp>
|
|
||||||
|
|
||||||
#include <opm/parser/eclipse/Parser/ParserKeywords/R.hpp>
|
|
||||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
|
||||||
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
|
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
|
||||||
|
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/RSTConfig.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
#include <opm/parser/eclipse/Parser/ParserKeywords/R.hpp>
|
||||||
|
#include <opm/parser/eclipse/Utility/Functional.hpp>
|
||||||
|
#include <opm/common/utility/OpmInputError.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
@ -56,38 +39,6 @@ inline bool is_int( const std::string& x ) {
|
|||||||
&& std::all_of( x.begin() + 1, x.end(), is_digit );
|
&& std::all_of( x.begin() + 1, x.end(), is_digit );
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const char* RSTIntegerKeywords[] = { "BASIC", // 1
|
|
||||||
"FLOWS", // 2
|
|
||||||
"FIP", // 3
|
|
||||||
"POT", // 4
|
|
||||||
"PBPD", // 5
|
|
||||||
"FREQ", // 6
|
|
||||||
"PRES", // 7
|
|
||||||
"VISC", // 8
|
|
||||||
"DEN", // 9
|
|
||||||
"DRAIN", // 10
|
|
||||||
"KRO", // 11
|
|
||||||
"KRW", // 12
|
|
||||||
"KRG", // 13
|
|
||||||
"PORO", // 14
|
|
||||||
"NOGRAD", // 15
|
|
||||||
"NORST", // 16 NORST - not supported
|
|
||||||
"SAVE", // 17
|
|
||||||
"SFREQ", // 18 SFREQ=?? - not supported
|
|
||||||
"ALLPROPS", // 19
|
|
||||||
"ROCKC", // 20
|
|
||||||
"SGTRAP", // 21
|
|
||||||
"", // 22 - Blank - ignored.
|
|
||||||
"RSSAT", // 23
|
|
||||||
"RVSAT", // 24
|
|
||||||
"GIMULT", // 25
|
|
||||||
"SURFBLK", // 26
|
|
||||||
"", // 27 - PCOW, PCOG, special cased
|
|
||||||
"STREAM", // 28 STREAM=?? - not supported
|
|
||||||
"RK", // 29
|
|
||||||
"VELOCITY", // 30
|
|
||||||
"COMPRESS" }; // 31
|
|
||||||
|
|
||||||
constexpr const char* SCHEDIntegerKeywords[] = { "PRES", // 1
|
constexpr const char* SCHEDIntegerKeywords[] = { "PRES", // 1
|
||||||
"SOIL", // 2
|
"SOIL", // 2
|
||||||
"SWAT", // 3
|
"SWAT", // 3
|
||||||
@ -168,6 +119,37 @@ constexpr const char* SCHEDIntegerKeywords[] = { "PRES", // 1
|
|||||||
"KRN", // 78
|
"KRN", // 78
|
||||||
"GRAD", // 79
|
"GRAD", // 79
|
||||||
};
|
};
|
||||||
|
constexpr const char* RSTIntegerKeywords[] = { "BASIC", // 1
|
||||||
|
"FLOWS", // 2
|
||||||
|
"FIP", // 3
|
||||||
|
"POT", // 4
|
||||||
|
"PBPD", // 5
|
||||||
|
"FREQ", // 6
|
||||||
|
"PRES", // 7
|
||||||
|
"VISC", // 8
|
||||||
|
"DEN", // 9
|
||||||
|
"DRAIN", // 10
|
||||||
|
"KRO", // 11
|
||||||
|
"KRW", // 12
|
||||||
|
"KRG", // 13
|
||||||
|
"PORO", // 14
|
||||||
|
"NOGRAD", // 15
|
||||||
|
"NORST", // 16 NORST - not supported
|
||||||
|
"SAVE", // 17
|
||||||
|
"SFREQ", // 18 SFREQ=?? - not supported
|
||||||
|
"ALLPROPS", // 19
|
||||||
|
"ROCKC", // 20
|
||||||
|
"SGTRAP", // 21
|
||||||
|
"", // 22 - Blank - ignored.
|
||||||
|
"RSSAT", // 23
|
||||||
|
"RVSAT", // 24
|
||||||
|
"GIMULT", // 25
|
||||||
|
"SURFBLK", // 26
|
||||||
|
"", // 27 - PCOW, PCOG, special cased
|
||||||
|
"STREAM", // 28 STREAM=?? - not supported
|
||||||
|
"RK", // 29
|
||||||
|
"VELOCITY", // 30
|
||||||
|
"COMPRESS" }; // 31
|
||||||
|
|
||||||
bool is_RPTRST_mnemonic( const std::string& kw ) {
|
bool is_RPTRST_mnemonic( const std::string& kw ) {
|
||||||
/* all eclipse 100 keywords we want to not simply ignore. The list is
|
/* all eclipse 100 keywords we want to not simply ignore. The list is
|
||||||
@ -191,6 +173,7 @@ bool is_RPTRST_mnemonic( const std::string& kw ) {
|
|||||||
return std::binary_search( std::begin( valid ), std::end( valid ), kw );
|
return std::binary_search( std::begin( valid ), std::end( valid ), kw );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_RPTSCHED_mnemonic( const std::string& kw ) {
|
bool is_RPTSCHED_mnemonic( const std::string& kw ) {
|
||||||
static constexpr const char* valid[] = {
|
static constexpr const char* valid[] = {
|
||||||
"ALKALINE", "ANIONS", "AQUCT", "AQUFET", "AQUFETP", "BFORG",
|
"ALKALINE", "ANIONS", "AQUCT", "AQUFET", "AQUFETP", "BFORG",
|
||||||
@ -216,53 +199,17 @@ bool is_RPTSCHED_mnemonic( const std::string& kw ) {
|
|||||||
return std::binary_search( std::begin( valid ), std::end( valid ), kw );
|
return std::binary_search( std::begin( valid ), std::end( valid ), kw );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::map< std::string, int >
|
||||||
|
RPTSCHED_integer( const std::vector< int >& ints ) {
|
||||||
|
const size_t size = std::min( ints.size(), sizeof( SCHEDIntegerKeywords ) );
|
||||||
|
|
||||||
|
std::map< std::string, int > mnemonics;
|
||||||
|
for( size_t i = 0; i < size; ++i )
|
||||||
|
mnemonics[ SCHEDIntegerKeywords[ i ] ] = ints[ i ];
|
||||||
|
|
||||||
|
return mnemonics;
|
||||||
}
|
}
|
||||||
|
|
||||||
RestartSchedule::RestartSchedule( size_t sched_restart) :
|
|
||||||
rptsched_restart_set( true ),
|
|
||||||
rptsched_restart( sched_restart )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RestartSchedule::RestartSchedule( size_t step, size_t b, size_t freq) :
|
|
||||||
timestep( step ),
|
|
||||||
basic( b ),
|
|
||||||
frequency( basic > 2 ? std::max( freq, size_t{ 1 } ) : freq )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* if basic > 2 and freq is default (zero) we're looking at an error
|
|
||||||
* (every Nth step where N = 0). Instead of throwing we default this to
|
|
||||||
* 1 so that basic > 2 and freq unset essentially is
|
|
||||||
* write-every-timestep. It could've just as easily been an exception,
|
|
||||||
* but to be more robust handling poorly written decks we instead set a
|
|
||||||
* reasonable default and carry on.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
RestartSchedule RestartSchedule::serializeObject()
|
|
||||||
{
|
|
||||||
RestartSchedule result(1, 2, 3);
|
|
||||||
result.rptsched_restart_set = true;
|
|
||||||
result.rptsched_restart = 4;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RestartSchedule::operator!=(const RestartSchedule & rhs) const {
|
|
||||||
return !( *this == rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RestartSchedule::operator==( const RestartSchedule& rhs ) const {
|
|
||||||
if( this->rptsched_restart_set ) {
|
|
||||||
return rhs.rptsched_restart_set
|
|
||||||
&& this->rptsched_restart == rhs.rptsched_restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->timestep == rhs.timestep &&
|
|
||||||
this->basic == rhs.basic &&
|
|
||||||
this->frequency == rhs.frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::map< std::string, int >
|
inline std::map< std::string, int >
|
||||||
RPTRST_integer( const std::vector< int >& ints ) {
|
RPTRST_integer( const std::vector< int >& ints ) {
|
||||||
const size_t PCO_index = 26;
|
const size_t PCO_index = 26;
|
||||||
@ -271,19 +218,30 @@ RPTRST_integer( const std::vector< int >& ints ) {
|
|||||||
std::map< std::string, int > mnemonics;
|
std::map< std::string, int > mnemonics;
|
||||||
const size_t size = std::min( ints.size(), sizeof( RSTIntegerKeywords ) );
|
const size_t size = std::min( ints.size(), sizeof( RSTIntegerKeywords ) );
|
||||||
|
|
||||||
/* fun with special cases. Eclipse seems to ignore the BASIC=0,
|
/* fun with special cases. Eclipse seems to ignore the BASIC=0, interpreting
|
||||||
* interpreting it as sort-of "don't modify". Handle this by *not*
|
* it as sort-of "don't modify". Handle this by *not* adding/updating the
|
||||||
* adding/updating the integer list sourced BASIC mnemonic, should it be
|
* integer list sourced BASIC mnemonic, should it be zero. I'm not sure if
|
||||||
* zero. I'm not sure if this applies to other mnemonics, but the eclipse
|
* this applies to other mnemonics, but the eclipse manual indicates that
|
||||||
* manual indicates that any zero here should disable the output.
|
* any zero here should disable the output.
|
||||||
*
|
*
|
||||||
* See https://github.com/OPM/opm-parser/issues/886 for reference
|
* See https://github.com/OPM/opm-parser/issues/886 for reference
|
||||||
|
*
|
||||||
|
* The current treatment of a mix on RPTRST and RPTSCHED integer keywords is
|
||||||
|
* probably not correct, but it is extremely difficult to comprehend exactly
|
||||||
|
* how it should be. Current code is a rather arbitrary hack to get through
|
||||||
|
* the tests.
|
||||||
*/
|
*/
|
||||||
if( size > 0 && ints[ BASIC_index ] != 0 )
|
|
||||||
mnemonics[ RSTIntegerKeywords[ BASIC_index ] ] = ints[ BASIC_index ];
|
|
||||||
|
|
||||||
for( size_t i = 1; i < std::min( size, PCO_index ); ++i )
|
if (size >= 26) {
|
||||||
mnemonics[ RSTIntegerKeywords[ i ] ] = ints[ i ];
|
for( size_t i = 0; i < std::min( size, PCO_index ); ++i )
|
||||||
|
mnemonics[ RSTIntegerKeywords[ i ] ] = ints[ i ];
|
||||||
|
} else {
|
||||||
|
if( size > 0 && ints[ BASIC_index ] != 0)
|
||||||
|
mnemonics[ RSTIntegerKeywords[ BASIC_index ] ] = ints[ BASIC_index ];
|
||||||
|
|
||||||
|
for( size_t i = 1; i < std::min( size, PCO_index ); ++i )
|
||||||
|
mnemonics[ RSTIntegerKeywords[ i ] ] = ints[ i ];
|
||||||
|
}
|
||||||
|
|
||||||
for( size_t i = PCO_index + 1; i < size; ++i )
|
for( size_t i = PCO_index + 1; i < size; ++i )
|
||||||
mnemonics[ RSTIntegerKeywords[ i ] ] = ints[ i ];
|
mnemonics[ RSTIntegerKeywords[ i ] ] = ints[ i ];
|
||||||
@ -297,16 +255,6 @@ RPTRST_integer( const std::vector< int >& ints ) {
|
|||||||
return mnemonics;
|
return mnemonics;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::map< std::string, int >
|
|
||||||
RPTSCHED_integer( const std::vector< int >& ints ) {
|
|
||||||
const size_t size = std::min( ints.size(), sizeof( SCHEDIntegerKeywords ) );
|
|
||||||
|
|
||||||
std::map< std::string, int > mnemonics;
|
|
||||||
for( size_t i = 0; i < size; ++i )
|
|
||||||
mnemonics[ SCHEDIntegerKeywords[ i ] ] = ints[ i ];
|
|
||||||
|
|
||||||
return mnemonics;
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename F, typename G >
|
template< typename F, typename G >
|
||||||
inline std::map< std::string, int > RPT( const DeckKeyword& keyword,
|
inline std::map< std::string, int > RPT( const DeckKeyword& keyword,
|
||||||
@ -388,331 +336,198 @@ inline std::map< std::string, int > RPT( const DeckKeyword& keyword,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void expand_RPTRST_mnemonics(std::map< std::string, int >& mnemonics) {
|
inline void expand_RPTRST_mnemonics(std::map< std::string, int >& mnemonics) {
|
||||||
const auto allprops = mnemonics.find( "ALLPROPS");
|
const auto allprops_iter = mnemonics.find( "ALLPROPS");
|
||||||
if (allprops != mnemonics.end()) {
|
if (allprops_iter != mnemonics.end()) {
|
||||||
const auto value = allprops->second;
|
const auto value = allprops_iter->second;
|
||||||
mnemonics.erase( "ALLPROPS" );
|
mnemonics.erase( allprops_iter );
|
||||||
|
|
||||||
for (const auto& kw : {"BG","BO","BW","KRG","KRO","KRW","VOIL","VGAS","VWAT","DEN"})
|
for (const auto& kw : {"BG","BO","BW","KRG","KRO","KRW","VOIL","VGAS","VWAT","DEN"})
|
||||||
mnemonics[kw] = value;
|
mnemonics[kw] = value;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<int> extract(std::map<std::string, int>& mnemonics, const std::string& key) {
|
||||||
|
auto iter = mnemonics.find(key);
|
||||||
|
if (iter == mnemonics.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
inline std::pair< std::map< std::string, int >, RestartSchedule >
|
int value = iter->second;
|
||||||
RPTRST( const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors, RestartSchedule prev, size_t step ) {
|
mnemonics.erase(iter);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::pair< std::map< std::string, int >, std::pair<std::optional<int>, std::optional<int>>>
|
||||||
|
RPTRST( const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
auto mnemonics = RPT( keyword, parseContext, errors, is_RPTRST_mnemonic, RPTRST_integer );
|
auto mnemonics = RPT( keyword, parseContext, errors, is_RPTRST_mnemonic, RPTRST_integer );
|
||||||
|
std::optional<int> basic = extract(mnemonics, "BASIC");
|
||||||
const bool has_freq = mnemonics.find( "FREQ" ) != mnemonics.end();
|
std::optional<int> freq = extract(mnemonics, "FREQ");
|
||||||
const bool has_basic = mnemonics.find( "BASIC" ) != mnemonics.end();
|
|
||||||
|
|
||||||
expand_RPTRST_mnemonics( mnemonics );
|
expand_RPTRST_mnemonics( mnemonics );
|
||||||
|
return {mnemonics, { basic, freq }};
|
||||||
if( !has_freq && !has_basic ) return { std::move( mnemonics ), {} };
|
|
||||||
|
|
||||||
const auto basic = has_basic ? mnemonics.at( "BASIC" ) : prev.basic;
|
|
||||||
const auto freq = has_freq ? mnemonics.at( "FREQ" ) : prev.frequency;
|
|
||||||
|
|
||||||
return { std::move( mnemonics ), { step, basic, freq } };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair< std::map< std::string, int >, RestartSchedule >
|
|
||||||
RPTSCHED( const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors ) {
|
template <typename T>
|
||||||
|
void update_optional(std::optional<T>& target, const std::optional<T>& src) {
|
||||||
|
if (src.has_value())
|
||||||
|
target = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// The handleRPTSOL() function is only invoked from the constructor which uses
|
||||||
|
// the SOLUTION section, and the only information actually extracted is whether
|
||||||
|
// to write the initial restart file.
|
||||||
|
|
||||||
|
void RSTConfig::handleRPTSOL( const DeckKeyword& keyword) {
|
||||||
|
const auto& record = keyword.getRecord(0);
|
||||||
|
const auto& item = record.getItem(0);
|
||||||
|
for (const auto& mnemonic : item.getData<std::string>()) {
|
||||||
|
auto mnemonic_RESTART_pos = mnemonic.find("RESTART=");
|
||||||
|
if (mnemonic_RESTART_pos != std::string::npos) {
|
||||||
|
std::string restart_no = mnemonic.substr(mnemonic_RESTART_pos + 8, mnemonic.size());
|
||||||
|
auto restart = std::strtoul(restart_no.c_str(), nullptr, 10);
|
||||||
|
this->write_rst_file = (restart > 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If no RESTART mnemonic is found, either it is not present or we might
|
||||||
|
have an old data set containing integer controls instead of mnemonics.
|
||||||
|
Restart integer switch is integer control nr 7 */
|
||||||
|
|
||||||
|
if (item.data_size() >= 7) {
|
||||||
|
const std::string& integer_control = item.get<std::string>(6);
|
||||||
|
auto restart = std::strtoul(integer_control.c_str(), nullptr, 10);
|
||||||
|
this->write_rst_file = (restart > 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RSTConfig::operator==(const RSTConfig& other) const {
|
||||||
|
return this->write_rst_file == other.write_rst_file &&
|
||||||
|
this->keywords == other.keywords &&
|
||||||
|
this->basic == other.basic &&
|
||||||
|
this->freq == other.freq &&
|
||||||
|
this->save == other.save;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RSTConfig::update_schedule(const std::pair<std::optional<int>, std::optional<int>>& basic_freq) {
|
||||||
|
update_optional(this->basic, basic_freq.first);
|
||||||
|
update_optional(this->freq, basic_freq.second);
|
||||||
|
if (this->basic.has_value()) {
|
||||||
|
auto basic_value = this->basic.value();
|
||||||
|
if (basic_value == 0)
|
||||||
|
this->write_rst_file = false;
|
||||||
|
else if (basic_value == 1 || basic_value == 2)
|
||||||
|
this->write_rst_file = true;
|
||||||
|
else
|
||||||
|
this->write_rst_file = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RSTConfig::handleRPTRST(const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
|
const auto& [mnemonics, basic_freq] = RPTRST(keyword, parseContext, errors);
|
||||||
|
this->update_schedule(basic_freq);
|
||||||
|
for (const auto& [kw,num] : mnemonics)
|
||||||
|
this->keywords[kw] = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSTConfig::handleRPTSCHED(const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
auto mnemonics = RPT( keyword, parseContext, errors, is_RPTSCHED_mnemonic, RPTSCHED_integer );
|
auto mnemonics = RPT( keyword, parseContext, errors, is_RPTSCHED_mnemonic, RPTSCHED_integer );
|
||||||
|
auto nothing = extract(mnemonics, "NOTHING");
|
||||||
|
if (nothing.has_value()) {
|
||||||
|
this->basic = {};
|
||||||
|
this->keywords.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if( mnemonics.count( "NOTHING" ) )
|
if (this->basic.value_or(2) <= 2) {
|
||||||
return { std::move( mnemonics ), { RestartSchedule(0) } };
|
auto restart = extract(mnemonics, "RESTART");
|
||||||
|
if (restart.has_value()) {
|
||||||
|
auto basic_value = std::min(2, restart.value());
|
||||||
|
this->update_schedule({basic_value , 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( mnemonics.count( "RESTART" ) )
|
for (const auto& [kw,num] : mnemonics)
|
||||||
return { std::move( mnemonics ), RestartSchedule( size_t( mnemonics.at( "RESTART" )) ) };
|
this->keywords[kw] = num;
|
||||||
|
|
||||||
return { std::move( mnemonics ), {} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RSTConfig::RSTConfig(const SOLUTIONSection& solution_section, const ParseContext& parseContext, ErrorGuard& errors)
|
||||||
|
{
|
||||||
|
this->write_rst_file = false;
|
||||||
|
if (solution_section.hasKeyword<ParserKeywords::RPTRST>()) {
|
||||||
|
const auto& keyword = solution_section.getKeyword<ParserKeywords::RPTRST>();
|
||||||
|
this->handleRPTRST(keyword, parseContext, errors);
|
||||||
|
|
||||||
void RestartConfig::handleScheduleSection(const SCHEDULESection& schedule, const ParseContext& parseContext, ErrorGuard& errors) {
|
// Guessing on eclipse rules for write of initial RESTART file (at time 0):
|
||||||
size_t current_step = 1;
|
// Write of initial restart file is (due to the eclipse reference manual)
|
||||||
RestartSchedule unset;
|
// governed by RPTSOL RESTART in solution section,
|
||||||
|
// if RPTSOL RESTART > 1 initial restart file is written.
|
||||||
|
// but - due to initial restart file written from Eclipse
|
||||||
|
// for data where RPTSOL RESTART not set - guessing that
|
||||||
|
// when RPTRST is set in SOLUTION (no basic though...) -> write inital restart.
|
||||||
|
this->write_rst_file = true;
|
||||||
|
}
|
||||||
|
|
||||||
auto ignore_RPTSCHED_RESTART = []( decltype( restart_schedule )& x ) {
|
if (solution_section.hasKeyword<ParserKeywords::RPTSOL>()) {
|
||||||
return x.back().basic > 2;
|
const auto& keyword = solution_section.getKeyword<ParserKeywords::RPTSOL>();
|
||||||
};
|
this->handleRPTSOL(keyword);
|
||||||
|
|
||||||
for( const auto& keyword : schedule ) {
|
|
||||||
const auto& name = keyword.name();
|
|
||||||
|
|
||||||
if( name == "DATES" ) {
|
|
||||||
current_step += keyword.size();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if( name == "TSTEP" ) {
|
|
||||||
current_step += keyword.getRecord( 0 ).getItem( 0 ).data_size();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( this->m_timemap.size() <= current_step ) continue;
|
|
||||||
|
|
||||||
if (name == "SAVE") {
|
|
||||||
this->save_keywords.at(current_step) = true;
|
|
||||||
} else {
|
|
||||||
this->save_keywords.at(current_step) = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !( name == "RPTRST" || name == "RPTSCHED" ) ) continue;
|
|
||||||
|
|
||||||
const bool is_RPTRST = name == "RPTRST";
|
|
||||||
const auto& prev_sched = this->restart_schedule.back();
|
|
||||||
|
|
||||||
auto config = is_RPTRST ? RPTRST( keyword, parseContext, errors, prev_sched, current_step )
|
|
||||||
: RPTSCHED( keyword , parseContext, errors);
|
|
||||||
|
|
||||||
/* add the missing entries from the previous step */
|
|
||||||
{
|
|
||||||
auto& mnemonics = config.first;
|
|
||||||
const auto& prev_mnemonics = this->restart_keywords.back();
|
|
||||||
mnemonics.insert( prev_mnemonics.begin(), prev_mnemonics.end() );
|
|
||||||
|
|
||||||
if( mnemonics.find( "NOTHING" ) != mnemonics.end() )
|
|
||||||
mnemonics.clear();
|
|
||||||
|
|
||||||
this->restart_keywords.update( current_step , mnemonics );
|
|
||||||
}
|
|
||||||
const bool ignore_RESTART =
|
|
||||||
!is_RPTRST && ignore_RPTSCHED_RESTART( this->restart_schedule );
|
|
||||||
|
|
||||||
const auto& rs = config.second;
|
|
||||||
if( rs == unset || ignore_RESTART ) continue;
|
|
||||||
|
|
||||||
if( 6 == rs.rptsched_restart || 6 == rs.basic )
|
|
||||||
throw std::runtime_error(
|
|
||||||
"OPM does not support the RESTART=6 setting "
|
|
||||||
"(write restart file every timestep)"
|
|
||||||
);
|
|
||||||
|
|
||||||
this->restart_schedule.update( current_step, rs );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RestartSchedule::writeRestartFile( size_t input_timestep , const TimeMap& timemap) const {
|
|
||||||
if (this->rptsched_restart_set && (this->rptsched_restart > 0))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
switch (this->basic) {
|
void RSTConfig::update(const DeckKeyword& keyword, const ParseContext& parseContext, ErrorGuard& errors) {
|
||||||
//Do not write restart files
|
if (keyword.name() == ParserKeywords::RPTRST::keywordName)
|
||||||
case 0: return false;
|
this->handleRPTRST(keyword, parseContext, errors);
|
||||||
|
else if (keyword.name() == ParserKeywords::RPTSCHED::keywordName) {
|
||||||
//Write restart file every report time
|
this->handleRPTSCHED(keyword, parseContext, errors);
|
||||||
case 1: return true;
|
} else
|
||||||
|
throw std::logic_error("The RSTConfig object can only use RPTRST and RPTSCHED keywords");
|
||||||
//Write restart file every report time
|
|
||||||
case 2: return true;
|
|
||||||
|
|
||||||
//Every n'th report time
|
|
||||||
case 3: return ((input_timestep % this->frequency) == 0) ? true : false;
|
|
||||||
|
|
||||||
//First reportstep of every year, or if n > 1, n'th years
|
|
||||||
case 4: return timemap.isTimestepInFirstOfMonthsYearsSequence(input_timestep, true , this->timestep, this->frequency);
|
|
||||||
|
|
||||||
//First reportstep of every month, or if n > 1, n'th months
|
|
||||||
case 5: return timemap.isTimestepInFirstOfMonthsYearsSequence(input_timestep, false , this->timestep, this->frequency);
|
|
||||||
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
RestartConfig::RestartConfig( const Deck& deck, const std::pair<std::time_t, std::size_t>& restart, const std::optional<int>& output_interval, const ParseContext& parseContext, T&& errors ) :
|
|
||||||
RestartConfig( deck, restart, output_interval, parseContext, errors)
|
|
||||||
{}
|
|
||||||
|
|
||||||
RestartConfig::RestartConfig( const Deck& deck, const std::pair<std::time_t, std::size_t>& restart, const std::optional<int>& output_interval) :
|
|
||||||
RestartConfig( deck, restart, output_interval, ParseContext(), ErrorGuard())
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
RestartConfig::RestartConfig( const Deck& deck, const std::pair<std::time_t, std::size_t>& restart, const std::optional<int>& output_interval, const ParseContext& parseContext, ErrorGuard& errors ) :
|
|
||||||
m_timemap( TimeMap(deck, restart) ),
|
|
||||||
m_first_restart_step( -1 ),
|
|
||||||
restart_schedule( m_timemap, {0,0,1}),
|
|
||||||
restart_keywords( m_timemap, {} ),
|
|
||||||
save_keywords( m_timemap.size(), false )
|
|
||||||
{
|
|
||||||
handleSolutionSection( SOLUTIONSection(deck), parseContext, errors );
|
|
||||||
handleScheduleSection( SCHEDULESection(deck), parseContext, errors );
|
|
||||||
initFirstOutput( );
|
|
||||||
|
|
||||||
if (output_interval.has_value())
|
|
||||||
this->overrideRestartWriteInterval(output_interval.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
RestartConfig RestartConfig::serializeObject()
|
|
||||||
{
|
|
||||||
RestartConfig result;
|
|
||||||
result.m_timemap = TimeMap::serializeObject();
|
|
||||||
result.m_first_restart_step = 2;
|
|
||||||
result.m_write_initial_RST_file = true;
|
|
||||||
result.restart_schedule = {{RestartSchedule::serializeObject()}, 2};
|
|
||||||
result.restart_keywords = {{{{"test",3}}}, 3};
|
|
||||||
result.save_keywords = {false, true};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
RestartSchedule RestartConfig::getNode( size_t timestep ) const{
|
|
||||||
return restart_schedule.get(timestep);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool RestartConfig::getWriteRestartFile(size_t timestep, bool log) const {
|
|
||||||
if (0 == timestep)
|
|
||||||
return m_write_initial_RST_file;
|
|
||||||
|
|
||||||
if (save_keywords[timestep]) {
|
|
||||||
if ( log ) {
|
|
||||||
std::string logstring = "Fast restart using SAVE is not supported. Standard restart file is written instead";
|
|
||||||
Opm::OpmLog::warning("Unhandled output keyword", logstring);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
RestartSchedule ts_restart_config = getNode( timestep );
|
|
||||||
return ts_restart_config.writeRestartFile( timestep , m_timemap );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::map< std::string, int >& RestartConfig::getRestartKeywords( size_t timestep ) const {
|
|
||||||
return restart_keywords.get( timestep );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Will initialize the internal variable holding the first report
|
|
||||||
step when restart output is queried.
|
|
||||||
|
|
||||||
The reason we are interested in this report step is that when we
|
|
||||||
reach this step the output files should be opened with mode 'w'
|
|
||||||
- whereas for subsequent steps they should be opened with mode
|
|
||||||
'a'.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void RestartConfig::initFirstOutput( ) {
|
|
||||||
size_t report_step = 0;
|
|
||||||
while (true) {
|
|
||||||
if (getWriteRestartFile(report_step)) {
|
|
||||||
m_first_restart_step = report_step;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
report_step++;
|
|
||||||
if (report_step == m_timemap.size())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RestartConfig::handleSolutionSection(const SOLUTIONSection& solutionSection, const ParseContext& parseContext, ErrorGuard& errors) {
|
|
||||||
using RST = ParserKeywords::RPTRST;
|
|
||||||
if (solutionSection.hasKeyword<RST>()) {
|
|
||||||
std::size_t step = 1;
|
|
||||||
const auto& rptrstkeyword = solutionSection.getKeyword<RST>();
|
|
||||||
|
|
||||||
const auto rptrst = RPTRST( rptrstkeyword, parseContext, errors, {}, step );
|
|
||||||
this->restart_keywords.update( step, rptrst.first );
|
|
||||||
this->restart_schedule.update( step, rptrst.second );
|
|
||||||
setWriteInitialRestartFile(true); // Guessing on eclipse rules for write of initial RESTART file (at time 0):
|
|
||||||
// Write of initial restart file is (due to the eclipse reference manual)
|
|
||||||
// governed by RPTSOL RESTART in solution section,
|
|
||||||
// if RPTSOL RESTART > 1 initial restart file is written.
|
|
||||||
// but - due to initial restart file written from Eclipse
|
|
||||||
// for data where RPTSOL RESTART not set - guessing that
|
|
||||||
// when RPTRST is set in SOLUTION (no basic though...) -> write inital restart.
|
|
||||||
} //RPTRST
|
|
||||||
|
|
||||||
|
|
||||||
if (solutionSection.hasKeyword("RPTSOL") && (m_timemap.size() > 0)) {
|
|
||||||
handleRPTSOL(solutionSection.getKeyword("RPTSOL"));
|
|
||||||
} //RPTSOL
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RestartConfig::overrideRestartWriteInterval(size_t interval) {
|
|
||||||
size_t step = 0;
|
|
||||||
/* write restart files if the interval is non-zero. The restart
|
|
||||||
* mnemonic (setting) that governs restart-on-interval is BASIC=3
|
|
||||||
*/
|
|
||||||
size_t basic = interval > 0 ? 3 : 0;
|
|
||||||
|
|
||||||
RestartSchedule rs( step, basic, interval );
|
|
||||||
restart_schedule.globalReset( rs );
|
|
||||||
|
|
||||||
setWriteInitialRestartFile( interval > 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RestartConfig::setWriteInitialRestartFile(bool writeInitialRestartFile) {
|
|
||||||
m_write_initial_RST_file = writeInitialRestartFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RestartConfig::handleRPTSOL( const DeckKeyword& keyword) {
|
|
||||||
const auto& record = keyword.getRecord(0);
|
|
||||||
|
|
||||||
size_t restart = 0;
|
|
||||||
size_t found_mnemonic_RESTART = 0;
|
|
||||||
bool handle_RPTSOL_RESTART = false;
|
|
||||||
|
|
||||||
const auto& item = record.getItem(0);
|
|
||||||
|
|
||||||
for (size_t index = 0; index < item.data_size(); ++index) {
|
|
||||||
const std::string& mnemonic = item.get< std::string >(index);
|
|
||||||
|
|
||||||
found_mnemonic_RESTART = mnemonic.find("RESTART=");
|
|
||||||
if (found_mnemonic_RESTART != std::string::npos) {
|
|
||||||
std::string restart_no = mnemonic.substr(found_mnemonic_RESTART+8, mnemonic.size());
|
|
||||||
restart = std::strtoul(restart_no.c_str(), nullptr, 10);
|
|
||||||
handle_RPTSOL_RESTART = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* If no RESTART mnemonic is found, either it is not present or we might
|
|
||||||
have an old data set containing integer controls instead of mnemonics.
|
|
||||||
Restart integer switch is integer control nr 7 */
|
|
||||||
|
|
||||||
if (found_mnemonic_RESTART == std::string::npos) {
|
|
||||||
if (item.data_size() >= 7) {
|
|
||||||
const std::string& integer_control = item.get< std::string >(6);
|
|
||||||
restart = std::strtoul(integer_control.c_str(), nullptr, 10);
|
|
||||||
if (restart != ULONG_MAX)
|
|
||||||
handle_RPTSOL_RESTART = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle_RPTSOL_RESTART) {
|
|
||||||
if (restart > 1) {
|
|
||||||
setWriteInitialRestartFile(true);
|
|
||||||
} else {
|
|
||||||
setWriteInitialRestartFile(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int RestartConfig::getFirstRestartStep() const {
|
|
||||||
return m_first_restart_step;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool RestartConfig::operator==(const RestartConfig& data) const {
|
|
||||||
return this->m_timemap == data.m_timemap &&
|
|
||||||
this->m_first_restart_step == data.m_first_restart_step &&
|
|
||||||
this->m_write_initial_RST_file == data.m_write_initial_RST_file &&
|
|
||||||
this->restart_schedule == data.restart_schedule &&
|
|
||||||
this->restart_keywords == data.restart_keywords &&
|
|
||||||
this->save_keywords == data.save_keywords;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RSTConfig RSTConfig::serializeObject() {
|
||||||
|
RSTConfig rst_config;
|
||||||
|
rst_config.basic = 10;
|
||||||
|
rst_config.freq = {};
|
||||||
|
rst_config.write_rst_file = true;
|
||||||
|
rst_config.save = true;
|
||||||
|
rst_config.keywords = {{"S1", 1}, {"S2", 2}};
|
||||||
|
return rst_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The RPTRST keyword is treated differently in the SOLUTION section and in the
|
||||||
|
SCHEDULE section. This function takes a RSTConfig object created from the
|
||||||
|
solution section and creates a transformed copy suitable as the first
|
||||||
|
RSTConfig to represent the Schedule section.
|
||||||
|
*/
|
||||||
|
RSTConfig RSTConfig::first(const RSTConfig& solution_config ) {
|
||||||
|
RSTConfig rst_config(solution_config);
|
||||||
|
auto basic = rst_config.basic;
|
||||||
|
if (!basic.has_value()) {
|
||||||
|
rst_config.write_rst_file = false;
|
||||||
|
return rst_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto basic_value = basic.value();
|
||||||
|
if (basic_value == 0)
|
||||||
|
rst_config.write_rst_file = false;
|
||||||
|
else if (basic_value == 1 || basic_value == 2)
|
||||||
|
rst_config.write_rst_file = true;
|
||||||
|
else if (basic_value >= 3)
|
||||||
|
rst_config.write_rst_file = {};
|
||||||
|
|
||||||
|
return rst_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -108,10 +108,9 @@ namespace {
|
|||||||
const std::optional<int>& output_interval,
|
const std::optional<int>& output_interval,
|
||||||
const RestartIO::RstState * rst)
|
const RestartIO::RstState * rst)
|
||||||
try :
|
try :
|
||||||
m_static( python, deck, runspec ),
|
m_static( python, deck, runspec, output_interval, parseContext, errors ),
|
||||||
m_restart_info( restart_info(rst)),
|
m_restart_info( restart_info(rst)),
|
||||||
m_sched_deck(deck, m_restart_info ),
|
m_sched_deck(deck, m_restart_info )
|
||||||
restart_config(deck, m_restart_info, output_interval, parseContext, errors)
|
|
||||||
{
|
{
|
||||||
if (rst) {
|
if (rst) {
|
||||||
auto restart_step = this->m_restart_info.second;
|
auto restart_step = this->m_restart_info.second;
|
||||||
@ -211,7 +210,6 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const std::optional
|
|||||||
Schedule result;
|
Schedule result;
|
||||||
|
|
||||||
result.m_static = ScheduleStatic::serializeObject();
|
result.m_static = ScheduleStatic::serializeObject();
|
||||||
result.restart_config = RestartConfig::serializeObject();
|
|
||||||
result.snapshots = { ScheduleState::serializeObject() };
|
result.snapshots = { ScheduleState::serializeObject() };
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1206,28 +1204,31 @@ void Schedule::iterateScheduleSection(std::size_t load_start, std::size_t load_e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestartConfig& Schedule::restart() {
|
bool Schedule::write_rst_file(std::size_t report_step, bool ) const {
|
||||||
return this->restart_config;
|
if (this->m_static.output_interval.has_value())
|
||||||
}
|
return this->m_static.output_interval.value() % report_step;
|
||||||
|
|
||||||
const RestartConfig& Schedule::restart() const {
|
if (report_step == 0)
|
||||||
return this->restart_config;
|
return this->m_static.rst_config.write_rst_file.value();
|
||||||
}
|
|
||||||
|
|
||||||
bool Schedule::write_rst_file(std::size_t report_step, bool log) const {
|
const auto& rst_config = this->snapshots[report_step - 1].rst_config();
|
||||||
return this->restart_config.getWriteRestartFile(report_step, log);
|
const auto& state = this->snapshots[report_step];
|
||||||
|
return state.rst_file(rst_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::map< std::string, int >& Schedule::rst_keywords( size_t timestep ) const {
|
const std::map< std::string, int >& Schedule::rst_keywords( size_t report_step ) const {
|
||||||
return this->restart_config.getRestartKeywords(timestep);
|
if (report_step == 0)
|
||||||
|
return this->m_static.rst_config.keywords;
|
||||||
|
|
||||||
|
const auto& keywords = this->snapshots[report_step - 1].rst_config().keywords;
|
||||||
|
return keywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Schedule::operator==(const Schedule& data) const {
|
bool Schedule::operator==(const Schedule& data) const {
|
||||||
|
|
||||||
return this->m_restart_info == data.m_restart_info &&
|
return this->m_restart_info == data.m_restart_info &&
|
||||||
this->m_static == data.m_static &&
|
this->m_static == data.m_static &&
|
||||||
this->restart_config == data.restart_config &&
|
|
||||||
this->snapshots == data.snapshots;
|
this->snapshots == data.snapshots;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1647,6 +1648,8 @@ void Schedule::create_first(const time_point& start_time, const std::optional<ti
|
|||||||
sched_state.glo.update( GasLiftOpt() );
|
sched_state.glo.update( GasLiftOpt() );
|
||||||
sched_state.guide_rate.update( GuideRateConfig() );
|
sched_state.guide_rate.update( GuideRateConfig() );
|
||||||
sched_state.rft_config.update( RFTConfig() );
|
sched_state.rft_config.update( RFTConfig() );
|
||||||
|
sched_state.rst_config.update( RSTConfig::first( this->m_static.rst_config ) );
|
||||||
|
//sched_state.update_date( start_time );
|
||||||
this->addGroup("FIELD", 0);
|
this->addGroup("FIELD", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ time_point clamp_time(time_point t) {
|
|||||||
return TimeService::from_time_t( TimeService::to_time_t( t ) );
|
return TimeService::from_time_t( TimeService::to_time_t( t ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::size_t, std::size_t> date_diff(time_point t2, time_point t1) {
|
std::pair<std::size_t, std::size_t> date_diff(const time_point& t2, const time_point& t1) {
|
||||||
auto ts1 = TimeStampUTC(TimeService::to_time_t(t1));
|
auto ts1 = TimeStampUTC(TimeService::to_time_t(t1));
|
||||||
auto ts2 = TimeStampUTC(TimeService::to_time_t(t2));
|
auto ts2 = TimeStampUTC(TimeService::to_time_t(t2));
|
||||||
auto year_diff = ts2.year() - ts1.year();
|
auto year_diff = ts2.year() - ts1.year();
|
||||||
@ -54,8 +54,12 @@ std::pair<std::size_t, std::size_t> date_diff(time_point t2, time_point t1) {
|
|||||||
|
|
||||||
|
|
||||||
ScheduleState::ScheduleState(const time_point& t1):
|
ScheduleState::ScheduleState(const time_point& t1):
|
||||||
m_start_time(clamp_time(t1))
|
m_start_time(clamp_time(t1)),
|
||||||
|
m_first_in_month(true),
|
||||||
|
m_first_in_year(true)
|
||||||
{
|
{
|
||||||
|
auto ts1 = TimeStampUTC(TimeService::to_time_t(this->m_start_time));
|
||||||
|
this->m_month_num = ts1.month() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleState::ScheduleState(const time_point& start_time, const time_point& end_time) :
|
ScheduleState::ScheduleState(const time_point& start_time, const time_point& end_time) :
|
||||||
@ -64,6 +68,19 @@ ScheduleState::ScheduleState(const time_point& start_time, const time_point& end
|
|||||||
this->m_end_time = clamp_time(end_time);
|
this->m_end_time = clamp_time(end_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScheduleState::update_date(const time_point& prev_time) {
|
||||||
|
auto [year_diff, month_diff] = date_diff(this->m_start_time, prev_time);
|
||||||
|
this->m_year_num += year_diff;
|
||||||
|
this->m_first_in_month = (month_diff > 0);
|
||||||
|
this->m_first_in_year = (year_diff > 0);
|
||||||
|
|
||||||
|
auto ts1 = TimeStampUTC(TimeService::to_time_t(this->m_start_time));
|
||||||
|
this->m_month_num = ts1.month() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time) :
|
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time) :
|
||||||
ScheduleState(src)
|
ScheduleState(src)
|
||||||
{
|
{
|
||||||
@ -79,14 +96,15 @@ ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_t
|
|||||||
if (next_rft.has_value())
|
if (next_rft.has_value())
|
||||||
this->rft_config.update( std::move(*next_rft) );
|
this->rft_config.update( std::move(*next_rft) );
|
||||||
|
|
||||||
auto [year_diff, month_diff] = date_diff(this->m_start_time, src.m_start_time);
|
this->update_date(src.m_start_time);
|
||||||
this->m_year_num += year_diff;
|
if (this->rst_config().save) {
|
||||||
this->m_month_num += month_diff;
|
auto new_rst = this->rst_config();
|
||||||
|
new_rst.save = false;
|
||||||
this->m_first_in_month = (this->m_month_num > src.m_month_num);
|
this->rst_config.update( std::move(new_rst) );
|
||||||
this->m_first_in_year = (this->m_year_num > src.m_year_num);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time, const time_point& end_time) :
|
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time, const time_point& end_time) :
|
||||||
ScheduleState(src, start_time)
|
ScheduleState(src, start_time)
|
||||||
{
|
{
|
||||||
@ -244,6 +262,7 @@ ScheduleState ScheduleState::serializeObject() {
|
|||||||
ts.guide_rate.update( GuideRateConfig::serializeObject() );
|
ts.guide_rate.update( GuideRateConfig::serializeObject() );
|
||||||
ts.glo.update( GasLiftOpt::serializeObject() );
|
ts.glo.update( GasLiftOpt::serializeObject() );
|
||||||
ts.rft_config.update( RFTConfig::serializeObject() );
|
ts.rft_config.update( RFTConfig::serializeObject() );
|
||||||
|
ts.rst_config.update( RSTConfig::serializeObject() );
|
||||||
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
@ -285,4 +304,44 @@ const WellGroupEvents& ScheduleState::wellgroup_events() const {
|
|||||||
return this->m_wellgroup_events;
|
return this->m_wellgroup_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Observe that the decision to write a restart file will typically be a
|
||||||
|
combination of the RST configuration from the previous report step, and the
|
||||||
|
first_in_year++ attributes of this report step. That is the reason the
|
||||||
|
function takes a RSTConfig argument - instead of using the rst_config member.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool ScheduleState::rst_file(const RSTConfig& rst) const {
|
||||||
|
if (rst.save)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (rst.write_rst_file.has_value())
|
||||||
|
return rst.write_rst_file.value();
|
||||||
|
|
||||||
|
auto freq = rst.freq.value_or(1);
|
||||||
|
auto basic = rst.basic.value();
|
||||||
|
|
||||||
|
if (basic == 3)
|
||||||
|
return (this->sim_step() % freq) == 0;
|
||||||
|
|
||||||
|
if (basic == 4) {
|
||||||
|
if (!this->first_in_year())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (this->m_year_num % freq) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basic == 5) {
|
||||||
|
if (!this->first_in_month())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (this->m_month_num % freq) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::logic_error(fmt::format("Unsupported BASIC={} value", basic));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013 Statoil ASA.
|
|
||||||
|
|
||||||
This file is part of the Open Porous Media project (OPM).
|
|
||||||
|
|
||||||
OPM is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OPM is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <iostream>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
#define BOOST_TEST_MODULE DynamicStateTests
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
||||||
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
Opm::TimeMap make_timemap(int num) {
|
|
||||||
std::vector<std::time_t> tp;
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
tp.push_back( Opm::asTimeT(Opm::TimeStampUTC(2010,1,i+1)));
|
|
||||||
|
|
||||||
Opm::TimeMap timeMap{ tp };
|
|
||||||
return timeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(CreateDynamicTest) {
|
|
||||||
const std::time_t startDate = Opm::TimeMap::mkdate(2010, 1, 1);
|
|
||||||
Opm::TimeMap timeMap({ startDate });
|
|
||||||
Opm::DynamicState<double> state(timeMap , 9.99);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(DynamicStateGetOutOfRangeThrows) {
|
|
||||||
const std::time_t startDate = Opm::TimeMap::mkdate(2010, 1, 1);
|
|
||||||
Opm::TimeMap timeMap({ startDate });
|
|
||||||
Opm::DynamicState<double> state(timeMap , 9.99);
|
|
||||||
BOOST_CHECK_THROW( state.get(1) , std::out_of_range );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(DynamicStateGetDefault) {
|
|
||||||
const std::time_t startDate = Opm::TimeMap::mkdate(2010, 1, 1);
|
|
||||||
Opm::TimeMap timeMap( { startDate } );
|
|
||||||
Opm::DynamicState<int> state(timeMap , 137);
|
|
||||||
BOOST_CHECK_EQUAL( 137 , state.get(0));
|
|
||||||
BOOST_CHECK_EQUAL( 137 , state.back() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(DynamicStateSetOutOfRangeThrows) {
|
|
||||||
Opm::TimeMap timeMap = make_timemap(3);
|
|
||||||
Opm::DynamicState<int> state(timeMap , 137);
|
|
||||||
|
|
||||||
BOOST_CHECK_THROW( state.update(3 , 100) , std::out_of_range );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(DynamicStateSetOK) {
|
|
||||||
Opm::TimeMap timeMap = make_timemap(11);
|
|
||||||
Opm::DynamicState<int> state(timeMap , 137);
|
|
||||||
|
|
||||||
state.update(2 , 23 );
|
|
||||||
BOOST_CHECK_EQUAL( 137 , state.get(0));
|
|
||||||
BOOST_CHECK_EQUAL( 137 , state.get(1));
|
|
||||||
BOOST_CHECK_EQUAL( 23 , state.get(2));
|
|
||||||
BOOST_CHECK_EQUAL( 23 , state.get(5));
|
|
||||||
|
|
||||||
state.update(2 , 17);
|
|
||||||
BOOST_CHECK_EQUAL( 137 , state.get(0));
|
|
||||||
BOOST_CHECK_EQUAL( 137 , state.get(1));
|
|
||||||
BOOST_CHECK_EQUAL( 17 , state.get(2));
|
|
||||||
BOOST_CHECK_EQUAL( 17 , state.get(5));
|
|
||||||
|
|
||||||
state.update(6 , 60);
|
|
||||||
BOOST_CHECK_EQUAL( 17 , state.get(2));
|
|
||||||
BOOST_CHECK_EQUAL( 17 , state.get(5));
|
|
||||||
BOOST_CHECK_EQUAL( 60 , state.get(6));
|
|
||||||
BOOST_CHECK_EQUAL( 60 , state.get(8));
|
|
||||||
BOOST_CHECK_EQUAL( 60 , state.get(9));
|
|
||||||
BOOST_CHECK_EQUAL( 60 , state.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( ResetGlobal ) {
|
|
||||||
Opm::TimeMap timeMap = make_timemap(11);
|
|
||||||
Opm::DynamicState<int> state(timeMap , 137);
|
|
||||||
|
|
||||||
state.update(5 , 100);
|
|
||||||
BOOST_CHECK_EQUAL( state.get(0) , 137 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(4) , 137 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(5) , 100 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(9) , 100 );
|
|
||||||
|
|
||||||
|
|
||||||
state.globalReset( 88 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(0) , 88 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(4) , 88 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(5) , 88 );
|
|
||||||
BOOST_CHECK_EQUAL( state.get(9) , 88 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( CheckReturn ) {
|
|
||||||
Opm::TimeMap timeMap = make_timemap(11);
|
|
||||||
Opm::DynamicState<int> state(timeMap , 137);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( false , state.update( 0 , 137 ));
|
|
||||||
BOOST_CHECK_EQUAL( false , state.update( 3 , 137 ));
|
|
||||||
BOOST_CHECK_EQUAL( true , state.update( 5 , 200 ));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
|||||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
|
||||||
|
|
||||||
using namespace Opm;
|
using namespace Opm;
|
||||||
|
|
||||||
@ -196,7 +195,6 @@ DATES
|
|||||||
|
|
||||||
auto deck = Parser().parseString( data);
|
auto deck = Parser().parseString( data);
|
||||||
IOConfig ioConfig( deck );
|
IOConfig ioConfig( deck );
|
||||||
RestartConfig rstConfig( deck, std::make_pair(std::time_t{0}, std::size_t{0}), {});
|
|
||||||
|
|
||||||
/*If no GRIDFILE nor NOGGF keywords are specified, default output an EGRID file*/
|
/*If no GRIDFILE nor NOGGF keywords are specified, default output an EGRID file*/
|
||||||
BOOST_CHECK( ioConfig.getWriteEGRIDFile() );
|
BOOST_CHECK( ioConfig.getWriteEGRIDFile() );
|
||||||
|
@ -202,14 +202,13 @@ RESTART=1
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(RPTRST_AND_RPTSOL_SOLUTION)
|
BOOST_AUTO_TEST_CASE(RPTRST_AND_RPTSOL_SOLUTION)
|
||||||
{
|
{
|
||||||
const auto input = std::string { R"(RUNSPEC
|
const auto input = std::string { R"(RUNSPEC
|
||||||
DIMENS
|
DIMENS
|
||||||
10 10 10 /
|
10 10 10 /
|
||||||
START
|
START
|
||||||
6 JLY 2020 /
|
6 JUN 2020 /
|
||||||
GRID
|
GRID
|
||||||
|
|
||||||
DXV
|
DXV
|
||||||
@ -259,27 +258,45 @@ END
|
|||||||
|
|
||||||
auto sched = make_schedule(input, false);
|
auto sched = make_schedule(input, false);
|
||||||
|
|
||||||
for (const std::size_t stepID : { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18 }) {
|
for (const std::size_t stepID : { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18 }) {
|
||||||
BOOST_CHECK_MESSAGE(! sched.write_rst_file(stepID),
|
BOOST_CHECK_MESSAGE(! sched.write_rst_file(stepID),
|
||||||
"Must not write restart information for excluded step " << stepID);
|
"Must not write restart information for excluded step " << stepID);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const std::size_t stepID : { 0, 11, 14, 17 }) {
|
for (const std::size_t stepID : { 0, 1, 11, 14, 17 }) {
|
||||||
BOOST_CHECK_MESSAGE(sched.write_rst_file(stepID),
|
BOOST_CHECK_MESSAGE(sched.write_rst_file(stepID),
|
||||||
"Must write restart information for included step " << stepID);
|
"Must write restart information for included step " << stepID);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<bool> first_in_month{true, false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, false, true, false};
|
std::vector<std::tuple<bool, bool, TimeStampUTC>> expected = {{true , true , TimeStampUTC(2020, 6, 6)}, // 0
|
||||||
std::vector<std::size_t> month_num{ 0,0,0,0,0, 1, 1, 2, 3, 4, 5, 6, 7, 10, 12, 17, 17, 18, 18 };
|
{true , false, TimeStampUTC(2020, 7, 7)}, // 1
|
||||||
|
{false, false, TimeStampUTC(2020, 7, 10)}, // 2
|
||||||
|
{false, false, TimeStampUTC(2020, 7, 20)}, // 3
|
||||||
|
{false, false, TimeStampUTC(2020, 7, 30)}, // 4
|
||||||
|
{true , false, TimeStampUTC(2020, 8, 5)}, // 5
|
||||||
|
{false, false, TimeStampUTC(2020, 8, 20)}, // 6
|
||||||
|
{true , false, TimeStampUTC(2020, 9, 5)}, // 7
|
||||||
|
{true , false, TimeStampUTC(2020, 10, 1)}, // 8
|
||||||
|
{true , false, TimeStampUTC(2020, 11, 1)}, // 9
|
||||||
|
{true , false, TimeStampUTC(2020, 12, 1)}, // 10
|
||||||
|
{true , true , TimeStampUTC(2021, 1, 5)}, // 11
|
||||||
|
{true , false, TimeStampUTC(2021, 2, 1)}, // 12
|
||||||
|
{true , false, TimeStampUTC(2021, 5, 17)}, // 13
|
||||||
|
{true , false, TimeStampUTC(2021, 7, 6)}, // 14
|
||||||
|
{true , false, TimeStampUTC(2021, 12, 1)}, // 15
|
||||||
|
{false, false, TimeStampUTC(2021, 12, 31)}, // 16
|
||||||
|
{true, true , TimeStampUTC(2022, 1, 21)}, // 17
|
||||||
|
{false, false, TimeStampUTC(2022, 1, 31)}}; // 18
|
||||||
|
|
||||||
for (std::size_t index = 0; index < sched.size(); index++) {
|
for (std::size_t index = 0; index < sched.size(); index++) {
|
||||||
const auto& state = sched[index];
|
const auto& state = sched[index];
|
||||||
BOOST_CHECK_EQUAL( state.month_num(), month_num[index] );
|
const auto& [first_in_month, first_in_year, ts] = expected[index];
|
||||||
BOOST_CHECK_EQUAL( state.first_in_month(), first_in_month[index] );
|
|
||||||
|
|
||||||
if (index == 0 || index == 11 || index == 17)
|
printf("index: %ld \n", index);
|
||||||
BOOST_CHECK( state.first_in_year());
|
BOOST_CHECK_EQUAL( state.month_num(), ts.month() - 1);
|
||||||
else
|
BOOST_CHECK_EQUAL( state.first_in_month(), first_in_month );
|
||||||
BOOST_CHECK(!state.first_in_year());
|
BOOST_CHECK_EQUAL( state.first_in_year(), first_in_year);
|
||||||
|
BOOST_CHECK( ts == TimeStampUTC( TimeService::to_time_t(state.start_time() )));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,23 +433,25 @@ PORO
|
|||||||
1000*0.25 /
|
1000*0.25 /
|
||||||
SOLUTION
|
SOLUTION
|
||||||
RPTRST -- PRES,DEN,PCOW,PCOG,RK,VELOCITY,COMPRESS
|
RPTRST -- PRES,DEN,PCOW,PCOG,RK,VELOCITY,COMPRESS
|
||||||
6*0 1 0 1 9*0 1 7*0 1 0 3*1 /
|
6*0 1 0 1 9*0 1 7*0 1 0 3*1 / -- Static
|
||||||
|
|
||||||
SCHEDULE
|
SCHEDULE
|
||||||
|
-- 0
|
||||||
DATES -- 1
|
DATES -- 1
|
||||||
10 OKT 2008 /
|
10 OKT 2008 /
|
||||||
/
|
/
|
||||||
RPTSCHED
|
RPTSCHED -- 1
|
||||||
RESTART=1
|
RESTART=1
|
||||||
/
|
/
|
||||||
DATES -- 2
|
DATES -- 2
|
||||||
20 JAN 2010 /
|
20 JAN 2010 /
|
||||||
/
|
/
|
||||||
RPTRST -- RK,VELOCITY,COMPRESS
|
RPTRST -- RK,VELOCITY,COMPRESS --2
|
||||||
18*0 0 8*0 /
|
18*0 0 8*0 /
|
||||||
DATES -- 3
|
DATES -- 3
|
||||||
20 FEB 2010 /
|
20 FEB 2010 /
|
||||||
/
|
/
|
||||||
RPTSCHED
|
RPTSCHED -- 3
|
||||||
RESTART=0
|
RESTART=0
|
||||||
/
|
/
|
||||||
)";
|
)";
|
||||||
@ -1256,28 +1275,28 @@ RPTRST
|
|||||||
BASIC=5 FREQ=2
|
BASIC=5 FREQ=2
|
||||||
/
|
/
|
||||||
DATES
|
DATES
|
||||||
22 MAY 1981 /
|
22 MAY 1981 / -- 1
|
||||||
23 MAY 1981 /
|
23 MAY 1981 / -- 2
|
||||||
24 MAY 1981 /
|
24 MAY 1981 / -- 3
|
||||||
1 JUN 1981 /
|
1 JUN 1981 / -- 4
|
||||||
1 JUL 1981 / -- write
|
1 JUL 1981 / -- 5 Write
|
||||||
1 JAN 1982 / -- write
|
1 JAN 1982 / -- 6 Write
|
||||||
2 JAN 1982 /
|
2 JAN 1982 / -- 7
|
||||||
1 FEB 1982 /
|
1 FEB 1982 / -- 8
|
||||||
1 MAR 1982 / -- write
|
1 MAR 1982 / -- 9 Write
|
||||||
1 APR 1983 / -- write
|
1 APR 1983 / --10
|
||||||
2 JUN 1983 / -- write
|
2 JUN 1983 / --11
|
||||||
/
|
/
|
||||||
)";
|
)";
|
||||||
|
|
||||||
auto sched = make_schedule(data);
|
auto sched = make_schedule(data);
|
||||||
/* BASIC=5, restart file is written at the first report step of each month.
|
/* BASIC=5, restart file is written at the first report step of each month.
|
||||||
*/
|
*/
|
||||||
for( size_t ts : { 1, 2, 3, 4, 7, 8 } )
|
for( size_t ts : { 1, 2, 3, 4, 7, 8, 10, 11 } )
|
||||||
BOOST_CHECK( !sched.write_rst_file( ts ) );
|
BOOST_CHECK( !sched.write_rst_file( ts ) );
|
||||||
|
|
||||||
for( size_t ts : { 5, 6, 9, 10, 11 } )
|
for( size_t ts : { 5, 6, 9} )
|
||||||
BOOST_CHECK( sched.write_rst_file( ts ) );
|
BOOST_CHECK_MESSAGE( sched.write_rst_file( ts ) , "Restart file expected for step: " << ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(BASIC_EQ_0) {
|
BOOST_AUTO_TEST_CASE(BASIC_EQ_0) {
|
||||||
@ -1369,7 +1388,7 @@ BASIC=4 FREQ=2
|
|||||||
DATES
|
DATES
|
||||||
22 MAY 1981 /
|
22 MAY 1981 /
|
||||||
/
|
/
|
||||||
RPTSCHED // BASIC >2, ignore RPTSCHED RESTART
|
RPTSCHED -- BASIC >2, ignore RPTSCHED RESTART
|
||||||
RESTART=3, FREQ=1
|
RESTART=3, FREQ=1
|
||||||
/
|
/
|
||||||
DATES
|
DATES
|
||||||
@ -1456,3 +1475,77 @@ TSTEP
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(RPTSCHED_INTEGER2) {
|
||||||
|
|
||||||
|
const std::string deckData1 = R"(
|
||||||
|
RUNSPEC
|
||||||
|
START -- 0
|
||||||
|
19 JUN 2007 /
|
||||||
|
DIMENS
|
||||||
|
10 10 10 /
|
||||||
|
GRID
|
||||||
|
|
||||||
|
DXV
|
||||||
|
10*1 /
|
||||||
|
|
||||||
|
DYV
|
||||||
|
10*1 /
|
||||||
|
|
||||||
|
DZV
|
||||||
|
10*1 /
|
||||||
|
|
||||||
|
DEPTHZ
|
||||||
|
121*1 /
|
||||||
|
|
||||||
|
PORO
|
||||||
|
1000*0.25 /
|
||||||
|
SOLUTION
|
||||||
|
RPTRST -- PRES,DEN,PCOW,PCOG,RK,VELOCITY,COMPRESS
|
||||||
|
1 5*0 1 0 1 9*0 1 7*0 1 0 3*1 / -- Static
|
||||||
|
|
||||||
|
SCHEDULE
|
||||||
|
-- 0
|
||||||
|
DATES -- 1
|
||||||
|
10 OKT 2008 /
|
||||||
|
/
|
||||||
|
RPTSCHED
|
||||||
|
RESTART=1
|
||||||
|
/
|
||||||
|
DATES -- 2
|
||||||
|
20 JAN 2010 /
|
||||||
|
/
|
||||||
|
RPTRST -- RK,VELOCITY,COMPRESS
|
||||||
|
18*0 0 8*0 /
|
||||||
|
DATES -- 3
|
||||||
|
20 FEB 2010 /
|
||||||
|
/
|
||||||
|
RPTSCHED
|
||||||
|
RESTART=0
|
||||||
|
/
|
||||||
|
|
||||||
|
DATES -- 4
|
||||||
|
1 MAR 2010 /
|
||||||
|
/
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto sched = make_schedule(deckData1, false);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL( sched.size(), 5);
|
||||||
|
BOOST_CHECK( sched.write_rst_file( 0 ) );
|
||||||
|
BOOST_CHECK( sched.write_rst_file( 1 ) );
|
||||||
|
BOOST_CHECK( sched.write_rst_file( 2 ) );
|
||||||
|
BOOST_CHECK( !sched.write_rst_file( 3 ) );
|
||||||
|
|
||||||
|
|
||||||
|
const auto& kw_list1 = filter_keywords(sched.rst_keywords(1));
|
||||||
|
const auto expected1 = {"BG","BO","BW","COMPRESS","DEN","KRG","KRO","KRW","PCOG","PCOW","PRES","RK","VELOCITY","VGAS","VOIL","VWAT"};
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS( expected1.begin(), expected1.end(),
|
||||||
|
kw_list1.begin(), kw_list1.end() );
|
||||||
|
|
||||||
|
const auto& kw_list2 = filter_keywords( sched.rst_keywords(3));
|
||||||
|
const auto expected2 = { "COMPRESS", "RK", "VELOCITY" };
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS( expected2.begin(), expected2.end(),
|
||||||
|
kw_list2.begin(), kw_list2.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -199,6 +199,9 @@ DATES
|
|||||||
DATES
|
DATES
|
||||||
21 'AUG' 2001 /
|
21 'AUG' 2001 /
|
||||||
/
|
/
|
||||||
|
|
||||||
|
SAVE
|
||||||
|
|
||||||
DATES
|
DATES
|
||||||
24 'AUG' 2001 /
|
24 'AUG' 2001 /
|
||||||
/
|
/
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
|
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
||||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||||
@ -138,6 +137,7 @@ BOOST_AUTO_TEST_CASE( NorneRestartConfig ) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( RestartConfig2 ) {
|
BOOST_AUTO_TEST_CASE( RestartConfig2 ) {
|
||||||
std::map<int, boost::gregorian::date> rptConfig;
|
std::map<int, boost::gregorian::date> rptConfig;
|
||||||
|
|
||||||
@ -145,6 +145,7 @@ BOOST_AUTO_TEST_CASE( RestartConfig2 ) {
|
|||||||
rptConfig.emplace(8 , boost::gregorian::date(2000,7,1));
|
rptConfig.emplace(8 , boost::gregorian::date(2000,7,1));
|
||||||
rptConfig.emplace(27 , boost::gregorian::date(2001,1,1));
|
rptConfig.emplace(27 , boost::gregorian::date(2001,1,1));
|
||||||
rptConfig.emplace(45 , boost::gregorian::date(2001,7,1));
|
rptConfig.emplace(45 , boost::gregorian::date(2001,7,1));
|
||||||
|
rptConfig.emplace(50 , boost::gregorian::date(2001,8,24));
|
||||||
rptConfig.emplace(61 , boost::gregorian::date(2002,1,1));
|
rptConfig.emplace(61 , boost::gregorian::date(2002,1,1));
|
||||||
rptConfig.emplace(79 , boost::gregorian::date(2002,7,1));
|
rptConfig.emplace(79 , boost::gregorian::date(2002,7,1));
|
||||||
rptConfig.emplace(89 , boost::gregorian::date(2003,1,1));
|
rptConfig.emplace(89 , boost::gregorian::date(2003,1,1));
|
||||||
@ -177,6 +178,55 @@ BOOST_AUTO_TEST_CASE( RestartConfig2 ) {
|
|||||||
EclipseState state( deck);
|
EclipseState state( deck);
|
||||||
Schedule schedule(deck, state, python);
|
Schedule schedule(deck, state, python);
|
||||||
verifyRestartConfig(schedule, rptConfig);
|
verifyRestartConfig(schedule, rptConfig);
|
||||||
|
|
||||||
|
auto keywords0 = schedule.rst_keywords(0);
|
||||||
|
std::map<std::string, int> expected0 = {{"BG", 1},
|
||||||
|
{"BO", 1},
|
||||||
|
{"BW", 1},
|
||||||
|
{"KRG", 1},
|
||||||
|
{"KRO", 1},
|
||||||
|
{"KRW", 1},
|
||||||
|
{"VOIL", 1},
|
||||||
|
{"VGAS", 1},
|
||||||
|
{"VWAT", 1},
|
||||||
|
{"DEN", 1},
|
||||||
|
{"RVSAT", 1},
|
||||||
|
{"RSSAT", 1},
|
||||||
|
{"PBPD", 1},
|
||||||
|
{"NORST", 1}};
|
||||||
|
for (const auto& [kw, num] : expected0)
|
||||||
|
BOOST_CHECK_EQUAL( keywords0.at(kw), num );
|
||||||
|
|
||||||
|
auto keywords1 = schedule.rst_keywords(1);
|
||||||
|
std::map<std::string, int> expected1 = {{"BG", 1},
|
||||||
|
{"BO", 1},
|
||||||
|
{"BW", 1},
|
||||||
|
{"KRG", 1},
|
||||||
|
{"KRO", 1},
|
||||||
|
{"KRW", 1},
|
||||||
|
{"VOIL", 1},
|
||||||
|
{"VGAS", 1},
|
||||||
|
{"VWAT", 1},
|
||||||
|
{"DEN", 1},
|
||||||
|
{"RVSAT", 1},
|
||||||
|
{"RSSAT", 1},
|
||||||
|
{"PBPD", 1},
|
||||||
|
{"NORST", 1},
|
||||||
|
{"FIP", 3},
|
||||||
|
{"WELSPECS", 1},
|
||||||
|
{"WELLS", 0},
|
||||||
|
{"NEWTON", 1},
|
||||||
|
{"SUMMARY", 1},
|
||||||
|
{"CPU", 1},
|
||||||
|
{"CONV", 10}};
|
||||||
|
|
||||||
|
for (const auto& [kw, num] : expected1)
|
||||||
|
BOOST_CHECK_EQUAL( keywords1.at(kw), num );
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(expected1.size(), keywords1.size());
|
||||||
|
|
||||||
|
auto keywords10 = schedule.rst_keywords(10);
|
||||||
|
BOOST_CHECK( keywords10 == keywords1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -701,8 +701,6 @@ BOOST_AUTO_TEST_CASE(Declared_Connection_Data)
|
|||||||
// XCONN (PROD) + (WINJ)
|
// XCONN (PROD) + (WINJ)
|
||||||
{
|
{
|
||||||
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XConn::index;
|
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XConn::index;
|
||||||
const auto& units = simCase.es.getUnits();
|
|
||||||
using M = ::Opm::UnitSystem::measure;
|
|
||||||
const auto& xconn = amconn.getXConn();
|
const auto& xconn = amconn.getXConn();
|
||||||
|
|
||||||
// PROD well
|
// PROD well
|
||||||
|
Loading…
Reference in New Issue
Block a user