Merge pull request #514 from bska/segment-summary

Serialization: Add Initial Support for Segment Information
This commit is contained in:
Joakim Hove
2018-10-25 15:19:22 +02:00
committed by GitHub
12 changed files with 1783 additions and 73 deletions

View File

@@ -275,6 +275,7 @@ if(ENABLE_ECL_OUTPUT)
tests/SUMMARY_EFF_FAC.DATA
tests/SPE1CASE1.DATA
tests/SPE9_CP_PACKED.DATA
tests/SOFR_TEST.DATA
)
endif()

View File

@@ -20,12 +20,14 @@
#ifndef OPM_OUTPUT_WELLS_HPP
#define OPM_OUTPUT_WELLS_HPP
#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <map>
#include <algorithm>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
namespace Opm {
@@ -120,6 +122,18 @@ namespace Opm {
void read(MessageBufferType& buffer);
};
struct Segment {
Rates rates;
double pressure;
std::size_t segNumber;
template <class MessageBufferType>
void write(MessageBufferType& buffer) const;
template <class MessageBufferType>
void read(MessageBufferType& buffer);
};
struct Well {
Rates rates;
double bhp;
@@ -127,6 +141,7 @@ namespace Opm {
double temperature;
int control;
std::vector< Connection > connections;
std::unordered_map<std::size_t, Segment> segments;
inline bool flowing() const noexcept;
template <class MessageBufferType>
@@ -300,6 +315,13 @@ namespace Opm {
buffer.write(this->effective_Kh);
}
template <class MessageBufferType>
void Segment::write(MessageBufferType& buffer) const {
buffer.write(this->segNumber);
this->rates.write(buffer);
buffer.write(this->pressure);
}
template <class MessageBufferType>
void Well::write(MessageBufferType& buffer) const {
this->rates.write(buffer);
@@ -311,6 +333,16 @@ namespace Opm {
buffer.write(size);
for (const Connection& comp : this->connections)
comp.write(buffer);
{
const auto nSeg =
static_cast<unsigned int>(this->segments.size());
buffer.write(nSeg);
for (const auto& seg : this->segments) {
seg.second.write(buffer);
}
}
}
template <class MessageBufferType>
@@ -341,6 +373,13 @@ namespace Opm {
buffer.read(this->effective_Kh);
}
template <class MessageBufferType>
void Segment::read(MessageBufferType& buffer) {
buffer.read(this->segNumber);
this->rates.read(buffer);
buffer.read(this->pressure);
}
template <class MessageBufferType>
void Well::read(MessageBufferType& buffer) {
this->rates.read(buffer);
@@ -348,6 +387,8 @@ namespace Opm {
buffer.read(this->thp);
buffer.read(this->temperature);
buffer.read(this->control);
// Connection information
unsigned int size = 0.0; //this->connections.size();
buffer.read(size);
this->connections.resize(size);
@@ -356,9 +397,25 @@ namespace Opm {
auto& comp = this->connections[ i ];
comp.read(buffer);
}
// Segment information (if applicable)
const auto nSeg = [&buffer]() -> unsigned int
{
auto n = 0u;
buffer.read(n);
return n;
}();
for (auto segID = 0*nSeg; segID < nSeg; ++segID) {
auto seg = Segment{};
seg.read(buffer);
const auto segNumber = seg.segNumber;
this->segments.emplace(segNumber, std::move(seg));
}
}
}
}
}} // Opm::data
#endif //OPM_OUTPUT_WELLS_HPP

View File

@@ -20,16 +20,17 @@
#ifndef OPM_OUTPUT_SUMMARY_HPP
#define OPM_OUTPUT_SUMMARY_HPP
#include <map>
#include <string>
#include <vector>
#include <unordered_map>
#include <ert/ecl/ecl_sum.h>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/SummaryState.hpp>
#include <opm/output/eclipse/RegionCache.hpp>
namespace Opm {

View File

@@ -24,7 +24,6 @@
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#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/parser/eclipse/EclipseState/Schedule/Connection.hpp>
@@ -32,9 +31,8 @@
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
//#include <opm/output/data/Wells.hpp>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <string>
@@ -127,9 +125,9 @@ namespace {
return firstSegNo;
}
int noConnectionsSegment(const Opm::WellConnections& compSet,
int noConnectionsSegment(const Opm::WellConnections& compSet,
const Opm::WellSegments& segSet,
const std::size_t segIndex)
const std::size_t segIndex)
{
auto segNumber = segSet[segIndex].segmentNumber();
int noConnections = 0;
@@ -142,10 +140,10 @@ namespace {
return noConnections;
}
int sumConnectionsSegment(const Opm::WellConnections& compSet,
const Opm::WellSegments& segSet,
const std::size_t segIndex)
const Opm::WellSegments& segSet,
const std::size_t segIndex)
{
// This function returns (for a given segment) the sum of number of connections for each segment
// with lower segment index than the currnet segment
@@ -163,7 +161,6 @@ namespace {
return sumConn;
}
std::vector<std::size_t>
inflowSegmentsIndex(const Opm::WellSegments& segSet, std::size_t segIndex) {
auto segNumber = segSet[segIndex].segmentNumber();
@@ -190,6 +187,7 @@ namespace {
}
return noIFBr;
}
//find the number of inflow branches (different from the current branch)
int sumNoInFlowBranches(const Opm::WellSegments& segSet, std::size_t segIndex) {
int sumIFB = 0;
@@ -206,9 +204,8 @@ namespace {
}
return sumIFB;
}
std::vector<std::size_t> segmentOrder(const Opm::WellSegments& segSet, const std::size_t segIndex) {
std::vector<std::size_t> segmentOrder(const Opm::WellSegments& segSet, const std::size_t segIndex) {
std::vector<std::size_t> ordSegNumber;
std::vector<std::size_t> tempOrdVect;
std::vector<std::size_t> segIndCB;
@@ -219,7 +216,7 @@ namespace {
bool endOrigBranch = true;
// loop down branch to find all segments in branch and number from "toe" to "heel"
while (newSInd < segSet.size()) {
endOrigBranch = true;
endOrigBranch = true;
const auto iSInd = inflowSegmentsIndex(segSet, newSInd);
for (auto isi : iSInd ) {
auto inflowBranch = segSet[isi].branchNumber();
@@ -258,7 +255,6 @@ namespace {
// set new index to exit while loop
newSInd = segSet.size();
}
//}
}
if (origBranchNo == 1) {
@@ -273,7 +269,6 @@ namespace {
}
}
int inflowSegmentCurBranch(const Opm::WellSegments& segSet, std::size_t segIndex) {
auto branch = segSet[segIndex].branchNumber();
auto segNumber = segSet[segIndex].segmentNumber();
@@ -342,14 +337,14 @@ namespace {
{
if (well.isMultiSegment(rptStep)) {
//loop over segment set and print out information
auto welSegSet = well.getWellSegments(rptStep);
auto completionSet = well.getConnections(rptStep);
auto noElmSeg = nisegz(inteHead);
const auto& welSegSet = well.getWellSegments(rptStep);
const auto& completionSet = well.getConnections(rptStep);
const auto& noElmSeg = nisegz(inteHead);
std::size_t segmentInd = 0;
auto orderedSegmentNo = segmentOrder(welSegSet, segmentInd);
for (int ind_seg = 1; ind_seg <= welSegSet.size(); ind_seg++) {
auto ind = welSegSet.segmentNumberToIndex(ind_seg);
auto iS = (ind_seg-1)*noElmSeg;
for (int segNumber = 1; segNumber <= welSegSet.size(); segNumber++) {
auto ind = welSegSet.segmentNumberToIndex(segNumber);
auto iS = (segNumber-1)*noElmSeg;
iSeg[iS + 0] = orderedSegmentNo[ind];
iSeg[iS + 1] = welSegSet[ind].outletSegment();
iSeg[iS + 2] = inflowSegmentCurBranch(welSegSet, ind);
@@ -387,44 +382,67 @@ namespace {
}
template <class RSegArray>
void staticContrib(const Opm::Well& well,
const std::size_t rptStep,
const std::vector<int>& inteHead,
const Opm::UnitSystem& units,
void staticContrib(const Opm::Well& well,
const std::size_t rptStep,
const std::vector<int>& inteHead,
const Opm::UnitSystem& units,
const ::Opm::SummaryState& smry,
RSegArray& rSeg)
RSegArray& rSeg)
{
if (well.isMultiSegment(rptStep)) {
int segNumber = 1;
// 'stringSegNum' is one-based (1 .. #segments inclusive)
std::string stringSegNum = std::to_string(segNumber);
using M = ::Opm::UnitSystem::measure;
const auto gfactor = (units.getType() == Opm::UnitSystem::UnitType::UNIT_TYPE_FIELD)
? 0.1781076 : 0.001;
//loop over segment set and print out information
auto welSegSet = well.getWellSegments(rptStep);
auto completionSet = well.getCompletions(rptStep);
auto noElmSeg = nrsegz(inteHead);
auto& wname = well.name();
std::string bhpKey = "WBHP:" + wname;
//treat the top segment individually
const auto noElmSeg = nrsegz(inteHead);
const auto& welSegSet = well.getWellSegments(rptStep);
const auto& wname = well.name();
// const auto completionSet = well.getCompletions(rptStep);
auto get = [&smry, &wname, &stringSegNum](const std::string& vector)
{
// 'stringSegNum' is one-based (1 .. #segments inclusive)
const auto key = vector + ':' + wname + ':' + stringSegNum;
return smry.has(key) ? smry.get(key) : 0.0;
};
// Treat the top segment individually
rSeg[0] = units.from_si(M::length, welSegSet.lengthTopSegment());
rSeg[1] = units.from_si(M::length, welSegSet.depthTopSegment());
rSeg[5] = units.from_si(M::volume, welSegSet.volumeTopSegment());
rSeg[6] = rSeg[0];
rSeg[7] = rSeg[1];
//Item 8: should be some segment cumulative flow rate, use a constant value for now
rSeg[8] = 200.;
//Item ind+9: not sure what this parameter is, the current value works well for tests on E100
rSeg[9] = 0.01;
// set item ind + 10 to 0.5 based on tests on E100
rSeg[10] = 0.5;
//Item 11 should be segment pressure - use flowing bottom hole pressure temporarily
//if (smry.has( bhpKey)) {
// rSeg[11] = smry.get(bhpKey);
//}
// use default value for now
rSeg[11] = 0.;
// segment pressure - set equal to item 8
rSeg[ 39] = rSeg[11];
//
//Field units:
//Rseg[8]= 1.0*sofr+0.1*swfr + 0.1781076*sgfr (= 1.0*sofr+0.1*swfr+0.001*1000*0.1781076*sgfr )
//Rseg[9] = swfr*0.1/ Rseg[8]
//Rseg[10]= sgfr*0.1781076*/ Rseg[8]
//Default values
//rSeg[ 39] = 1.0;
//Metric units:
//Rseg[8]= 1.0*sofr+0.1*swfr + 0.001*sgfr
//Rseg[9] = swfr*0.1/ Rseg[8]
//Rseg[10]= sgfr*0.001/ Rseg[8]
// Note: Segment flow rates and pressure from 'smry' have correct
// output units and sign conventions.
auto temp_o = get("SOFR");
auto temp_w = get("SWFR")*0.1;
auto temp_g = get("SGFR")*gfactor;
rSeg[ 8] = temp_o + temp_w + temp_g;
rSeg[ 9] = (std::abs(temp_w) > 0) ? temp_w / rSeg[8] : 0.;
rSeg[10] = (std::abs(temp_g) > 0) ? temp_g / rSeg[8] : 0.;
//Item 12 Segment pressure
rSeg[11] = get("SPR");
// segment pressure
rSeg[ 39] = rSeg[11];
rSeg[105] = 1.0;
rSeg[106] = 1.0;
@@ -434,12 +452,15 @@ namespace {
rSeg[110] = 1.0;
//Treat subsequent segments
for (int ind_seg = 2; ind_seg <= welSegSet.size(); ind_seg++) {
for (segNumber = 2; segNumber <= welSegSet.size(); segNumber++) {
// 'stringSegNum' is one-based (1 .. #segments inclusive)
stringSegNum = std::to_string(segNumber);
// set the elements of the rSeg array
auto ind = welSegSet.segmentNumberToIndex(ind_seg);
auto ind = welSegSet.segmentNumberToIndex(segNumber);
auto outSeg = welSegSet[ind].outletSegment();
auto ind_ofs = welSegSet.segmentNumberToIndex(outSeg);
auto iS = (ind_seg-1)*noElmSeg;
auto iS = (segNumber-1)*noElmSeg;
rSeg[iS + 0] = units.from_si(M::length, (welSegSet[ind].totalLength() - welSegSet[ind_ofs].totalLength()));
rSeg[iS + 1] = units.from_si(M::length, (welSegSet[ind].depth() - welSegSet[ind_ofs].depth()));
rSeg[iS + 2] = units.from_si(M::length, (welSegSet[ind].internalDiameter()));
@@ -450,18 +471,18 @@ namespace {
rSeg[iS + 5] = units.from_si(M::volume, (welSegSet[ind].volume()));
rSeg[iS + 6] = units.from_si(M::length, (welSegSet[ind].totalLength()));
rSeg[iS + 7] = units.from_si(M::length, (welSegSet[ind].depth()));
//Item ind+8: should be some segment cumulative flow rate, use a constant value for now
rSeg[iS + 8] = 200.;
//Item ind+9: not sure what this parameter is, the current value works well for tests on E100
rSeg[iS + 9] = 0.01;
// set item ind + 10 to 0.5 based on tests on E100
rSeg[iS + 10] = 0.5;
// segment pressure (to be added!!)
rSeg[iS + 11] = rSeg[11];
//see section above for explanation of values
temp_o = get("SOFR");
temp_w = get("SWFR")*0.1;
temp_g = get("SGFR")*gfactor;
//Default values
rSeg[iS + 8] = temp_o + temp_w + temp_g;
rSeg[iS + 9] = (std::abs(temp_w) > 0) ? temp_w / rSeg[iS + 8] : 0.;
rSeg[iS + 10] = (std::abs(temp_g) > 0) ? temp_g / rSeg[iS + 8] : 0.;
//Item 12 Segment pressure
rSeg[iS + 11] = get("SPR");
rSeg[iS + 39] = rSeg[iS + 11];
rSeg[iS + 105] = 1.0;
@@ -473,7 +494,7 @@ namespace {
}
}
else {
throw std::invalid_argument("No such multisegment well: " + well.name());
throw std::invalid_argument("No such multisegment well: " + well.name());
}
}
} // RSeg

View File

@@ -37,10 +37,12 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/Eqldims.hpp>
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <string>
#include <unordered_set>
#include <vector>
@@ -469,12 +471,31 @@ void save(const std::string& filename,
const auto inteHD = writeHeader(rst_file.get(), sim_step, report_step,
seconds_elapsed, schedule, grid, es);
writeGroup(rst_file.get(), sim_step, ecl_compatible_rst, schedule, sumState, inteHD);
writeGroup(rst_file.get(), sim_step, ecl_compatible_rst,
schedule, sumState, inteHD);
writeMSWData(rst_file.get(), sim_step, units, schedule, grid, sumState, inteHD);
// Write well and MSW data only when applicable (i.e., when present)
{
const auto& wells = schedule.getWells(sim_step);
writeWell(rst_file.get(), sim_step, ecl_compatible_rst, es.runspec().phases(), units,
grid, schedule, value.wells, sumState, inteHD);
if (! wells.empty()) {
const auto numMSW =
std::count_if(std::begin(wells), std::end(wells),
[sim_step](const Well* well)
{
return well->isMultiSegment(sim_step);
});
if (numMSW > 0) {
writeMSWData(rst_file.get(), sim_step, units,
schedule, grid, sumState, inteHD);
}
writeWell(rst_file.get(), sim_step, ecl_compatible_rst,
es.runspec().phases(), units, grid, schedule,
value.wells, sumState, inteHD);
}
}
writeSolution(rst_file.get(), value, ecl_compatible_rst, write_double);

View File

@@ -17,12 +17,14 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <exception>
#include <initializer_list>
#include <iterator>
#include <numeric>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <opm/common/OpmLog/OpmLog.hpp>
@@ -46,6 +48,13 @@
#include <ert/ecl/ecl_kw_magic.h>
namespace {
struct SegmentResultDescriptor
{
std::string vector;
std::string well;
std::size_t segNumber;
};
std::vector<std::string> requiredRestartVectors()
{
return {
@@ -95,6 +104,42 @@ namespace {
return entities;
}
std::vector<SegmentResultDescriptor>
requiredSegmentVectors(const ::Opm::Schedule& sched)
{
using SRD = SegmentResultDescriptor;
auto ret = std::vector<SRD>{};
auto makeVectors =
[&ret](const std::string& well,
const std::size_t segNumber) -> void
{
ret.push_back(SRD{"SOFR", well, segNumber});
ret.push_back(SRD{"SGFR", well, segNumber});
ret.push_back(SRD{"SWFR", well, segNumber});
ret.push_back(SRD{"SPR" , well, segNumber});
};
const auto last_timestep = sched.getTimeMap().last();
for (const auto* well : sched.getWells()) {
if (! well->isMultiSegment(last_timestep)) {
// Don't allocate MS summary vectors for non-MS wells.
continue;
}
const auto& wname = well->name();
const auto nSeg =
well->getWellSegments(last_timestep).size();
for (auto segID = 0*nSeg; segID < nSeg; ++segID) {
makeVectors(wname, segID + 1); // One-based
}
}
return ret;
}
std::string genKey(const std::string& vector,
const std::string& entity)
{
@@ -103,6 +148,12 @@ namespace {
: vector + ':' + entity;
}
std::string genKey(const SegmentResultDescriptor& segRes)
{
return segRes.vector + ':' + segRes.well +
':' + std::to_string(segRes.segNumber);
}
ERT::ert_unique_ptr<smspec_node_type, smspec_node_free>
makeRestartVectorSMSPEC(const std::string& vector,
const std::string& entity)
@@ -117,6 +168,20 @@ namespace {
"UNIT", ":", dims, 0, 0, 0.0f)
};
}
ERT::ert_unique_ptr<smspec_node_type, smspec_node_free>
makeRestartVectorSMSPEC(const SegmentResultDescriptor& segRes)
{
const auto var_type = ECL_SMSPEC_SEGMENT_VAR;
const int dims[] = { 1, 1, 1 };
return ERT::ert_unique_ptr<smspec_node_type, smspec_node_free> {
smspec_node_alloc(var_type, segRes.well.c_str(), segRes.vector.c_str(),
"UNIT", ":", dims,
static_cast<int>(segRes.segNumber), 0, 0.0f)
};
}
} // namespace Anonymous
/*
@@ -363,6 +428,39 @@ inline quantity crate( const fn_args& args ) {
return { v, rate_unit< phase >() };
}
template< rt phase, bool polymer = false >
inline quantity srate( const fn_args& args ) {
const quantity zero = { 0, rate_unit< phase >() };
// The args.num value is the literal value which will go to the
// NUMS array in the eclispe SMSPEC file; the values in this array
// are offset 1 - whereas we need to use this index here to look
// up a completion with offset 0.
const size_t segNumber = args.num;
if( args.schedule_wells.empty() ) return zero;
const auto& well = args.schedule_wells.front();
const auto& name = well->name();
if( args.wells.count( name ) == 0 ) return zero;
const auto& well_data = args.wells.at( name );
const auto& segment = well_data.segments.find(segNumber);
if( segment == well_data.segments.end() ) return zero;
double eff_fac = efac( args.eff_factors, name );
double concentration = polymer
? well->getPolymerProperties( args.sim_step ).m_polymerConcentration
: 1;
auto v = segment->second.rates.get( phase, 0.0 ) * eff_fac * concentration;
//switch sign of rate - opposite convention in flow vs eclipse
v *= -1;
if( polymer ) return { v, measure::mass_rate };
return { v, rate_unit< phase >() };
}
inline quantity trans_factors ( const fn_args& args ) {
const quantity zero = { 0, measure::transmissibility };
@@ -391,6 +489,31 @@ inline quantity trans_factors ( const fn_args& args ) {
return { v, measure::transmissibility };
}
inline quantity spr ( const fn_args& args ) {
const quantity zero = { 0, measure::pressure };
if( args.schedule_wells.empty() ) return zero;
// Like completion rate we need to look
// up a connection with offset 0.
const size_t segNumber = args.num;
if( args.schedule_wells.empty() ) return zero;
const auto& well = args.schedule_wells.front();
const auto& name = well->name();
if( args.wells.count( name ) == 0 ) return zero;
const auto& well_data = args.wells.at( name );
const auto& segment = well_data.segments.find(segNumber);
if( segment == well_data.segments.end() ) return zero;
const auto& v = segment->second.pressure;
return { v, measure::pressure };
}
inline quantity bhp( const fn_args& args ) {
const quantity zero = { 0, measure::pressure };
if( args.schedule_wells.empty() ) return zero;
@@ -835,6 +958,11 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "ROPT" , mul( region_rate< rt::oil, producer >, duration ) },
{ "RGPT" , mul( region_rate< rt::gas, producer >, duration ) },
{ "RWPT" , mul( region_rate< rt::wat, producer >, duration ) },
//Multisegment well segment data
{ "SOFR", srate< rt::oil > },
{ "SWFR", srate< rt::wat > },
{ "SGFR", srate< rt::gas > },
{ "SPR", spr },
};
@@ -892,7 +1020,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 };
@@ -1105,6 +1236,7 @@ Summary::Summary( const EclipseState& st,
auto& rvec = this->handlers->rstvec_backing_store;
auto& hndlrs = this->handlers->handlers;
// Required restart vectors for wells, groups, and field.
for (const auto& vector : requiredRestartVectors(schedule)) {
const auto& kw = vector.first;
const auto& entity = vector.second;
@@ -1126,6 +1258,26 @@ Summary::Summary( const EclipseState& st,
rvec.push_back(makeRestartVectorSMSPEC(kw, entity));
hndlrs.emplace_back(rvec.back().get(), func->second);
}
// Required restart vectors for segments (if applicable).
for (const auto& segRes : requiredSegmentVectors(schedule)) {
const auto key = genKey(segRes);
if (ecl_sum_has_key(this->ecl_sum.get(), key.c_str())) {
// Segment result already requested in SUMMARY section.
// Don't add a second evaluation of this.
continue;
}
auto func = funs.find(segRes.vector);
if (func == std::end(funs)) {
throw std::logic_error {
"Unable to find handler for '" + segRes.vector + "'"
};
}
rvec.push_back(makeRestartVectorSMSPEC(segRes));
hndlrs.emplace_back(rvec.back().get(), func->second);
}
}
for (const auto& pair : this->handlers->handlers) {

View File

@@ -381,6 +381,212 @@ inline std::array< int, 3 > getijk( const Connection& completion ) {
}
}
bool isKnownSegmentKeyword(const DeckKeyword& keyword)
{
const auto& kw = keyword.name();
if (kw.size() > 4) {
// Easy check first--handles SUMMARY and SUMTHIN &c.
return false;
}
const auto kw_whitelist = std::vector<const char*> {
"SOFR", "SGFR", "SWFR", "SPR",
};
return std::any_of(kw_whitelist.begin(), kw_whitelist.end(),
[&kw](const char* known) -> bool
{
return kw == known;
});
}
bool isMultiSegmentWell(const std::size_t last_timestep,
const Well* well)
{
for (auto step = 0*last_timestep;
step <= last_timestep; ++step)
{
if (well->isMultiSegment(step)) {
return true;
}
}
return false;
}
int maxNumWellSegments(const std::size_t last_timestep,
const Well* well)
{
auto numSeg = 0;
for (auto step = 0*last_timestep;
step <= last_timestep; ++step)
{
if (! well->isMultiSegment(step)) {
continue;
}
const auto nseg =
well->getWellSegments(last_timestep).size();
if (nseg > numSeg) {
numSeg = nseg;
}
}
return numSeg;
}
void makeSegmentNodes(const std::size_t last_timestep,
const int segID,
const DeckKeyword& keyword,
const std::vector<const Well*>& wells,
SummaryConfig::keyword_list& list)
{
// Modifies 'list' in place.
auto makeNode = [&keyword, &list]
(const std::string& well, const int segNumber)
{
// Grid dimensions immaterial for segment related vectors.
const int dims[] = { 1, 1, 1 };
list.push_back(SummaryConfig::keyword_type {
smspec_node_alloc(ECL_SMSPEC_SEGMENT_VAR, well.c_str(),
keyword.name().c_str(), "", ":",
dims, segNumber, 0, 0)
});
};
for (const auto* well : wells) {
if (! isMultiSegmentWell(last_timestep, well)) {
// Not an MSW. Don't create summary vectors for segments.
continue;
}
const auto& wname = well->name();
if (segID < 1) {
// Segment number defaulted. Allocate a summary
// vector for each segment.
const auto nSeg = maxNumWellSegments(last_timestep, well);
for (auto segNumber = 0*nSeg;
segNumber < nSeg; ++segNumber)
{
// One-based segment number.
makeNode(wname, segNumber + 1);
}
}
else {
// Segment number specified. Allocate single
// summary vector for that segment number.
makeNode(wname, segID);
}
}
}
void keywordSNoRecords(const std::size_t last_timestep,
const DeckKeyword& keyword,
const Schedule& schedule,
SummaryConfig::keyword_list& list)
{
// No keyword records. Allocate summary vectors for all
// segments in all wells at all times.
//
// Expected format:
//
// SGFR
// / -- All segments in all MS wells at all times.
const auto segID = -1;
makeSegmentNodes(last_timestep, segID, keyword,
schedule.getWells(), list);
}
void keywordSWithRecords(const std::size_t last_timestep,
const ParseContext& parseContext,
const DeckKeyword& keyword,
const Schedule& schedule,
SummaryConfig::keyword_list& list)
{
// Keyword has explicit records. Process those and create
// segment-related summary vectors for those wells/segments
// that match the description.
//
// Expected formats:
//
// SOFR
// 'W1' 1 /
// 'W1' 10 /
// 'W3' / -- All segments
// /
//
// SPR
// 1* 2 / -- Segment 2 in all multi-segmented wells
// /
for (const auto& record : keyword) {
const auto& wellitem = record.getItem(0);
const auto& wells = wellitem.defaultApplied(0)
? schedule.getWells()
: schedule.getWellsMatching(wellitem.getTrimmedString(0));
if (wells.empty()) {
handleMissingWell(parseContext, keyword.name(),
wellitem.getTrimmedString(0));
}
// Negative 1 (< 0) if segment ID defaulted. Defaulted
// segment number in record implies all segments.
const auto segID = record.getItem(1).defaultApplied(0)
? -1 : record.getItem(1).get<int>(0);
makeSegmentNodes(last_timestep, segID, keyword, wells, list);
}
}
inline void keywordS(SummaryConfig::keyword_list& list,
const ParseContext& parseContext,
const DeckKeyword& keyword,
const Schedule& schedule)
{
// Generate SMSPEC nodes for SUMMARY keywords of the form
//
// SOFR
// 'W1' 1 /
// 'W1' 10 /
// 'W3' / -- All segments
// /
//
// SPR
// 1* 2 / -- Segment 2 in all multi-segmented wells
// /
//
// SGFR
// / -- All segments in all MS wells at all times.
if (! isKnownSegmentKeyword(keyword)) {
// Ignore keywords that have not been explicitly white-listed
// for treatment as segment summary vectors.
return;
}
const auto last_timestep = schedule.getTimeMap().last();
if (keyword.size() > 0) {
// Keyword with explicit records.
// Handle as alternatives SOFR and SPR above
keywordSWithRecords(last_timestep, parseContext,
keyword, schedule, list);
}
else {
// Keyword with no explicit records.
// Handle as alternative SGFR above.
keywordSNoRecords(last_timestep, keyword, schedule, list);
}
}
inline void handleKW( SummaryConfig::keyword_list& list,
const DeckKeyword& keyword,
const Schedule& schedule,
@@ -396,6 +602,7 @@ inline std::array< int, 3 > getijk( const Connection& completion ) {
case ECL_SMSPEC_BLOCK_VAR: return keywordB( list, keyword, dims );
case ECL_SMSPEC_REGION_VAR: return keywordR( list, keyword, tables, dims );
case ECL_SMSPEC_COMPLETION_VAR: return keywordC( list, parseContext, keyword, schedule, dims);
case ECL_SMSPEC_SEGMENT_VAR: return keywordS( list, parseContext, keyword, schedule );
case ECL_SMSPEC_MISC_VAR: return keywordMISC( list, keyword );
default: return;

View File

@@ -0,0 +1,18 @@
{
"name" : "SEGMENT_PROBE" ,
"sections" : ["SUMMARY"],
"deck_names" : [
"SGFR",
"SOFR",
"SPR",
"SWFR"
],
"comment" : "This list is incomplete",
"items" : [
{"name": "Well" , "value_type" : "STRING"},
{"name": "Segment", "value_type" : "INT"}
]
}

View File

@@ -265,7 +265,7 @@ set( keywords
000_Eclipse100/R/RPTSMRY
000_Eclipse100/R/RS
000_Eclipse100/R/RSCONST
000_Eclipse100/R/RSCONSTT
000_Eclipse100/R/RSCONSTT
000_Eclipse100/R/RSVD
000_Eclipse100/R/RTEMP
000_Eclipse100/R/RTEMPA
@@ -280,6 +280,7 @@ set( keywords
000_Eclipse100/S/SCALECRS
000_Eclipse100/S/SCHEDULE
000_Eclipse100/S/SDENSITY
000_Eclipse100/S/SEGMENT_PROBE
000_Eclipse100/S/SEPARATE
000_Eclipse100/S/SGAS
000_Eclipse100/S/SGCR

246
tests/SOFR_TEST.DATA Normal file
View File

@@ -0,0 +1,246 @@
-- Most of this simulation case is trivial. Its only purpose is to
-- define a moderately relevant setup of a multi-segmented well
-- ('PROD01') to exercise the handling of segment related summary
-- vectors.
--
-- Multi-segment well setup sourced from 'opm-tests/msw_3d_hfa/3D_MSW.DATA'
RUNSPEC
TITLE
'Test Case for Segment Summary Vectors' /
DIMENS
10 10 10 /
OIL
WATER
GAS
METRIC
WELLDIMS
-- MAX CONN WELLS IN
-- WELLS PR WELL GROUPS GROUP
2 100 2 1 /
EQLDIMS
1 /
WSEGDIMS
2 100 10 10 /
TABDIMS
/
-- =====================================
GRID
DXV
10*200 /
DYV
10*200 /
DZV
10*25 /
TOPS
100*2500 /
PORO
1000*0.3 /
PERMX
1000*100 /
COPY
'PERMX' 'PERMY' /
'PERMX' 'PERMZ' /
/
MULTIPLY
'PERMZ' 0.1 /
/
-- =====================================
PROPS
SWOF
0 0 1 0
1 1 0 0 /
SGOF
0 0 1 0
1 1 0 0 /
PVTW
100 1.0 1.0E-5 0.2 0.0 /
PVDO
1.01325 1.0 1.0
800.0 0.9999 1.0001 /
PVDG
1.01325 1.0 0.01
800.0 0.01 0.02 /
-- =====================================
SOLUTION
EQUIL
-- Datum P woc Pc goc Pc
2525. 270 2700 0.0 2525.0 0.0 /
-- =====================================
SUMMARY
-- ALL
-- SUMTHIN is here to verify that the explicit keyword white-listing
-- in SummaryConfig.cpp works correctly. We should not treat SUMTHIN
-- as a segment-related summary vector.
SUMTHIN
1 /
SOFR
'PROD01' 1 /
'PROD01' 10 /
'PROD01' 21 /
/
SGFR
'PROD01' /
/
SPR
1* 10 /
/
SWFR
/
-- ======================================
SCHEDULE
WELSPECS
'INJE01' 'I' 1 1 1* 'WATER' /
'PROD01' 'P' 10 10 1* 'OIL' /
/
COMPDAT
'INJE01' 1 1 7 9 'OPEN' 1* 200. 0.5 /
'PROD01' 10 10 1 1 'OPEN' 1* 200. 0.5 /
'PROD01' 10 10 2 2 'OPEN' 1* 200. 0.5 /
'PROD01' 10 10 3 3 'OPEN' 1* 200. 0.4 /
'PROD01' 10 10 4 4 'OPEN' 1* 200. 0.4 /
'PROD01' 10 10 5 5 'OPEN' 1* 200. 0.4 /
'PROD01' 10 10 6 6 'OPEN' 1* 200. 0.4 /
'PROD01' 9 10 2 2 'OPEN' 1* 200. 0.4 /
'PROD01' 8 10 2 2 'OPEN' 1* 200. 0.4 /
'PROD01' 7 10 2 2 'OPEN' 1* 200. 0.4 /
'PROD01' 6 10 2 2 'OPEN' 1* 200. 0.4 /
'PROD01' 5 10 2 2 'OPEN' 1* 200. 0.4 /
'PROD01' 10 9 3 3 'OPEN' 1* 200. 0.4 /
'PROD01' 10 8 3 3 'OPEN' 1* 200. 0.4 /
'PROD01' 10 7 3 3 'OPEN' 1* 200. 0.4 /
'PROD01' 10 6 3 3 'OPEN' 1* 200. 0.4 /
'PROD01' 10 5 3 3 'OPEN' 1* 200. 0.4 /
'PROD01' 9 10 5 5 'OPEN' 1* 200. 0.4 /
'PROD01' 8 10 5 5 'OPEN' 1* 200. 0.4 /
'PROD01' 7 10 5 5 'OPEN' 1* 200. 0.4 /
'PROD01' 6 10 5 5 'OPEN' 1* 200. 0.4 /
'PROD01' 5 10 5 5 'OPEN' 1* 200. 0.4 /
'PROD01' 10 9 6 6 'OPEN' 1* 200. 0.4 /
'PROD01' 10 8 6 6 'OPEN' 1* 200. 0.4 /
'PROD01' 10 7 6 6 'OPEN' 1* 200. 0.4 /
'PROD01' 10 6 6 6 'OPEN' 1* 200. 0.4 /
'PROD01' 10 5 6 6 'OPEN' 1* 200. 0.4 /
/
WELSEGS
'PROD01' 2512.5 2512.5 1.0e-5 'ABS' 'HFA' 'HO' /
2 2 1 1 2537.5 2534.5 0.3 0.00010 /
3 3 1 2 2562.5 2560.5 0.3 0.00010 /
4 4 1 3 2587.5 2593.5 0.3 0.00010 /
5 5 1 4 2612.5 2614.5 0.3 0.00010 /
6 6 1 5 2637.5 2635.5 0.3 0.00010 /
7 7 2 2 2737.5 2538.5 0.2 0.00010 /
8 8 2 7 2937.5 2537.5 0.2 0.00010 /
9 9 2 8 3137.5 2539.5 0.2 0.00010 /
10 10 2 9 3337.5 2535.5 0.2 0.00010 /
11 11 2 10 3537.5 2536.5 0.2 0.00010 /
12 12 3 3 2762.5 2563.5 0.2 0.00010 /
13 13 3 12 2962.5 2562.5 0.1 0.00010 /
14 14 3 13 3162.5 2562.5 0.1 0.00010 /
15 15 3 14 3362.5 2564.5 0.1 0.00010 /
16 16 3 15 3562.5 2562.5 0.1 0.00010 /
17 17 4 5 2812.5 2613.5 0.2 0.00010 /
18 18 4 17 3012.5 2612.5 0.1 0.00010 /
19 19 4 18 3212.5 2612.5 0.1 0.00010 /
20 20 4 19 3412.5 2612.5 0.1 0.00010 /
21 21 4 20 3612.5 2613.5 0.1 0.00010 /
22 22 5 6 2837.5 2634.5 0.2 0.00010 /
23 23 5 22 3037.5 2637.5 0.2 0.00010 /
24 24 5 23 3237.5 2638.5 0.2 0.00010 /
25 25 5 24 3437.5 2639.5 0.1 0.00010 /
26 26 5 25 3637.5 2639.5 0.1 0.00010 /
/
COMPSEGS
'PROD01'/
10 10 1 1 2512.5 2525.0 /
10 10 2 1 2525.0 2550.0 /
10 10 3 1 2550.0 2575.0 /
10 10 4 1 2575.0 2600.0 /
10 10 5 1 2600.0 2625.0 /
10 10 6 1 2625.0 2650.0 /
9 10 2 2 2637.5 2837.5 /
8 10 2 2 2837.5 3037.5 /
7 10 2 2 3037.5 3237.5 /
6 10 2 2 3237.5 3437.5 /
5 10 2 2 3437.5 3637.5 /
10 9 3 3 2662.5 2862.5 /
10 8 3 3 2862.5 3062.5 /
10 7 3 3 3062.5 3262.5 /
10 6 3 3 3262.5 3462.5 /
10 5 3 3 3462.5 3662.5 /
9 10 5 4 2712.5 2912.5 /
8 10 5 4 2912.5 3112.5 /
7 10 5 4 3112.5 3312.5 /
6 10 5 4 3312.5 3512.5 /
5 10 5 4 3512.5 3712.5 /
10 9 6 5 2737.5 2937.5 /
10 8 6 5 2937.5 3137.5 /
10 7 6 5 3137.5 3337.5 /
10 6 6 5 3337.5 3537.5 /
10 5 6 5 3537.5 3737.5 /
/
WCONINJE
'INJE01' 'WATER' 'OPEN' 'RATE' 15000.00 1* 450 /
/
WCONPROD
'PROD01' 'OPEN' 'BHP' 5* 260 /
/
TSTEP
2*0.5
2*4.5
2*25
4*100 /
END

View File

@@ -28,6 +28,8 @@
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <algorithm>
using namespace Opm;
static Deck createDeck_no_wells( const std::string& summary ) {
@@ -621,3 +623,155 @@ BOOST_AUTO_TEST_CASE( SUMMARY_MISC) {
}
}
BOOST_AUTO_TEST_CASE(Summary_Segment)
{
const auto input = std::string { "SOFR_TEST.DATA" };
const auto ctxt = ParseContext{};
const auto deck = Parser{}.parseFile(input, ctxt);
const auto state = EclipseState { deck, ctxt };
const auto schedule = Schedule { deck, state, ctxt };
const auto summary = SummaryConfig {
deck, schedule, state.getTableManager(), ctxt
};
// SOFR PROD01 segments 1, 10, 21.
BOOST_CHECK(deck.hasKeyword("SOFR"));
BOOST_CHECK(summary.hasKeyword("SOFR"));
BOOST_CHECK(summary.hasSummaryKey("SOFR:PROD01:1"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:2"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:3"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:4"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:5"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:6"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:7"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:8"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:9"));
BOOST_CHECK(summary.hasSummaryKey("SOFR:PROD01:10"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:11"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:12"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:13"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:14"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:15"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:16"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:17"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:18"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:19"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:20"));
BOOST_CHECK(summary.hasSummaryKey("SOFR:PROD01:21"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:22"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:23"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:24"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:25"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:26"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:PROD01:27"));
BOOST_CHECK(!summary.hasSummaryKey("SOFR:INJE01:1"));
{
auto sofr = std::find_if(summary.begin(), summary.end(),
[](const SummaryNode& node)
{
return node.keyword() == "SOFR";
});
BOOST_REQUIRE(sofr != summary.end());
BOOST_CHECK_EQUAL(sofr->type(), ecl_smspec_var_type::ECL_SMSPEC_SEGMENT_VAR);
BOOST_CHECK_EQUAL(sofr->wgname(), "PROD01");
}
BOOST_CHECK(deck.hasKeyword("SGFR"));
BOOST_CHECK(summary.hasKeyword("SGFR"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:1"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:2"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:3"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:4"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:5"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:6"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:7"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:8"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:9"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:10"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:11"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:12"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:13"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:14"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:15"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:16"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:17"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:18"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:19"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:20"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:21"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:22"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:23"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:24"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:25"));
BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:26"));
BOOST_CHECK(!summary.hasSummaryKey("SGFR:PROD01:27")); // No such segment.
// SPR PROD01 segment 10 only.
BOOST_CHECK(deck.hasKeyword("SPR"));
BOOST_CHECK(summary.hasKeyword("SPR"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:1"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:2"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:3"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:4"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:5"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:6"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:7"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:8"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:9"));
BOOST_CHECK(summary.hasSummaryKey("SPR:PROD01:10"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:11"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:12"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:13"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:14"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:15"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:16"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:17"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:18"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:19"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:20"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:21"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:22"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:23"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:24"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:25"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:PROD01:26"));
BOOST_CHECK(!summary.hasSummaryKey("SPR:INJE01:10"));
// SWFR for all segments in all MS wells.
BOOST_CHECK(deck.hasKeyword("SWFR"));
BOOST_CHECK(summary.hasKeyword("SWFR"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:1"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:2"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:3"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:4"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:5"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:6"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:7"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:8"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:9"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:10"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:11"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:12"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:13"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:14"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:15"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:16"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:17"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:18"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:19"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:20"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:21"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:22"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:23"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:24"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:25"));
BOOST_CHECK(summary.hasSummaryKey("SWFR:PROD01:26"));
BOOST_CHECK(!summary.hasSummaryKey("SWFR:INJE01:1"));
}

View File

@@ -23,7 +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>
@@ -43,9 +46,23 @@
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
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)
*/
@@ -141,6 +158,14 @@ static data::Wells result_wells() {
crates3.set( rt::reservoir_oil, 300.7 / day );
crates3.set( rt::reservoir_gas, 300.8 / day );
// Segment vectors
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.pressure = 314.159*unit::barsa;
segment.segNumber = 1;
/*
The global index assigned to the completion must be manually
syncronized with the global index in the COMPDAT keyword in the
@@ -151,10 +176,15 @@ static data::Wells result_wells() {
data::Connection well2_comp2 { 101, crates3, 1.11 , 123.4, 150.6, 0.001, 0.89, 100.0};
data::Connection well3_comp1 { 2 , crates3, 1.11 , 123.4, 456.78, 0.0, 0.15, 432.1};
/*
The completions
*/
data::Well well1 { rates1, 0.1 * ps, 0.2 * ps, 0.3 * ps, 1, { {well1_comp1} } };
data::Well well1 {
rates1, 0.1 * ps, 0.2 * ps, 0.3 * ps, 1,
{ {well1_comp1} },
{ { segment.segNumber, segment } },
};
data::Well well2 { rates2, 1.1 * ps, 1.2 * ps, 1.3 * ps, 2, { {well2_comp1 , well2_comp2} } };
data::Well well3 { rates3, 2.1 * ps, 2.2 * ps, 2.3 * ps, 3, { {well3_comp1} } };
@@ -164,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;
}
@@ -1178,6 +1211,16 @@ 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& 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.pressure, 314.159*unit::barsa, 1.0e-10);
BOOST_CHECK_EQUAL(seg.segNumber, 1);
// No data for segment 10 of well W_2 (or no such segment).
const auto& W2 = wellRatesCopy.at("W_2");
BOOST_CHECK_THROW(W2.segments.at(10), std::out_of_range);
}
BOOST_AUTO_TEST_CASE(efficiency_factor) {
@@ -1294,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 {
@@ -1961,3 +2013,782 @@ 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", "SOFR", "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);
}
}
// ====================================================================
namespace {
bool hasSegmentVariable_Prod01(const ecl_sum_type* ecl_sum,
const char* vector,
const int segID)
{
const auto lookup_kw = genKeyPROD01(vector, segID);
return ecl_sum_has_general_var(ecl_sum, lookup_kw.c_str());
}
double getSegmentVariable_Prod01(const ecl_sum_type* ecl_sum,
const int timeIdx,
const char* vector,
const int segID)
{
const auto lookup_kw = genKeyPROD01(vector, segID);
return ecl_sum_get_general_var(ecl_sum, timeIdx, lookup_kw.c_str());
}
} // Anonymous
BOOST_AUTO_TEST_CASE(Write_Read)
{
const setup config{"test.Restart.Segment.RW", "SOFR_TEST.DATA"};
::Opm::out::Summary writer {
config.es, config.config, config.grid, config.schedule
};
writer.add_timestep(0, 0*day, config.es, config.schedule, config.wells, {});
writer.add_timestep(1, 1*day, config.es, config.schedule, config.wells, {});
writer.add_timestep(2, 2*day, config.es, config.schedule, config.wells, {});
writer.write();
auto res = readsum("SOFR_TEST");
const auto* resp = res.get();
const int timeIdx = 2;
// Rate Setup
//
// 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()));
//
// Pressure Setup
// res.pressure = (100.0 + segID)*unit::barsa;
// Note: Producer rates reported as positive.
// SOFR_TEST Summary Section:
//
// SUMMARY
//
// -- ALL
//
// SOFR
// 'PROD01' 1 /
// 'PROD01' 10 /
// 'PROD01' 21 /
// /
//
// SGFR
// 'PROD01' /
// /
//
// SPR
// 1* 10 /
// /
//
// SWFR
// /
// Segment 1: SOFR, SGFR, SWFR
{
const auto segID = 1;
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SOFR", segID),
segID*1000.0 + 200.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 2: SGFR, SWFR
{
const auto segID = 2;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 3: SGFR, SWFR
{
const auto segID = 3;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 4: SGFR, SWFR
{
const auto segID = 4;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 5: SGFR, SWFR
{
const auto segID = 5;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 6: SGFR, SWFR
{
const auto segID = 6;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 7: SGFR, SWFR
{
const auto segID = 7;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 8: SGFR, SWFR
{
const auto segID = 8;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 9: SGFR, SWFR
{
const auto segID = 9;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 10: SOFR, SGFR, SWFR, SPR
{
const auto segID = 10;
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SPR", segID),
100.0 + segID, 1.0e-10);
}
// Segment 11: SGFR, SWFR
{
const auto segID = 11;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 12: SGFR, SWFR
{
const auto segID = 12;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 13: SGFR, SWFR
{
const auto segID = 13;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 14: SGFR, SWFR
{
const auto segID = 14;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 15: SGFR, SWFR
{
const auto segID = 15;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 16: SGFR, SWFR
{
const auto segID = 16;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 17: SGFR, SWFR
{
const auto segID = 17;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 18: SGFR, SWFR
{
const auto segID = 18;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 19: SGFR, SWFR
{
const auto segID = 19;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 20: SGFR, SWFR
{
const auto segID = 20;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 21: SOFR, SGFR, SWFR
{
const auto segID = 21;
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SOFR", segID),
segID*1000.0 + 200.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 22: SGFR, SWFR
{
const auto segID = 22;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 23: SGFR, SWFR
{
const auto segID = 23;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 24: SGFR, SWFR
{
const auto segID = 24;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 25: SGFR, SWFR
{
const auto segID = 25;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 26: SGFR, SWFR
{
const auto segID = 26;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK( hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SGFR", segID),
segID*1000.0 + 400.0, 1.0e-10);
BOOST_CHECK_CLOSE(getSegmentVariable_Prod01(resp, timeIdx, "SWFR", segID),
segID*1000.0 + 100.0, 1.0e-10);
}
// Segment 256: No such segment
{
const auto segID = 256;
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SOFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SGFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SWFR", segID));
BOOST_CHECK(!hasSegmentVariable_Prod01(resp, "SPR" , segID));
}
}
BOOST_AUTO_TEST_SUITE_END()