Merge pull request #514 from bska/segment-summary
Serialization: Add Initial Support for Segment Information
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"}
|
||||
]
|
||||
}
|
||||
@@ -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
246
tests/SOFR_TEST.DATA
Normal 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
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user