Summary: Transmit Segment Values to "prev_state"

This commit makes the helper function find_wells() aware of summary
vectors defined on segments.  Previously, this helper function would
return an empty list of wells in the case of ECL_SMSPEC_SEGMENT_VAR
whence all segment-related summary vectors would be zero at all
times.

Add a small set of unit tests to verify that we transmit the known
(small) set of segment-related summary vectors (SOFR, SGFR, SWFR,
SPR) to the internal "prev_state" with correct output units and sign
convention (producing flow rates--reservoir to well--positive).
This commit is contained in:
Bård Skaflestad 2018-10-10 17:03:47 +02:00
parent decd0b10a9
commit f275fd6089
2 changed files with 300 additions and 10 deletions

View File

@ -1019,7 +1019,10 @@ inline std::vector< const Well* > find_wells( const Schedule& schedule,
const auto* name = smspec_node_get_wgname( node );
const auto type = smspec_node_get_var_type( node );
if( type == ECL_SMSPEC_WELL_VAR || type == ECL_SMSPEC_COMPLETION_VAR ) {
if ((type == ECL_SMSPEC_WELL_VAR) ||
(type == ECL_SMSPEC_COMPLETION_VAR) ||
(type == ECL_SMSPEC_SEGMENT_VAR))
{
const auto* well = schedule.getWell( name );
if( !well ) return {};
return { well };

View File

@ -23,8 +23,10 @@
#include <boost/test/unit_test.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <cstddef>
#include <exception>
#include <stdexcept>
#include <unordered_map>
#include <ert/ecl/ecl_sum.h>
#include <ert/ecl/smspec_node.h>
@ -49,6 +51,18 @@
using namespace Opm;
using rt = data::Rates::opt;
namespace {
double sm3_pr_day()
{
return unit::cubic(unit::meter) / unit::day;
}
} // Anonymous
namespace SegmentResultHelpers {
data::Well prod01_results();
data::Well inje01_results();
} // SegmentResultHelpers
/* conversion factor for whenever 'day' is the unit of measure, whereas we
* expect input in SI units (seconds)
*/
@ -145,11 +159,10 @@ static data::Wells result_wells() {
crates3.set( rt::reservoir_gas, 300.8 / day );
// Segment vectors
const auto sm3_pr_day = unit::cubic(unit::meter) / day;
auto segment = ::Opm::data::Segment{};
segment.rates.set(rt::wat, 123.45*sm3_pr_day);
segment.rates.set(rt::oil, 543.21*sm3_pr_day);
segment.rates.set(rt::gas, 1729.496*sm3_pr_day);
segment.rates.set(rt::wat, 123.45*sm3_pr_day());
segment.rates.set(rt::oil, 543.21*sm3_pr_day());
segment.rates.set(rt::gas, 1729.496*sm3_pr_day());
segment.pressure = 314.159*unit::barsa;
segment.segNumber = 1;
@ -181,6 +194,9 @@ static data::Wells result_wells() {
wellrates["W_2"] = well2;
wellrates["W_3"] = well3;
wellrates["INJE01"] = SegmentResultHelpers::inje01_results();
wellrates["PROD01"] = SegmentResultHelpers::prod01_results();
return wellrates;
}
@ -1195,12 +1211,10 @@ BOOST_AUTO_TEST_CASE(READ_WRITE_WELLDATA) {
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_1" , rt::wat) , wellRates.get( "W_1" , rt::wat), 1e-16);
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_2" , 101 , rt::wat) , wellRates.get( "W_2" , 101 , rt::wat), 1e-16);
const auto sm3_pr_day = unit::cubic(unit::meter) / day;
const auto& seg = wellRatesCopy.at("W_1").segments.at(1);
BOOST_CHECK_CLOSE(seg.rates.get(rt::wat), 123.45*sm3_pr_day, 1.0e-10);
BOOST_CHECK_CLOSE(seg.rates.get(rt::oil), 543.21*sm3_pr_day, 1.0e-10);
BOOST_CHECK_CLOSE(seg.rates.get(rt::gas), 1729.496*sm3_pr_day, 1.0e-10);
BOOST_CHECK_CLOSE(seg.rates.get(rt::wat), 123.45*sm3_pr_day(), 1.0e-10);
BOOST_CHECK_CLOSE(seg.rates.get(rt::oil), 543.21*sm3_pr_day(), 1.0e-10);
BOOST_CHECK_CLOSE(seg.rates.get(rt::gas), 1729.496*sm3_pr_day(), 1.0e-10);
BOOST_CHECK_CLOSE(seg.pressure, 314.159*unit::barsa, 1.0e-10);
BOOST_CHECK_EQUAL(seg.segNumber, 1);
@ -1323,6 +1337,15 @@ namespace {
});
}
auto calculateRestartVectorsSegment()
-> decltype(calculateRestartVectors({"test.Restart.Segment",
"SOFR_TEST.DATA"}))
{
return calculateRestartVectors({
"test.Restart.Segment", "SOFR_TEST.DATA"
});
}
std::vector<std::string> restartVectors()
{
return {
@ -1990,3 +2013,267 @@ BOOST_AUTO_TEST_CASE(Field_Vectors_Correct)
}
BOOST_AUTO_TEST_SUITE_END()
// ####################################################################
namespace {
void fill_surface_rates(const std::size_t id,
const double sign,
data::Rates& rates)
{
const auto topRate = id * 1000*sm3_pr_day();
rates.set(data::Rates::opt::wat, sign * (topRate + 100*sm3_pr_day()));
rates.set(data::Rates::opt::oil, sign * (topRate + 200*sm3_pr_day()));
rates.set(data::Rates::opt::gas, sign * (topRate + 400*sm3_pr_day()));
}
std::size_t numSegProd01()
{
return 26;
}
data::Connection conn_results(const std::size_t connID,
const std::size_t cellID,
const double sign)
{
auto res = data::Connection{};
res.index = cellID;
fill_surface_rates(connID, sign, res.rates);
// Not meant to be realistic, other than possibly order of magnitude.
res.pressure = (200.0 + connID)*unit::barsa;
res.reservoir_rate = (125.0 + connID)*sm3_pr_day();
res.cell_pressure = (250.0 + cellID)*unit::barsa;
return res;
}
data::Segment seg_results(const std::size_t segID, const double sign)
{
auto res = data::Segment{};
fill_surface_rates(segID, sign, res.rates);
res.pressure = (100.0 + segID)*unit::barsa;
res.segNumber = segID;
return res;
}
std::unordered_map<std::size_t, data::Segment> prod01_seg_results()
{
auto res = std::unordered_map<std::size_t, data::Segment>{};
// Flow's producer rates are negative (positive fluxes well -> reservoir).
const auto sign = -1.0;
for (auto nSeg = numSegProd01(), segID = 0*nSeg;
segID < nSeg; ++segID)
{
res[segID + 1] = seg_results(segID + 1, sign);
}
return res;
}
std::vector<data::Connection> prod01_conn_results()
{
auto res = std::vector<data::Connection>{};
res.reserve(26);
const auto cellID = std::vector<std::size_t> {
99, // IJK = (10, 10, 1)
199, // IJK = (10, 10, 2)
299, // IJK = (10, 10, 3)
399, // IJK = (10, 10, 4)
499, // IJK = (10, 10, 5)
599, // IJK = (10, 10, 6)
198, // IJK = ( 9, 10, 2)
197, // IJK = ( 8, 10, 2)
196, // IJK = ( 7, 10, 2)
195, // IJK = ( 6, 10, 2)
194, // IJK = ( 5, 10, 2)
289, // IJK = (10, 9, 3)
279, // IJK = (10, 8, 3)
269, // IJK = (10, 7, 3)
259, // IJK = (10, 6, 3)
249, // IJK = (10, 5, 3)
498, // IJK = ( 9, 10, 5)
497, // IJK = ( 8, 10, 5)
496, // IJK = ( 7, 10, 5)
495, // IJK = ( 6, 10, 5)
494, // IJK = ( 5, 10, 5)
589, // IJK = (10, 9, 6)
579, // IJK = (10, 8, 6)
569, // IJK = (10, 7, 6)
559, // IJK = (10, 6, 6)
549, // IJK = (10, 5, 6)
};
// Flow's producer rates are negative (positive fluxes well -> reservoir).
const auto sign = -1.0;
for (auto nConn = cellID.size(), connID = 0*nConn;
connID < nConn; ++connID)
{
res.push_back(conn_results(connID, cellID[connID], sign));
}
return res;
}
std::vector<data::Connection> inje01_conn_results()
{
auto res = std::vector<data::Connection>{};
res.reserve(3);
const auto cellID = std::vector<std::size_t> {
600, // IJK = ( 1, 1, 7)
700, // IJK = ( 1, 1, 8)
800, // IJK = ( 1, 1, 9)
};
// Flow's injection rates are positive (positive fluxes well -> reservoir).
const auto sign = +1.0;
for (auto nConn = cellID.size(), connID = 0*nConn;
connID < nConn; ++connID)
{
res.push_back(conn_results(connID, cellID[connID], sign));
}
return res;
}
std::string genKeyPROD01(const std::string& vector,
const std::size_t segID)
{
return vector + ":PROD01:" + std::to_string(segID);
}
} // Anonymous
data::Well SegmentResultHelpers::prod01_results()
{
auto res = data::Well{};
fill_surface_rates(0, -1.0, res.rates);
res.bhp = 123.45*unit::barsa;
res.thp = 60.221409*unit::barsa;
res.temperature = 298.15;
res.control = 0;
res.connections = prod01_conn_results();
res.segments = prod01_seg_results();
return res;
}
data::Well SegmentResultHelpers::inje01_results()
{
auto res = data::Well{};
fill_surface_rates(0, 1.0, res.rates);
res.bhp = 543.21*unit::barsa;
res.thp = 256.821*unit::barsa;
res.temperature = 298.15;
res.control = 0;
res.connections = inje01_conn_results();
return res;
}
// ====================================================================
BOOST_AUTO_TEST_SUITE(Restart_Segment)
BOOST_AUTO_TEST_CASE(Vectors_Present)
{
const auto rstrt = calculateRestartVectorsSegment();
for (const auto* vector : { "SGFR", "SGFR", "SPR", "SWFR"}) {
for (auto nSeg = numSegProd01(), segID = 0*nSeg;
segID < nSeg; ++segID)
{
BOOST_CHECK(rstrt.has(genKeyPROD01(vector, segID + 1)));
}
BOOST_CHECK(!rstrt.has(genKeyPROD01(vector, 27)));
BOOST_CHECK(!rstrt.has(vector + std::string{":INJE01:1"}));
}
}
// ====================================================================
BOOST_AUTO_TEST_CASE(Pressure_Correct)
{
const auto rstrt = calculateRestartVectorsSegment();
for (auto nSeg = numSegProd01(), segID = 0*nSeg;
segID < nSeg; ++segID)
{
const auto& key = genKeyPROD01("SPR", segID + 1);
// Pressure value converted to METRIC output units (bars).
BOOST_CHECK_CLOSE(rstrt.get(key), 100.0 + (segID + 1), 1.0e-10);
}
}
// ====================================================================
BOOST_AUTO_TEST_CASE(OilRate_Correct)
{
const auto rstrt = calculateRestartVectorsSegment();
for (auto nSeg = numSegProd01(), segID = 0*nSeg;
segID < nSeg; ++segID)
{
const auto& key = genKeyPROD01("SOFR", segID + 1);
// Producer rates positive in 'rstrt', converted to METRIC
// output units (SM3/day).
BOOST_CHECK_CLOSE(rstrt.get(key), 1000.0*(segID + 1) + 200, 1.0e-10);
}
}
// ====================================================================
BOOST_AUTO_TEST_CASE(GasRate_Correct)
{
const auto rstrt = calculateRestartVectorsSegment();
for (auto nSeg = numSegProd01(), segID = 0*nSeg;
segID < nSeg; ++segID)
{
const auto& key = genKeyPROD01("SGFR", segID + 1);
// Producer rates positive in 'rstrt', converted to METRIC
// output units (SM3/day).
BOOST_CHECK_CLOSE(rstrt.get(key), 1000.0*(segID + 1) + 400, 1.0e-10);
}
}
// ====================================================================
BOOST_AUTO_TEST_CASE(WaterRate_Correct)
{
const auto rstrt = calculateRestartVectorsSegment();
for (auto nSeg = numSegProd01(), segID = 0*nSeg;
segID < nSeg; ++segID)
{
const auto& key = genKeyPROD01("SWFR", segID + 1);
// Producer rates positive in 'rstrt', converted to METRIC
// output units (SM3/day).
BOOST_CHECK_CLOSE(rstrt.get(key), 1000.0*(segID + 1) + 100, 1.0e-10);
}
}
BOOST_AUTO_TEST_SUITE_END()