Merge pull request #3039 from bska/rst-glo-compat

Increase Compatibility of GLO Restart Output
This commit is contained in:
Markus Blatt 2022-06-07 11:53:31 +02:00 committed by GitHub
commit 3a5b17a070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 375 additions and 65 deletions

View File

@ -16,9 +16,9 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <opm/output/eclipse/AggregateGroupData.hpp>
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
#include <opm/output/eclipse/VectorItems/group.hpp>
#include <opm/output/eclipse/VectorItems/well.hpp>
@ -28,15 +28,21 @@
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Group/GTNode.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <exception>
#include <map>
#include <optional>
#include <string>
#include <stdexcept>
#include <tuple>
#include <utility>
#include <vector>
#include <fmt/format.h>
#define ENABLE_GCNTL_DEBUG_OUTPUT 0
@ -961,24 +967,42 @@ void assignGroupProductionTargets(const Opm::Group& group,
}
}
// Compatibility shim for restart output of gas-lift rates and limits. The
// values are intentionally discontinuous in small interval close to zero.
template <typename SGProp>
float getGLORate(const SGProp& sgprop, const std::optional<double>& rate)
{
if (! rate.has_value()) {
// Defaulted rate limit (e.g., "supply" or "total").
return ::Opm::RestartIO::Helpers::
VectorItems::SGroup::Value::NoGLOLimit;
}
// Note: These thresholds and values are in output units.
const auto smallRateThreshold = 1.0e-20f;
const auto smallRateDefaultValue = 1.0e-6f;
const auto glo_rate =
sgprop(Opm::UnitSystem::measure::gas_surface_rate, rate.value());
if ((glo_rate < 0.0f) || !(glo_rate < smallRateThreshold)) {
// rate \not\in [0, smallRateThreshold) -> Unchanged
return glo_rate;
}
// rate \in [0, smallRateThreshold) -> smallRateDefaultValue
return smallRateDefaultValue;
}
template <typename SGProp, class SGrpArray>
void assignGasLiftOptimisation(const Opm::GasLiftOpt::Group& group,
SGProp&& sgprop,
const SGProp& sgprop,
SGrpArray& sGrp)
{
using Ix = ::Opm::RestartIO::Helpers::VectorItems::SGroup::prod_index;
using M = ::Opm::UnitSystem::measure;
sGrp[Ix::GLOMaxSupply] = sGrp[Ix::GLOMaxRate] =
::Opm::RestartIO::Helpers::VectorItems::SGroup::Value::NoGLOLimit;
if (const auto& max_supply = group.max_lift_gas(); max_supply.has_value()) {
sGrp[Ix::GLOMaxSupply] = sgprop(M::gas_surface_rate, max_supply.value());
}
if (const auto& max_total = group.max_total_gas(); max_total.has_value()) {
sGrp[Ix::GLOMaxRate] = sgprop(M::gas_surface_rate, max_total.value());
}
sGrp[Ix::GLOMaxSupply] = getGLORate(sgprop, group.max_lift_gas());
sGrp[Ix::GLOMaxRate] = getGLORate(sgprop, group.max_total_gas());
}
template <class SGrpArray>

View File

