Merge pull request #548 from bska/flow-flow-restart

Add Support for Restarting Flow from ECLIPSE Compatible Restart File
This commit is contained in:
Joakim Hove
2019-02-13 18:49:30 +01:00
committed by GitHub
23 changed files with 1815 additions and 481 deletions

View File

@@ -528,7 +528,9 @@ if(ENABLE_ECL_OUTPUT)
opm/output/data/Solution.hpp
opm/output/data/Wells.hpp
opm/output/eclipse/VectorItems/connection.hpp
opm/output/eclipse/VectorItems/group.hpp
opm/output/eclipse/VectorItems/intehead.hpp
opm/output/eclipse/VectorItems/msw.hpp
opm/output/eclipse/VectorItems/well.hpp
opm/output/eclipse/AggregateGroupData.hpp
opm/output/eclipse/AggregateConnectionData.hpp

View File

@@ -89,12 +89,16 @@ namespace Opm { namespace RestartIO { namespace Helpers {
const std::vector<std::string> restart_group_keys = {"GOPP", "GWPP", "GOPR", "GWPR", "GGPR",
"GVPR", "GWIR", "GGIR", "GWCT", "GGOR",
"GOPT", "GWPT", "GGPT", "GVPT", "GWIT",
"GGIT"};
"GGIT",
"GOPTH", "GWPTH", "GGPTH",
"GWITH", "GGITH"};
const std::vector<std::string> restart_field_keys = {"FOPP", "FWPP", "FOPR", "FWPR", "FGPR",
"FVPR", "FWIR", "FGIR", "FWCT", "FGOR",
"FOPT", "FWPT", "FGPT", "FVPT", "FWIT",
"FGIT"};
"FGIT",
"FOPTH", "FWPTH", "FGPTH",
"FWITH", "FGITH"};
const std::map<std::string, size_t> groupKeyToIndex = {
{"GOPR", 0},
@@ -113,6 +117,11 @@ namespace Opm { namespace RestartIO { namespace Helpers {
{"GGIT", 16},
{"GOPP", 22},
{"GWPP", 23},
{"GOPTH", 135},
{"GWPTH", 139},
{"GWITH", 140},
{"GGPTH", 143},
{"GGITH", 144},
};
const std::map<std::string, size_t> fieldKeyToIndex = {
@@ -132,6 +141,11 @@ namespace Opm { namespace RestartIO { namespace Helpers {
{"FGIT", 16},
{"FOPP", 22},
{"FWPP", 23},
{"FOPTH", 135},
{"FWPTH", 139},
{"FWITH", 140},
{"FGPTH", 143},
{"FGITH", 144},
};
private:

View File

@@ -53,6 +53,7 @@ namespace Opm { namespace RestartIO {
const double cnvT);
DoubHEAD& timeStamp(const TimeStamp& ts);
DoubHEAD& nextStep(const double nextTimeStep);
DoubHEAD& drsdt(const Schedule& sched,
const std::size_t lookup_step,

View File

@@ -1,4 +1,5 @@
/*
Copyright (c) 2018 Equinor ASA
Copyright (c) 2016 Statoil ASA
Copyright (c) 2013-2015 Andreas Lauser
Copyright (c) 2013 SINTEF ICT, Applied Mathematics.
@@ -23,9 +24,6 @@
#ifndef RESTART_IO_HPP
#define RESTART_IO_HPP
#include <vector>
#include <map>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
@@ -35,24 +33,29 @@
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/RestartValue.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
#include <ert/ecl/EclKW.hpp>
#include <ert/ecl/ecl_rsthead.h>
#include <ert/ecl/ecl_rst_file.h>
#include <ert/util/util.h>
#include <map>
#include <utility>
#include <vector>
namespace Opm {
class EclipseGrid;
class EclipseState;
class Phases;
class Schedule;
class SummaryState;
class EclipseGrid;
class EclipseState;
class Phases;
class Schedule;
namespace RestartIO {
} // namespace Opm
/*
The two loose functions RestartIO::save() and RestartIO::load() can
The two free functions RestartIO::save() and RestartIO::load() can
be used to save and load reservoir and well state from restart
files. Observe that these functions 'just do it', i.e. the checking
of which report step to load from, if output is enabled at all and
@@ -69,39 +72,30 @@ namespace RestartIO {
load("CASE.X0010" , 99 , ...)
save("CASE.X0010" , 99 , ...)
will read and write to the file "CASE.X0010" - completely ignoring
will read from and write to the file "CASE.X0010" - completely ignoring
the report step argument '99'.
*/
namespace Opm { namespace RestartIO {
/*void save(const std::string& filename,
int report_step,
double seconds_elapsed,
data::Solution cells,
data::Wells wells,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
std::map<std::string, std::vector<double>> extra_data = {},
bool write_double = false);
*/
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const SummaryState& sumState,
bool write_double = false);
void save(const std::string& filename,
int report_step,
double seconds_elapsed,
RestartValue value,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const SummaryState& sumState,
bool write_double = false);
RestartValue load( const std::string& filename,
int report_step,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::vector<RestartKey>& extra_keys = {});
std::pair<RestartValue, SummaryState>
load(const std::string& filename,
int report_step,
const std::vector<RestartKey>& solution_keys,
const EclipseState& es,
const EclipseGrid& grid,
const Schedule& schedule,
const std::vector<RestartKey>& extra_keys = {});
}
}
#endif
}} // namespace Opm::RestartIO
#endif // RESTART_IO_HPP

View File

@@ -63,6 +63,8 @@ class Summary {
const SummaryState& get_restart_vectors() const;
void reset_cumulative_quantities(const SummaryState& rstrt);
private:
class keyword_handlers;

View File

@@ -66,6 +66,8 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
WaterRate = 1, // Surface flow rate (water)
GasRate = 2, // Surface Flow rate (gas)
Pressure = 34, // Connection pressure value
ResVRate = 49, // Reservoir voidage rate
};
} // XConn

View File

@@ -0,0 +1,37 @@
/*
Copyright (c) 2018 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_OUTPUT_ECLIPSE_VECTOR_DOUBHEAD_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_DOUBHEAD_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
// This is a subset of the items in src/opm/output/eclipse/DoubHEAD.cpp .
// Promote items from that list to this in order to make them public.
enum doubhead : std::vector<double>::size_type {
TsInit = 1, // Maximum Length of Next Timestep
TsMaxz = 2, // Maximum Length of Timestep After Next
TsMinz = 3, // Minumum Length of All Timesteps
};
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_DOUBHEAD_HPP

View File

@@ -0,0 +1,67 @@
/*
Copyright (c) 2018 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_OUTPUT_ECLIPSE_VECTOR_GROUP_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_GROUP_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
namespace XGroup {
enum index : std::vector<double>::size_type {
OilPrRate = 0, // Group's oil production rate
WatPrRate = 1, // Group's water production rate
GasPrRate = 2, // Group's gas production rate
LiqPrRate = 3, // Group's liquid production rate
WatInjRate = 5, // Group's water injection rate
GasInjRate = 6, // Group's gas injection rate
WatCut = 8, // Group's producing water cut
GORatio = 9, // Group's producing gas/oil ratio
OilPrTotal = 10, // Group's total cumulative oil production
WatPrTotal = 11, // Group's total cumulative water production
GasPrTotal = 12, // Group's total cumulative gas production
VoidPrTotal = 13, // Group's total cumulative reservoir
// voidage production
WatInjTotal = 15, // Group's total cumulative water injection
GasInjTotal = 16, // Group's total cumulative gas injection
OilPrPot = 22, // Group's oil production potential
WatPrPot = 23, // Group's water production potential
HistOilPrTotal = 135, // Group's total cumulative oil
// production (observed/historical rates)
HistWatPrTotal = 139, // Group's total cumulative water
// production (observed/historical rates)
HistWatInjTotal = 140, // Group's total cumulative water
// injection (observed/historical rates)
HistGasPrTotal = 143, // Group's total cumulative gas
// production (observed/historical rates)
HistGasInjTotal = 144, // Group's total cumulative gas injection
// (observed/historical rates)
};
} // XGroup
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_GROUP_HPP

View File

@@ -0,0 +1,64 @@
/*
Copyright (c) 2018 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_OUTPUT_ECLIPSE_VECTOR_MSW_HPP
#define OPM_OUTPUT_ECLIPSE_VECTOR_MSW_HPP
#include <vector>
namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems {
namespace ISeg {
enum index : std::vector<int>::size_type {
SegNo = 0, // Segment number (one-based)
OutSeg = 1, // Outlet segment (one-based)
InSegCurBranch = 2, // Inflow segment current branch (one-based)
BranchNo = 3, // Branch number (one-based)
};
} // ISeg
namespace RSeg {
enum index : std::vector<double>::size_type {
DistOutlet = 0, // Segment's distance to outlet
OutletDepthDiff = 1, // Segment's depth differential to outlet
SegDiam = 2, // Internal diameter of segment
SegRough = 3, // Roughness parameter of segment
SegArea = 4, // Cross-sectional area of segment
SegVolume = 5, // Physical volume of segment
DistBHPRef = 6, // Segment's distance to BHP reference node
DepthBHPRef = 7, // Segment's depth differential to BHP ref. node
TotFlowRate = 8, // Normalised total segment flow rate
WatFlowFract = 9, // Normalised Water flow rate fraction
GasFlowFract = 10, // Normalised Gas flow rate fraction
Pressure = 11, // Segment pressure
item40 = 39, // Unknown
item106 = 105, // Unknown
item107 = 106, // Unknown
item108 = 107, // Unknown
item109 = 108, // Unknown
item110 = 109, // Unknown
item111 = 110, // Unknown
};
} // RSeg
}}}} // Opm::RestartIO::Helpers::VectorItems
#endif // OPM_OUTPUT_ECLIPSE_VECTOR_MSW_HPP

View File

@@ -26,26 +26,30 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
namespace IWell {
enum index : std::vector<int>::size_type {
IHead = 0, // I-location (one-based) of well head
JHead = 1, // J-location (one-based) of well head
FirstK = 2, // Layer ID (one-based) of top/first connection
LastK = 3, // Layer ID (one-based) of bottom/last connection
NConn = 4, // Number of active cells connected to well
Group = 5, // Index (one-based) of well's current group
WType = 6, // Well type
WCtrl = 7, // Well control
IHead = 0, // I-location (one-based) of well head
JHead = 1, // J-location (one-based) of well head
FirstK = 2, // Layer ID (one-based) of top/first connection
LastK = 3, // Layer ID (one-based) of bottom/last connection
NConn = 4, // Number of active cells connected to well
Group = 5, // Index (one-based) of well's current group
WType = 6, // Well type (producer vs. injector)
ActWCtrl = 7, // Well's active target control mode (constraint).
item9 = 8, // Unknown
item11 = 10, // Unknown
item9 = 8, // Unknown
item11 = 10, // Unknown
VFPTab = 11, // ID (one-based) of well's current VFP table.
VFPTab = 11, // ID (one-based) of well's current VFP table
PredReqWCtrl = 15, // Well's requested control mode from
// simulation deck (WCONINJE, WCONPROD).
item18 = 17, // Unknown
XFlow = 22,
item25 = 24, // Unknown
item32 = 31, // Unknown
item48 = 47, // Unknown
item50 = 49, // Unknown
HistReqWCtrl = 49, // Well's requested control mode from
// simulation deck (WCONHIST, WCONINJH)
MsWID = 70, // Multisegment well ID
// Value 0 for regular wells
@@ -116,10 +120,15 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
BHPTarget = 6, // Well's bottom hole pressure target
DatumDepth = 9, // Well's reference depth for BHP
LiqRateTarget_2 = 33, //Well's liquid rate target/limit for a well on WCONINJH control or for a producer
GasRateTarget_2 = 54, //Well's gas rate target/limit for a well on WCONINJH control or for producer
BHPTarget_2 = 55, //Well's bottom hole pressure target/limit
HistLiqRateTarget = 33, // Well's historical/observed liquid
// rate target/limit
HistGasRateTarget = 54, // Well's historical/observed gas rate
// target/limit
HistBHPTarget = 55, // Well's historical/observed bottom
// hole pressure target/limit
};
} // SWell
@@ -146,13 +155,22 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
GasFVF = 34, // Well's producing gas formation volume factor.
item37 = 36, // Unknown
item38 = 37, // Unknown
item37 = 36, // Unknown
item38 = 37, // Unknown
BHPTarget = 41, // Well's current BHP Target/Limit
BHPTarget = 41, // Well's current BHP Target/Limit
item82 = 81, // Unknown
item83 = 82, // Unknown
HistOilPrTotal = 75, // Well's total cumulative oil production
// (observed/historical rates)
HistWatPrTotal = 76, // Well's total cumulative water
// production (observed/historical rates)
HistGasPrTotal = 77, // Well's total cumulative gas production
// (observed(historical rates)
HistWatInjTotal = 81, // Well's total cumulative water injection
// (observed/historical rates)
HistGasInjTotal = 82, // Well's total cumulative gas injection
// (observed/historical rates)
WatVoidPrRate = 122, // Well's voidage production rate
GasVoidPrRate = 123, // Well's voidage production rate

View File

@@ -47,7 +47,8 @@ namespace Opm { namespace RestartIO { namespace Helpers {
createDoubHead(const EclipseState& es,
const Schedule& sched,
const std::size_t lookup_step,
const double simTime);
const double simTime,
const double nextTimeStep);

View File

@@ -246,6 +246,8 @@ namespace {
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XConn::index;
using R = ::Opm::data::Rates::opt;
xConn[Ix::Pressure] = units.from_si(M::pressure, x.pressure);
// Note flow rate sign. Treat production rates as positive.
const auto& Q = x.rates;

View File

@@ -381,7 +381,8 @@ namespace {
for (const auto& key : keys) {
if ((key[3] == 'T') && ((key[2] == 'I') || (key[2] == 'P'))) {
// Don't write cumulative quantities in case of
// Don't write cumulative quantities in case of OPM
// extended restart files.
continue;
}
@@ -424,7 +425,7 @@ namespace {
}*/
}
}
}
} // XGrp
namespace ZGrp {
std::size_t entriesPerGroup(const std::vector<int>& inteHead)
@@ -447,7 +448,13 @@ namespace {
WV::WindowSize{ entriesPerGroup(inteHead) }
};
}
}
template <class ZGroupArray>
void staticContrib(const Opm::Group& group, ZGroupArray& zGroup)
{
zGroup[0] = group.name();
}
} // ZGrp
} // Anonymous
void
@@ -520,19 +527,20 @@ captureDeclaredGroupData(const Opm::Schedule& sched,
auto it = indexGroupMap.begin();
while (it != indexGroupMap.end())
{
curGroups[static_cast<int>(it->first)] = it->second;
it++;
}
{
groupLoop(curGroups, [sched, simStep, inteHead, this]
(const Group& group, const std::size_t groupID) -> void
{
auto ig = this->iGroup_[groupID];
IGrp::staticContrib(sched, group, this->nWGMax_, this->nGMaxz_, simStep, ig, inteHead);
});
curGroups[static_cast<int>(it->first)] = it->second;
it++;
}
groupLoop(curGroups, [&sched, simStep, &inteHead, this]
(const Group& group, const std::size_t groupID) -> void
{
auto ig = this->iGroup_[groupID];
IGrp::staticContrib(sched, group, this->nWGMax_, this->nGMaxz_,
simStep, ig, inteHead);
});
// Define Static Contributions to SGrp Array.
groupLoop(curGroups,
[this](const Group& group, const std::size_t groupID) -> void
@@ -541,23 +549,25 @@ captureDeclaredGroupData(const Opm::Schedule& sched,
SGrp::staticContrib(sw);
});
// Define DynamicContributions to XGrp Array.
groupLoop(curGroups,
[restart_group_keys, restart_field_keys, groupKeyToIndex, fieldKeyToIndex, ecl_compatible_rst, sumState, this]
// Define Dynamic Contributions to XGrp Array.
groupLoop(curGroups, [&restart_group_keys, &restart_field_keys,
&groupKeyToIndex, &fieldKeyToIndex,
ecl_compatible_rst, &sumState, this]
(const Group& group, const std::size_t groupID) -> void
{
auto xg = this->xGroup_[groupID];
XGrp::dynamicContrib( restart_group_keys, restart_field_keys, groupKeyToIndex, fieldKeyToIndex, group, sumState, ecl_compatible_rst, xg);
XGrp::dynamicContrib(restart_group_keys, restart_field_keys,
groupKeyToIndex, fieldKeyToIndex, group,
sumState, ecl_compatible_rst, xg);
});
// Define Static Contributions to ZGrp Array.
groupLoop(curGroups,
[this](const Group& group, const std::size_t groupID) -> void
groupLoop(curGroups, [this, &nameIndexMap]
(const Group& group, const std::size_t /* groupID */) -> void
{
auto zw = this->zGroup_[groupID];
zw[0] = group.name();
auto zg = this->zGroup_[ nameIndexMap.at(group.name()) ];
ZGrp::staticContrib(group, zg);
});
}
// ---------------------------------------------------------------------

View File

@@ -30,7 +30,6 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
//#include <opm/output/data/Wells.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
@@ -118,47 +117,22 @@ namespace {
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
}
int groupIndex(const std::string& grpName,
const std::map <const std::string, size_t>& currentGroupMapNameIndex)
{
}
int groupIndex(const std::string& grpName,
const std::map <const std::string, size_t>& currentGroupMapNameIndex)
{
int ind = 0;
auto searchGTName = currentGroupMapNameIndex.find(grpName);
if (searchGTName != currentGroupMapNameIndex.end())
{
ind = searchGTName->second + 1;
auto searchGTName = currentGroupMapNameIndex.find(grpName);
if (searchGTName != currentGroupMapNameIndex.end()) {
ind = searchGTName->second + 1;
}
else
{
else {
std::cout << "group Name: " << grpName << std::endl;
throw std::invalid_argument( "Invalid group name" );
}
return ind;
}
/*int groupIndex(const std::string& grpName,
const std::vector<std::string>& groupNames,
const int maxGroups)
{
if (grpName == "FIELD") {
// Not really supposed to happen since wells are
// not supposed to be parented dirctly to FIELD.
return maxGroups + 1;
}
auto b = std::begin(groupNames);
auto e = std::end (groupNames);
auto i = std::find(b, e, grpName);
if (i == e) {
// Not really supposed to happen since wells are
// not supposed to be parented dirctly to FIELD.
return maxGroups + 1;
}
// One-based indexing.
return std::distance(b, i) + 1;
} */
return ind;
}
int wellType(const Opm::Well& well,
const std::size_t sim_step)
@@ -199,16 +173,6 @@ namespace {
using WMCtrlVal = ::Opm::RestartIO::Helpers::
VectorItems::IWell::Value::WellCtrlMode;
/*{
const auto stat = well.getStatus(sim_step);
using WStat = ::Opm::WellCommon::StatusEnum;
if (stat == WStat::SHUT) {
return WMCtrlVal::Shut;
}
}*/
if (well.isInjector(sim_step)) {
const auto& prop = well
.getInjectionProperties(sim_step);
@@ -236,16 +200,16 @@ namespace {
case CMode::GRUP: return WMCtrlVal::Group;
default:
{
const auto stat = well.getStatus(sim_step);
{
const auto stat = well.getStatus(sim_step);
using WStat = ::Opm::WellCommon::StatusEnum;
using WStat = ::Opm::WellCommon::StatusEnum;
if (stat == WStat::SHUT) {
return WMCtrlVal::Shut;
}
}
return WMCtrlVal::WMCtlUnk;
if (stat == WStat::SHUT) {
return WMCtrlVal::Shut;
}
}
return WMCtrlVal::WMCtlUnk;
}
}
else if (well.isProducer(sim_step)) {
@@ -263,19 +227,19 @@ namespace {
case CMode::THP: return WMCtrlVal::THP;
case CMode::BHP: return WMCtrlVal::BHP;
case CMode::CRAT: return WMCtrlVal::CombRate;
case CMode::GRUP: return WMCtrlVal::Group;
default:
{
const auto stat = well.getStatus(sim_step);
case CMode::GRUP: return WMCtrlVal::Group;
using WStat = ::Opm::WellCommon::StatusEnum;
default:
{
const auto stat = well.getStatus(sim_step);
if (stat == WStat::SHUT) {
return WMCtrlVal::Shut;
}
}
return WMCtrlVal::WMCtlUnk;
using WStat = ::Opm::WellCommon::StatusEnum;
if (stat == WStat::SHUT) {
return WMCtrlVal::Shut;
}
}
return WMCtrlVal::WMCtlUnk;
}
}
@@ -316,31 +280,29 @@ namespace {
const auto& conn = well.getConnections(sim_step);
iWell[Ix::NConn] = static_cast<int>(conn.size());
if (well.isMultiSegment(sim_step))
{
// Set top and bottom connections to zero for multi segment wells
iWell[Ix::FirstK] = 0;
iWell[Ix::LastK] = 0;
}
else
{
iWell[Ix::FirstK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(0).getK() + 1;
iWell[Ix::LastK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(conn.size() - 1).getK() + 1;
}
if (well.isMultiSegment(sim_step)) {
// Set top and bottom connections to zero for multi
// segment wells
iWell[Ix::FirstK] = 0;
iWell[Ix::LastK] = 0;
}
else {
iWell[Ix::FirstK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(0).getK() + 1;
iWell[Ix::LastK] = (iWell[Ix::NConn] == 0)
? 0 : conn.get(conn.size() - 1).getK() + 1;
}
}
iWell[Ix::Group] =
groupIndex(trim(well.getGroupName(sim_step)),
GroupMapNameInd);
groupIndex(trim(well.getGroupName(sim_step)),
GroupMapNameInd);
iWell[Ix::WType] = wellType (well, sim_step);
iWell[Ix::WCtrl] = ctrlMode (well, sim_step);
iWell[Ix::VFPTab] = wellVFPTab(well, sim_step);
iWell[Ix::XFlow] = well.getAllowCrossFlow() ? 1 : 0;
iWell[Ix::XFlow] = well.getAllowCrossFlow() ? 1 : 0;
// The following items aren't fully characterised yet, but
// needed for restart of M2. Will need further refinement.
@@ -349,7 +311,31 @@ namespace {
iWell[Ix::item32] = 7;
iWell[Ix::item48] = - 1;
iWell[Ix::item50] = iWell[Ix::WCtrl];
// Deliberate misrepresentation. Function 'ctrlMode()' returns
// the target control mode requested in the simulation deck.
// This item is supposed to be the well's actual, active target
// control mode in the simulator.
iWell[Ix::ActWCtrl] = ctrlMode(well, sim_step);
const auto isPred =
(well.isProducer(sim_step) &&
well.getProductionProperties(sim_step).predictionMode)
||
(well.isInjector(sim_step) &&
well.getInjectionProperties(sim_step).predictionMode);
if (isPred) {
// Well in prediction mode (WCONPROD, WCONINJE). Assign
// requested control mode for prediction.
iWell[Ix::PredReqWCtrl] = iWell[Ix::ActWCtrl];
iWell[Ix::HistReqWCtrl] = 0;
}
else {
// Well controlled by observed rates/BHP (WCONHIST,
// WCONINJH). Assign requested control mode for history.
iWell[Ix::PredReqWCtrl] = 0; // Possibly =1 instead.
iWell[Ix::HistReqWCtrl] = iWell[Ix::ActWCtrl];
}
// Multi-segmented well information
iWell[Ix::MsWID] = 0; // MS Well ID (0 or 1..#MS wells)
@@ -387,7 +373,7 @@ namespace {
});
iWell[Ix::item9] = any_flowing_conn
? iWell[Ix::WCtrl] : -1;
? iWell[Ix::ActWCtrl] : -1;
iWell[Ix::item11] = 1;
}
@@ -481,7 +467,7 @@ namespace {
void staticContrib(const Opm::Well& well,
const Opm::UnitSystem& units,
const std::size_t sim_step,
const ::Opm::SummaryState& smry,
const ::Opm::SummaryState& smry,
SWellArray& sWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SWell::index;
@@ -491,17 +477,17 @@ namespace {
{
return static_cast<float>(units.from_si(u, x));
};
assignDefaultSWell(sWell);
if (well.isProducer(sim_step)) {
const auto& pp = well.getProductionProperties(sim_step);
const auto& predMode = pp.predictionMode;
const auto& predMode = pp.predictionMode;
if ((pp.OilRate != 0.0) || (!predMode)) {
sWell[Ix::OilRateTarget] =
swprop(M::liquid_surface_rate, pp.OilRate);
}
}
if ((pp.WaterRate != 0.0) || (!predMode)) {
sWell[Ix::WatRateTarget] =
@@ -511,13 +497,13 @@ namespace {
if ((pp.GasRate != 0.0) || (!predMode)) {
sWell[Ix::GasRateTarget] =
swprop(M::gas_surface_rate, pp.GasRate);
sWell[Ix::GasRateTarget_2] = sWell[Ix::GasRateTarget];
sWell[Ix::HistGasRateTarget] = sWell[Ix::GasRateTarget];
}
if (pp.LiquidRate != 0.0 || (!predMode)) {
sWell[Ix::LiqRateTarget] =
swprop(M::liquid_surface_rate, pp.LiquidRate);
sWell[Ix::LiqRateTarget_2] = sWell[Ix::LiqRateTarget];
sWell[Ix::HistLiqRateTarget] = sWell[Ix::LiqRateTarget];
}
else {
sWell[Ix::LiqRateTarget] =
@@ -528,45 +514,51 @@ namespace {
sWell[Ix::ResVRateTarget] =
swprop(M::rate, pp.ResVRate);
}
else if ((smry.has("WVPR:" + well.name())) && (!predMode)) {
else if ((smry.has("WVPR:" + well.name())) && (!predMode)) {
// Write out summary voidage production rate if
// target/limit is not set
auto vr = static_cast<float>(smry.get("WVPR:" + well.name()));
if (vr != 0.0) sWell[Ix::ResVRateTarget] = vr;
auto vr = static_cast<float>(smry.get("WVPR:" + well.name()));
if (vr != 0.0) {
sWell[Ix::ResVRateTarget] = vr;
}
}
sWell[Ix::THPTarget] = pp.THPLimit != 0.0
sWell[Ix::THPTarget] = pp.THPLimit != 0.0
? swprop(M::pressure, pp.THPLimit)
: 0.;
sWell[Ix::BHPTarget] = pp.BHPLimit != 0.0
: 0.0;
sWell[Ix::BHPTarget] = pp.BHPLimit != 0.0
? swprop(M::pressure, pp.BHPLimit)
: swprop(M::pressure, 1.0*::Opm::unit::atm);
sWell[Ix::BHPTarget_2] = sWell[Ix::BHPTarget];
sWell[Ix::HistBHPTarget] = sWell[Ix::BHPTarget];
}
else if (well.isInjector(sim_step)) {
const auto& ip = well.getInjectionProperties(sim_step);
using IP = ::Opm::WellInjector::ControlModeEnum;
using IT = ::Opm::WellInjector::TypeEnum;
using IT = ::Opm::WellInjector::TypeEnum;
if (ip.hasInjectionControl(IP::RATE)) {
if (ip.injectorType == IT::OIL) {
sWell[Ix::OilRateTarget] = swprop(M::liquid_surface_rate, ip.surfaceInjectionRate);
}
if (ip.injectorType == IT::WATER) {
sWell[Ix::WatRateTarget] = swprop(M::liquid_surface_rate, ip.surfaceInjectionRate);
sWell[Ix::LiqRateTarget_2] = sWell[Ix::WatRateTarget];
}
if (ip.injectorType == IT::GAS) {
sWell[Ix::GasRateTarget] = swprop(M::gas_surface_rate, ip.surfaceInjectionRate);
sWell[Ix::GasRateTarget_2] = sWell[Ix::GasRateTarget];
}
if (ip.hasInjectionControl(IP::RATE)) {
if (ip.injectorType == IT::OIL) {
sWell[Ix::OilRateTarget] =
swprop(M::liquid_surface_rate, ip.surfaceInjectionRate);
}
if (ip.injectorType == IT::WATER) {
sWell[Ix::WatRateTarget] =
swprop(M::liquid_surface_rate, ip.surfaceInjectionRate);
sWell[Ix::HistLiqRateTarget] = sWell[Ix::WatRateTarget];
}
if (ip.injectorType == IT::GAS) {
sWell[Ix::GasRateTarget] =
swprop(M::gas_surface_rate, ip.surfaceInjectionRate);
sWell[Ix::HistGasRateTarget] = sWell[Ix::GasRateTarget];
}
}
if (ip.hasInjectionControl(IP::RESV)) {
sWell[Ix::ResVRateTarget] = swprop(M::rate, ip.reservoirInjectionRate);
}
if (ip.hasInjectionControl(IP::RESV)) {
sWell[Ix::ResVRateTarget] =
swprop(M::rate, ip.reservoirInjectionRate);
}
if (ip.hasInjectionControl(IP::THP)) {
sWell[Ix::THPTarget] = swprop(M::pressure, ip.THPLimit);
@@ -575,7 +567,7 @@ namespace {
sWell[Ix::BHPTarget] = ip.hasInjectionControl(IP::BHP)
? swprop(M::pressure, ip.BHPLimit)
: swprop(M::pressure, 1.0E05*::Opm::unit::psia);
sWell[Ix::BHPTarget_2] = sWell[Ix::BHPTarget];
sWell[Ix::HistBHPTarget] = sWell[Ix::BHPTarget];
}
sWell[Ix::DatumDepth] =
@@ -647,15 +639,41 @@ namespace {
xWell[Ix::WatCut] = get("WWCT");
xWell[Ix::GORatio] = get("WGOR");
if (ecl_compatible_rst) {
xWell[Ix::OilPrTotal] = get("WOPT");
xWell[Ix::WatPrTotal] = get("WWPT");
xWell[Ix::GasPrTotal] = get("WGPT");
xWell[Ix::VoidPrTotal] = get("WVPT");
}
if (ecl_compatible_rst) {
xWell[Ix::OilPrTotal] = get("WOPT");
xWell[Ix::WatPrTotal] = get("WWPT");
xWell[Ix::GasPrTotal] = get("WGPT");
xWell[Ix::VoidPrTotal] = get("WVPT");
}
// Not fully characterised.
xWell[Ix::item37] = xWell[Ix::WatPrRate];
xWell[Ix::item38] = xWell[Ix::GasPrRate];
if (ecl_compatible_rst) {
xWell[Ix::HistOilPrTotal] = get("WOPTH");
xWell[Ix::HistWatPrTotal] = get("WWPTH");
xWell[Ix::HistGasPrTotal] = get("WGPTH");
}
}
template <class GetSummaryVector, class XWellArray>
void assignCommonInjector(GetSummaryVector& get,
const bool ecl_compatible_rst,
XWellArray& xWell)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::XWell::index;
xWell[Ix::FlowBHP] = get("WBHP");
if (ecl_compatible_rst) {
// Note: Assign both water and gas cumulatives to support
// case of well alternating between injecting water and gas.
xWell[Ix::WatInjTotal] = get("WWIT");
xWell[Ix::GasInjTotal] = get("WGIT");
xWell[Ix::HistWatInjTotal] = get("WWITH");
xWell[Ix::HistGasInjTotal] = get("WGITH");
}
}
template <class XWellArray>
@@ -673,19 +691,14 @@ namespace {
return smry.has(key) ? smry.get(key) : 0.0;
};
// Injection rates reported as negative, cumulative
// totals as positive.
assignCommonInjector(get, ecl_compatible_rst, xWell);
// Injection rates reported as negative.
xWell[Ix::WatPrRate] = -get("WWIR");
xWell[Ix::LiqPrRate] = xWell[Ix::WatPrRate];
xWell[Ix::FlowBHP] = get("WBHP");
if (ecl_compatible_rst) {
xWell[Ix::WatInjTotal] = get("WWIT");
}
// Not fully characterised.
xWell[Ix::item37] = xWell[Ix::WatPrRate];
xWell[Ix::item82] = xWell[Ix::WatInjTotal];
xWell[Ix::WatVoidPrRate] = -get("WWVIR");
}
@@ -705,26 +718,22 @@ namespace {
return smry.has(key) ? smry.get(key) : 0.0;
};
// Injection rates reported as negative production rates,
// cumulative injection totals as positive.
assignCommonInjector(get, ecl_compatible_rst, xWell);
// Injection rates reported as negative production rates.
xWell[Ix::GasPrRate] = -get("WGIR");
xWell[Ix::VoidPrRate] = -get("WGVIR");
xWell[Ix::FlowBHP] = get("WBHP");
if (ecl_compatible_rst) {
xWell[Ix::GasInjTotal] = get("WGIT");
}
xWell[Ix::GasFVF] = (std::abs(xWell[Ix::GasPrRate]) > 0.0)
? xWell[Ix::VoidPrRate] / xWell[Ix::GasPrRate]
: 0.0;
if (std::isnan(xWell[Ix::GasFVF])) xWell[Ix::GasFVF] = 0.;
if (std::isnan(xWell[Ix::GasFVF])) {
xWell[Ix::GasFVF] = 0.0;
}
// Not fully characterised.
xWell[Ix::item38] = xWell[Ix::GasPrRate];
xWell[Ix::item83] = xWell[Ix::GasInjTotal];
xWell[Ix::GasVoidPrRate] = xWell[Ix::VoidPrRate];
}

View File

@@ -1,4 +1,5 @@
/*
Copyright (c) 2018 Equinor ASA
Copyright (c) 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
@@ -24,6 +25,7 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <chrono>
@@ -76,15 +78,23 @@ Opm::RestartIO::Helpers::
createDoubHead(const EclipseState& es,
const Schedule& sched,
const std::size_t lookup_step,
const double simTime)
const double simTime,
const double nextTimeStep)
{
const auto& usys = es.getDeckUnitSystem();
const auto dh = DoubHEAD{}
.tuningParameters(sched.getTuning(), lookup_step,
getTimeConv(usys))
const auto& usys = es.getDeckUnitSystem();
const auto tconv = getTimeConv(usys);
auto dh = DoubHEAD{}
.tuningParameters(sched.getTuning(), lookup_step, tconv)
.timeStamp (computeTimeStamp(sched, simTime))
.drsdt (sched, lookup_step, getTimeConv(usys))
.drsdt (sched, lookup_step, tconv)
;
if (nextTimeStep > 0.0) {
using M = ::Opm::UnitSystem::measure;
dh.nextStep(usys.from_si(M::time, nextTimeStep));
}
return dh.data();
}

View File

@@ -28,6 +28,8 @@
#include <opm/output/eclipse/InteHEAD.hpp> // Opm::RestartIO::makeUTCTime()
#include <opm/output/eclipse/VectorItems/doubhead.hpp>
#include <chrono>
#include <cmath>
#include <ctime>
@@ -38,12 +40,14 @@
#include <utility>
#include <vector>
namespace VI = Opm::RestartIO::Helpers::VectorItems;
enum Index : std::vector<double>::size_type {
// 0..9
SimTime = 0,
TsInit = 1,
TsMaxz = 2,
TsMinz = 3,
TsInit = VI::doubhead::TsInit,
TsMaxz = VI::doubhead::TsMaxz,
TsMinz = VI::doubhead::TsMinz,
TsMchp = 4,
TsFMax = 5,
TsFMin = 6,
@@ -303,7 +307,7 @@ enum Index : std::vector<double>::size_type {
dh_218 = 218,
dh_219 = 219,
// 220..227
// 220..228
dh_220 = 220,
dh_221 = 221,
dh_222 = 222,
@@ -376,7 +380,6 @@ namespace {
Opm::RestartIO::DoubHEAD::DoubHEAD()
: data_(Index::NUMBER_OF_ITEMS, 0.0)
//: data_(Index::NUMBER_OF_ITEMS, -1.0e20)
{
// Numbers below have unknown usage, values have been determined by
// experiments to be constant across a range of reference cases.
@@ -588,6 +591,16 @@ Opm::RestartIO::DoubHEAD::timeStamp(const TimeStamp& ts)
return *this;
}
Opm::RestartIO::DoubHEAD&
Opm::RestartIO::DoubHEAD::nextStep(const double nextTimeStep)
{
if (nextTimeStep > 0.0) {
this->data_[Index::TsInit] = nextTimeStep;
}
return *this;
}
Opm::RestartIO::DoubHEAD&
Opm::RestartIO::DoubHEAD::drsdt(const Schedule& sched,
const std::size_t lookup_step,

View File

@@ -500,7 +500,14 @@ RestartValue EclipseIO::loadRestart(const std::vector<RestartKey>& solution_keys
report_step,
false );
return RestartIO::load( filename , report_step , solution_keys , es, grid , schedule, extra_keys);
auto rst = RestartIO::load(filename, report_step, solution_keys,
es, grid, schedule, extra_keys);
// Technically a violation of 'const'. Allowed because 'impl' is
// constant pointer to mutable Impl.
this->impl->summary.reset_cumulative_quantities(rst.second);
return std::move(rst.first);
}
EclipseIO::EclipseIO( const EclipseState& es,

File diff suppressed because it is too large Load Diff

View File

@@ -42,6 +42,7 @@
#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <string>
#include <unordered_set>
@@ -74,6 +75,13 @@ namespace {
return extra_solution.count(vector) > 0;
}
double nextStepSize(const Opm::RestartValue& rst_value)
{
return rst_value.hasExtra("OPMEXTRA")
? rst_value.getExtra("OPMEXTRA")[0]
: 0.0;
}
std::vector<int>
serialize_OPM_IWEL(const data::Wells& wells,
const std::vector<const Well*>& sched_wells)
@@ -262,9 +270,10 @@ namespace {
std::vector<int>
writeHeader(::Opm::RestartIO::ecl_rst_file_type* rst_file,
int sim_step,
int report_step,
double simTime,
const int sim_step,
const int report_step,
const double next_step_size,
const double simTime,
const Schedule& schedule,
const EclipseGrid& grid,
const EclipseState& es)
@@ -274,7 +283,8 @@ namespace {
}
// write INTEHEAD to restart file
const auto ih = Helpers::createInteHead(es, grid, schedule, simTime, sim_step, sim_step);
const auto ih = Helpers::createInteHead(es, grid, schedule,
simTime, sim_step, sim_step);
write_kw(rst_file, "INTEHEAD", ih);
// write LOGIHEAD to restart file
@@ -282,7 +292,8 @@ namespace {
write_kw(rst_file, "LOGIHEAD", lh);
// write DOUBHEAD to restart file
const auto dh = Helpers::createDoubHead(es, schedule, sim_step, simTime);
const auto dh = Helpers::createDoubHead(es, schedule, sim_step,
simTime, next_step_size);
write_kw(rst_file, "DOUBHEAD", dh);
// return the inteHead vector
@@ -291,7 +302,7 @@ namespace {
void writeGroup(::Opm::RestartIO::ecl_rst_file_type* rst_file,
int sim_step,
const bool ecl_compatible_rst,
const bool ecl_compatible_rst,
const Schedule& schedule,
const Opm::SummaryState& sumState,
const std::vector<int>& ih)
@@ -301,15 +312,15 @@ namespace {
auto groupData = Helpers::AggregateGroupData(ih);
auto & rst_g_keys = groupData.restart_group_keys;
auto & rst_f_keys = groupData.restart_field_keys;
auto & grpKeyToInd = groupData.groupKeyToIndex;
auto & fldKeyToInd = groupData.fieldKeyToIndex;
const auto& rst_g_keys = groupData.restart_group_keys;
const auto& rst_f_keys = groupData.restart_field_keys;
const auto& grpKeyToInd = groupData.groupKeyToIndex;
const auto& fldKeyToInd = groupData.fieldKeyToIndex;
groupData.captureDeclaredGroupData(schedule,
rst_g_keys, rst_f_keys,
grpKeyToInd, fldKeyToInd,
ecl_compatible_rst,
ecl_compatible_rst,
simStep, sumState, ih);
write_kw(rst_file, "IGRP", groupData.getIGroup());
write_kw(rst_file, "SGRP", groupData.getSGroup());
@@ -322,14 +333,16 @@ namespace {
const UnitSystem& units,
const Schedule& schedule,
const EclipseGrid& grid,
const Opm::SummaryState& sumState,
const Opm::data::Wells& wells,
const Opm::SummaryState& sumState,
const Opm::data::Wells& wells,
const std::vector<int>& ih)
{
// write ISEG, RSEG, ILBS and ILBR to restart file
const size_t simStep = static_cast<size_t> (sim_step);
const auto simStep = static_cast<std::size_t> (sim_step);
auto MSWData = Helpers::AggregateMSWData(ih);
MSWData.captureDeclaredMSWData(schedule, simStep, units, ih, grid, sumState, wells);
MSWData.captureDeclaredMSWData(schedule, simStep, units,
ih, grid, sumState, wells);
write_kw(rst_file, "ISEG", MSWData.getISeg());
write_kw(rst_file, "ILBS", MSWData.getILBs());
@@ -339,7 +352,7 @@ namespace {
void writeWell(::Opm::RestartIO::ecl_rst_file_type* rst_file,
int sim_step,
const bool ecl_compatible_rst,
const bool ecl_compatible_rst,
const Phases& phases,
const UnitSystem& units,
const EclipseGrid& grid,
@@ -350,7 +363,9 @@ namespace {
{
auto wellData = Helpers::AggregateWellData(ih);
wellData.captureDeclaredWellData(schedule, units, sim_step, sumState, ih);
wellData.captureDynamicWellData(schedule, sim_step, ecl_compatible_rst, wells, sumState);
wellData.captureDynamicWellData(schedule, sim_step,
ecl_compatible_rst,
wells, sumState);
write_kw(rst_file, "IWEL", wellData.getIWell());
write_kw(rst_file, "SWEL", wellData.getSWell());
@@ -358,7 +373,7 @@ namespace {
write_kw(rst_file, "ZWEL", serialize_ZWEL(wellData.getZWell()));
// Extended set of OPM well vectors
if (!ecl_compatible_rst)
if (!ecl_compatible_rst)
{
const auto sched_wells = schedule.getWells(sim_step);
@@ -372,17 +387,81 @@ namespace {
}
auto connectionData = Helpers::AggregateConnectionData(ih);
connectionData.captureDeclaredConnData(schedule, grid, units, wells, sim_step);
connectionData.captureDeclaredConnData(schedule, grid, units,
wells, sim_step);
write_kw(rst_file, "ICON", connectionData.getIConn());
write_kw(rst_file, "SCON", connectionData.getSConn());
write_kw(rst_file, "XCON", connectionData.getXConn());
}
bool haveHysteresis(const RestartValue& value)
{
for (const auto* key : { "KRNSW_OW", "PCSWM_OW",
"KRNSW_GO", "PCSWM_GO", })
{
if (value.solution.has(key)) { return true; }
}
return false;
}
std::vector<double>
convertedHysteresisSat(const RestartValue& value,
const std::string& primary,
const std::string& fallback)
{
auto smax = std::vector<double>{};
if (value.solution.has(primary)) {
smax = value.solution.data(primary);
}
else if (value.solution.has(fallback)) {
smax = value.solution.data(fallback);
}
if (! smax.empty()) {
std::transform(std::begin(smax), std::end(smax), std::begin(smax),
[](const double s) { return 1.0 - s; });
}
return smax;
}
template <class OutputVector>
void writeEclipseCompatHysteresis(const RestartValue& value,
const bool write_double,
OutputVector&& writeVector)
{
// Convert Flow-specific vectors {KRNSW,PCSWM}_OW to ECLIPSE's
// requisite SOMAX vector. Only partially characterised.
// Sufficient for Norne.
{
const auto somax =
convertedHysteresisSat(value, "KRNSW_OW", "PCSWM_OW");
if (! somax.empty()) {
writeVector("SOMAX", somax, write_double);
}
}
// Convert Flow-specific vectors {KRNSW,PCSWM}_GO to ECLIPSE's
// requisite SGMAX vector. Only partially characterised.
// Sufficient for Norne.
{
const auto sgmax =
convertedHysteresisSat(value, "KRNSW_GO", "PCSWM_GO");
if (! sgmax.empty()) {
writeVector("SGMAX", sgmax, write_double);
}
}
}
void writeSolution(ecl_rst_file_type* rst_file,
const RestartValue& value,
const bool ecl_compatible_rst,
const bool write_double_arg)
const bool ecl_compatible_rst,
const bool write_double_arg)
{
ecl_rst_file_start_solution(rst_file);
@@ -396,8 +475,6 @@ namespace {
};
for (const auto& elm : value.solution) {
if (ecl_compatible_rst && (elm.first == "TEMP")) continue;
if (elm.second.target == data::TargetType::RESTART_SOLUTION)
{
write(elm.first, elm.second.data, write_double_arg);
@@ -413,9 +490,15 @@ namespace {
}
}
if (ecl_compatible_rst && haveHysteresis(value)) {
writeEclipseCompatHysteresis(value, write_double_arg, write);
}
ecl_rst_file_end_solution(rst_file);
if (ecl_compatible_rst) return;
if (ecl_compatible_rst) {
return;
}
for (const auto& elm : value.solution) {
if (elm.second.target == data::TargetType::RESTART_AUXILIARY) {
@@ -452,25 +535,24 @@ void save(const std::string& filename,
bool write_double)
{
::Opm::RestartIO::checkSaveArguments(es, value, grid);
bool ecl_compatible_rst = es.getIOConfig().getEclCompatibleRST();
const auto ecl_compatible_rst = es.getIOConfig().getEclCompatibleRST();
const auto sim_step = std::max(report_step - 1, 0);
const auto& units = es.getUnits();
auto rst_file = openRestartFile(filename, report_step);
if (ecl_compatible_rst)
write_double = false;
// Convert solution fields and extra values from SI to user units.
value.solution.convertFromSI(units);
for (auto& extra_value : value.extra) {
const auto& restart_key = extra_value.first;
auto& data = extra_value.second;
units.from_si(restart_key.dim, data);
if (ecl_compatible_rst) {
write_double = false;
}
const auto inteHD = writeHeader(rst_file.get(), sim_step, report_step,
seconds_elapsed, schedule, grid, es);
// Convert solution fields and extra values from SI to user units.
value.convertFromSI(units);
const auto inteHD =
writeHeader(rst_file.get(), sim_step, report_step,
nextStepSize(value), seconds_elapsed,
schedule, grid, es);
writeGroup(rst_file.get(), sim_step, ecl_compatible_rst,
schedule, sumState, inteHD);
@@ -480,14 +562,14 @@ void save(const std::string& filename,
const auto& wells = schedule.getWells(sim_step);
if (! wells.empty()) {
const auto numMSW =
std::count_if(std::begin(wells), std::end(wells),
const auto haveMSW =
std::any_of(std::begin(wells), std::end(wells),
[sim_step](const Well* well)
{
return well->isMultiSegment(sim_step);
});
if (numMSW > 0) {
if (haveMSW) {
writeMSWData(rst_file.get(), sim_step, units,
schedule, grid, sumState, value.wells, inteHD);
}
@@ -500,8 +582,9 @@ void save(const std::string& filename,
writeSolution(rst_file.get(), value, ecl_compatible_rst, write_double);
if (!ecl_compatible_rst)
::Opm::RestartIO::writeExtraData(rst_file.get(), value.extra);
if (! ecl_compatible_rst) {
writeExtraData(rst_file.get(), value.extra);
}
}
}} // Opm::RestartIO

View File

@@ -65,6 +65,8 @@ namespace {
"WIR", "GIR",
"WIT", "GIT",
"WCT", "GOR",
"OPTH", "WPTH", "GPTH",
"WITH", "GITH",
};
}
@@ -1527,4 +1529,23 @@ const SummaryState& Summary::get_restart_vectors() const
return this->prev_state;
}
void Summary::reset_cumulative_quantities(const SummaryState& rstrt)
{
for (const auto& f : this->handlers->handlers) {
if (! smspec_node_is_total(f.first)) {
// Ignore quantities that are not cumulative ("total").
continue;
}
const auto* genkey = smspec_node_get_gen_key1(f.first);
if (rstrt.has(genkey)) {
// Assume 'rstrt' uses output units. This is satisfied if rstrt
// is constructed from information in a restart file--i.e., from
// the double precision restart vectors 'XGRP' and 'XWEL' during
// RestartIO::load().
this->prev_state.add(genkey, rstrt.get(genkey));
}
}
}
}} // namespace Opm::out

View File

@@ -1,4 +1,5 @@
/*
Copyright 2019 Equinor
Copyright 2018 Statoil ASA
This file is part of the Open Porous Media project (OPM).
@@ -232,6 +233,11 @@ TSTEP -- 8
state.add("WWCT:OP_1" , 0.625);
state.add("WGOR:OP_1" , 234.5);
state.add("WBHP:OP_1" , 314.15);
state.add("WOPTH:OP_1", 345.6);
state.add("WWPTH:OP_1", 456.7);
state.add("WGPTH:OP_1", 567.8);
state.add("WWITH:OP_1", 0.0);
state.add("WGITH:OP_1", 0.0);
state.add("WGVIR:OP_1", 0.0);
state.add("WWVIR:OP_1", 0.0);
@@ -250,6 +256,11 @@ TSTEP -- 8
state.add("WWCT:OP_2" , 0.0);
state.add("WGOR:OP_2" , 0.0);
state.add("WBHP:OP_2" , 400.6);
state.add("WOPTH:OP_2", 0.0);
state.add("WWPTH:OP_2", 0.0);
state.add("WGPTH:OP_2", 0.0);
state.add("WWITH:OP_2", 1515.0);
state.add("WGITH:OP_2", 3030.0);
state.add("WGVIR:OP_2", 1234.0);
state.add("WWVIR:OP_2", 4321.0);
@@ -268,6 +279,11 @@ TSTEP -- 8
state.add("WWCT:OP_3" , 0.0625);
state.add("WGOR:OP_3" , 1234.5);
state.add("WBHP:OP_3" , 314.15);
state.add("WOPTH:OP_3", 2345.6);
state.add("WWPTH:OP_3", 3456.7);
state.add("WGPTH:OP_3", 4567.8);
state.add("WWITH:OP_3", 0.0);
state.add("WGITH:OP_3", 0.0);
state.add("WGVIR:OP_3", 0.0);
state.add("WWVIR:OP_3", 43.21);
@@ -532,7 +548,7 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step1)
const auto& iwell = awd.getIWell();
BOOST_CHECK_EQUAL(iwell[i0 + Ix::item9 ], iwell[i0 + Ix::WCtrl]);
BOOST_CHECK_EQUAL(iwell[i0 + Ix::item9 ], iwell[i0 + Ix::ActWCtrl]);
BOOST_CHECK_EQUAL(iwell[i0 + Ix::item11], 1);
}
@@ -561,17 +577,27 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step1)
BOOST_CHECK_CLOSE(xwell[i0 + Ix::LiqPrRate], 1.0 + 2.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::VoidPrRate], 4.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::FlowBHP], 314.15, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::WatCut] , 0.625, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::GORatio], 234.5, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::FlowBHP], 314.15 , 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::WatCut] , 0.625, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::GORatio], 234.5 , 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::OilPrTotal], 10.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::WatPrTotal], 20.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::GasPrTotal], 30.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::VoidPrTotal], 40.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::item37], xwell[i0 + Ix::WatPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::item38], xwell[i0 + Ix::GasPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::item37],
xwell[i0 + Ix::WatPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::item38],
xwell[i0 + Ix::GasPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistOilPrTotal], 345.6, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistWatPrTotal], 456.7, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistGasPrTotal], 567.8, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistWatInjTotal], 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistGasInjTotal], 0.0, 1.0e-10);
}
// XWEL (OP_2)
@@ -585,6 +611,7 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step1)
BOOST_CHECK_CLOSE(xwell[i1 + Ix::VoidPrRate], -1234.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::FlowBHP], 400.6, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::WatInjTotal], 1000.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::GasInjTotal], 2000.0, 1.0e-10);
// Bg = VGIR / GIR = 1234.0 / 200.0
@@ -593,11 +620,11 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step1)
BOOST_CHECK_CLOSE(xwell[i1 + Ix::item38],
xwell[i1 + Ix::GasPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::item83],
xwell[i1 + Ix::GasInjTotal], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::GasVoidPrRate],
xwell[i1 + Ix::VoidPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistOilPrTotal] , 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistWatPrTotal] , 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistGasPrTotal] , 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistWatInjTotal], 1515.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistGasInjTotal], 3030.0, 1.0e-10);
}
}
@@ -641,7 +668,7 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step2)
const auto& iwell = awd.getIWell();
BOOST_CHECK_EQUAL(iwell[i1 + Ix::item9],
iwell[i1 + Ix::WCtrl]);
iwell[i1 + Ix::ActWCtrl]);
BOOST_CHECK_EQUAL(iwell[i1 + Ix::item11], 1);
}
@@ -672,6 +699,10 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step2)
BOOST_CHECK_CLOSE(xwell[i0 + Ix::item38],
xwell[i0 + Ix::GasPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistOilPrTotal], 345.6, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistWatPrTotal], 456.7, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i0 + Ix::HistGasPrTotal], 567.8, 1.0e-10);
}
// XWEL (OP_2) -- water injector
@@ -690,14 +721,17 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step2)
BOOST_CHECK_CLOSE(xwell[i1 + Ix::FlowBHP], 400.6, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::WatInjTotal], 1000.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::GasInjTotal], 2000.0, 1.0e-10);
// Copy of WWIR
BOOST_CHECK_CLOSE(xwell[i1 + Ix::item37],
xwell[i1 + Ix::WatPrRate], 1.0e-10);
// Copy of WWIT
BOOST_CHECK_CLOSE(xwell[i1 + Ix::item82],
xwell[i1 + Ix::WatInjTotal], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistOilPrTotal] , 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistWatPrTotal] , 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistGasPrTotal] , 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistWatInjTotal], 1515.0, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i1 + Ix::HistGasInjTotal], 3030.0, 1.0e-10);
// WWVIR
BOOST_CHECK_CLOSE(xwell[i1 + Ix::WatVoidPrRate],
@@ -733,6 +767,10 @@ BOOST_AUTO_TEST_CASE (Dynamic_Well_Data_Step2)
// Copy of WGPR
BOOST_CHECK_CLOSE(xwell[i2 + Ix::item38],
xwell[i2 + Ix::GasPrRate], 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i2 + Ix::HistOilPrTotal], 2345.6, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i2 + Ix::HistWatPrTotal], 3456.7, 1.0e-10);
BOOST_CHECK_CLOSE(xwell[i2 + Ix::HistGasPrTotal], 4567.8, 1.0e-10);
}
}

View File

@@ -366,6 +366,11 @@ Opm::SummaryState sim_state()
state.add("WWCT:OP_1" , 0.625);
state.add("WGOR:OP_1" , 234.5);
state.add("WBHP:OP_1" , 314.15);
state.add("WOPTH:OP_1", 345.6);
state.add("WWPTH:OP_1", 456.7);
state.add("WGPTH:OP_1", 567.8);
state.add("WWITH:OP_1", 0.0);
state.add("WGITH:OP_1", 0.0);
state.add("WGVIR:OP_1", 0.0);
state.add("WWVIR:OP_1", 0.0);
@@ -384,6 +389,11 @@ Opm::SummaryState sim_state()
state.add("WWCT:OP_2" , 0.0);
state.add("WGOR:OP_2" , 0.0);
state.add("WBHP:OP_2" , 400.6);
state.add("WOPTH:OP_2", 0.0);
state.add("WWPTH:OP_2", 0.0);
state.add("WGPTH:OP_2", 0.0);
state.add("WWITH:OP_2", 1515.0);
state.add("WGITH:OP_2", 3030.0);
state.add("WGVIR:OP_2", 1234.0);
state.add("WWVIR:OP_2", 4321.0);
@@ -402,9 +412,58 @@ Opm::SummaryState sim_state()
state.add("WWCT:OP_3" , 0.0625);
state.add("WGOR:OP_3" , 1234.5);
state.add("WBHP:OP_3" , 314.15);
state.add("WOPTH:OP_3", 2345.6);
state.add("WWPTH:OP_3", 3456.7);
state.add("WGPTH:OP_3", 4567.8);
state.add("WWITH:OP_3", 0.0);
state.add("WGITH:OP_3", 0.0);
state.add("WGVIR:OP_3", 0.0);
state.add("WWVIR:OP_3", 43.21);
state.add("GOPR:OP" , 110.0);
state.add("GWPR:OP" , 120.0);
state.add("GGPR:OP" , 130.0);
state.add("GVPR:OP" , 140.0);
state.add("GOPT:OP" , 1100.0);
state.add("GWPT:OP" , 1200.0);
state.add("GGPT:OP" , 1300.0);
state.add("GVPT:OP" , 1400.0);
state.add("GWIR:OP" , - 256.0);
state.add("GGIR:OP" , - 65536.0);
state.add("GWIT:OP" , 31415.9);
state.add("GGIT:OP" , 27182.8);
state.add("GWCT:OP" , 0.625);
state.add("GGOR:OP" , 1234.5);
state.add("GGVIR:OP", 123.45);
state.add("GWVIR:OP", 1234.56);
state.add("GOPTH:OP", 5678.90);
state.add("GWPTH:OP", 6789.01);
state.add("GGPTH:OP", 7890.12);
state.add("GWITH:OP", 8901.23);
state.add("GGITH:OP", 9012.34);
state.add("FOPR" , 1100.0);
state.add("FWPR" , 1200.0);
state.add("FGPR" , 1300.0);
state.add("FVPR" , 1400.0);
state.add("FOPT" , 11000.0);
state.add("FWPT" , 12000.0);
state.add("FGPT" , 13000.0);
state.add("FVPT" , 14000.0);
state.add("FWIR" , - 2560.0);
state.add("FGIR" , - 655360.0);
state.add("FWIT" , 314159.2);
state.add("FGIT" , 271828.1);
state.add("FWCT" , 0.625);
state.add("FGOR" , 1234.5);
state.add("FOPTH", 56789.01);
state.add("FWPTH", 67890.12);
state.add("FGPTH", 78901.23);
state.add("FWITH", 89012.34);
state.add("FGITH", 90123.45);
state.add("FGVIR", 1234.56);
state.add("FWVIR", 12345.67);
return state;
}
@@ -688,7 +747,7 @@ BOOST_AUTO_TEST_CASE(ExtraData_content) {
/* extra_keys = */ {
{"EXTRA" , UnitSystem::measure::pressure, true} ,
{"EXTRA2", UnitSystem::measure::identity, false}
});
}).first;
BOOST_CHECK(!rst_value.hasExtra("EXTRA2"));
BOOST_CHECK( rst_value.hasExtra("EXTRA"));
@@ -777,4 +836,136 @@ BOOST_AUTO_TEST_CASE(STORE_THPRES) {
BOOST_AUTO_TEST_CASE(Restore_Cumulatives)
{
Setup setup("FIRST_SIM.DATA");
// Write fully ECLIPSE compatible output. This also saves cumulatives.
setup.es.getIOConfig().setEclCompatibleRST(true);
const auto restart_value = RestartValue {
mkSolution(setup.grid.getNumActive()),
mkWells()
};
const auto sumState = sim_state();
RestartIO::save("FILE.UNRST", 1, 100, restart_value,
setup.es, setup.grid, setup.schedule, sumState);
const auto rst_value = RestartIO::load("FILE.UNRST", 1,
/* solution_keys = */ {
RestartKey("SWAT", UnitSystem::measure::identity),
},
setup.es, setup.grid, setup.schedule,
/* extra_keys = */ {});
const auto& rstSumState = rst_value.second;
// Verify that the restored summary state has all of its requisite
// cumulative summary vectors.
// Producer => W*IT{,H} saved/restored as zero (0.0)
BOOST_CHECK(rstSumState.has("WOPT:OP_1"));
BOOST_CHECK(rstSumState.has("WGPT:OP_1"));
BOOST_CHECK(rstSumState.has("WWPT:OP_1"));
BOOST_CHECK(rstSumState.has("WVPT:OP_1"));
BOOST_CHECK(rstSumState.has("WWIT:OP_1"));
BOOST_CHECK(rstSumState.has("WGIT:OP_1"));
BOOST_CHECK(rstSumState.has("WOPTH:OP_1"));
BOOST_CHECK(rstSumState.has("WGPTH:OP_1"));
BOOST_CHECK(rstSumState.has("WWPTH:OP_1"));
BOOST_CHECK(rstSumState.has("WWITH:OP_1"));
BOOST_CHECK(rstSumState.has("WGITH:OP_1"));
BOOST_CHECK_CLOSE(rstSumState.get("WOPT:OP_1"), 10.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGPT:OP_1"), 30.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWPT:OP_1"), 20.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WVPT:OP_1"), 40.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWIT:OP_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGIT:OP_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WOPTH:OP_1"), 345.6, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWPTH:OP_1"), 456.7, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGPTH:OP_1"), 567.8, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWITH:OP_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGITH:OP_1"), 0.0, 1.0e-10);
// Gas injector => W*PT{,H} saved/restored as zero (0.0)
BOOST_CHECK(rstSumState.has("WOPT:OP_2"));
BOOST_CHECK(rstSumState.has("WGPT:OP_2"));
BOOST_CHECK(rstSumState.has("WWPT:OP_2"));
BOOST_CHECK(rstSumState.has("WVPT:OP_2"));
BOOST_CHECK(rstSumState.has("WWIT:OP_2"));
BOOST_CHECK(rstSumState.has("WGIT:OP_2"));
BOOST_CHECK(rstSumState.has("WOPTH:OP_2"));
BOOST_CHECK(rstSumState.has("WGPTH:OP_2"));
BOOST_CHECK(rstSumState.has("WWPTH:OP_2"));
BOOST_CHECK(rstSumState.has("WWITH:OP_2"));
BOOST_CHECK(rstSumState.has("WGITH:OP_2"));
BOOST_CHECK_CLOSE(rstSumState.get("WOPT:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGPT:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWPT:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WVPT:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWIT:OP_2"), 1000.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGIT:OP_2"), 2000.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WOPTH:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGPTH:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWPTH:OP_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WWITH:OP_2"), 1515.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("WGITH:OP_2"), 3030.0, 1.0e-10);
// Group cumulatives saved/restored for all phases
BOOST_CHECK(rstSumState.has("GOPT:OP"));
BOOST_CHECK(rstSumState.has("GGPT:OP"));
BOOST_CHECK(rstSumState.has("GWPT:OP"));
BOOST_CHECK(rstSumState.has("GVPT:OP"));
BOOST_CHECK(rstSumState.has("GWIT:OP"));
BOOST_CHECK(rstSumState.has("GGIT:OP"));
BOOST_CHECK(rstSumState.has("GOPTH:OP"));
BOOST_CHECK(rstSumState.has("GGPTH:OP"));
BOOST_CHECK(rstSumState.has("GWPTH:OP"));
BOOST_CHECK(rstSumState.has("GWITH:OP"));
BOOST_CHECK(rstSumState.has("GGITH:OP"));
BOOST_CHECK_CLOSE(rstSumState.get("GOPT:OP"), 1100.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GWPT:OP"), 1200.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GGPT:OP"), 1300.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GVPT:OP"), 1400.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GWIT:OP"), 31415.9, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GGIT:OP"), 27182.8, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GOPTH:OP"), 5678.90, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GGPTH:OP"), 7890.12, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GWPTH:OP"), 6789.01, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GWITH:OP"), 8901.23, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("GGITH:OP"), 9012.34, 1.0e-10);
// Field cumulatives saved/restored for all phases
BOOST_CHECK(rstSumState.has("FOPT"));
BOOST_CHECK(rstSumState.has("FGPT"));
BOOST_CHECK(rstSumState.has("FWPT"));
BOOST_CHECK(rstSumState.has("FVPT"));
BOOST_CHECK(rstSumState.has("FWIT"));
BOOST_CHECK(rstSumState.has("FGIT"));
BOOST_CHECK(rstSumState.has("FOPTH"));
BOOST_CHECK(rstSumState.has("FGPTH"));
BOOST_CHECK(rstSumState.has("FWPTH"));
BOOST_CHECK(rstSumState.has("FWITH"));
BOOST_CHECK(rstSumState.has("FGITH"));
BOOST_CHECK_CLOSE(rstSumState.get("FOPT"), 11000.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FWPT"), 12000.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FGPT"), 13000.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FVPT"), 14000.0, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FWIT"), 314159.2, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FGIT"), 271828.1, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FOPTH"), 56789.01, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FGPTH"), 78901.23, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FWPTH"), 67890.12, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FWITH"), 89012.34, 1.0e-10);
BOOST_CHECK_CLOSE(rstSumState.get("FGITH"), 90123.45, 1.0e-10);
}
}

