Merge pull request #3696 from bska/msw-rst-fixup
Fix Multiple Issues in MSW Output Array Creation Logic
This commit is contained in:
commit
a8d3dff2a4
@ -69,6 +69,7 @@ namespace Opm {
|
|||||||
|
|
||||||
// Status: OPEN or SHUT
|
// Status: OPEN or SHUT
|
||||||
ICDStatus status() const;
|
ICDStatus status() const;
|
||||||
|
int ecl_status() const;
|
||||||
|
|
||||||
void setConMaxCrossArea(const double area);
|
void setConMaxCrossArea(const double area);
|
||||||
|
|
||||||
|
@ -36,39 +36,18 @@ namespace Opm {
|
|||||||
|
|
||||||
namespace Opm { namespace RestartIO { namespace Helpers {
|
namespace Opm { namespace RestartIO { namespace Helpers {
|
||||||
|
|
||||||
struct BranchSegmentPar {
|
|
||||||
int outletS;
|
|
||||||
int noSegInBranch;
|
|
||||||
int firstSeg;
|
|
||||||
int lastSeg;
|
|
||||||
int branch;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentSetSourceSinkTerms {
|
|
||||||
std::vector<double> qosc;
|
|
||||||
std::vector<double> qwsc;
|
|
||||||
std::vector<double> qgsc;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentSetFlowRates {
|
|
||||||
std::vector<double> sofr;
|
|
||||||
std::vector<double> swfr;
|
|
||||||
std::vector<double> sgfr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AggregateMSWData
|
class AggregateMSWData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AggregateMSWData(const std::vector<int>& inteHead);
|
explicit AggregateMSWData(const std::vector<int>& inteHead);
|
||||||
|
|
||||||
void captureDeclaredMSWData(const Opm::Schedule& sched,
|
void captureDeclaredMSWData(const Opm::Schedule& sched,
|
||||||
const std::size_t rptStep,
|
const std::size_t rptStep,
|
||||||
const Opm::UnitSystem& units,
|
const Opm::UnitSystem& units,
|
||||||
const std::vector<int>& inteHead,
|
const std::vector<int>& inteHead,
|
||||||
const Opm::EclipseGrid& grid,
|
const Opm::EclipseGrid& grid,
|
||||||
const Opm::SummaryState& smry,
|
const Opm::SummaryState& smry,
|
||||||
const Opm::data::Wells& wr
|
const Opm::data::Wells& wr);
|
||||||
);
|
|
||||||
|
|
||||||
/// Retrieve Integer Multisegment well data Array.
|
/// Retrieve Integer Multisegment well data Array.
|
||||||
const std::vector<int>& getISeg() const
|
const std::vector<int>& getISeg() const
|
||||||
@ -94,7 +73,6 @@ namespace Opm { namespace RestartIO { namespace Helpers {
|
|||||||
return this->iLBR_.data();
|
return this->iLBR_.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Aggregate 'ISEG' array (Integer) for all multisegment wells
|
/// Aggregate 'ISEG' array (Integer) for all multisegment wells
|
||||||
WindowedArray<int> iSeg_;
|
WindowedArray<int> iSeg_;
|
||||||
@ -106,8 +84,7 @@ namespace Opm { namespace RestartIO { namespace Helpers {
|
|||||||
WindowedArray<int> iLBS_;
|
WindowedArray<int> iLBS_;
|
||||||
|
|
||||||
/// Aggregate 'ILBR' array (Integer) for all multisegment wells
|
/// Aggregate 'ILBR' array (Integer) for all multisegment wells
|
||||||
WindowedArray<int> iLBR_;
|
WindowedMatrix<int> iLBR_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}}} // Opm::RestartIO::Helpers
|
}}} // Opm::RestartIO::Helpers
|
||||||
|
@ -40,6 +40,16 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
|
|||||||
|
|
||||||
} // ISeg
|
} // ISeg
|
||||||
|
|
||||||
|
namespace ILbr {
|
||||||
|
enum index : std::vector<int>::size_type {
|
||||||
|
OutletSegment = 0, // Branch's outlet segment (one-based)
|
||||||
|
NumBranchSegments = 1, // Number of segments on branch
|
||||||
|
FirstSegment = 2, // First segment on branch (kick-off, heel)
|
||||||
|
LastSegment = 3, // Last segment on branch (toe)
|
||||||
|
KickOffDiscoveryOffset = 4, // Segment traversal order at which this branch was encountered
|
||||||
|
};
|
||||||
|
} // ILbr
|
||||||
|
|
||||||
namespace RSeg {
|
namespace RSeg {
|
||||||
enum index : std::vector<double>::size_type {
|
enum index : std::vector<double>::size_type {
|
||||||
DistOutlet = 0, // Segment's distance to outlet
|
DistOutlet = 0, // Segment's distance to outlet
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
|
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
|
||||||
|
|
||||||
|
#include "icd_convert.hpp"
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
@ -130,6 +132,11 @@ namespace Opm {
|
|||||||
return m_status;
|
return m_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Valve::ecl_status() const
|
||||||
|
{
|
||||||
|
return to_int(this->status());
|
||||||
|
}
|
||||||
|
|
||||||
double Valve::conFlowCoefficient() const {
|
double Valve::conFlowCoefficient() const {
|
||||||
return m_con_flow_coeff;
|
return m_con_flow_coeff;
|
||||||
}
|
}
|
||||||
|
@ -18,31 +18,43 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <opm/output/eclipse/AggregateMSWData.hpp>
|
#include <opm/output/eclipse/AggregateMSWData.hpp>
|
||||||
|
|
||||||
#include <opm/output/eclipse/InteHEAD.hpp>
|
#include <opm/output/eclipse/InteHEAD.hpp>
|
||||||
#include <opm/output/eclipse/VectorItems/msw.hpp>
|
#include <opm/output/eclipse/VectorItems/msw.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/MSW/AICD.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/MSW/Segment.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/MSW/SICD.hpp>
|
#include <opm/input/eclipse/Schedule/MSW/SICD.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
|
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/MSW/Segment.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
|
|
||||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <exception>
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
#include <queue>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
// #####################################################################
|
// #####################################################################
|
||||||
// Class Opm::RestartIO::Helpers::AggregateMSWData
|
// Class Opm::RestartIO::Helpers::AggregateMSWData
|
||||||
@ -50,6 +62,18 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct SegmentSetSourceSinkTerms {
|
||||||
|
std::vector<double> qosc;
|
||||||
|
std::vector<double> qwsc;
|
||||||
|
std::vector<double> qgsc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SegmentSetFlowRates {
|
||||||
|
std::vector<double> sofr;
|
||||||
|
std::vector<double> swfr;
|
||||||
|
std::vector<double> sgfr;
|
||||||
|
};
|
||||||
|
|
||||||
std::size_t nswlmx(const std::vector<int>& inteHead)
|
std::size_t nswlmx(const std::vector<int>& inteHead)
|
||||||
{
|
{
|
||||||
// inteHead(175) = NSWLMX
|
// inteHead(175) = NSWLMX
|
||||||
@ -75,56 +99,38 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::size_t>
|
std::vector<std::size_t>
|
||||||
inflowSegmentsIndex(const Opm::WellSegments& segSet, const std::size_t& segIndex) {
|
inflowSegmentsIndex(const Opm::WellSegments& segSet,
|
||||||
const auto& segNumber = segSet[segIndex].segmentNumber();
|
const std::size_t segIndex)
|
||||||
|
{
|
||||||
std::vector<std::size_t> inFlowSegInd;
|
std::vector<std::size_t> inFlowSegInd;
|
||||||
|
|
||||||
|
const auto segNumber = segSet[segIndex].segmentNumber();
|
||||||
|
|
||||||
for (std::size_t ind = 0; ind < segSet.size(); ind++) {
|
for (std::size_t ind = 0; ind < segSet.size(); ind++) {
|
||||||
const auto& i_outletSeg = segSet[ind].outletSegment();
|
const auto& i_outletSeg = segSet[ind].outletSegment();
|
||||||
if (segNumber == i_outletSeg) {
|
if (segNumber == i_outletSeg) {
|
||||||
inFlowSegInd.push_back(ind);
|
inFlowSegInd.push_back(ind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return inFlowSegInd;
|
return inFlowSegInd;
|
||||||
}
|
}
|
||||||
|
|
||||||
Opm::RestartIO::Helpers::BranchSegmentPar
|
std::vector<std::size_t>
|
||||||
getBranchSegmentParam(const Opm::WellSegments& segSet, const int branch)
|
segmentIndFromOrderedSegmentInd(const Opm::WellSegments& segSet,
|
||||||
|
const std::vector<std::size_t>& ordSegNo)
|
||||||
{
|
{
|
||||||
int noSegInBranch = 0;
|
|
||||||
int firstSeg = -1;
|
|
||||||
int lastSeg = -1;
|
|
||||||
int outletS = 0;
|
|
||||||
for (std::size_t segInd = 0; segInd < segSet.size(); segInd++) {
|
|
||||||
const auto& segNo = segSet[segInd].segmentNumber();
|
|
||||||
const auto& i_branch = segSet[segInd].branchNumber();
|
|
||||||
const auto& i_outS = segSet[segInd].outletSegment();
|
|
||||||
if (i_branch == branch) {
|
|
||||||
noSegInBranch +=1;
|
|
||||||
if (firstSeg < 0) {
|
|
||||||
firstSeg = segNo;
|
|
||||||
outletS = (branch > 1) ? i_outS : 0;
|
|
||||||
}
|
|
||||||
lastSeg = segNo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
outletS,
|
|
||||||
noSegInBranch,
|
|
||||||
firstSeg,
|
|
||||||
lastSeg,
|
|
||||||
branch
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector <std::size_t> segmentIndFromOrderedSegmentInd(const Opm::WellSegments& segSet, const std::vector<std::size_t>& ordSegNo) {
|
|
||||||
std::vector <std::size_t> sNFOSN (segSet.size(),0);
|
std::vector <std::size_t> sNFOSN (segSet.size(),0);
|
||||||
for (std::size_t segInd = 0; segInd < segSet.size(); segInd++) {
|
for (std::size_t segInd = 0; segInd < segSet.size(); segInd++) {
|
||||||
sNFOSN[ordSegNo[segInd]] = segInd;
|
sNFOSN[ordSegNo[segInd]] = segInd;
|
||||||
}
|
}
|
||||||
return sNFOSN;
|
return sNFOSN;
|
||||||
}
|
}
|
||||||
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> ordSegNumber;
|
||||||
std::vector<std::size_t> segIndCB;
|
std::vector<std::size_t> segIndCB;
|
||||||
// Store "heel" segment since that will not always be at the end of the list
|
// Store "heel" segment since that will not always be at the end of the list
|
||||||
@ -177,16 +183,18 @@ namespace {
|
|||||||
return ordSegNumber;
|
return ordSegNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::size_t> segmentOrder(const Opm::WellSegments& segSet) {
|
std::vector<std::size_t>
|
||||||
|
segmentOrder(const Opm::WellSegments& segSet)
|
||||||
|
{
|
||||||
return segmentOrder(segSet, 0);
|
return segmentOrder(segSet, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accumulate connection flow rates (surface conditions) to their connecting segment.
|
/// Accumulate connection flow rates (surface conditions) to their connecting segment.
|
||||||
Opm::RestartIO::Helpers::SegmentSetSourceSinkTerms
|
SegmentSetSourceSinkTerms
|
||||||
getSegmentSetSSTerms(const Opm::WellSegments& segSet,
|
getSegmentSetSSTerms(const Opm::WellSegments& segSet,
|
||||||
const std::vector<Opm::data::Connection>& rateConns,
|
const std::vector<Opm::data::Connection>& rateConns,
|
||||||
const Opm::WellConnections& welConns,
|
const Opm::WellConnections& welConns,
|
||||||
const Opm::UnitSystem& units)
|
const Opm::UnitSystem& units)
|
||||||
{
|
{
|
||||||
std::vector<double> qosc (segSet.size(), 0.);
|
std::vector<double> qosc (segSet.size(), 0.);
|
||||||
std::vector<double> qwsc (segSet.size(), 0.);
|
std::vector<double> qwsc (segSet.size(), 0.);
|
||||||
@ -232,11 +240,11 @@ namespace {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Opm::RestartIO::Helpers::SegmentSetFlowRates
|
SegmentSetFlowRates
|
||||||
getSegmentSetFlowRates(const Opm::WellSegments& segSet,
|
getSegmentSetFlowRates(const Opm::WellSegments& segSet,
|
||||||
const std::vector<Opm::data::Connection>& rateConns,
|
const std::vector<Opm::data::Connection>& rateConns,
|
||||||
const Opm::WellConnections& welConns,
|
const Opm::WellConnections& welConns,
|
||||||
const Opm::UnitSystem& units)
|
const Opm::UnitSystem& units)
|
||||||
{
|
{
|
||||||
std::vector<double> sofr (segSet.size(), 0.);
|
std::vector<double> sofr (segSet.size(), 0.);
|
||||||
std::vector<double> swfr (segSet.size(), 0.);
|
std::vector<double> swfr (segSet.size(), 0.);
|
||||||
@ -273,31 +281,6 @@ namespace {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::size_t> SegmentSetBranches(const Opm::WellSegments& segSet) {
|
|
||||||
std::vector<std::size_t> branches;
|
|
||||||
for (std::size_t segInd = 0; segInd < segSet.size(); segInd++) {
|
|
||||||
const auto& i_branch = segSet[segInd].branchNumber();
|
|
||||||
if (std::find(branches.begin(), branches.end(), i_branch) == branches.end()) {
|
|
||||||
branches.push_back(i_branch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return branches;
|
|
||||||
}
|
|
||||||
|
|
||||||
int firstSegmentInBranch(const Opm::WellSegments& segSet, const int branch) {
|
|
||||||
int firstSegInd = 0;
|
|
||||||
std::size_t segInd = 0;
|
|
||||||
while ((segInd < segSet.size()) && (firstSegInd == 0)) {
|
|
||||||
const auto& i_branch = segSet[segInd].branchNumber();
|
|
||||||
if (branch == i_branch) {
|
|
||||||
firstSegInd = segInd;
|
|
||||||
}
|
|
||||||
segInd+=1;
|
|
||||||
}
|
|
||||||
return firstSegInd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int noConnectionsSegment(const Opm::WellConnections& compSet,
|
int noConnectionsSegment(const Opm::WellConnections& compSet,
|
||||||
const Opm::WellSegments& segSet,
|
const Opm::WellSegments& segSet,
|
||||||
const std::size_t segIndex)
|
const std::size_t segIndex)
|
||||||
@ -332,9 +315,12 @@ namespace {
|
|||||||
return sumConn;
|
return sumConn;
|
||||||
}
|
}
|
||||||
|
|
||||||
int noInFlowBranches(const Opm::WellSegments& segSet, std::size_t segIndex) {
|
int noInFlowBranches(const Opm::WellSegments& segSet,
|
||||||
const auto& segNumber = segSet[segIndex].segmentNumber();
|
const std::size_t segIndex)
|
||||||
const auto& branch = segSet[segIndex].branchNumber();
|
{
|
||||||
|
const auto segNumber = segSet[segIndex].segmentNumber();
|
||||||
|
const auto branch = segSet[segIndex].branchNumber();
|
||||||
|
|
||||||
int noIFBr = 0;
|
int noIFBr = 0;
|
||||||
for (std::size_t ind = 0; ind < segSet.size(); ind++) {
|
for (std::size_t ind = 0; ind < segSet.size(); ind++) {
|
||||||
const auto& o_segNum = segSet[ind].outletSegment();
|
const auto& o_segNum = segSet[ind].outletSegment();
|
||||||
@ -343,12 +329,16 @@ namespace {
|
|||||||
noIFBr+=1;
|
noIFBr+=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return noIFBr;
|
return noIFBr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//find the number of inflow branch-segments (segments that has a branch) from the
|
//find the number of inflow branch-segments (segments that has a branch) from the
|
||||||
// first segment to the current segment for segments that has at least one inflow branch
|
// first segment to the current segment for segments that has at least one inflow branch
|
||||||
// Segments with no inflow branches get the value zero
|
// Segments with no inflow branches get the value zero
|
||||||
int sumNoInFlowBranches(const Opm::WellSegments& segSet, const std::size_t& segIndex) {
|
int sumNoInFlowBranches(const Opm::WellSegments& segSet,
|
||||||
|
const std::size_t segIndex)
|
||||||
|
{
|
||||||
int sumIFB = 0;
|
int sumIFB = 0;
|
||||||
//auto segInd = segIndex;
|
//auto segInd = segIndex;
|
||||||
for (int segInd = static_cast<int>(segIndex); segInd >= 0; segInd--) {
|
for (int segInd = static_cast<int>(segIndex); segInd >= 0; segInd--) {
|
||||||
@ -362,15 +352,19 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the segment has inflow branches - if yes return sumIFB else return zero
|
// check if the segment has inflow branches - if yes return sumIFB else return zero
|
||||||
return (noInFlowBranches(segSet, segIndex) >= 1)
|
return (noInFlowBranches(segSet, segIndex) >= 1)
|
||||||
? sumIFB : 0;
|
? sumIFB : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int inflowSegmentCurBranch(const std::string& wname,
|
||||||
|
const Opm::WellSegments& segSet,
|
||||||
|
const std::size_t segIndex)
|
||||||
|
{
|
||||||
|
const auto branch = segSet[segIndex].branchNumber();
|
||||||
|
const auto segNumber = segSet[segIndex].segmentNumber();
|
||||||
|
|
||||||
int inflowSegmentCurBranch(const std::string& wname, const Opm::WellSegments& segSet, std::size_t segIndex) {
|
|
||||||
const auto& branch = segSet[segIndex].branchNumber();
|
|
||||||
const auto& segNumber = segSet[segIndex].segmentNumber();
|
|
||||||
int inFlowSegInd = -1;
|
int inFlowSegInd = -1;
|
||||||
for (std::size_t ind = 0; ind < segSet.size(); ind++) {
|
for (std::size_t ind = 0; ind < segSet.size(); ind++) {
|
||||||
const auto& i_segNum = segSet[ind].segmentNumber();
|
const auto& i_segNum = segSet[ind].segmentNumber();
|
||||||
@ -390,6 +384,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (inFlowSegInd == -1) ? 0 : inFlowSegInd;
|
return (inFlowSegInd == -1) ? 0 : inFlowSegInd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +430,6 @@ namespace {
|
|||||||
VectorItems::ISeg::index;
|
VectorItems::ISeg::index;
|
||||||
|
|
||||||
const auto& sicd = segment.spiralICD();
|
const auto& sicd = segment.spiralICD();
|
||||||
iSeg[baseIndex + Ix::SegmentType] = segment.ecl_type_id();
|
|
||||||
iSeg[baseIndex + Ix::ICDScalingMode] = sicd.methodFlowScaling();
|
iSeg[baseIndex + Ix::ICDScalingMode] = sicd.methodFlowScaling();
|
||||||
iSeg[baseIndex + Ix::ICDOpenShutFlag] = sicd.ecl_status();
|
iSeg[baseIndex + Ix::ICDOpenShutFlag] = sicd.ecl_status();
|
||||||
}
|
}
|
||||||
@ -449,11 +443,21 @@ namespace {
|
|||||||
VectorItems::ISeg::index;
|
VectorItems::ISeg::index;
|
||||||
|
|
||||||
const auto& aicd = segment.autoICD();
|
const auto& aicd = segment.autoICD();
|
||||||
iSeg[baseIndex + Ix::SegmentType] = segment.ecl_type_id();
|
|
||||||
iSeg[baseIndex + Ix::ICDScalingMode] = aicd.methodFlowScaling();
|
iSeg[baseIndex + Ix::ICDScalingMode] = aicd.methodFlowScaling();
|
||||||
iSeg[baseIndex + Ix::ICDOpenShutFlag] = aicd.ecl_status();
|
iSeg[baseIndex + Ix::ICDOpenShutFlag] = aicd.ecl_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ISegArray>
|
||||||
|
void assignValveCharacteristics(const Opm::Segment& segment,
|
||||||
|
const std::size_t baseIndex,
|
||||||
|
ISegArray& iSeg)
|
||||||
|
{
|
||||||
|
using Ix = ::Opm::RestartIO::Helpers::VectorItems::ISeg::index;
|
||||||
|
|
||||||
|
const auto& valve = segment.valve();
|
||||||
|
iSeg[baseIndex + Ix::ICDOpenShutFlag] = valve.ecl_status();
|
||||||
|
}
|
||||||
|
|
||||||
template <class ISegArray>
|
template <class ISegArray>
|
||||||
void assignSegmentTypeCharacteristics(const Opm::Segment& segment,
|
void assignSegmentTypeCharacteristics(const Opm::Segment& segment,
|
||||||
const std::size_t baseIndex,
|
const std::size_t baseIndex,
|
||||||
@ -462,9 +466,14 @@ namespace {
|
|||||||
if (segment.isSpiralICD()) {
|
if (segment.isSpiralICD()) {
|
||||||
assignSpiralICDCharacteristics(segment, baseIndex, iSeg);
|
assignSpiralICDCharacteristics(segment, baseIndex, iSeg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment.isAICD()) {
|
if (segment.isAICD()) {
|
||||||
assignAICDCharacteristics(segment, baseIndex, iSeg);
|
assignAICDCharacteristics(segment, baseIndex, iSeg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (segment.isValve()) {
|
||||||
|
assignValveCharacteristics(segment, baseIndex, iSeg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ISegArray>
|
template <class ISegArray>
|
||||||
@ -491,7 +500,7 @@ namespace {
|
|||||||
const auto& segment = welSegSet[ind];
|
const auto& segment = welSegSet[ind];
|
||||||
auto segNumber = segment.segmentNumber();
|
auto segNumber = segment.segmentNumber();
|
||||||
auto iS = (segNumber-1)*noElmSeg;
|
auto iS = (segNumber-1)*noElmSeg;
|
||||||
iSeg[iS + Ix::SegNo] = welSegSet[orderedSegmentNo[ind]].segmentNumber();
|
iSeg[ind*noElmSeg + Ix::SegNo] = welSegSet[orderedSegmentNo[ind]].segmentNumber();
|
||||||
iSeg[iS + Ix::OutSeg] = segment.outletSegment();
|
iSeg[iS + Ix::OutSeg] = segment.outletSegment();
|
||||||
iSeg[iS + Ix::InSegCurBranch] = (inflowSegmentCurBranch(well.name(), welSegSet, ind) == 0) ? 0 : welSegSet[inflowSegmentCurBranch(well.name(), welSegSet, ind)].segmentNumber();
|
iSeg[iS + Ix::InSegCurBranch] = (inflowSegmentCurBranch(well.name(), welSegSet, ind) == 0) ? 0 : welSegSet[inflowSegmentCurBranch(well.name(), welSegSet, ind)].segmentNumber();
|
||||||
iSeg[iS + Ix::BranchNo] = segment.branchNumber();
|
iSeg[iS + Ix::BranchNo] = segment.branchNumber();
|
||||||
@ -764,6 +773,7 @@ namespace {
|
|||||||
bool haveWellRes = (well.getStatus() != Opm::Well::Status::SHUT) ? (wRatesIt != wr.end()) : false;
|
bool haveWellRes = (well.getStatus() != Opm::Well::Status::SHUT) ? (wRatesIt != wr.end()) : false;
|
||||||
const auto volFromLengthUnitConv = units.from_si(M::length, units.from_si(M::length, units.from_si(M::length, 1.)));
|
const auto volFromLengthUnitConv = units.from_si(M::length, units.from_si(M::length, units.from_si(M::length, 1.)));
|
||||||
const auto areaFromLengthUnitConv = units.from_si(M::length, units.from_si(M::length, 1.));
|
const auto areaFromLengthUnitConv = units.from_si(M::length, units.from_si(M::length, 1.));
|
||||||
|
|
||||||
//
|
//
|
||||||
//Initialize temporary variables
|
//Initialize temporary variables
|
||||||
double temp_o = 0.;
|
double temp_o = 0.;
|
||||||
@ -771,10 +781,9 @@ namespace {
|
|||||||
double temp_g = 0.;
|
double temp_g = 0.;
|
||||||
|
|
||||||
// find well connections and calculate segment rates based on well connection production/injection terms
|
// find well connections and calculate segment rates based on well connection production/injection terms
|
||||||
auto sSFR = Opm::RestartIO::Helpers::SegmentSetFlowRates{};
|
const auto sSFR = haveWellRes
|
||||||
if (haveWellRes) {
|
? getSegmentSetFlowRates(welSegSet, wRatesIt->second.connections, welConns, units)
|
||||||
sSFR = getSegmentSetFlowRates(welSegSet, wRatesIt->second.connections, welConns, units);
|
: SegmentSetFlowRates{};
|
||||||
}
|
|
||||||
|
|
||||||
auto get = [&smry, &wname](const std::string& vector, const std::string& segment_nr)
|
auto get = [&smry, &wname](const std::string& vector, const std::string& segment_nr)
|
||||||
{
|
{
|
||||||
@ -782,7 +791,6 @@ namespace {
|
|||||||
return smry.get(key, 0.0);
|
return smry.get(key, 0.0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Treat the top segment individually
|
// Treat the top segment individually
|
||||||
{
|
{
|
||||||
const int segNumber = segment0.segmentNumber();
|
const int segNumber = segment0.segmentNumber();
|
||||||
@ -904,6 +912,287 @@ namespace {
|
|||||||
}
|
}
|
||||||
} // RSeg
|
} // RSeg
|
||||||
|
|
||||||
|
namespace LateralBranch {
|
||||||
|
/// Discover segment and branch tree structure through traversal.
|
||||||
|
/// Uses Segment::inletSegments() as the primary link in the tree
|
||||||
|
/// structure.
|
||||||
|
///
|
||||||
|
/// Information conveyed to the user through callback routines.
|
||||||
|
///
|
||||||
|
/// As an example, the segments in the following tree will be
|
||||||
|
/// visited in the order
|
||||||
|
///
|
||||||
|
/// 1, 2, 3, 4, 5, 6 -- Branch (1)
|
||||||
|
/// 11, 12, 13, 14, 15, 16 -- Branch (2)
|
||||||
|
/// 7, 8, 9, 10 -- Branch (3)
|
||||||
|
/// 20, 22, 23, 24 -- Branch (5)
|
||||||
|
/// 21, -- Branch (6)
|
||||||
|
/// 17, 18, 19 -- Branch (4)
|
||||||
|
///
|
||||||
|
/// +------------------------------------------------------------+
|
||||||
|
/// | |
|
||||||
|
/// | 12 13 14 15 16 |
|
||||||
|
/// | o----o----o-----o------o-----o (2) |
|
||||||
|
/// | 11 / 20 \ 21 \ |
|
||||||
|
/// | / o o (6) |
|
||||||
|
/// | / \ |
|
||||||
|
/// | / 22 \ 23 24 |
|
||||||
|
/// | 1 2 3 / 4 5 6 o----o----o (5) |
|
||||||
|
/// | ---o---o---o-----o---o---o (1) |
|
||||||
|
/// | \ |
|
||||||
|
/// | 7 \ 8 9 10 |
|
||||||
|
/// | o---o---o-----o (3) |
|
||||||
|
/// | \ |
|
||||||
|
/// | 17 \ 18 19 |
|
||||||
|
/// | o----o----o (4) |
|
||||||
|
/// | |
|
||||||
|
/// +------------------------------------------------------------+
|
||||||
|
///
|
||||||
|
class Topology
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Callback for discovering/visiting a new segment.
|
||||||
|
using NewSegmentCallback = std::function<void(const ::Opm::Segment& seg)>;
|
||||||
|
|
||||||
|
/// Callback for discovering/creating a new branch.
|
||||||
|
using NewBranchCallback = std::function<
|
||||||
|
void(std::string_view well,
|
||||||
|
const int branchId,
|
||||||
|
const int kickOffSegment,
|
||||||
|
const int outletSegment)
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
///
|
||||||
|
/// \param[in] well Name of current MS well.
|
||||||
|
/// \param[in] segSet Well's segments and branches.
|
||||||
|
explicit Topology(std::string_view well,
|
||||||
|
const ::Opm::WellSegments& segSet)
|
||||||
|
: well_ { well }
|
||||||
|
, segSet_ { std::cref(segSet) }
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// Set callback for visiting a new segment.
|
||||||
|
///
|
||||||
|
/// \param[in] callback New callback routine.
|
||||||
|
/// \return \c *this.
|
||||||
|
Topology& setNewSegmentCallback(NewSegmentCallback callback)
|
||||||
|
{
|
||||||
|
this->runNewSegmentCallback_ = std::move(callback);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set callback for visiting a new branch.
|
||||||
|
///
|
||||||
|
/// \param[in] callback New callback routine.
|
||||||
|
/// \return \c *this.
|
||||||
|
Topology& setNewBranchCallback(NewBranchCallback callback)
|
||||||
|
{
|
||||||
|
this->runNewBranchCallback_ = std::move(callback);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Walk well's segment tree from top (segment 1, branch 1).
|
||||||
|
///
|
||||||
|
/// New branches and segments are searched in a depth first
|
||||||
|
/// order. Furthermore, new branches are visited in order of
|
||||||
|
/// discovery, but we always search to the end of the current
|
||||||
|
/// branch, visiting all of its segments, before visiting the
|
||||||
|
/// first segment of a new branch. Each segment is visited
|
||||||
|
/// exactly once.
|
||||||
|
///
|
||||||
|
/// Invokes the user-defined callback routines for new segments
|
||||||
|
/// and branches and imparts segment tree structure to caller
|
||||||
|
/// through these routines.
|
||||||
|
void traverseStructure();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Name of well being explored.
|
||||||
|
std::string_view well_{};
|
||||||
|
|
||||||
|
/// Well's segments and branches.
|
||||||
|
std::reference_wrapper<const ::Opm::WellSegments> segSet_;
|
||||||
|
|
||||||
|
/// Callback routine for visiting a new segment.
|
||||||
|
NewSegmentCallback runNewSegmentCallback_{};
|
||||||
|
|
||||||
|
/// Callback routine for visiting a new branch.
|
||||||
|
NewBranchCallback runNewBranchCallback_{};
|
||||||
|
|
||||||
|
/// Segments from which to kick off searching new branches.
|
||||||
|
std::queue<int> kickOffSegments_{};
|
||||||
|
|
||||||
|
/// One-based segment number of currently visited segment.
|
||||||
|
int currentSegment_{};
|
||||||
|
|
||||||
|
/// Find all segments on current branch, in order from heel to
|
||||||
|
/// toe.
|
||||||
|
///
|
||||||
|
/// Invokes new segment callback, once for each segment.
|
||||||
|
void buildCurrentBranch();
|
||||||
|
|
||||||
|
/// Enqueue collection of new branches from common kick-off
|
||||||
|
/// point.
|
||||||
|
///
|
||||||
|
/// \param[in] outletSegment Segment from which new branches
|
||||||
|
/// kick off.
|
||||||
|
///
|
||||||
|
/// \param[in] children Collection of new branch start segments.
|
||||||
|
/// One child/kick-off segment for each new branch.
|
||||||
|
void discoverNewBranches(const int outletSegment,
|
||||||
|
const std::vector<int>& children);
|
||||||
|
|
||||||
|
/// Enqueue new branch.
|
||||||
|
///
|
||||||
|
/// Will be visited later. Invokes new branch callback.
|
||||||
|
///
|
||||||
|
/// \param[in] branchId Branch number for new branch.
|
||||||
|
///
|
||||||
|
/// \param[in] kickOffSegment First segment on new branch.
|
||||||
|
///
|
||||||
|
/// \param[in] outletSegment Segment on branch from which the
|
||||||
|
/// new branch kicks off.
|
||||||
|
void discoverNewBranch(const int branchId,
|
||||||
|
const int kickOffSegment,
|
||||||
|
const int outletSegment);
|
||||||
|
|
||||||
|
/// Split child segments of current segment into groups
|
||||||
|
/// based on their associate branch number.
|
||||||
|
///
|
||||||
|
/// \return Child segment grouping. The \c .first group
|
||||||
|
/// contains child segments associated to branches different to
|
||||||
|
/// that of the current segment. This collection is empty if
|
||||||
|
/// there are no child segments on other branches. The \c
|
||||||
|
/// .second group is the single child segment on the same branch
|
||||||
|
/// as the current segment. This will be \c nullopt if there is
|
||||||
|
/// no such child segment, thus signifiying the end of the
|
||||||
|
/// current branch.
|
||||||
|
std::pair<std::vector<int>, std::optional<int>>
|
||||||
|
characteriseChildSegments() const;
|
||||||
|
|
||||||
|
/// Get current segment object.
|
||||||
|
const Opm::Segment& currentSegment() const;
|
||||||
|
|
||||||
|
/// Get segment object from one-based segment number.
|
||||||
|
///
|
||||||
|
/// \param[in] segNum One-based segment number.
|
||||||
|
///
|
||||||
|
/// \return Segment object corresponding to \p segNum.
|
||||||
|
const Opm::Segment& segment(const int segNum) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Topology::traverseStructure()
|
||||||
|
{
|
||||||
|
this->kickOffSegments_.push(1);
|
||||||
|
|
||||||
|
while (! this->kickOffSegments_.empty()) {
|
||||||
|
this->currentSegment_ = this->kickOffSegments_.front();
|
||||||
|
this->kickOffSegments_.pop();
|
||||||
|
|
||||||
|
this->buildCurrentBranch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Topology::buildCurrentBranch()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
const auto& seg = this->currentSegment();
|
||||||
|
|
||||||
|
this->runNewSegmentCallback_(seg);
|
||||||
|
|
||||||
|
const auto& [newBranchChildren, sameBranchChild] =
|
||||||
|
this->characteriseChildSegments();
|
||||||
|
|
||||||
|
this->discoverNewBranches(seg.segmentNumber(), newBranchChildren);
|
||||||
|
|
||||||
|
if (sameBranchChild.has_value()) {
|
||||||
|
// Child on same branch as currentSegment(). This child
|
||||||
|
// will be the next segment in our search order.
|
||||||
|
this->currentSegment_ = *sameBranchChild;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Branch completed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Topology::discoverNewBranches(const int outletSegment,
|
||||||
|
const std::vector<int>& children)
|
||||||
|
{
|
||||||
|
for (const auto& child : children) {
|
||||||
|
const auto branch = this->segment(child).branchNumber();
|
||||||
|
this->discoverNewBranch(branch, child, outletSegment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Topology::discoverNewBranch(const int branchId,
|
||||||
|
const int kickOffSegment,
|
||||||
|
const int outletSegment)
|
||||||
|
{
|
||||||
|
this->runNewBranchCallback_(this->well_,
|
||||||
|
branchId,
|
||||||
|
kickOffSegment,
|
||||||
|
outletSegment);
|
||||||
|
|
||||||
|
this->kickOffSegments_.push(kickOffSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<int>, std::optional<int>>
|
||||||
|
Topology::characteriseChildSegments() const
|
||||||
|
{
|
||||||
|
auto children = this->currentSegment().inletSegments();
|
||||||
|
|
||||||
|
auto sameBranchPos =
|
||||||
|
std::stable_partition(children.begin(), children.end(),
|
||||||
|
[this, currBranch = this->currentSegment().branchNumber()]
|
||||||
|
(const int segNum)
|
||||||
|
{
|
||||||
|
return this->segment(segNum).branchNumber() != currBranch;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sameBranchPos == children.end()) {
|
||||||
|
// Every child is on another branch--or there are no children
|
||||||
|
return {
|
||||||
|
std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(std::move(children)),
|
||||||
|
std::forward_as_tuple()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (const auto numSameBranch = std::distance(sameBranchPos, children.end());
|
||||||
|
numSameBranch != std::vector<int>::difference_type{1})
|
||||||
|
{
|
||||||
|
throw std::invalid_argument {
|
||||||
|
fmt::format("Segment {} of well {} has {} "
|
||||||
|
"inlet segments on branch {}",
|
||||||
|
this->currentSegment().segmentNumber(),
|
||||||
|
this->well_, numSameBranch,
|
||||||
|
this->currentSegment().branchNumber())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common case: The segment at *sameBranchPos continues the
|
||||||
|
// current branch. All other child segments start new
|
||||||
|
// branches.
|
||||||
|
return {
|
||||||
|
std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(children.begin(), sameBranchPos),
|
||||||
|
std::forward_as_tuple(*sameBranchPos)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Opm::Segment& Topology::currentSegment() const
|
||||||
|
{
|
||||||
|
return this->segment(this->currentSegment_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Opm::Segment& Topology::segment(const int segNum) const
|
||||||
|
{
|
||||||
|
return this->segSet_.get().getFromSegmentNumber(segNum);
|
||||||
|
}
|
||||||
|
} // LateralBranch
|
||||||
|
|
||||||
namespace ILBS {
|
namespace ILBS {
|
||||||
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
|
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
|
||||||
@ -922,70 +1211,46 @@ namespace {
|
|||||||
WV::WindowSize{ entriesPerMSW(inteHead) }
|
WV::WindowSize{ entriesPerMSW(inteHead) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ILBSArray>
|
|
||||||
void staticContrib(const Opm::Well& well,
|
|
||||||
ILBSArray& iLBS)
|
|
||||||
{
|
|
||||||
if (well.isMultiSegment()) {
|
|
||||||
//
|
|
||||||
// Store the segment number of the first segment in branch for branch number
|
|
||||||
// 2 and upwards
|
|
||||||
const auto& welSegSet = well.getSegments();
|
|
||||||
const auto& branches = SegmentSetBranches(welSegSet);
|
|
||||||
for (auto it = branches.begin()+1; it != branches.end(); it++){
|
|
||||||
iLBS[*it-2] = welSegSet[firstSegmentInBranch(welSegSet, *it)].segmentNumber();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw std::invalid_argument("No such multisegment well: " + well.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // ILBS
|
} // ILBS
|
||||||
|
|
||||||
namespace ILBR {
|
namespace ILBR {
|
||||||
std::size_t entriesPerMSW(const std::vector<int>& inteHead)
|
class Array
|
||||||
{
|
{
|
||||||
// inteHead(177) = NLBRMX
|
public:
|
||||||
// inteHead(180) = NILBRZ
|
using Matrix = Opm::RestartIO::Helpers::WindowedMatrix<int>;
|
||||||
return inteHead[177] * inteHead[180];
|
|
||||||
|
explicit Array(Matrix& ilbr,
|
||||||
|
const Matrix::Idx msWellID)
|
||||||
|
: ilbr_ { std::ref(ilbr) }
|
||||||
|
, well_ { msWellID }
|
||||||
|
{}
|
||||||
|
|
||||||
|
decltype(auto) operator[](const Matrix::Idx branch)
|
||||||
|
{
|
||||||
|
return this->ilbr_.get()(this->well_, branch - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::reference_wrapper<Matrix> ilbr_;
|
||||||
|
Matrix::Idx well_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t maxBranchesPerMSWell(const std::vector<int>& inteHead)
|
||||||
|
{
|
||||||
|
return inteHead[177];
|
||||||
}
|
}
|
||||||
|
|
||||||
Opm::RestartIO::Helpers::WindowedArray<int>
|
Opm::RestartIO::Helpers::WindowedMatrix<int>
|
||||||
allocate(const std::vector<int>& inteHead)
|
allocate(const std::vector<int>& inteHead)
|
||||||
{
|
{
|
||||||
using WV = Opm::RestartIO::Helpers::WindowedArray<int>;
|
using WM = Opm::RestartIO::Helpers::WindowedMatrix<int>;
|
||||||
|
|
||||||
return WV {
|
return WM {
|
||||||
WV::NumWindows{ nswlmx(inteHead) },
|
WM::NumRows { nswlmx(inteHead) },
|
||||||
WV::WindowSize{ entriesPerMSW(inteHead) }
|
WM::NumCols { maxBranchesPerMSWell(inteHead) },
|
||||||
|
WM::WindowSize{ nilbrz(inteHead) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ILBRArray>
|
|
||||||
void staticContrib(const Opm::Well& well,
|
|
||||||
const std::vector<int>& inteHead,
|
|
||||||
ILBRArray& iLBR)
|
|
||||||
{
|
|
||||||
if (well.isMultiSegment()) {
|
|
||||||
//
|
|
||||||
const auto& welSegSet = well.getSegments();
|
|
||||||
const auto& branches = SegmentSetBranches(welSegSet);
|
|
||||||
const auto& noElmBranch = nilbrz(inteHead);
|
|
||||||
for (auto it = branches.begin(); it != branches.end(); it++){
|
|
||||||
const auto iB = (*it-1)*noElmBranch;
|
|
||||||
const auto& branchParam = getBranchSegmentParam(welSegSet, *it);
|
|
||||||
iLBR[iB ] = branchParam.outletS;
|
|
||||||
iLBR[iB+1] = branchParam.noSegInBranch;
|
|
||||||
iLBR[iB+2] = branchParam.firstSeg;
|
|
||||||
iLBR[iB+3] = branchParam.lastSeg;
|
|
||||||
iLBR[iB+4] = branchParam.branch - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw std::invalid_argument("No such multisegment well: " + well.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // ILBR
|
} // ILBR
|
||||||
|
|
||||||
} // Anonymous
|
} // Anonymous
|
||||||
@ -1004,60 +1269,90 @@ AggregateMSWData(const std::vector<int>& inteHead)
|
|||||||
|
|
||||||
void
|
void
|
||||||
Opm::RestartIO::Helpers::AggregateMSWData::
|
Opm::RestartIO::Helpers::AggregateMSWData::
|
||||||
captureDeclaredMSWData(const Schedule& sched,
|
captureDeclaredMSWData(const Schedule& sched,
|
||||||
const std::size_t rptStep,
|
const std::size_t rptStep,
|
||||||
const Opm::UnitSystem& units,
|
const Opm::UnitSystem& units,
|
||||||
const std::vector<int>& inteHead,
|
const std::vector<int>& inteHead,
|
||||||
const Opm::EclipseGrid& grid,
|
const Opm::EclipseGrid& grid,
|
||||||
const Opm::SummaryState& smry,
|
const Opm::SummaryState& smry,
|
||||||
const Opm::data::Wells& wr
|
const Opm::data::Wells& wr)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
const auto& wells = sched.getWells(rptStep);
|
const auto& wells = sched.getWells(rptStep);
|
||||||
auto msw = std::vector<const Opm::Well*>{};
|
auto msw = std::vector<const Opm::Well*>{};
|
||||||
|
|
||||||
//msw.reserve(wells.size());
|
|
||||||
for (const auto& well : wells) {
|
for (const auto& well : wells) {
|
||||||
if (well.isMultiSegment())
|
if (well.isMultiSegment()) {
|
||||||
msw.push_back(&well);
|
msw.push_back(&well);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Extract Contributions to ISeg Array
|
|
||||||
{
|
|
||||||
MSWLoop(msw, [&inteHead, this]
|
|
||||||
(const Well& well, const std::size_t mswID) -> void
|
|
||||||
{
|
|
||||||
auto imsw = this->iSeg_[mswID];
|
|
||||||
|
|
||||||
ISeg::staticContrib(well, inteHead, imsw);
|
// Extract contributions to the ISEG and RSEG arrays.
|
||||||
});
|
MSWLoop(msw, [&units, &inteHead, &sched, &grid, &smry, &wr, this]
|
||||||
}
|
(const Well& well, const std::size_t mswID)
|
||||||
// Extract Contributions to RSeg Array
|
|
||||||
{
|
{
|
||||||
MSWLoop(msw, [&units, &inteHead, &sched, &grid, &smry, this, &wr]
|
auto imsw = this->iSeg_[mswID];
|
||||||
(const Well& well, const std::size_t mswID) -> void
|
auto rmsw = this->rSeg_[mswID];
|
||||||
{
|
|
||||||
auto rmsw = this->rSeg_[mswID];
|
|
||||||
RSeg::staticContrib_useMSW(sched.runspec(), well, inteHead, grid, units, smry, wr, rmsw);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Extract Contributions to ILBS Array
|
|
||||||
{
|
|
||||||
MSWLoop(msw, [this]
|
|
||||||
(const Well& well, const std::size_t mswID) -> void
|
|
||||||
{
|
|
||||||
auto ilbs_msw = this->iLBS_[mswID];
|
|
||||||
|
|
||||||
ILBS::staticContrib(well, ilbs_msw);
|
ISeg::staticContrib(well, inteHead, imsw);
|
||||||
});
|
RSeg::staticContrib_useMSW(sched.runspec(), well, inteHead,
|
||||||
}
|
grid, units, smry, wr, rmsw);
|
||||||
// Extract Contributions to ILBR Array
|
});
|
||||||
{
|
|
||||||
MSWLoop(msw, [&inteHead, this]
|
|
||||||
(const Well& well, const std::size_t mswID) -> void
|
|
||||||
{
|
|
||||||
auto ilbr_msw = this->iLBR_[mswID];
|
|
||||||
|
|
||||||
ILBR::staticContrib(well, inteHead, ilbr_msw);
|
// Extract contributions to the ILBS and ILBR arrays.
|
||||||
});
|
MSWLoop(msw, [this](const Well& well, const std::size_t mswID)
|
||||||
}
|
{
|
||||||
|
using Ix = VectorItems::ILbr::index;
|
||||||
|
|
||||||
|
auto ilbs = this->iLBS_[mswID];
|
||||||
|
auto ilbr = ILBR::Array { this->iLBR_, mswID };
|
||||||
|
|
||||||
|
// The top segment (segment 1) is always the first segment of branch
|
||||||
|
// 1, at an offset of 0 with no outlet segment. Describe it as such.
|
||||||
|
ilbr[1][Ix::OutletSegment] = 0;
|
||||||
|
ilbr[1][Ix::NumBranchSegments] = 0;
|
||||||
|
ilbr[1][Ix::FirstSegment] = 1;
|
||||||
|
ilbr[1][Ix::KickOffDiscoveryOffset] = 0;
|
||||||
|
|
||||||
|
LateralBranch::Topology { well.name(), well.getSegments() }
|
||||||
|
.setNewSegmentCallback([&ilbr](const Segment& seg)
|
||||||
|
{
|
||||||
|
auto currBranch = ilbr[seg.branchNumber()];
|
||||||
|
|
||||||
|
// Attribute 'seg' to current branch. The LastSegment is
|
||||||
|
// intentionally updated on every call since every new
|
||||||
|
// segment is the last segment along the branch until it
|
||||||
|
// isn't anymore.
|
||||||
|
//
|
||||||
|
// We do it this way since the branch traversal visits each
|
||||||
|
// segment exactly once.
|
||||||
|
currBranch[Ix::LastSegment] = seg.segmentNumber();
|
||||||
|
currBranch[Ix::NumBranchSegments] += 1;
|
||||||
|
})
|
||||||
|
.setNewBranchCallback([&ilbr, &ilbs, insertIndex = 0]
|
||||||
|
(std::string_view wellName,
|
||||||
|
const int newBranchId,
|
||||||
|
const int kickOffSegment,
|
||||||
|
const int outletSegment) mutable
|
||||||
|
{
|
||||||
|
ilbs[insertIndex] = kickOffSegment;
|
||||||
|
|
||||||
|
auto newBranch = ilbr[newBranchId];
|
||||||
|
|
||||||
|
// Add one to the kick-off discovery offset to account for
|
||||||
|
// branch 1 which is not in ILBS.
|
||||||
|
newBranch[Ix::OutletSegment] = outletSegment;
|
||||||
|
newBranch[Ix::FirstSegment] = kickOffSegment;
|
||||||
|
newBranch[Ix::KickOffDiscoveryOffset] = insertIndex + 1;
|
||||||
|
|
||||||
|
if (newBranch[Ix::NumBranchSegments] > 0) {
|
||||||
|
throw std::invalid_argument {
|
||||||
|
fmt::format("Looped branch {} for well {} "
|
||||||
|
"is not supported", newBranchId, wellName)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
++insertIndex;
|
||||||
|
})
|
||||||
|
.traverseStructure();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -18,41 +18,50 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define BOOST_TEST_MODULE Aggregate_MSW_Data
|
#define BOOST_TEST_MODULE Aggregate_MSW_Data
|
||||||
|
|
||||||
#include <opm/output/eclipse/AggregateMSWData.hpp>
|
#include <opm/output/eclipse/AggregateMSWData.hpp>
|
||||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <opm/output/eclipse/AggregateWellData.hpp>
|
|
||||||
#include <opm/input/eclipse/Python/Python.hpp>
|
|
||||||
|
|
||||||
#include <opm/output/eclipse/VectorItems/intehead.hpp>
|
#include <opm/output/eclipse/VectorItems/intehead.hpp>
|
||||||
#include <opm/output/eclipse/VectorItems/well.hpp>
|
|
||||||
#include <opm/output/eclipse/VectorItems/msw.hpp>
|
#include <opm/output/eclipse/VectorItems/msw.hpp>
|
||||||
|
#include <opm/output/eclipse/VectorItems/well.hpp>
|
||||||
|
|
||||||
|
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||||
|
|
||||||
#include <opm/output/data/Wells.hpp>
|
#include <opm/output/data/Wells.hpp>
|
||||||
|
|
||||||
#include <opm/io/eclipse/rst/segment.hpp>
|
#include <opm/io/eclipse/rst/segment.hpp>
|
||||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
|
||||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
|
||||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||||
|
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||||
|
|
||||||
#include <opm/common/utility/TimeService.hpp>
|
#include <opm/common/utility/TimeService.hpp>
|
||||||
|
|
||||||
#include <exception>
|
#include <opm/input/eclipse/Python/Python.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
|
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
|
||||||
|
|
||||||
Opm::Deck first_sim(std::string fname) {
|
Opm::Deck first_sim(const std::string& fname)
|
||||||
return Opm::Parser {} .parseFile(fname);
|
{
|
||||||
|
return Opm::Parser {}.parseFile(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opm::SummaryState sim_state()
|
Opm::SummaryState sim_state()
|
||||||
@ -92,6 +101,7 @@ Opm::SummaryState sim_state()
|
|||||||
state.update_well_var("WINJ", "WBHP", 234.);
|
state.update_well_var("WINJ", "WBHP", 234.);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
Opm::data::Wells wr()
|
Opm::data::Wells wr()
|
||||||
{
|
{
|
||||||
using o = ::Opm::data::Rates::opt;
|
using o = ::Opm::data::Rates::opt;
|
||||||
@ -142,21 +152,110 @@ Opm::data::Wells wr()
|
|||||||
}
|
}
|
||||||
return xw;
|
return xw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------+
|
||||||
|
// Models a multi-lateral well with the following segment structure |
|
||||||
|
//------------------------------------------------------------------+
|
||||||
|
// |
|
||||||
|
// 12 13 14 15 16 |
|
||||||
|
// o----o----o-----o------o-----o (2) |
|
||||||
|
// 11 / 20 \ 21 \ |
|
||||||
|
// / o o (6) |
|
||||||
|
// / \ |
|
||||||
|
// / 22 \ 23 24 |
|
||||||
|
// 1 2 3 / 4 5 6 o----o----o (5) |
|
||||||
|
// ---o---o---o-----o---o---o (1) |
|
||||||
|
// \ |
|
||||||
|
// 7 \ 8 9 10 |
|
||||||
|
// o---o---o-----o (3) |
|
||||||
|
// \ |
|
||||||
|
// 17 \ 18 19 |
|
||||||
|
// o----o----o (4) |
|
||||||
|
//------------------------------------------------------------------+
|
||||||
|
// Branch (1): 1, 2, 3, 4, 5, 6 |
|
||||||
|
// Branch (2): 11, 12, 13, 14, 15, 16 |
|
||||||
|
// Branch (3): 7, 8, 9, 10 |
|
||||||
|
// Branch (4): 17, 18, 19 |
|
||||||
|
// Branch (5): 20, 22, 23, 24 |
|
||||||
|
// Branch (6): 21 |
|
||||||
|
//------------------------------------------------------------------+
|
||||||
|
Opm::Deck multilaterals()
|
||||||
|
{
|
||||||
|
return Opm::Parser{}.parseString(R"(RUNSPEC
|
||||||
|
START
|
||||||
|
29 'SEP' 2023 /
|
||||||
|
DIMENS
|
||||||
|
10 10 3 /
|
||||||
|
OIL
|
||||||
|
GAS
|
||||||
|
WATER
|
||||||
|
DISGAS
|
||||||
|
VAPOIL
|
||||||
|
GRID
|
||||||
|
DXV
|
||||||
|
10*100.0 /
|
||||||
|
DYV
|
||||||
|
10*100.0 /
|
||||||
|
DZV
|
||||||
|
3*5.0 /
|
||||||
|
PERMX
|
||||||
|
300*100.0 /
|
||||||
|
COPY
|
||||||
|
PERMX PERMY /
|
||||||
|
PERMX PERMZ /
|
||||||
|
/
|
||||||
|
MULTIPLY
|
||||||
|
PERMZ 0.1 /
|
||||||
|
/
|
||||||
|
PORO
|
||||||
|
300*0.3 /
|
||||||
|
DEPTHZ
|
||||||
|
121*2000.0 /
|
||||||
|
SCHEDULE
|
||||||
|
WELSPECS
|
||||||
|
'MLP' 'G' 10 10 2002.5 'OIL' /
|
||||||
|
/
|
||||||
|
COMPDAT
|
||||||
|
'MLP' 10 10 3 3 'OPEN' 1* 123.4 /
|
||||||
|
/
|
||||||
|
WELSEGS
|
||||||
|
'MLP' 2002.5 0.0 1* 'INC' 'H--' /
|
||||||
|
--
|
||||||
|
2 6 1 1 0.1 0.1 0.2 0.01 /
|
||||||
|
7 10 3 5 0.1 0.1 0.2 0.01 /
|
||||||
|
11 16 2 3 0.1 0.1 0.2 0.01 /
|
||||||
|
17 19 4 10 0.1 0.1 0.2 0.01 /
|
||||||
|
20 20 5 14 0.1 0.1 0.2 0.01 /
|
||||||
|
21 21 6 15 0.1 0.1 0.2 0.01 /
|
||||||
|
22 24 5 20 0.1 0.1 0.2 0.01 /
|
||||||
|
/
|
||||||
|
COMPSEGS
|
||||||
|
'MLP' /
|
||||||
|
--
|
||||||
|
10 10 3 5 0.0 1.0 'Z' /
|
||||||
|
/
|
||||||
|
WCONPROD
|
||||||
|
'MLP' 'OPEN' 'ORAT' 321.0 4* 10.0 /
|
||||||
|
/
|
||||||
|
TSTEP
|
||||||
|
5*30 /
|
||||||
|
END
|
||||||
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
struct SimulationCase
|
struct SimulationCase
|
||||||
{
|
{
|
||||||
explicit SimulationCase(const Opm::Deck& deck)
|
explicit SimulationCase(const Opm::Deck& deck)
|
||||||
: es ( deck )
|
: es (deck)
|
||||||
, grid ( deck )
|
, grid (deck)
|
||||||
, python( std::make_shared<Opm::Python>() )
|
, sched(deck, es, std::make_shared<Opm::Python>())
|
||||||
, sched( deck, es, python )
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Order requirement: 'es' must be declared/initialised before 'sched'.
|
// Order requirement: 'es' must be declared/initialised before 'sched'.
|
||||||
Opm::EclipseState es;
|
Opm::EclipseState es;
|
||||||
Opm::EclipseGrid grid;
|
Opm::EclipseGrid grid;
|
||||||
std::shared_ptr<Opm::Python> python;
|
|
||||||
Opm::Schedule sched;
|
Opm::Schedule sched;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,7 +263,6 @@ struct SimulationCase
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(Aggregate_MSW)
|
BOOST_AUTO_TEST_SUITE(Aggregate_MSW)
|
||||||
|
|
||||||
|
|
||||||
// test dimensions of multisegment data
|
// test dimensions of multisegment data
|
||||||
BOOST_AUTO_TEST_CASE (Constructor)
|
BOOST_AUTO_TEST_CASE (Constructor)
|
||||||
{
|
{
|
||||||
@ -191,46 +289,36 @@ BOOST_AUTO_TEST_CASE (Constructor)
|
|||||||
const auto nrsegz = VI::intehead::NRSEGZ;
|
const auto nrsegz = VI::intehead::NRSEGZ;
|
||||||
const auto nlbrmx = VI::intehead::NLBRMX;
|
const auto nlbrmx = VI::intehead::NLBRMX;
|
||||||
const auto nilbrz = VI::intehead::NILBRZ;
|
const auto nilbrz = VI::intehead::NILBRZ;
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getISeg().size()), ih[nswlmx] * ih[nsegmx] * ih[nisegz]);
|
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getISeg().size()), ih[nswlmx] * ih[nsegmx] * ih[nisegz]);
|
||||||
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getRSeg().size()), ih[nswlmx] * ih[nsegmx] * ih[nrsegz]);
|
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getRSeg().size()), ih[nswlmx] * ih[nsegmx] * ih[nrsegz]);
|
||||||
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getILBs().size()), ih[nswlmx] * ih[nlbrmx]);
|
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getILBs().size()), ih[nswlmx] * ih[nlbrmx]);
|
||||||
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getILBr().size()), ih[nswlmx] * ih[nlbrmx] * ih[nilbrz]);
|
BOOST_CHECK_EQUAL(static_cast<int>(amswd.getILBr().size()), ih[nswlmx] * ih[nlbrmx] * ih[nilbrz]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE (Declared_MSW_Data)
|
BOOST_AUTO_TEST_CASE (Declared_MSW_Data)
|
||||||
{
|
{
|
||||||
|
|
||||||
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};
|
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};
|
||||||
|
|
||||||
Opm::EclipseState es = simCase.es;
|
const auto& es = simCase.es;
|
||||||
Opm::Runspec rspec = es.runspec();
|
const auto& grid = simCase.grid;
|
||||||
Opm::SummaryState smry = sim_state();
|
const auto& sched = simCase.sched;
|
||||||
Opm::Schedule sched = simCase.sched;
|
const auto& units = es.getUnits();
|
||||||
Opm::EclipseGrid grid = simCase.grid;
|
const auto smry = sim_state();
|
||||||
const auto& units = es.getUnits();
|
|
||||||
|
|
||||||
|
|
||||||
// Report Step 1: 2008-10-10 --> 2011-01-20
|
// Report Step 1: 2008-10-10 --> 2011-01-20
|
||||||
const auto rptStep = std::size_t {1};
|
const auto rptStep = std::size_t {1};
|
||||||
|
|
||||||
double secs_elapsed = 3.1536E07;
|
const double secs_elapsed = 3.1536E07;
|
||||||
const auto ih = Opm::RestartIO::Helpers::
|
const auto ih = Opm::RestartIO::Helpers::
|
||||||
createInteHead(es, grid, sched, secs_elapsed,
|
createInteHead(es, grid, sched, secs_elapsed,
|
||||||
rptStep, rptStep+1, rptStep);
|
rptStep, rptStep + 1, rptStep);
|
||||||
|
|
||||||
//BOOST_CHECK_EQUAL(ih.nwells, MockIH::Sz{2});
|
|
||||||
|
|
||||||
const Opm::data::Wells wrc = wr();
|
const Opm::data::Wells wrc = wr();
|
||||||
|
|
||||||
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
||||||
amswd.captureDeclaredMSWData(simCase.sched,
|
amswd.captureDeclaredMSWData(sched, rptStep, units,
|
||||||
rptStep,
|
ih, grid, smry, wrc);
|
||||||
units,
|
|
||||||
ih,
|
|
||||||
grid,
|
|
||||||
smry,
|
|
||||||
wrc
|
|
||||||
);
|
|
||||||
|
|
||||||
// ISEG (PROD)
|
// ISEG (PROD)
|
||||||
{
|
{
|
||||||
@ -409,39 +497,214 @@ BOOST_AUTO_TEST_CASE (Declared_MSW_Data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The segments and branches must appear in the following order in the
|
||||||
|
// ILBS/ILBR output arrays.
|
||||||
|
//
|
||||||
|
// 1, 2, 3, 4, 5, 6 -- Branch (1)
|
||||||
|
// 11, 12, 13, 14, 15, 16 -- Branch (2)
|
||||||
|
// 7, 8, 9, 10 -- Branch (3)
|
||||||
|
// 20, 22, 23, 24 -- Branch (5)
|
||||||
|
// 21, -- Branch (6)
|
||||||
|
// 17, 18, 19 -- Branch (4)
|
||||||
|
//
|
||||||
|
BOOST_AUTO_TEST_CASE(Multilateral_Branches)
|
||||||
|
{
|
||||||
|
const auto cse = SimulationCase { multilaterals() };
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(MSW_AICD) {
|
const auto& es = cse.es;
|
||||||
|
const auto& grid = cse.grid;
|
||||||
|
const auto& sched = cse.sched;
|
||||||
|
const auto& units = es.getUnits();
|
||||||
|
const auto smry = Opm::SummaryState { Opm::TimeService::now() };
|
||||||
|
|
||||||
|
// Report Step 1: 2023-09-29 --> 2023-10-23
|
||||||
|
const auto rptStep = std::size_t {1};
|
||||||
|
|
||||||
|
const double secs_elapsed = 30 * 86'400.0;
|
||||||
|
const auto ih = Opm::RestartIO::Helpers::
|
||||||
|
createInteHead(es, grid, sched, secs_elapsed,
|
||||||
|
rptStep, rptStep + 1, rptStep);
|
||||||
|
|
||||||
|
const auto xw = Opm::data::Wells {};
|
||||||
|
|
||||||
|
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
||||||
|
amswd.captureDeclaredMSWData(sched, rptStep, units,
|
||||||
|
ih, grid, smry, xw);
|
||||||
|
|
||||||
|
// ILBS--First segment on each branch other than branch 1. Ordered by
|
||||||
|
// discovery.
|
||||||
|
{
|
||||||
|
const auto& ilbs = amswd.getILBs();
|
||||||
|
|
||||||
|
// No WSEGDIMS => size = maximum branch number
|
||||||
|
BOOST_CHECK_EQUAL(ilbs.size(), std::vector<int>::size_type{6});
|
||||||
|
|
||||||
|
const auto expect = std::vector {
|
||||||
|
11, 7, 20, 21, 17, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(ilbs .begin(), ilbs .end(),
|
||||||
|
expect.begin(), expect.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ilbrOffset = [&ih](const int branch)
|
||||||
|
{
|
||||||
|
return ih[VI::intehead::NILBRZ] * (branch - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ILBR, branch 1
|
||||||
|
{
|
||||||
|
const auto* ilbr = &amswd.getILBr()[ilbrOffset(1)];
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::OutletSegment], 0);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::NumBranchSegments], 6);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::FirstSegment], 1);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::LastSegment], 6);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::KickOffDiscoveryOffset], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ILBR, branch 2
|
||||||
|
{
|
||||||
|
const auto* ilbr = &amswd.getILBr()[ilbrOffset(2)];
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::OutletSegment], 3);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::NumBranchSegments], 6);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::FirstSegment], 11);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::LastSegment], 16);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::KickOffDiscoveryOffset], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ILBR, branch 3
|
||||||
|
{
|
||||||
|
const auto* ilbr = &amswd.getILBr()[ilbrOffset(3)];
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::OutletSegment], 5);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::NumBranchSegments], 4);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::FirstSegment], 7);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::LastSegment], 10);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::KickOffDiscoveryOffset], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ILBR, branch 4
|
||||||
|
{
|
||||||
|
const auto* ilbr = &amswd.getILBr()[ilbrOffset(4)];
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::OutletSegment], 10);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::NumBranchSegments], 3);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::FirstSegment], 17);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::LastSegment], 19);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::KickOffDiscoveryOffset], 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ILBR, branch 5
|
||||||
|
{
|
||||||
|
const auto* ilbr = &amswd.getILBr()[ilbrOffset(5)];
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::OutletSegment], 14);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::NumBranchSegments], 4);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::FirstSegment], 20);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::LastSegment], 24);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::KickOffDiscoveryOffset], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ILBR, branch 6
|
||||||
|
{
|
||||||
|
const auto* ilbr = &amswd.getILBr()[ilbrOffset(6)];
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::OutletSegment], 15);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::NumBranchSegments], 1);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::FirstSegment], 21);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::LastSegment], 21);
|
||||||
|
BOOST_CHECK_EQUAL(ilbr[VI::ILbr::KickOffDiscoveryOffset], 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The segments must appear in the following depth first search toe-to-heel
|
||||||
|
// order in ISEG[0]. We furthermore, go along kick-off branches before
|
||||||
|
// searching the main branch. Note that this order is *different* from
|
||||||
|
// ILBS/ILBR.
|
||||||
|
//
|
||||||
|
// 24, 23, 22, 20, -- Branch (5)
|
||||||
|
// 21, -- Branch (6)
|
||||||
|
// 16, 15, 14, 13, 12, 11, -- Branch (2)
|
||||||
|
// 19, 18, 17, -- Branch (4)
|
||||||
|
// 10, 9, 8, 7, -- Branch (3)
|
||||||
|
// 6, 5, 4, 3, 2, 1, -- Branch (1)
|
||||||
|
//
|
||||||
|
BOOST_AUTO_TEST_CASE(Multilateral_Segments_ISEG_0)
|
||||||
|
{
|
||||||
|
const auto cse = SimulationCase { multilaterals() };
|
||||||
|
|
||||||
|
const auto& es = cse.es;
|
||||||
|
const auto& grid = cse.grid;
|
||||||
|
const auto& sched = cse.sched;
|
||||||
|
const auto& units = es.getUnits();
|
||||||
|
const auto smry = Opm::SummaryState { Opm::TimeService::now() };
|
||||||
|
|
||||||
|
// Report Step 1: 2023-09-29 --> 2023-10-23
|
||||||
|
const auto rptStep = std::size_t {1};
|
||||||
|
|
||||||
|
const double secs_elapsed = 30 * 86'400.0;
|
||||||
|
const auto ih = Opm::RestartIO::Helpers::
|
||||||
|
createInteHead(es, grid, sched, secs_elapsed,
|
||||||
|
rptStep, rptStep + 1, rptStep);
|
||||||
|
|
||||||
|
const auto xw = Opm::data::Wells {};
|
||||||
|
|
||||||
|
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
||||||
|
amswd.captureDeclaredMSWData(sched, rptStep, units,
|
||||||
|
ih, grid, smry, xw);
|
||||||
|
|
||||||
|
auto isegOffset = [&ih](const int ix)
|
||||||
|
{
|
||||||
|
return ih[VI::intehead::NISEGZ] * ix;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto expect = std::vector {
|
||||||
|
24, 23, 22, 20, // Branch (5)
|
||||||
|
21, // Branch (6)
|
||||||
|
16, 15, 14, 13, 12, 11, // Branch (2)
|
||||||
|
19, 18, 17, // Branch (4)
|
||||||
|
10, 9, 8, 7, // Branch (3)
|
||||||
|
6, 5, 4, 3, 2, 1, // Branch (1)
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto& iseg = amswd.getISeg();
|
||||||
|
|
||||||
|
for (auto i = 0*expect.size(); i < expect.size(); ++i) {
|
||||||
|
BOOST_CHECK_MESSAGE(iseg[isegOffset(i)] == expect[i],
|
||||||
|
"ISEG[0](" << i << ") == "
|
||||||
|
<< iseg[isegOffset(i)]
|
||||||
|
<< " differs from expected value "
|
||||||
|
<< expect[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(MSW_AICD)
|
||||||
|
{
|
||||||
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};
|
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};
|
||||||
|
|
||||||
Opm::EclipseState es = simCase.es;
|
const auto& es = simCase.es;
|
||||||
Opm::Runspec rspec = es.runspec();
|
const auto& grid = simCase.grid;
|
||||||
Opm::SummaryState smry = sim_state();
|
const auto& sched = simCase.sched;
|
||||||
Opm::Schedule sched = simCase.sched;
|
const auto& units = es.getUnits();
|
||||||
Opm::EclipseGrid grid = simCase.grid;
|
const auto smry = sim_state();
|
||||||
const auto& units = es.getUnits();
|
|
||||||
|
|
||||||
|
|
||||||
// Report Step 1: 2008-10-10 --> 2011-01-20
|
// Report Step 1: 2008-10-10 --> 2011-01-20
|
||||||
const auto rptStep = std::size_t {1};
|
const auto rptStep = std::size_t {1};
|
||||||
|
|
||||||
double secs_elapsed = 3.1536E07;
|
const double secs_elapsed = 3.1536E07;
|
||||||
const auto ih = Opm::RestartIO::Helpers::
|
const auto ih = Opm::RestartIO::Helpers::
|
||||||
createInteHead(es, grid, sched, secs_elapsed,
|
createInteHead(es, grid, sched, secs_elapsed,
|
||||||
rptStep, rptStep+1, rptStep);
|
rptStep, rptStep + 1, rptStep);
|
||||||
|
|
||||||
|
|
||||||
const Opm::data::Wells wrc = wr();
|
const Opm::data::Wells wrc = wr();
|
||||||
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
|
||||||
amswd.captureDeclaredMSWData(simCase.sched,
|
|
||||||
rptStep,
|
|
||||||
units,
|
|
||||||
ih,
|
|
||||||
grid,
|
|
||||||
smry,
|
|
||||||
wrc
|
|
||||||
);
|
|
||||||
|
|
||||||
// ISEG (PROD)
|
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
||||||
|
amswd.captureDeclaredMSWData(sched, rptStep, units,
|
||||||
|
ih, grid, smry, wrc);
|
||||||
|
|
||||||
|
// ISEG (PROD)
|
||||||
{
|
{
|
||||||
const auto& iSeg = amswd.getISeg();
|
const auto& iSeg = amswd.getISeg();
|
||||||
auto start = 7*ih[VI::intehead::NISEGZ];
|
auto start = 7*ih[VI::intehead::NISEGZ];
|
||||||
@ -507,48 +770,38 @@ BOOST_AUTO_TEST_CASE(MSW_AICD) {
|
|||||||
BOOST_CHECK_CLOSE(rseg[i0 + VI::RSeg::index::flowFractionOilViscosityExponent], 1.01 , 1.0e-10);
|
BOOST_CHECK_CLOSE(rseg[i0 + VI::RSeg::index::flowFractionOilViscosityExponent], 1.01 , 1.0e-10);
|
||||||
BOOST_CHECK_CLOSE(rseg[i0 + VI::RSeg::index::flowFractionWaterViscosityExponent], 1.02 , 1.0e-10);
|
BOOST_CHECK_CLOSE(rseg[i0 + VI::RSeg::index::flowFractionWaterViscosityExponent], 1.02 , 1.0e-10);
|
||||||
BOOST_CHECK_CLOSE(rseg[i0 + VI::RSeg::index::flowFractionGasViscosityExponent], 1.03 , 1.0e-10);
|
BOOST_CHECK_CLOSE(rseg[i0 + VI::RSeg::index::flowFractionGasViscosityExponent], 1.03 , 1.0e-10);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(MSW_RST)
|
||||||
BOOST_AUTO_TEST_CASE(MSW_RST) {
|
{
|
||||||
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};
|
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};
|
||||||
|
|
||||||
Opm::EclipseState es = simCase.es;
|
const auto& es = simCase.es;
|
||||||
Opm::Runspec rspec = es.runspec();
|
const auto& grid = simCase.grid;
|
||||||
Opm::SummaryState smry = sim_state();
|
const auto& sched = simCase.sched;
|
||||||
Opm::Schedule sched = simCase.sched;
|
const auto& units = es.getUnits();
|
||||||
Opm::EclipseGrid grid = simCase.grid;
|
const auto smry = sim_state();
|
||||||
const auto& units = es.getUnits();
|
|
||||||
|
|
||||||
|
|
||||||
// Report Step 1: 2008-10-10 --> 2011-01-20
|
// Report Step 1: 2008-10-10 --> 2011-01-20
|
||||||
const auto rptStep = std::size_t {1};
|
const auto rptStep = std::size_t {1};
|
||||||
|
|
||||||
double secs_elapsed = 3.1536E07;
|
const double secs_elapsed = 3.1536E07;
|
||||||
const auto ih = Opm::RestartIO::Helpers::
|
const auto ih = Opm::RestartIO::Helpers::
|
||||||
createInteHead(es, grid, sched, secs_elapsed,
|
createInteHead(es, grid, sched, secs_elapsed,
|
||||||
rptStep, rptStep+1, rptStep);
|
rptStep, rptStep + 1, rptStep);
|
||||||
|
|
||||||
|
|
||||||
const Opm::data::Wells wrc = wr();
|
const Opm::data::Wells wrc = wr();
|
||||||
|
|
||||||
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
|
||||||
amswd.captureDeclaredMSWData(simCase.sched,
|
amswd.captureDeclaredMSWData(sched, rptStep, units,
|
||||||
rptStep,
|
ih, grid, smry, wrc);
|
||||||
units,
|
|
||||||
ih,
|
|
||||||
grid,
|
|
||||||
smry,
|
|
||||||
wrc
|
|
||||||
);
|
|
||||||
|
|
||||||
const auto& iseg = amswd.getISeg();
|
const auto& iseg = amswd.getISeg();
|
||||||
const auto& rseg = amswd.getRSeg();
|
const auto& rseg = amswd.getRSeg();
|
||||||
auto segment = Opm::RestartIO::RstSegment(simCase.es.getUnits(), 1, iseg.data(), rseg.data());
|
|
||||||
|
auto segment = Opm::RestartIO::RstSegment(simCase.es.getUnits(), 1,
|
||||||
|
iseg.data(), rseg.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END() // Aggregate_MSW
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
|
||||||
|
Loading…
Reference in New Issue
Block a user