@ -488,52 +488,6 @@ Opm::SummaryState sim_state()
return state;
}
#if 0
Opm::SummaryState sim_state()
{
auto state = Opm::SummaryState {Opm::TimeService::now()};
state.update("GOPR:GRP1", 235.);
state.update("GGPR:GRP1", 100237.);
state.update("GWPR:GRP1", 239.);
state.update("GOPGR:GRP1", 345.6);
state.update("GWPGR:GRP1", 456.7);
state.update("GGPGR:GRP1", 567.8);
state.update("GVPGR:GRP1", 678.9);
state.update("GOIGR:GRP1", 0.123);
state.update("GWIGR:GRP1", 1234.5);
state.update("GGIGR:GRP1", 2345.6);
state.update("GOPR:WGRP1", 23.);
state.update("GGPR:WGRP1", 50237.);
state.update("GWPR:WGRP1", 29.);
state.update("GOPGR:WGRP1", 456.7);
state.update("GWPGR:WGRP1", 567.8);
state.update("GGPGR:WGRP1", 678.9);
state.update("GVPGR:WGRP1", 789.1);
state.update("GOIGR:WGRP1", 1.23);
state.update("GWIGR:WGRP1", 2345.6);
state.update("GGIGR:WGRP1", 3456.7);
state.update("GOPR:WGRP2", 43.);
state.update("GGPR:WGRP2", 70237.);
state.update("GWPR:WGRP2", 59.);
state.update("GOPGR:WGRP2", 56.7);
state.update("GWPGR:WGRP2", 67.8);
state.update("GGPGR:WGRP2", 78.9);
state.update("GVPGR:WGRP2", 89.1);
state.update("GOIGR:WGRP2", 12.3);
state.update("GWIGR:WGRP2", 345.6);
state.update("GGIGR:WGRP2", 456.7);
state.update("FOPR", 3456.);
state.update("FGPR", 2003456.);
state.update("FWPR", 5678.);
return state;
}
#endif
Opm::SummaryState sim_state_2()
{
auto state = Opm::SummaryState {Opm::TimeService::now()};
@ -596,21 +550,68 @@ Opm::SummaryState sim_state_2()
return state;
}
Opm::SummaryState sim_state_3()
{
auto state = Opm::SummaryState {Opm::TimeService::now()};
state.update("FMCTP", 0.0); // FIELD: Production mode NONE
state.update("FMCTW", 3.0); // FIELD: Injection mode VREP for water
state.update("FMCTG", 0.0); // FIELD: Injection mode NONE for gas
state.update_group_var("PLAT-A", "GMCTP", -1.0);
state.update_group_var("PLAT-A", "GMCTW", 0.0);
state.update_group_var("PLAT-A", "GMCTG", 0.0);
state.update_group_var("M5S", "GMCTP", 1.0);
state.update_group_var("M5S", "GMCTW", 3.0);
state.update_group_var("M5S", "GMCTG", 0.0);
state.update_group_var("M5N", "GMCTP", -1.0);
state.update_group_var("M5N", "GMCTW", 0.0);
state.update_group_var("M5N", "GMCTG", 0.0);
state.update_group_var("B1", "GMCTP", 0.0);
state.update_group_var("B1", "GMCTW", 0.0);
state.update_group_var("B1", "GMCTG", 0.0);
state.update_group_var("C1", "GMCTP", 0.0);
state.update_group_var("C1", "GMCTW", 0.0);
state.update_group_var("C1", "GMCTG", 0.0);
state.update_group_var("F1", "GMCTP", 0.0);
state.update_group_var("F1", "GMCTW", 0.0);
state.update_group_var("F1", "GMCTG", 0.0);
state.update_well_var("B-1H", "WMCTL", -1.0);
state.update_well_var("B-2H", "WMCTL", 0.0);
state.update_well_var("B-3H", "WMCTL", -1.0);
state.update_well_var("G-3H", "WMCTL", -1.0);
state.update_well_var("G-4H", "WMCTL", -1.0);
state.update_well_var("C-1H", "WMCTL", -1.0);
state.update_well_var("C-2H", "WMCTL", -1.0);
state.update_well_var("F-1H", "WMCTL", -1.0);
state.update_well_var("F-2H", "WMCTL", -1.0);
return state;
}
}
struct SimulationCase
{
explicit SimulationCase(const char* deck)
: SimulationCase { Opm::Parser{}.parseString(deck) }
{}
explicit SimulationCase(const Opm::Deck& deck)
: es ( deck )
: es { deck }
, grid { deck }
, python( std::make_shared<Opm::Python>() )
, sched (deck, es, python )
, sched { deck, es, std::make_shared<Opm::Python>() }
{}
// Order requirement: 'es' must be declared/initialised before 'sched'.
Opm::EclipseState es;
Opm::EclipseGrid grid;
std::shared_ptr<Opm::Python> python;
Opm::Schedule sched;
};
@ -865,4 +866,289 @@ BOOST_AUTO_TEST_CASE (Declared_Group_Data_2)
}
}
BOOST_AUTO_TEST_CASE (GasLiftOtimisation)
{
// Abridged, and amended, copy of opm-tests/model5/4_GLIFT_MODEL5.DATA
const auto cse = SimulationCase { R"(
RUNSPEC
DIMENS
20 30 10 /
OIL
WATER
GAS
DISGAS
METRIC
START
01 'JAN' 2020 /
EQLDIMS
1 100 25 /
TABDIMS
/
WELLDIMS
--max.well max.con/well max.grup max.w/grup
10 15 9 10 /
--FLOW THP WCT GCT ALQ VFP
VFPPDIMS
22 13 10 13 13 50 /
UNIFIN
UNIFOUT
GRID
DXV
20*100
/
DYV
30*100
/
DZV
10*2
/
TOPS
600*2000 /
PORO
6000*0.28 /
PERMX
6000*10000.0 /
PERMZ
6000*1000.0 /
COPY
PERMX PERMY /
/
PROPS
REGIONS
SOLUTION
EQUIL
-- Datum P woc Pc goc Pc Rsvd Rvvd
2000.00 195.0 2070 0.0 500.00 0.0 1 0 0 /
PBVD
2000.00 75.00
2150.00 75.00 /
------------------------------------------------------------------------------------------------
SCHEDULE
------------------------------------------------------------------------------------------------
--
-- FIELD
-- |
-- PLAT-A
-- ---------------+---------------------
-- | |
-- M5S M5N
-- ---------+---------- -----+-------
-- | | | |
-- B1 G1 C1 F1
-- ----+------ ---+--- ---+--- ---+---
-- | | | | | | | | |
-- B-1H B-2H B-3H G-3H G-4H C-1H C-2H F-1H F-2H
--
GRUPTREE
'PROD' 'FIELD' /
'M5S' 'PLAT-A' /
'M5N' 'PLAT-A' /
'C1' 'M5N' /
'F1' 'M5N' /
'B1' 'M5S' /
'G1' 'M5S' /
/
WELSPECS
--WELL GROUP IHEEL JHEEL DREF PHASE DRAD INFEQ SIINS XFLOW PRTAB DENS
'B-1H' 'B1' 11 3 1* OIL 1* 1* SHUT 1* 1* 1* /
'B-2H' 'B1' 4 7 1* OIL 1* 1* SHUT 1* 1* 1* /
'B-3H' 'B1' 11 12 1* OIL 1* 1* SHUT 1* 1* 1* /
'C-1H' 'C1' 13 20 1* OIL 1* 1* SHUT 1* 1* 1* /
'C-2H' 'C1' 12 27 1* OIL 1* 1* SHUT 1* 1* 1* /
/
WELSPECS
'F-1H' 'F1' 19 4 1* WATER 1* 1* SHUT 1* 1* 1* /
'F-2H' 'F1' 19 12 1* WATER 1* 1* SHUT 1* 1* 1* /
'G-3H' 'G1' 19 21 1* WATER 1* 1* SHUT 1* 1* 1* /
'G-4H' 'G1' 19 25 1* WATER 1* 1* SHUT 1* 1* 1* /
/
COMPDAT
--WELL I J K1 K2 OP/SH SATN TRAN WBDIA KH SKIN DFACT DIR PEQVR
'B-1H' 11 3 1 5 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'B-2H' 4 7 1 6 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'B-3H' 11 12 1 4 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'C-1H' 13 20 1 4 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'C-2H' 12 27 1 5 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
/
COMPDAT
'F-1H' 19 4 6 10 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'F-2H' 19 12 6 10 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'G-3H' 19 21 6 10 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
'G-4H' 19 25 6 10 OPEN 1* 1* 0.216 1* 0 1* Z 1* /
/
WCONPROD
-- Well_name Status Ctrl Orate Wrate Grate Lrate RFV FBHP WHP VFP Glift
'B-1H' OPEN ORAT 4000.0 1* 1* 6000.0 1* 100.0 30 0 1* /
'B-2H' SHUT ORAT 4000.0 1* 1* 6000.0 1* 100.0 30 0 1* /
'B-3H' OPEN ORAT 4000.0 1* 1* 6000.0 1* 100.0 30 0 1* /
'C-1H' OPEN ORAT 4000.0 1* 1* 6000.0 1* 100.0 30 0 1* /
'C-2H' SHUT ORAT 4000.0 1* 1* 6000.0 1* 100.0 30 0 1* /
/
GCONINJE
'FIELD' 'WATER' 'VREP' 3* 1.020 'NO' 5* /
/
GCONPROD
'PLAT-A' ORAT 10000 /
/
WCONINJE
-- Well_name Type Status Ctrl SRate1 Rrate BHP THP VFP
'F-1H' WATER OPEN GRUP 4000 1* 225.0 1* 1* /
'F-2H' WATER OPEN GRUP 4000 1* 225.0 1* 1* /
'G-3H' WATER OPEN GRUP 4000 1* 225.0 1* 1* /
'G-4H' WATER OPEN GRUP 4000 1* 225.0 1* 1* /
/
-- Turns on gas lift optimization
LIFTOPT
12500 5E-3 0.0 YES /
-- Group lift gas limits for gas lift optimization
GLIFTOPT
'PLAT-A' 12345 / --
'M5S' 1* 12345 /
'M5N' -1.0 0.0 /
'B1' 0.0 1.0E-20 /
'G1' -12.345 0.99E-20 /
'C1' 1.0E-8 1.0E-8 /
/
GCONPROD
'PLAT-A' ORAT 10000 /
/
DATES
1 FEB 2020 /
1 MAR 2020 /
1 APR 2020 /
/
END
)" };
const auto rptStep = std::size_t {1};
double secs_elapsed = 3.1536E07;
const auto& es = cse.es;
const auto& sched = cse.sched;
const auto& grid = cse.grid;
const auto& units = es.getUnits();
const auto st = sim_state_3();
const auto ih = Opm::RestartIO::Helpers::createInteHead(es, grid, sched, secs_elapsed,
rptStep, rptStep + 1, rptStep);
auto agrpd = Opm::RestartIO::Helpers::AggregateGroupData(ih);
agrpd.captureDeclaredGroupData(sched, units, rptStep, st, ih);
const auto& sgrp = agrpd.getSGroup();
const auto& zgrp = agrpd.getZGroup();
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
using namespace std::string_literals;
using Ix = VI::SGroup::prod_index;
auto requireGroup = [&zgrp, &ih](const int groupID, const std::string& name)
{
BOOST_REQUIRE_EQUAL(zgrp[groupID*ih[VI::intehead::NZGRPZ] + 0].c_str(), name);
};
auto sgrpValue = [&ih, &sgrp](const int groupID, const int item)
{
return sgrp[groupID*ih[VI::intehead::NSGRPZ] + item];
};
// PLAT-A
{
const auto groupID = 2;
requireGroup(groupID, "PLAT-A "s);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxSupply), 12345.0f, 1.0e-5f);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxRate) , - 10.0f, 1.0e-5f); // Defaulted -> no limit
}
// M5S
{
const auto groupID = 1;
requireGroup(groupID, "M5S "s);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxSupply), - 10.0f, 1.0e-5f); // Defaulted -> no limit
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxRate) , 12345.0f, 1.0e-5f);
}
// M5N
{
const auto groupID = 3;
requireGroup(groupID, "M5N "s);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxSupply), - 10.0f, 1.0e-5f); // Negative -> defaulted
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxRate) , 1.0e-6f, 1.0e-5f); // 0.0 -> small
}
// B1
{
const auto groupID = 6;
requireGroup(groupID, "B1 "s);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxSupply), 1.0e-6f, 1.0e-5f); // 0.0 -> small
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxRate) , 1.0e-20f, 1.0e-5f); // >= threshold -> preserve
}
// G1
{
const auto groupID = 7;
requireGroup(groupID, "G1 "s);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxSupply), -10.0f, 1.0e-5f); // Negative -> defaulted
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxRate) , 1.0e-6f, 1.0e-5f); // < threshold -> small
}
// C1
{
const auto groupID = 4;
requireGroup(groupID, "C1 "s);
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxSupply), 1.0e-8f, 1.0e-5f); // >= threshold -> preserve
BOOST_CHECK_CLOSE(sgrpValue(groupID, Ix::GLOMaxRate) , 1.0e-8f, 1.0e-5f); // >= threshold -> preserve
}
}
BOOST_AUTO_TEST_SUITE_END()