View File

@@ -2899,3 +2899,176 @@ BOOST_AUTO_TEST_CASE(Write_Read)
}
BOOST_AUTO_TEST_SUITE_END()
// =====================================================================
BOOST_AUTO_TEST_SUITE(Reset_Cumulative_Vectors)
BOOST_AUTO_TEST_CASE(Reset)
{
const auto config = setup { "test.Reset.Cumulative" };
::Opm::out::Summary smry {
config.es, config.config, config.grid,
config.schedule, "Ignore.This"
};
auto rstrt = ::Opm::SummaryState{};
rstrt.add("WOPT:W_1", 1.0);
rstrt.add("WWPT:W_1", 2.0);
rstrt.add("WGPT:W_1", 3.0);
rstrt.add("WVPT:W_1", 4.0);
rstrt.add("WWIT:W_1", 5.0);
rstrt.add("WGIT:W_1", 6.0);
rstrt.add("WOPTH:W_1", 0.1);
rstrt.add("WWPTH:W_1", 0.2);
rstrt.add("WGPTH:W_1", 0.3);
rstrt.add("WWITH:W_1", 0.5);
rstrt.add("WGITH:W_1", 0.6);
rstrt.add("GOPT:NoSuchGroup", 1.0);
rstrt.add("GWPT:NoSuchGroup", 2.0);
rstrt.add("GGPT:NoSuchGroup", 3.0);
rstrt.add("GVPT:NoSuchGroup", 4.0);
rstrt.add("GWIT:NoSuchGroup", 5.0);
rstrt.add("GGIT:NoSuchGroup", 6.0);
rstrt.add("FOPT", 10.0);
rstrt.add("FWPT", 20.0);
rstrt.add("FGPT", 30.0);
rstrt.add("FVPT", 40.0);
rstrt.add("FWIT", 50.0);
rstrt.add("FGIT", 60.0);
rstrt.add("FOPTH", 0.01);
rstrt.add("FWPTH", 0.02);
rstrt.add("FGPTH", 0.03);
rstrt.add("FWITH", 0.05);
rstrt.add("FGITH", 0.06);
smry.reset_cumulative_quantities(rstrt);
const auto& sumstate = smry.get_restart_vectors();
// Cumulatives don't affect rates, BHP, WCT, or GOR.
for (const auto* w : { "W_1", "W_2", "W_3" }) {
auto get = [w, &sumstate](const std::string& vector) {
return sumstate.get(vector + ':' + std::string(w));
};
BOOST_CHECK_THROW(get("WWPR"), std::out_of_range);
BOOST_CHECK_THROW(get("WOPR"), std::out_of_range);
BOOST_CHECK_THROW(get("WGPR"), std::out_of_range);
BOOST_CHECK_THROW(get("WVPR"), std::out_of_range);
BOOST_CHECK_THROW(get("WWIR"), std::out_of_range);
BOOST_CHECK_THROW(get("WGIR"), std::out_of_range);
BOOST_CHECK_THROW(get("WBHP"), std::out_of_range);
BOOST_CHECK_THROW(get("WWCT"), std::out_of_range);
BOOST_CHECK_THROW(get("WGOR"), std::out_of_range);
}
// Cumulatives reset for W_1.
BOOST_CHECK_CLOSE(sumstate.get("WOPT:W_1"), 1.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWPT:W_1"), 2.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGPT:W_1"), 3.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WVPT:W_1"), 4.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWIT:W_1"), 5.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGIT:W_1"), 6.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WOPTH:W_1"), 0.1, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWPTH:W_1"), 0.2, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGPTH:W_1"), 0.3, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWITH:W_1"), 0.5, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGITH:W_1"), 0.6, 1.0e-10);
// Cumulatives unset for W_2.
BOOST_CHECK_CLOSE(sumstate.get("WOPT:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWPT:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGPT:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WVPT:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWIT:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGIT:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WOPTH:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWPTH:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGPTH:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWITH:W_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGITH:W_2"), 0.0, 1.0e-10);
// Cumulatives unset for W_3.
BOOST_CHECK_CLOSE(sumstate.get("WOPT:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWPT:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGPT:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WVPT:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWIT:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGIT:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WOPTH:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWPTH:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGPTH:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WWITH:W_3"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("WGITH:W_3"), 0.0, 1.0e-10);
// Cumulatives unset for G_1.
BOOST_CHECK_CLOSE(sumstate.get("GOPT:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWPT:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGPT:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GVPT:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWIT:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGIT:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GOPTH:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWPTH:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGPTH:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWITH:G_1"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGITH:G_1"), 0.0, 1.0e-10);
// Cumulatives unset for G_2.
BOOST_CHECK_CLOSE(sumstate.get("GOPT:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWPT:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGPT:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GVPT:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWIT:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGIT:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GOPTH:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWPTH:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGPTH:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GWITH:G_2"), 0.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("GGITH:G_2"), 0.0, 1.0e-10);
// Cumulatives reset for FIELD.
BOOST_CHECK_CLOSE(sumstate.get("FOPT"), 10.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FWPT"), 20.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FGPT"), 30.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FVPT"), 40.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FWIT"), 50.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FGIT"), 60.0, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FOPTH"), 0.01, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FWPTH"), 0.02, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FGPTH"), 0.03, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FWITH"), 0.05, 1.0e-10);
BOOST_CHECK_CLOSE(sumstate.get("FGITH"), 0.06, 1.0e-10);
}
BOOST_AUTO_TEST_SUITE_END()